]> 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.
 
        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
        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,
        (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.
 
        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"
 */
 
 #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)
 {
                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;
 
        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;
                }
                {
                        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;
                }
                {
                        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)
 {
        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;
        }
        {
                *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)
 }
 
 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;
 }
 
        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)
 {
                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;
 
        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;
                }
                {
                        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;
                }
                {
                        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;
 }
 
        return 0;
 }
 
-size_t utf16_length(const le16_t* str)
+size_t exfat_utf16_length(const le16_t* str)
 {
        size_t i = 0;
 
 {
        size_t i = 0;