]> git.sven.stormbind.net Git - sven/fuse-exfat.git/blobdiff - libexfat/utf.c
New upstream version 1.3.0+git20220115
[sven/fuse-exfat.git] / libexfat / utf.c
index fd16fe96410aa6786ade00f1cdb218bef5faa457..96f4608c8250f925993cc35e17dd820c1f9ea193 100644 (file)
@@ -2,11 +2,12 @@
        utf.c (13.09.09)
        exFAT file system implementation library.
 
-       Copyright (C) 2010-2013  Andrew Nayenko
+       Free exFAT implementation.
+       Copyright (C) 2010-2018  Andrew Nayenko
 
-       This program is free software: you can redistribute it and/or modify
+       This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
-       the Free Software Foundation, either version 3 of the License, or
+       the Free Software Foundation, either version 2 of the License, or
        (at your option) any later version.
 
        This program is distributed in the hope that it will be useful,
@@ -14,8 +15,9 @@
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
 
-       You should have received a copy of the GNU General Public License
-       along with this program.  If not, see <http://www.gnu.org/licenses/>.
+       You should have received a copy of the GNU General Public License along
+       with this program; if not, write to the Free Software Foundation, Inc.,
+       51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
 #include "exfat.h"
@@ -99,81 +101,95 @@ static const le16_t* utf16_to_wchar(const le16_t* input, wchar_t* wc,
        }
 }
 
-int utf16_to_utf8(char* output, const le16_t* input, size_t outsize,
+int exfat_utf16_to_utf8(char* output, const le16_t* input, size_t outsize,
                size_t insize)
 {
-       const le16_t* inp = input;
-       char* outp = output;
+       const le16_t* iptr = input;
+       const le16_t* iend = input + insize;
+       char* optr = output;
+       const char* oend = output + outsize;
        wchar_t wc;
 
-       while (inp - input < insize && le16_to_cpu(*inp))
+       while (iptr < iend)
        {
-               inp = utf16_to_wchar(inp, &wc, insize - (inp - input));
-               if (inp == NULL)
+               iptr = utf16_to_wchar(iptr, &wc, iend - iptr);
+               if (iptr == NULL)
                {
                        exfat_error("illegal UTF-16 sequence");
                        return -EILSEQ;
                }
-               outp = wchar_to_utf8(outp, wc, outsize - (outp - output));
-               if (outp == NULL)
+               optr = wchar_to_utf8(optr, wc, oend - optr);
+               if (optr == NULL)
                {
                        exfat_error("name is too long");
                        return -ENAMETOOLONG;
                }
+               if (wc == 0)
+                       return 0;
        }
-       *outp = '\0';
+       if (optr >= oend)
+       {
+               exfat_error("name is too long");
+               return -ENAMETOOLONG;
+       }
+       *optr = '\0';
        return 0;
 }
 
 static const char* utf8_to_wchar(const char* input, wchar_t* wc,
                size_t insize)
 {
-       if ((input[0] & 0x80) == 0 && insize >= 1)
+       size_t size;
+       size_t i;
+
+       if (insize == 0)
+               exfat_bug("no input for utf8_to_wchar");
+
+       if ((input[0] & 0x80) == 0)
        {
                *wc = (wchar_t) input[0];
                return input + 1;
        }
-       if ((input[0] & 0xe0) == 0xc0 && insize >= 2)
+       else if ((input[0] & 0xe0) == 0xc0)
        {
-               *wc = (((wchar_t) input[0] & 0x1f) << 6) |
-                      ((wchar_t) input[1] & 0x3f);
-               return input + 2;
+               *wc = ((wchar_t) input[0] & 0x1f) << 6;
+               size = 2;
+       }
+       else if ((input[0] & 0xf0) == 0xe0)
+       {
+               *wc = ((wchar_t) input[0] & 0x0f) << 12;
+               size = 3;
        }
-       if ((input[0] & 0xf0) == 0xe0 && insize >= 3)
+       else if ((input[0] & 0xf8) == 0xf0)
        {
-               *wc = (((wchar_t) input[0] & 0x0f) << 12) |
-                     (((wchar_t) input[1] & 0x3f) << 6) |
-                      ((wchar_t) input[2] & 0x3f);
-               return input + 3;
+               *wc = ((wchar_t) input[0] & 0x07) << 18;
+               size = 4;
        }
-       if ((input[0] & 0xf8) == 0xf0 && insize >= 4)
+       else if ((input[0] & 0xfc) == 0xf8)
        {
-               *wc = (((wchar_t) input[0] & 0x07) << 18) |
-                     (((wchar_t) input[1] & 0x3f) << 12) |
-                     (((wchar_t) input[2] & 0x3f) << 6) |
-                      ((wchar_t) input[3] & 0x3f);
-               return input + 4;
+               *wc = ((wchar_t) input[0] & 0x03) << 24;
+               size = 5;
        }
-       if ((input[0] & 0xfc) == 0xf8 && insize >= 5)
+       else if ((input[0] & 0xfe) == 0xfc)
        {
-               *wc = (((wchar_t) input[0] & 0x03) << 24) |
-                     (((wchar_t) input[1] & 0x3f) << 18) |
-                     (((wchar_t) input[2] & 0x3f) << 12) |
-                     (((wchar_t) input[3] & 0x3f) << 6) |
-                      ((wchar_t) input[4] & 0x3f);
-               return input + 5;
+               *wc = ((wchar_t) input[0] & 0x01) << 30;
+               size = 6;
        }
-       if ((input[0] & 0xfe) == 0xfc && insize >= 6)
+       else
+               return NULL;
+
+       if (insize < size)
+               return NULL;
+
+       /* the first byte is handled above */
+       for (i = 1; i < size; i++)
        {
-               *wc = (((wchar_t) input[0] & 0x01) << 30) |
-                     (((wchar_t) input[1] & 0x3f) << 24) |
-                     (((wchar_t) input[2] & 0x3f) << 18) |
-                     (((wchar_t) input[3] & 0x3f) << 12) |
-                     (((wchar_t) input[4] & 0x3f) << 6) |
-                      ((wchar_t) input[5] & 0x3f);
-               return input + 6;
+               if ((input[i] & 0xc0) != 0x80)
+                       return NULL;
+               *wc |= (input[i] & 0x3f) << ((size - i - 1) * 6);
        }
-       return NULL;
+
+       return input + size;
 }
 
 static le16_t* wchar_to_utf16(le16_t* output, wchar_t wc, size_t outsize)
@@ -193,33 +209,42 @@ static le16_t* wchar_to_utf16(le16_t* output, wchar_t wc, size_t outsize)
        return output + 2;
 }
 
