-/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----\r
-\r
- Copyright (c) 2014-2015 Datalight, Inc.\r
- All Rights Reserved Worldwide.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU General Public License as published by\r
- the Free Software Foundation; use version 2 of the License.\r
-\r
- This program is distributed in the hope that it will be useful,\r
- but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty\r
- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- GNU General Public License for more details.\r
-\r
- You should have received a copy of the GNU General Public License along\r
- with this program; if not, write to the Free Software Foundation, Inc.,\r
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
-*/\r
-/* Businesses and individuals that for commercial or other reasons cannot\r
- comply with the terms of the GPLv2 license may obtain a commercial license\r
- before incorporating Reliance Edge into proprietary software for\r
- distribution in any form. Visit http://www.datalight.com/reliance-edge for\r
- more information.\r
-*/\r
-/** @file\r
- @brief Implements utilities that convert strings to numbers.\r
-*/\r
-#include <redfs.h>\r
-#include <redtestutils.h>\r
-\r
-\r
-#define ISHEXDIGITU(c) (((c) >= 'A') && ((c) <= 'F'))\r
-#define ISHEXDIGITL(c) (((c) >= 'a') && ((c) <= 'f'))\r
-#define ISHEXDIGIT(c) (ISHEXDIGITL(c) || ISHEXDIGITU(c))\r
-\r
-\r
-/** @brief Converts an ASCII number into an int32_t.\r
-\r
- Converts all decimal digit numbers up to the end of the string or to the\r
- first non-numerical character.\r
-\r
- @note This function does *not* ignore leading white space.\r
-\r
- @param pszNum Pointer to a constant array of characters.\r
-\r
- @return The integer represented in the string.\r
-*/\r
-int32_t RedAtoI(\r
- const char *pszNum)\r
-{\r
- int32_t lValue = 0;\r
- int32_t lNegative = 1;\r
- uint32_t ulIdx = 0U;\r
-\r
- if(pszNum[ulIdx] == '+')\r
- {\r
- ulIdx++;\r
- }\r
- else if(pszNum[ulIdx] == '-')\r
- {\r
- ulIdx++;\r
- lNegative = -1;\r
- }\r
- else\r
- {\r
- /* No sign, implicitly positive.\r
- */\r
- }\r
-\r
- while(ISDIGIT(pszNum[ulIdx]))\r
- {\r
- lValue *= 10;\r
- lValue += pszNum[ulIdx] - '0';\r
- ulIdx++;\r
- }\r
-\r
- lValue *= lNegative;\r
-\r
- return lValue;\r
-}\r
-\r
-\r
-/** @brief Convert a hexadecimal ASCII number into a uint32_t value.\r
-\r
- The function processes all hex digits up to a NUL-terminator, or to the\r
- first non-hex character. Only hexadecimal digits are processed, so leading\r
- white space, or a leading "0x" prefix are not allowed.\r
-\r
- If pachNum points to an empty string (points to a NUL), this function will\r
- return NULL, and the value at *pulNum will not be modified.\r
-\r
- @note This function does not check for overflow. If there are more\r
- significant digits than can be represented in a uint32_t variable, the\r
- output is unspecified.\r
-\r
- @param pachNum A pointer to a constant array of hex characters.\r
- @param pulNum A pointer to the location in which to store the uint32_t\r
- result. Upon return, this value will be modified ONLY if\r
- the function succeeds and the returned pointer is valid (not\r
- NULL).\r
-\r
- @return A pointer to the byte following the converted number or NULL to\r
- indicate failure.\r
-*/\r
-const char *RedHtoUL(\r
- const char *pszNum,\r
- uint32_t *pulNum)\r
-{\r
- uint64_t ullValue;\r
- const char *pszReturn;\r
-\r
- pszReturn = RedHtoULL(pszNum, &ullValue);\r
- if(pszReturn != NULL)\r
- {\r
- if(ullValue < UINT32_MAX)\r
- {\r
- *pulNum = (uint32_t)ullValue;\r
- }\r
- else\r
- {\r
- pszReturn = NULL;\r
- }\r
- }\r
-\r
- return pszReturn;\r
-}\r
-\r
-\r
-/** @brief Convert a hexadecimal ASCII number into a D_UINT64 value.\r
-\r
- The function processes all hex digits up to a NUL-terminator, or to the\r
- first non-hex character. Only hexadecimal digits are processed, so leading\r
- white space, or a leading "0x" prefix are not allowed.\r
-\r
- If pachNum points to an empty string (points to a NUL), this function will\r
- return NULL, and the value at *pulNum will not be modified.\r
-\r
- @note This function does not check for overflow. If there are more\r
- significant digits than can be represented in a uint64_t variable, the\r
- output is unspecified.\r
-\r
- @param pszNum A pointer to a constant array of hex characters.\r
- @param pullNum A pointer to the location in which to store the uint64_t\r
- result. Upon return, this value will be modified ONLY if\r
- the function succeeds and the returned pointer is valid (not\r
- NULL).\r
-\r
- @return A pointer to the byte following the converted number, or NULL to\r
- indicate failure.\r
-*/\r
-const char *RedHtoULL(\r
- const char *pszNum,\r
- uint64_t *pullNum)\r
-{\r
- uint64_t ullValue = 0U;\r
- const char *pszReturn = NULL;\r
- uint32_t ulIdx = 0U;\r
-\r
- REDASSERT(pszNum != NULL);\r
- REDASSERT(pullNum != NULL);\r
-\r
- while(pszNum[ulIdx] != '\0')\r
- {\r
- char cDigit = pszNum[ulIdx];\r
-\r
- if(ISDIGIT(cDigit))\r
- {\r
- cDigit -= '0';\r
- }\r
- else if(ISHEXDIGITU(cDigit))\r
- {\r
- cDigit -= ('A' - 10);\r
- }\r
- else if(ISHEXDIGITL(cDigit))\r
- {\r
- cDigit -= ('a' - 10);\r
- }\r
- else\r
- {\r
- break;\r
- }\r
-\r
- REDASSERT((ullValue & UINT64_SUFFIX(0xF000000000000000)) == 0U);\r
-\r
- ullValue <<= 4U;\r
- ullValue += cDigit;\r
-\r
- ulIdx++;\r
- pszReturn = &pszNum[ulIdx];\r
- }\r
-\r
- /* Modify the number returned only if we found one or more valid hex\r
- digits.\r
- */\r
- if(pszReturn != NULL)\r
- {\r
- *pullNum = ullValue;\r
- }\r
-\r
- return pszReturn;\r
-}\r
-\r
-\r
-/** @brief Convert the ASCII number to a uint32_t value.\r
-\r
- The number may be hex or decimal. Hex numbers must be prefixed by '0x', and\r
- they may be upper or lower case. The conversion process will stop with the\r
- first non hex or decimal digit.\r
-\r
- If the number is negative (the first character is a '-' sign), the value\r
- will be range checked and returned as the equivalent unsigned value.\r
-\r
- @note This function will NOT fail for numbers which exceed the size of a\r
- uint32_t value.\r
-\r
- @param pszNum A pointer to the ASCII number to convert\r
- @param pulNum A pointer to the uint32_t location to store the result.\r
- This value will be modified on return only if the function\r
- succeeds and the returned pointer is valid (not NULL).\r
-\r
- @return A pointer to the byte following the converted number, or NULL to\r
- indicate failure.\r
-*/\r
-const char *RedNtoUL(\r
- const char *pszNum,\r
- uint32_t *pulNum)\r
-{\r
- bool fNegative = false;\r
- uint32_t ulIdx = 0U;\r
- const char *pszReturn;\r
-\r
- REDASSERT(pszNum != NULL);\r
- REDASSERT(pulNum != NULL);\r
-\r
- if(pszNum[ulIdx] == '-')\r
- {\r
- fNegative = true;\r
- ulIdx++;\r
- }\r
-\r
- /* Hex numbers must be prefixed with '0x'.\r
- */\r
- if((pszNum[ulIdx] == '0') && ((pszNum[ulIdx + 1U] == 'x') || (pszNum[ulIdx + 1U] == 'X')))\r
- {\r
- ulIdx += 2U;\r
-\r
- if(ISDIGIT(pszNum[ulIdx]) || ISHEXDIGIT(pszNum[ulIdx]))\r
- {\r
- pszReturn = RedHtoUL(&pszNum[ulIdx], pulNum);\r
- }\r
- else\r
- {\r
- pszReturn = NULL;\r
- }\r
- }\r
- else if(ISDIGIT(pszNum[ulIdx]))\r
- {\r
- uint32_t ulTemp;\r
-\r
- ulTemp = RedAtoI(&pszNum[ulIdx]);\r
-\r
- while(ISDIGIT(pszNum[ulIdx]))\r
- {\r
- ulIdx++;\r
- }\r
-\r
- if(fNegative)\r
- {\r
- /* Fail if the number is out of range.\r
- */\r
- if(ulTemp > INT32_MAX)\r
- {\r
- pszReturn = NULL;\r
- }\r
- else\r
- {\r
- *pulNum = -((int32_t)ulTemp);\r
- pszReturn = &pszNum[ulIdx];\r
- }\r
- }\r
- else\r
- {\r
- *pulNum = ulTemp;\r
- pszReturn = &pszNum[ulIdx];\r
- }\r
- }\r
- else\r
- {\r
- /* Return an error if there is not at least one hex or decimal digit.\r
- */\r
- pszReturn = NULL;\r
- }\r
-\r
- return pszReturn;\r
-}\r
-\r
-\r
-/** @brief Convert the ASCII number pointed to by pachNum to a uint64_t value.\r
-\r
- The number may be hex or decimal. Hex numbers must be prefixed by '0x', and\r
- they may be upper or lower case. The conversion process will stop with the\r
- first non hex or decimal digit.\r
-\r
- If the number is negative (the first character is a '-' sign), the value\r
- will be range checked and returned as the equivalent unsigned value.\r
-\r
- @param pszNum A pointer to the ASCII number to convert.\r
- @param pullNum A pointer to the uint64_t location to store the result.\r
- This value will be modified on return only if the function\r
- succeeds and the returned pointer is valid (not NULL).\r
-\r
- @return A pointer to the byte following the converted number, or NULL to\r
- indicate failure.\r
-*/\r
-const char *RedNtoULL(\r
- const char *pszNum,\r
- uint64_t *pullNum)\r
-{\r
- bool fNegative = false;\r
- uint32_t ulIdx = 0U;\r
- const char *pszReturn;\r
-\r
- REDASSERT(pszNum != NULL);\r
- REDASSERT(pullNum != NULL);\r
-\r
- if(pszNum[ulIdx] == '-')\r
- {\r
- fNegative = true;\r
- ulIdx++;\r
- }\r
-\r
- /* Hex numbers must be prefixed with '0x'.\r
- */\r
- if((pszNum[ulIdx] == '0') && ((pszNum[ulIdx + 1U] == 'x') || (pszNum[ulIdx + 1U] == 'X')))\r
- {\r
- ulIdx += 2U;\r
-\r
- if(ISDIGIT(pszNum[ulIdx]) || ISHEXDIGIT(pszNum[ulIdx]))\r
- {\r
- pszReturn = RedHtoULL(&pszNum[ulIdx], pullNum);\r
- }\r
- else\r
- {\r
- pszReturn = NULL;\r
- }\r
- }\r
- else if(ISDIGIT(pszNum[ulIdx]))\r
- {\r
- uint64_t ullTemp = 0U;\r
-\r
- while(ISDIGIT(pszNum[ulIdx]))\r
- {\r
- ullTemp *= 10U;\r
- ullTemp += pszNum[ulIdx] - '0';\r
- ulIdx++;\r
- }\r
-\r
- if(fNegative)\r
- {\r
- /* Fail if the number is out of range.\r
- */\r
- if(ullTemp > INT64_MAX)\r
- {\r
- pszReturn = NULL;\r
- }\r
- else\r
- {\r
- *pullNum = (uint64_t)(-((int64_t)ullTemp));\r
- pszReturn = &pszNum[ulIdx];\r
- }\r
- }\r
- else\r
- {\r
- *pullNum = ullTemp;\r
- pszReturn = &pszNum[ulIdx];\r
- }\r
- }\r
- else\r
- {\r
- /* Return an error if there is not at least one hex or decimal digit.\r
- */\r
- pszReturn = NULL;\r
- }\r
-\r
- return pszReturn;\r
-}\r
-\r
-\r
-/** @brief Convert an ASCII hex or decimal number, which may may have a "B",\r
- "KB", or "MB" suffix (case insensitive), to a binary value.\r
-\r
- Hex numbers must be prefixed with "0x".\r
-\r
- @note If there is no postfix, KB is assumed!\r
-\r
- May fail due to bad formatting or overflow.\r
-\r
- @param pszNum A pointer to the ASCII number to convert.\r
- @param pulResult A pointer to a uint32_t in which to place the result.\r
-\r
- @return A pointer to the byte following the string, or NULL to indicate an\r
- error. In the event of an error, *pulResult will not be modified.\r
-*/\r
-const char *RedSizeToUL(\r
- const char *pszNum,\r
- uint32_t *pulResult)\r
-{\r
- uint32_t ulResult;\r
- const char *pszSuffix;\r
- const char *pszReturn;\r
- uint32_t ulIdx = 0U;\r
-\r
- REDASSERT(pszNum != NULL);\r
- REDASSERT(pulResult != NULL);\r
-\r
- /* Do the basic hex/decimal conversion\r
- */\r
- pszSuffix = RedNtoUL(pszNum, &ulResult);\r
- if(pszSuffix != NULL)\r
- {\r
- if((pszSuffix[ulIdx] == 'B') || (pszSuffix[ulIdx] == 'b'))\r
- {\r
- ulIdx++;\r
- pszReturn = &pszSuffix[ulIdx];\r
- }\r
- else if( ((pszSuffix[ulIdx] == 'M') || (pszSuffix[ulIdx] == 'm'))\r
- && ((pszSuffix[ulIdx + 1U] == 'B') || (pszSuffix[ulIdx + 1U] == 'b')))\r
- {\r
- ulIdx += 2U;\r
-\r
- if(ulResult > (UINT32_MAX / (1024U * 1024U)))\r
- {\r
- pszReturn = NULL;\r
- }\r
- else\r
- {\r
- ulResult *= 1024U * 1024U;\r
- pszReturn = &pszSuffix[ulIdx];\r
- }\r
- }\r
- else\r
- {\r
- /* The number is either postfixed with "KB" or something\r
- else (we don't care), but we must increment the pointer\r
- if it is something recognize.\r
- */\r
- if( ((pszSuffix[ulIdx] == 'K') || (pszSuffix[ulIdx] == 'k'))\r
- && ((pszSuffix[ulIdx + 1U] == 'B') || (pszSuffix[ulIdx + 1U] == 'b')))\r
- {\r
- ulIdx += 2U;\r
- }\r
-\r
- /* "B" or "MB" were not specified, so it must be "KB"\r
- */\r
- if(ulResult > (UINT32_MAX / 1024U))\r
- {\r
- pszReturn = NULL;\r
- }\r
- else\r
- {\r
- ulResult *= 1024UL;\r
- pszReturn = &pszSuffix[ulIdx];\r
- }\r
- }\r
-\r
- if(pszReturn != NULL)\r
- {\r
- *pulResult = ulResult;\r
- }\r
- }\r
- else\r
- {\r
- pszReturn = NULL;\r
- }\r
-\r
- return pszReturn;\r
-}\r
-\r
+/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
+
+ Copyright (c) 2014-2015 Datalight, Inc.
+ All Rights Reserved Worldwide.
+
+ 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; use version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
+ of 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, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+/* Businesses and individuals that for commercial or other reasons cannot
+ comply with the terms of the GPLv2 license may obtain a commercial license
+ before incorporating Reliance Edge into proprietary software for
+ distribution in any form. Visit http://www.datalight.com/reliance-edge for
+ more information.
+*/
+/** @file
+ @brief Implements utilities that convert strings to numbers.
+*/
+#include <redfs.h>
+#include <redtestutils.h>
+
+
+#define ISHEXDIGITU(c) (((c) >= 'A') && ((c) <= 'F'))
+#define ISHEXDIGITL(c) (((c) >= 'a') && ((c) <= 'f'))
+#define ISHEXDIGIT(c) (ISHEXDIGITL(c) || ISHEXDIGITU(c))
+
+
+/** @brief Converts an ASCII number into an int32_t.
+
+ Converts all decimal digit numbers up to the end of the string or to the
+ first non-numerical character.
+
+ @note This function does *not* ignore leading white space.
+
+ @param pszNum Pointer to a constant array of characters.
+
+ @return The integer represented in the string.
+*/
+int32_t RedAtoI(
+ const char *pszNum)
+{
+ int32_t lValue = 0;
+ int32_t lNegative = 1;
+ uint32_t ulIdx = 0U;
+
+ if(pszNum[ulIdx] == '+')
+ {
+ ulIdx++;
+ }
+ else if(pszNum[ulIdx] == '-')
+ {
+ ulIdx++;
+ lNegative = -1;
+ }
+ else
+ {
+ /* No sign, implicitly positive.
+ */
+ }
+
+ while(ISDIGIT(pszNum[ulIdx]))
+ {
+ lValue *= 10;
+ lValue += pszNum[ulIdx] - '0';
+ ulIdx++;
+ }
+
+ lValue *= lNegative;
+
+ return lValue;
+}
+
+
+/** @brief Convert a hexadecimal ASCII number into a uint32_t value.
+
+ The function processes all hex digits up to a NUL-terminator, or to the
+ first non-hex character. Only hexadecimal digits are processed, so leading
+ white space, or a leading "0x" prefix are not allowed.
+
+ If pachNum points to an empty string (points to a NUL), this function will
+ return NULL, and the value at *pulNum will not be modified.
+
+ @note This function does not check for overflow. If there are more
+ significant digits than can be represented in a uint32_t variable, the
+ output is unspecified.
+
+ @param pszNum A pointer to a constant array of hex characters.
+ @param pulNum A pointer to the location in which to store the uint32_t
+ result. Upon return, this value will be modified ONLY if
+ the function succeeds and the returned pointer is valid (not
+ NULL).
+
+ @return A pointer to the byte following the converted number or NULL to
+ indicate failure.
+*/
+const char *RedHtoUL(
+ const char *pszNum,
+ uint32_t *pulNum)
+{
+ uint64_t ullValue;
+ const char *pszReturn;
+
+ pszReturn = RedHtoULL(pszNum, &ullValue);
+ if(pszReturn != NULL)
+ {
+ if(ullValue < UINT32_MAX)
+ {
+ *pulNum = (uint32_t)ullValue;
+ }
+ else
+ {
+ pszReturn = NULL;
+ }
+ }
+
+ return pszReturn;
+}
+
+
+/** @brief Convert a hexadecimal ASCII number into a D_UINT64 value.
+
+ The function processes all hex digits up to a NUL-terminator, or to the
+ first non-hex character. Only hexadecimal digits are processed, so leading
+ white space, or a leading "0x" prefix are not allowed.
+
+ If pachNum points to an empty string (points to a NUL), this function will
+ return NULL, and the value at *pulNum will not be modified.
+
+ @note This function does not check for overflow. If there are more
+ significant digits than can be represented in a uint64_t variable, the
+ output is unspecified.
+
+ @param pszNum A pointer to a constant array of hex characters.
+ @param pullNum A pointer to the location in which to store the uint64_t
+ result. Upon return, this value will be modified ONLY if
+ the function succeeds and the returned pointer is valid (not
+ NULL).
+
+ @return A pointer to the byte following the converted number, or NULL to
+ indicate failure.
+*/
+const char *RedHtoULL(
+ const char *pszNum,
+ uint64_t *pullNum)
+{
+ uint64_t ullValue = 0U;
+ const char *pszReturn = NULL;
+ uint32_t ulIdx = 0U;
+
+ REDASSERT(pszNum != NULL);
+ REDASSERT(pullNum != NULL);
+
+ while(pszNum[ulIdx] != '\0')
+ {
+ char cDigit = pszNum[ulIdx];
+
+ if(ISDIGIT(cDigit))
+ {
+ cDigit -= '0';
+ }
+ else if(ISHEXDIGITU(cDigit))
+ {
+ cDigit -= ('A' - 10);
+ }
+ else if(ISHEXDIGITL(cDigit))
+ {
+ cDigit -= ('a' - 10);
+ }
+ else
+ {
+ break;
+ }
+
+ REDASSERT((ullValue & UINT64_SUFFIX(0xF000000000000000)) == 0U);
+
+ ullValue <<= 4U;
+ ullValue += cDigit;
+
+ ulIdx++;
+ pszReturn = &pszNum[ulIdx];
+ }
+
+ /* Modify the number returned only if we found one or more valid hex
+ digits.
+ */
+ if(pszReturn != NULL)
+ {
+ *pullNum = ullValue;
+ }
+
+ return pszReturn;
+}
+
+
+/** @brief Convert the ASCII number to a uint32_t value.
+
+ The number may be hex or decimal. Hex numbers must be prefixed by '0x', and
+ they may be upper or lower case. The conversion process will stop with the
+ first non hex or decimal digit.
+
+ If the number is negative (the first character is a '-' sign), the value
+ will be range checked and returned as the equivalent unsigned value.
+
+ @note This function will NOT fail for numbers which exceed the size of a
+ uint32_t value.
+
+ @param pszNum A pointer to the ASCII number to convert
+ @param pulNum A pointer to the uint32_t location to store the result.
+ This value will be modified on return only if the function
+ succeeds and the returned pointer is valid (not NULL).
+
+ @return A pointer to the byte following the converted number, or NULL to
+ indicate failure.
+*/
+const char *RedNtoUL(
+ const char *pszNum,
+ uint32_t *pulNum)
+{
+ bool fNegative = false;
+ uint32_t ulIdx = 0U;
+ const char *pszReturn;
+
+ REDASSERT(pszNum != NULL);
+ REDASSERT(pulNum != NULL);
+
+ if(pszNum[ulIdx] == '-')
+ {
+ fNegative = true;
+ ulIdx++;
+ }
+
+ /* Hex numbers must be prefixed with '0x'.
+ */
+ if((pszNum[ulIdx] == '0') && ((pszNum[ulIdx + 1U] == 'x') || (pszNum[ulIdx + 1U] == 'X')))
+ {
+ ulIdx += 2U;
+
+ if(ISDIGIT(pszNum[ulIdx]) || ISHEXDIGIT(pszNum[ulIdx]))
+ {
+ pszReturn = RedHtoUL(&pszNum[ulIdx], pulNum);
+ }
+ else
+ {
+ pszReturn = NULL;
+ }
+ }
+ else if(ISDIGIT(pszNum[ulIdx]))
+ {
+ uint32_t ulTemp;
+
+ ulTemp = RedAtoI(&pszNum[ulIdx]);
+
+ while(ISDIGIT(pszNum[ulIdx]))
+ {
+ ulIdx++;
+ }
+
+ if(fNegative)
+ {
+ /* Fail if the number is out of range.
+ */
+ if(ulTemp > INT32_MAX)
+ {
+ pszReturn = NULL;
+ }
+ else
+ {
+ *pulNum = -((int32_t)ulTemp);
+ pszReturn = &pszNum[ulIdx];
+ }
+ }
+ else
+ {
+ *pulNum = ulTemp;
+ pszReturn = &pszNum[ulIdx];
+ }
+ }
+ else
+ {
+ /* Return an error if there is not at least one hex or decimal digit.
+ */
+ pszReturn = NULL;
+ }
+
+ return pszReturn;
+}
+
+
+/** @brief Convert the ASCII number pointed to by pachNum to a uint64_t value.
+
+ The number may be hex or decimal. Hex numbers must be prefixed by '0x', and
+ they may be upper or lower case. The conversion process will stop with the
+ first non hex or decimal digit.
+
+ If the number is negative (the first character is a '-' sign), the value
+ will be range checked and returned as the equivalent unsigned value.
+
+ @param pszNum A pointer to the ASCII number to convert.
+ @param pullNum A pointer to the uint64_t location to store the result.
+ This value will be modified on return only if the function
+ succeeds and the returned pointer is valid (not NULL).
+
+ @return A pointer to the byte following the converted number, or NULL to
+ indicate failure.
+*/
+const char *RedNtoULL(
+ const char *pszNum,
+ uint64_t *pullNum)
+{
+ bool fNegative = false;
+ uint32_t ulIdx = 0U;
+ const char *pszReturn;
+
+ REDASSERT(pszNum != NULL);
+ REDASSERT(pullNum != NULL);
+
+ if(pszNum[ulIdx] == '-')
+ {
+ fNegative = true;
+ ulIdx++;
+ }
+
+ /* Hex numbers must be prefixed with '0x'.
+ */
+ if((pszNum[ulIdx] == '0') && ((pszNum[ulIdx + 1U] == 'x') || (pszNum[ulIdx + 1U] == 'X')))
+ {
+ ulIdx += 2U;
+
+ if(ISDIGIT(pszNum[ulIdx]) || ISHEXDIGIT(pszNum[ulIdx]))
+ {
+ pszReturn = RedHtoULL(&pszNum[ulIdx], pullNum);
+ }
+ else
+ {
+ pszReturn = NULL;
+ }
+ }
+ else if(ISDIGIT(pszNum[ulIdx]))
+ {
+ uint64_t ullTemp = 0U;
+
+ while(ISDIGIT(pszNum[ulIdx]))
+ {
+ ullTemp *= 10U;
+ ullTemp += pszNum[ulIdx] - '0';
+ ulIdx++;
+ }
+
+ if(fNegative)
+ {
+ /* Fail if the number is out of range.
+ */
+ if(ullTemp > INT64_MAX)
+ {
+ pszReturn = NULL;
+ }
+ else
+ {
+ *pullNum = (uint64_t)(-((int64_t)ullTemp));
+ pszReturn = &pszNum[ulIdx];
+ }
+ }
+ else
+ {
+ *pullNum = ullTemp;
+ pszReturn = &pszNum[ulIdx];
+ }
+ }
+ else
+ {
+ /* Return an error if there is not at least one hex or decimal digit.
+ */
+ pszReturn = NULL;
+ }
+
+ return pszReturn;
+}
+
+
+/** @brief Convert an ASCII hex or decimal number, which may may have a "B",
+ "KB", or "MB" suffix (case insensitive), to a binary value.
+
+ Hex numbers must be prefixed with "0x".
+
+ @note If there is no postfix, KB is assumed!
+
+ May fail due to bad formatting or overflow.
+
+ @param pszNum A pointer to the ASCII number to convert.
+ @param pulResult A pointer to a uint32_t in which to place the result.
+
+ @return A pointer to the byte following the string, or NULL to indicate an
+ error. In the event of an error, *pulResult will not be modified.
+*/
+const char *RedSizeToUL(
+ const char *pszNum,
+ uint32_t *pulResult)
+{
+ uint32_t ulResult;
+ const char *pszSuffix;
+ const char *pszReturn;
+ uint32_t ulIdx = 0U;
+
+ REDASSERT(pszNum != NULL);
+ REDASSERT(pulResult != NULL);
+
+ /* Do the basic hex/decimal conversion
+ */
+ pszSuffix = RedNtoUL(pszNum, &ulResult);
+ if(pszSuffix != NULL)
+ {
+ if((pszSuffix[ulIdx] == 'B') || (pszSuffix[ulIdx] == 'b'))
+ {
+ ulIdx++;
+ pszReturn = &pszSuffix[ulIdx];
+ }
+ else if( ((pszSuffix[ulIdx] == 'M') || (pszSuffix[ulIdx] == 'm'))
+ && ((pszSuffix[ulIdx + 1U] == 'B') || (pszSuffix[ulIdx + 1U] == 'b')))
+ {
+ ulIdx += 2U;
+
+ if(ulResult > (UINT32_MAX / (1024U * 1024U)))
+ {
+ pszReturn = NULL;
+ }
+ else
+ {
+ ulResult *= 1024U * 1024U;
+ pszReturn = &pszSuffix[ulIdx];
+ }
+ }
+ else
+ {
+ /* The number is either postfixed with "KB" or something
+ else (we don't care), but we must increment the pointer
+ if it is something recognize.
+ */
+ if( ((pszSuffix[ulIdx] == 'K') || (pszSuffix[ulIdx] == 'k'))
+ && ((pszSuffix[ulIdx + 1U] == 'B') || (pszSuffix[ulIdx + 1U] == 'b')))
+ {
+ ulIdx += 2U;
+ }
+
+ /* "B" or "MB" were not specified, so it must be "KB"
+ */
+ if(ulResult > (UINT32_MAX / 1024U))
+ {
+ pszReturn = NULL;
+ }
+ else
+ {
+ ulResult *= 1024UL;
+ pszReturn = &pszSuffix[ulIdx];
+ }
+ }
+
+ if(pszReturn != NULL)
+ {
+ *pulResult = ulResult;
+ }
+ }
+ else
+ {
+ pszReturn = NULL;
+ }
+
+ return pszReturn;
+}
+