]> Chaos Git - corbenik/ctrulib.git/commitdiff
Robustify UTF translation
authorMichael Theall <pigman46@gmail.com>
Thu, 19 Nov 2015 19:49:31 +0000 (13:49 -0600)
committerMichael Theall <pigman46@gmail.com>
Thu, 19 Nov 2015 19:49:31 +0000 (13:49 -0600)
libctru/include/3ds/types.h
libctru/include/3ds/util/utf.h
libctru/source/romfs_dev.c
libctru/source/sdmc_dev.c
libctru/source/util/utf/utf16_to_utf32.c
libctru/source/util/utf/utf16_to_utf8.c
libctru/source/util/utf/utf32_to_utf16.c
libctru/source/util/utf/utf32_to_utf8.c
libctru/source/util/utf/utf8_to_utf16.c
libctru/source/util/utf/utf8_to_utf32.c

index 6fa2dfec667aec60084e3d26604b9b7aa3085f75..fea97e65970916376f2ba7f035acd8fb7d09fe7d 100644 (file)
 /// The maximum value of a u64.
 #define U64_MAX        UINT64_MAX
 
+/// would be nice if newlib had this already
+#ifndef SSIZE_MAX
+#ifdef SIZE_MAX
+#define SSIZE_MAX ((SIZE_MAX) >> 1)
+#endif
+#endif
+
 typedef uint8_t u8;   ///<  8-bit unsigned integer
 typedef uint16_t u16; ///< 16-bit unsigned integer
 typedef uint32_t u32; ///< 32-bit unsigned integer
index bc2966d67de23b383efb91907bcd0e2be3db46c1..c4046660f25fe1658bb47f806425195018781b3c 100644 (file)
@@ -52,61 +52,104 @@ ssize_t encode_utf8 (uint8_t *out, uint32_t in);
 ssize_t encode_utf16(uint16_t *out, uint32_t in);
 
 /** Convert a UTF-8 sequence into a UTF-16 sequence
+ *
+ *  Fills the output buffer up to \a len code units.
+ *  Returns the number of code units that the input would produce;
+ *  if it returns greater than \a len, the output has been
+ *  truncated.
  *
  *  @param[out] out Output sequence
- *  @param[in]  in  Input sequence
+ *  @param[in]  in  Input sequence (null-terminated)
+ *  @param[in]  len Output length
  *
  *  @returns number of output code units produced
  *  @returns -1 for error
+ *
+ *  @note \a out is not null-terminated
  */
-size_t utf8_to_utf16(uint16_t *out, const uint8_t  *in, size_t len);
+ssize_t utf8_to_utf16(uint16_t *out, const uint8_t  *in, size_t len);
 
 /** Convert a UTF-8 sequence into a UTF-32 sequence
+ *
+ *  Fills the output buffer up to \a len code units.
+ *  Returns the number of code units that the input would produce;
+ *  if it returns greater than \a len, the output has been
+ *  truncated.
  *
  *  @param[out] out Output sequence
- *  @param[in]  in  Input sequence
+ *  @param[in]  in  Input sequence (null-terminated)
+ *  @param[in]  len Output length
  *
  *  @returns number of output code units produced
  *  @returns -1 for error
+ *
+ *  @note \a out is not null-terminated
  */
-size_t utf8_to_utf32(uint32_t *out, const uint8_t  *in, size_t len);
+ssize_t utf8_to_utf32(uint32_t *out, const uint8_t  *in, size_t len);
 
 /** Convert a UTF-16 sequence into a UTF-8 sequence
+ *
+ *  Fills the output buffer up to \a len code units.
+ *  Returns the number of code units that the input would produce;
+ *  if it returns greater than \a len, the output has been
+ *  truncated.
  *
  *  @param[out] out Output sequence
- *  @param[in]  in  Input sequence
+ *  @param[in]  in  Input sequence (null-terminated)
+ *  @param[in]  len Output length
  *
  *  @returns number of output code units produced
  *  @returns -1 for error
+ *
+ *  @note \a out is not null-terminated
  */
