Explorar o código

extended ascii to uint32 method with overflow protection and a customizable base
added unittests

stefan hai 9 meses
pai
achega
f9dbc35cc6

+ 1 - 0
makefile

@@ -64,6 +64,7 @@ UNITTEST_SOURCES := test/unittest/test_main.cpp
                     test/unittest/shellmatta_opt/test_opt_peekNextHunk.cpp              \
                     test/unittest/shellmatta_utils/test_utils_writeEcho.cpp             \
                     test/unittest/shellmatta_utils/test_utils_shellItoa.cpp             \
+                    test/unittest/shellmatta_utils/test_utils_shellAsciiToUInt32.cpp    \
                     test/unittest/shellmatta_utils/test_utils_saveCursorPos.cpp         \
                     test/unittest/shellmatta_utils/test_utils_restoreCursorPos.cpp      \
                     test/unittest/shellmatta_utils/test_utils_eraseLine.cpp             \

+ 28 - 5
src/shellmatta_utils.c

@@ -93,30 +93,53 @@ uint32_t utils_shellItoa(int32_t value, char *buffer, uint32_t base)
  * @warning     will overflow if number is larger than UINT32_MAX
  * @param[in]   str     pointer to the string
  * @param[out]  result  the value of the string as unsigned 32-bit integer
+ * @param[in]   base    base of the conversion
  * @return      errorcode   #SHELLMATTA_OK
  *                          #SHELLMATTA_USE_FAULT (param err)
  *                          #SHELLMATTA_ERROR (invalid characters)
 */
-shellmatta_retCode_t utils_shellAsciiToUInt32(char* str, uint32_t *result)
+shellmatta_retCode_t utils_shellAsciiToUInt32(char* str, uint32_t *result, uint32_t base)
 {
     shellmatta_retCode_t ret = SHELLMATTA_OK;
     uint32_t val;
 
-    if((NULL != str) && (NULL != result))
+    if((NULL != str) && (NULL != result) && (base <= 16u))
     {
         *result = 0u;
 
         while(*str && (' ' != *str) && (SHELLMATTA_OK == ret))
         {
-            val = ((uint32_t)*str - 48u);
+            /** -# convert character to value */
+            if((*str >= '0') && (*str <= '9'))
+            {
+                val = ((uint32_t)*str - '0');
+            }
+            else if((*str >= 'A') && (*str <= 'F'))
+            {
+                val = ((uint32_t)*str - 'A') + 10u;
+            }
+            else if((*str >= 'a') && (*str <= 'f'))
+            {
+                val = ((uint32_t)*str - 'a') + 10u;
+            }
+            else
+            {
+                ret = SHELLMATTA_ERROR;
+            }
 
-            if(val > 9u)
+            /** -# return error in case the value is outside of the expected base */
+            if(val > (base - 1u))
             {
                 ret = SHELLMATTA_ERROR;
             }
             else
             {
-                *result = (*result * 10u) + val;
+                /** -# check for overflow */
+                if((UINT32_MAX - val) / base < *result)
+                {
+                    ret = SHELLMATTA_ERROR;
+                }
+                *result = (*result * base) + val;
             }
             str ++;
         }

+ 2 - 1
src/shellmatta_utils.h

@@ -115,7 +115,8 @@ uint32_t utils_shellItoa(           int32_t value,
                                     uint32_t base);
 
 shellmatta_retCode_t utils_shellAsciiToUInt32(  char* str,
-                                                uint32_t *result);
+                                                uint32_t *result,
+                                                uint32_t base);
 
 void utils_saveCursorPos(           shellmatta_instance_t *inst);
 

+ 2 - 1
src/shellmatta_ymodem.c

@@ -89,7 +89,8 @@ shellmatta_retCode_t processPacket(shellmatta_handle_t handle)
         fileName = (char*)inst->ymodem.packet.packetData;
 
         ret = utils_shellAsciiToUInt32((char*)&inst->ymodem.packet.packetData[strlen(fileName) + 1u],
-                                       &inst->ymodem.fileSize);
+                                       &inst->ymodem.fileSize,
+                                       10u);
 
         /** -# pass filename and size to the callback */
         inst->ymodem.recvHeaderCallback(inst->ymodem.fileSize, fileName);

+ 156 - 0
test/unittest/shellmatta_utils/test_utils_shellAsciiToUInt32.cpp