-int utf8_to_utf16(le16_t* output, const char* input, size_t outsize,
+int exfat_utf8_to_utf16(le16_t* output, const char* input, size_t outsize,
                size_t insize)
 {
-       const char* inp = input;
-       le16_t* outp = output;
+       const char* iptr = input;
+       const char* iend = input + insize;
+       le16_t* optr = output;
+       const le16_t* oend = output + outsize;
        wchar_t wc;
 
-       while (inp - input < insize && *inp)
+       while (iptr < iend)
        {
-               inp = utf8_to_wchar(inp, &wc, insize - (inp - input));
-               if (inp == NULL)
+               iptr = utf8_to_wchar(iptr, &wc, iend - iptr);
+               if (iptr == NULL)
                {
                        exfat_error("illegal UTF-8 sequence");
                        return -EILSEQ;
                }
-               outp = wchar_to_utf16(outp, wc, outsize - (outp - output));
-               if (outp == NULL)
+               optr = wchar_to_utf16(optr, wc, oend - optr);
+               if (optr == NULL)
                {
                        exfat_error("name is too long");
                        return -ENAMETOOLONG;
                }
+               if (wc == 0)
+                       break;
+       }
+       if (optr >= oend)
+       {
+               exfat_error("name is too long");
+               return -ENAMETOOLONG;
        }
-       *outp = cpu_to_le16(0);
+       *optr = cpu_to_le16(0);
        return 0;
 }
 
-size_t utf16_length(const le16_t* str)
+size_t exfat_utf16_length(const le16_t* str)
 {
        size_t i = 0;