-size_t utf16_to_utf8(uint8_t  *out, const uint16_t *in, size_t len);
+ssize_t utf16_to_utf8(uint8_t  *out, const uint16_t *in, size_t len);
 
 /** Convert a UTF-16 sequence into a UTF-32 sequence
+ *
+ *  Fills the output buffer up to \a len code units.
+ *  Returns the number of code units that the input would produce;
+ *  if it returns greater than \a len, the output has been
+ *  truncated.
  *
  *  @param[out] out Output sequence
- *  @param[in]  in  Input sequence
+ *  @param[in]  in  Input sequence (null-terminated)
+ *  @param[in]  len Output length
  *
  *  @returns number of output code units produced
  *  @returns -1 for error
+ *
+ *  @note \a out is not null-terminated
  */
-size_t utf16_to_utf32(uint32_t *out, const uint16_t *in, size_t len);
+ssize_t utf16_to_utf32(uint32_t *out, const uint16_t *in, size_t len);
 
 /** Convert a UTF-32 sequence into a UTF-8 sequence
+ *
+ *  Fills the output buffer up to \a len code units.
+ *  Returns the number of code units that the input would produce;
+ *  if it returns greater than \a len, the output has been
+ *  truncated.
  *
  *  @param[out] out Output sequence
- *  @param[in]  in  Input sequence
+ *  @param[in]  in  Input sequence (null-terminated)
+ *  @param[in]  len Output length
  *
  *  @returns number of output code units produced
  *  @returns -1 for error
+ *
+ *  @note \a out is not null-terminated
  */
-size_t utf32_to_utf8(uint8_t  *out, const uint32_t *in, size_t len);
+ssize_t utf32_to_utf8(uint8_t  *out, const uint32_t *in, size_t len);
 
 /** Convert a UTF-32 sequence into a UTF-16 sequence
  *
  *  @param[out] out Output sequence
- *  @param[in]  in  Input sequence
+ *  @param[in]  in  Input sequence (null-terminated)
+ *  @param[in]  len Output length
  *
  *  @returns number of output code units produced
  *  @returns -1 for error
+ *
+ *  @note \a out is not null-terminated
  */
-size_t utf32_to_utf16(uint16_t *out, const uint32_t *in, size_t len);
+ssize_t utf32_to_utf16(uint16_t *out, const uint32_t *in, size_t len);
index 3b25602a812dcdb8866da9045a59cc08fb5413b3..6c502eee755e713b92c5ba5e94d0ed7590e04c08 100644 (file)
@@ -133,8 +133,9 @@ Result romfsInit(void)
                } else
                        return 2;
 
-               size_t units = utf8_to_utf16(__utf16path, (const uint8_t*)filename, PATH_MAX+1);
-               if (units == (size_t)-1) return 3;
+               ssize_t units = utf8_to_utf16(__utf16path, (const uint8_t*)filename, PATH_MAX);
+               if (units < 0)         return 3;
+               if (units >= PATH_MAX) return 4;
                __utf16path[units] = 0;
 
                FS_Archive arch = { ARCHIVE_SDMC, { PATH_EMPTY, 1, (u8*)"" }, 0 };
@@ -284,7 +285,7 @@ static romfs_file* searchForFile(romfs_dir* parent, u16* name, u32 namelen)
 
 static int navigateToDir(romfs_dir** ppDir, const char** pPath, bool isDir)
 {
-       size_t units;
+       ssize_t units;
 
        char* colonPos = strchr(*pPath, ':');
        if (colonPos) *pPath = colonPos+1;
@@ -331,9 +332,11 @@ static int navigateToDir(romfs_dir** ppDir, const char** pPath, bool isDir)
                        }
                }
 
-               units = utf8_to_utf16(__utf16path, (const uint8_t*)component, PATH_MAX+1);
-               if (units == (size_t)-1)
+               units = utf8_to_utf16(__utf16path, (const uint8_t*)component, PATH_MAX);
+               if (units < 0)
                        return EILSEQ;