@@ -0,0 +1,156 @@
+#include "test/framework/catch.hpp"
+#include "src/shellmatta_utils.c"
+#include <string.h>
+
+SCENARIO("Check utils_shellAsciiToUInt32 with valid strings")
+{
+    GIVEN("Initialized shellmatta utils module")
+    {
+        shellmatta_retCode_t ret;
+        uint32_t result = 0xFFFFFFFFu;
+        WHEN("Passing 123456789 with base 10")
+        {
+            ret = utils_shellAsciiToUInt32((char*)"123456789", &result, 10u);
+            THEN("utils_shellAsciiToUInt32 returns successfully")
+            {
+                CHECK(ret == SHELLMATTA_OK);
+                REQUIRE(result == 123456789);
+            }
+        }
+        WHEN("Passing 4294967295 with base 10")
+        {
+            ret = utils_shellAsciiToUInt32((char*)"4294967295", &result, 10u);
+            THEN("utils_shellAsciiToUInt32 returns successfully")
+            {
+                CHECK(ret == SHELLMATTA_OK);
+                REQUIRE(result == 4294967295);
+            }
+        }
+        WHEN("Passing 110100100001110011100011 with base 2")
+        {
+            ret = utils_shellAsciiToUInt32((char*)"110100100001110011100011", &result, 2u);
+            THEN("utils_shellAsciiToUInt32 returns successfully")
+            {
+                CHECK(ret == SHELLMATTA_OK);
+                REQUIRE(result == 0b110100100001110011100011);
+            }
+        }
+        WHEN("Passing 435476600 with base 8")
+        {
+            ret = utils_shellAsciiToUInt32((char*)"435476600", &result, 8u);
+            THEN("utils_shellAsciiToUInt32 returns successfully")
+            {
+                CHECK(ret == SHELLMATTA_OK);
+                REQUIRE(result == 0435476600);
+            }
+        }
+        WHEN("Passing AABBCCDD with base 16")
+        {
+            ret = utils_shellAsciiToUInt32((char*)"AABBCCDD", &result, 16u);
+            THEN("utils_shellAsciiToUInt32 returns successfully")
+            {
+                CHECK(ret == SHELLMATTA_OK);
+                REQUIRE(result == 0xAABBCCDDu);
+            }
+        }
+        WHEN("Passing deadbeef with base 16")
+        {
+            ret = utils_shellAsciiToUInt32((char*)"deadbeef", &result, 16u);
+            THEN("utils_shellAsciiToUInt32 returns successfully")
+            {
+                CHECK(ret == SHELLMATTA_OK);
+                REQUIRE(result == 0xdeadbeefu);
+            }
+        }
+        WHEN("Passing an empty string with base 16")
+        {
+            ret = utils_shellAsciiToUInt32((char*)"", &result, 16u);
+            THEN("utils_shellAsciiToUInt32 returns successfully")
+            {
+                CHECK(ret == SHELLMATTA_OK);
+                REQUIRE(result == 0u);
+            }
+        }
+    }
+}
+
+SCENARIO("Check utils_shellAsciiToUInt32 with invalid strings")
+{
+    GIVEN("Initialized shellmatta utils module")
+    {
+        shellmatta_retCode_t ret;
+        uint32_t result = 0xFFFFFFFFu;
+        WHEN("Passing 4294967296 with base 10 - overflow")
+        {
+            ret = utils_shellAsciiToUInt32((char*)"4294967296", &result, 10u);
+            THEN("utils_shellAsciiToUInt32 returns an error")
+            {
+                REQUIRE(ret == SHELLMATTA_ERROR);
+            }
+        }
+        WHEN("Passing 123456 with base 2 - wrong base")
+        {
+            ret = utils_shellAsciiToUInt32((char*)"123456", &result, 2u);
+            THEN("utils_shellAsciiToUInt32 returns an error")
+            {
+                REQUIRE(ret == SHELLMATTA_ERROR);
+            }
+        }
+        WHEN("Passing FOOBAR with base 16 - wrong characters")
+        {
+            ret = utils_shellAsciiToUInt32((char*)"FOOBAR", &result, 16u);
+            THEN("utils_shellAsciiToUInt32 returns an error")
+            {
+                REQUIRE(ret == SHELLMATTA_ERROR);
+            }
+        }
+        WHEN("Passing = with base 16 - wrong characters")
+        {
+            ret = utils_shellAsciiToUInt32((char*)"=", &result, 16u);
+            THEN("utils_shellAsciiToUInt32 returns an error")
+            {
+                REQUIRE(ret == SHELLMATTA_ERROR);
+            }
+        }
+        WHEN("Passing / with base 16 - wrong characters")
+        {
+            ret = utils_shellAsciiToUInt32((char*)"/", &result, 16u);
+            THEN("utils_shellAsciiToUInt32 returns an error")
+            {
+                REQUIRE(ret == SHELLMATTA_ERROR);
+            }
+        }
+        WHEN("Passing } with base 16 - wrong characters")
+        {
+            ret = utils_shellAsciiToUInt32((char*)"}", &result, 16u);
+            THEN("utils_shellAsciiToUInt32 returns an error")
+            {
+                REQUIRE(ret == SHELLMATTA_ERROR);
+            }
+        }
+        WHEN("Passing invalid string")
+        {
+            ret = utils_shellAsciiToUInt32(NULL, &result, 16u);
+            THEN("utils_shellAsciiToUInt32 returns an error")
+            {
+                CHECK(ret == SHELLMATTA_USE_FAULT);
+            }
+        }
+        WHEN("Passing invalid result")
+        {
+            ret = utils_shellAsciiToUInt32((char*)"", NULL, 16u);
+            THEN("utils_shellAsciiToUInt32 returns an error")
+            {
+                CHECK(ret == SHELLMATTA_USE_FAULT);
+            }
+        }
+        WHEN("Passing invalid base")
+        {
+            ret = utils_shellAsciiToUInt32((char*)"", &result, 17u);
+            THEN("utils_shellAsciiToUInt32 returns an error")
+            {
+                CHECK(ret == SHELLMATTA_USE_FAULT);
+            }
+        }
+    }
+}