+               if (units >= PATH_MAX)
+                       return ENAMETOOLONG;
 
                *ppDir = searchForDir(*ppDir, __utf16path, units);
                if (!*ppDir)
@@ -363,12 +366,17 @@ int romfs_open(struct _reent *r, void *fileStruct, const char *path, int flags,
        if (r->_errno != 0)
                return -1;
 
-       size_t units = utf8_to_utf16(__utf16path, (const uint8_t*)path, PATH_MAX+1);
-       if (!units || units == (size_t)-1)
+       ssize_t units = utf8_to_utf16(__utf16path, (const uint8_t*)path, PATH_MAX);
+       if (units <= 0)
        {
                r->_errno = EILSEQ;
                return -1;
        }
+       if (units >= PATH_MAX)
+       {
+               r->_errno = ENAMETOOLONG;
+               return -1;
+       }
 
        romfs_file* file = searchForFile(curDir, __utf16path, units);
        if (!file)
index dc8d1242e09f075d291cca653b7c1f68e91c7ac3..9ef66821c0efb5040b9b76c92e03e2b55faff38c 100644 (file)
@@ -118,7 +118,7 @@ static const char*
 sdmc_fixpath(struct _reent *r,
              const char    *path)
 {
-  size_t        units;
+  ssize_t       units;
   uint32_t      code;
   const uint8_t *p = (const uint8_t*)path;
 
@@ -126,7 +126,7 @@ sdmc_fixpath(struct _reent *r,
   do
   {
     units = decode_utf8(&code, p);
-    if(units == (size_t)-1)
+    if(units < 0)
     {
       r->_errno = EILSEQ;
       return NULL;
@@ -145,7 +145,7 @@ sdmc_fixpath(struct _reent *r,
   do
   {
     units = decode_utf8(&code, p);
-    if(units == (size_t)-1)
+    if(units < 0)
     {
       r->_errno = EILSEQ;
       return NULL;
@@ -182,7 +182,7 @@ static const FS_Path
 sdmc_utf16path(struct _reent *r,
                const char    *path)
 {
-  size_t  units;
+  ssize_t units;
   FS_Path fspath;
 
   fspath.data = NULL;
@@ -190,14 +190,13 @@ sdmc_utf16path(struct _reent *r,
   if(sdmc_fixpath(r, path) == NULL)
     return fspath;
 
-  units = utf8_to_utf16(__utf16path, (const uint8_t*)__fixedpath, PATH_MAX+1);
-  if(units == (size_t)-1)
+  units = utf8_to_utf16(__utf16path, (const uint8_t*)__fixedpath, PATH_MAX);
+  if(units < 0)
   {
     r->_errno = EILSEQ;
     return fspath;
   }
-
-  if(__utf16path[PATH_MAX] != 0)
+  if(units >= PATH_MAX)
   {
     r->_errno = ENAMETOOLONG;
     return fspath;
@@ -220,7 +219,7 @@ static bool sdmcInitialised = false;
 /*! Initialize SDMC device */
 Result sdmcInit(void)
 {
-  size_t   units;
+  ssize_t  units;
   uint32_t code;
   char     *p;
   Result   rc = 0;
@@ -253,7 +252,7 @@ Result sdmcInit(void)
             do
             {
               units = decode_utf8(&code, (const uint8_t*)p);
-              if(units == (size_t)-1)
+              if(units < 0)
               {
                 last_slash = NULL;
                 break;
@@ -909,9 +908,9 @@ sdmc_dirnext(struct _reent *r,
              char          *filename,
              struct stat   *filestat)
 {
-  Result rc;
-  u32    entries;
-  size_t units;
+  Result  rc;
+  u32     entries;
+  ssize_t units;
 
   /* get pointer to our data */
   sdmc_dir_t *dir = (sdmc_dir_t*)(dirState->dirStruct);
@@ -938,13 +937,13 @@ sdmc_dirnext(struct _reent *r,
     /* convert name from UTF-16 to UTF-8 */
     memset(filename, 0, NAME_MAX);
     units = utf16_to_utf8((uint8_t*)filename, dir->entry_data.name, NAME_MAX);
-    if(units == (size_t)-1)
+    if(units < 0)
     {
       r->_errno = EILSEQ;
       return -1;
     }
 
-    if(filename[NAME_MAX-1] != 0)
+    if(units >= NAME_MAX)
     {
       r->_errno = ENAMETOOLONG;
       return -1;
index 9ed21ac7541033440aaddb151bc14619951573f6..3a9c5cec245704a14a4e664af4c1f01b30b348f0 100644 (file)
@@ -1,11 +1,12 @@
+#include "3ds/types.h"
 #include "3ds/util/utf.h"
 
-size_t
+ssize_t
 utf16_to_utf32(uint32_t       *out,
                const uint16_t *in,
                size_t         len)
 {
-  size_t   rc = 0;
+  ssize_t  rc = 0;
   ssize_t  units;
   uint32_t code;
 
@@ -13,7 +14,7 @@ utf16_to_utf32(uint32_t       *out,
   {
     units = decode_utf16(&code, in);
     if(units == -1)
-      return (size_t)-1;
+      return -1;
 
     if(code > 0)
     {
@@ -23,11 +24,12 @@ utf16_to_utf32(uint32_t       *out,
       {
         if(rc < len)
           *out++ = code;
-        else
-          return rc;
       }
 
-      ++rc;
+      if(SSIZE_MAX - 1 <= rc)
+        ++rc;
+      else
+        return -1;
     }
   } while(code > 0);
 
index 3567e6358b4fe66dacaacb2285f12074a020ea6a..9802dd35b65610df92dfc350d681331beae2ddd9 100644 (file)
@@ -1,20 +1,21 @@
+#include "3ds/types.h"
 #include "3ds/util/utf.h"
 
-size_t
+ssize_t
 utf16_to_utf8(uint8_t        *out,
               const uint16_t *in,
               size_t         len)
 {
-  size_t   rc = 0;
+  ssize_t  rc = 0;
   ssize_t  units;
   uint32_t code;
-  uint8_t encoded[4];
+  uint8_t  encoded[4];
 
   do
   {
     units = decode_utf16(&code, in);
     if(units == -1)
-      return (size_t)-1;
+      return -1;
 
     if(code > 0)
     {
@@ -22,7 +23,7 @@ utf16_to_utf8(uint8_t        *out,
 
       units = encode_utf8(encoded, code);
       if(units == -1)
-        return (size_t)-1;
+        return -1;
 
       if(out != NULL)
       {
@@ -36,11 +37,12 @@ utf16_to_utf8(uint8_t        *out,
           if(units > 3)
             *out++ = encoded[3];
         }
-        else
-          return rc;
       }
 
-      rc += units;
+      if(SSIZE_MAX - units <= rc)
+        rc += units;
+      else
+        return -1;
     }
   } while(code > 0);
 
index 81ce2039f1f3a1a98ebd2207d23e30dc83cc4c90..6ac28f3a2e622d1c7f6f3b34e889c9a4c0a68298 100644 (file)
@@ -1,19 +1,20 @@
+#include "3ds/types.h"
 #include "3ds/util/utf.h"
 
-size_t
+ssize_t
 utf32_to_utf16(uint16_t       *out,
                const uint32_t *in,
                size_t         len)
 {
-  size_t   rc = 0;
+  ssize_t  rc = 0;
   ssize_t  units;
-  uint16_t  encoded[2];
+  uint16_t encoded[2];
 
   while(*in > 0)
   {
     units = encode_utf16(encoded, *in++);
     if(units == -1)
-      return (size_t)-1;
+      return -1;
 
     if(out != NULL)
     {
@@ -23,11 +24,12 @@ utf32_to_utf16(uint16_t       *out,
         if(units > 1)
           *out++ = encoded[1];
       }
-      else
-        return rc;
     }
 
-    rc += units;
+    if(SSIZE_MAX - units <= rc)
+      rc += units;
+    else
+      return -1;
   }
 
   return rc;
index 80fc7c5a19749e41636510906603e7c616d1b826..4bfd3570e37bd8c4c2e7621de81f06faca0fc2be 100644 (file)
@@ -1,11 +1,12 @@
+#include "3ds/types.h"
 #include "3ds/util/utf.h"
 
-size_t
+ssize_t
 utf32_to_utf8(uint8_t        *out,
               const uint32_t *in,
               size_t         len)
 {
-  size_t   rc = 0;
+  ssize_t  rc = 0;
   ssize_t  units;
   uint8_t  encoded[4];
 
@@ -13,7 +14,7 @@ utf32_to_utf8(uint8_t        *out,
   {
     units = encode_utf8(encoded, *in++);
     if(units == -1)
-      return (size_t)-1;
+      return -1;
 
     if(out != NULL)
     {
@@ -27,11 +28,12 @@ utf32_to_utf8(uint8_t        *out,
         if(units > 3)
           *out++ = encoded[3];
       }
-      else
-        return rc;
     }
 
-    rc += units;
+    if(SSIZE_MAX - units <= rc)
+      rc += units;
+    else
+      return -1;
   }
 
   return rc;
index 6991b3f2b5c13424c37690167790262e0f78d3df..2a450afe5bb0cc8a40f431dca678fe18ee72b1a9 100644 (file)
@@ -1,11 +1,12 @@
+#include "3ds/types.h"
 #include "3ds/util/utf.h"
 
-size_t
+ssize_t
 utf8_to_utf16(uint16_t      *out,
               const uint8_t *in,
               size_t        len)
 {
-  size_t   rc = 0;
+  ssize_t  rc = 0;
   ssize_t  units;
   uint32_t code;
   uint16_t encoded[2];
@@ -14,7 +15,7 @@ utf8_to_utf16(uint16_t      *out,
   {
     units = decode_utf8(&code, in);
     if(units == -1)
-      return (size_t)-1;
+      return -1;
 
     if(code > 0)
     {
@@ -22,7 +23,7 @@ utf8_to_utf16(uint16_t      *out,
 
       units = encode_utf16(encoded, code);
       if(units == -1)
-        return (size_t)-1;
+        return -1;
 
       if(out != NULL)
       {
@@ -32,11 +33,12 @@ utf8_to_utf16(uint16_t      *out,
           if(units > 1)
             *out++ = encoded[1];
         }
-        else
-          return rc;
       }
 
-      rc += units;
+      if(SSIZE_MAX - units <= rc)
+        rc += units;
+      else
+        return -1;
     }
   } while(code > 0);
 
index fac6acd94cb22196d10fedfc1cbebf4e981a73ce..4a5ba81f7c0b55eaeb59e2f42341603b30dcc9a9 100644 (file)
@@ -1,11 +1,12 @@
+#include "3ds/types.h"
 #include "3ds/util/utf.h"
 
-size_t
+ssize_t
 utf8_to_utf32(uint32_t      *out,
               const uint8_t *in,
               size_t        len)
 {
-  size_t   rc = 0;
+  ssize_t  rc = 0;
   ssize_t  units;
   uint32_t code;
 
@@ -13,7 +14,7 @@ utf8_to_utf32(uint32_t      *out,
   {
     units = decode_utf8(&code, in);
     if(units == -1)
-      return (size_t)-1;
+      return -1;
 
     if(code > 0)
     {
@@ -23,11 +24,12 @@ utf8_to_utf32(uint32_t      *out,
       {
         if(rc < len)
           *out++ = code;
-        else
-          return rc;
       }
 
-      ++rc;
+      if(SSIZE_MAX - 1 <= rc)
+        ++rc;
+      else
+        return -1;
     }
   } while(code > 0);