Changeset 79562 in vbox for trunk/src/VBox
- Timestamp:
- Jul 5, 2019 8:37:19 PM (6 years ago)
- Location:
- trunk/src/VBox/Runtime
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/string/strtonum.cpp
r76553 r79562 40 40 * Global Variables * 41 41 *********************************************************************************************************************************/ 42 /** 8-bit char -> digit. */ 42 /** 8-bit char -> digit. 43 * Non-digits have values 255 (most), 254 (zero), 253 (colon) and 252 (space). 44 */ 43 45 static const unsigned char g_auchDigits[256] = 44 46 { 45 25 5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,46 25 5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255,47 254,255,255,255,255,255,255,255,255,252,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 48 252,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,253,255,255,255,255,255, 47 49 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,255,255,255,255,255, 48 50 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,255,255,255,255,255, … … 52 54 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 53 55 }; 56 54 57 /** Approximated overflow shift checks. */ 55 58 static const char g_auchShift[36] = … … 75 78 else if (i >= 'A' && i <= 'Z') 76 79 ch = i - 'A' + 10; 80 else if (i == 0) 81 ch = 254; 82 else if (i == ':') 83 ch = 253; 84 else if (i == ' ' || i == '\t') 85 ch = 252; 77 86 if (i == 0) 78 87 printf("\n %3d", ch); … … 973 982 974 983 984 RTDECL(int) RTStrConvertHexBytesEx(char const *pszHex, void *pv, size_t cb, uint32_t fFlags, 985 const char **ppszNext, size_t *pcbReturned) 986 { 987 size_t cbDst = cb; 988 uint8_t *pbDst = (uint8_t *)pv; 989 const unsigned char *pszSrc = (const unsigned char *)pszHex; 990 unsigned char uchDigit; 991 992 if (pcbReturned) 993 *pcbReturned = 0; 994 if (ppszNext) 995 *ppszNext = NULL; 996 AssertPtrReturn(pszHex, VERR_INVALID_POINTER); 997 AssertReturn(!(fFlags & ~RTSTRCONVERTHEXBYTES_F_SEP_COLON), VERR_INVALID_FLAGS); 998 999 if (fFlags & RTSTRCONVERTHEXBYTES_F_SEP_COLON) 1000 { 1001 /* 1002 * Optional colon separators. 1003 */ 1004 bool fPrevColon = true; /* leading colon is taken to mean leading zero byte */ 1005 for (;;) 1006 { 1007 /* Pick the next two digit from the string. */ 1008 uchDigit = g_auchDigits[*pszSrc++]; 1009 if (uchDigit >= 16) 1010 { 1011 if (uchDigit == 253 /* colon */) 1012 { 1013 Assert(pszSrc[-1] == ':'); 1014 if (!fPrevColon) 1015 fPrevColon = true; 1016 /* Add zero byte if there is room. */ 1017 else if (cbDst > 0) 1018 { 1019 cbDst--; 1020 *pbDst++ = 0; 1021 } 1022 else 1023 { 1024 if (pcbReturned) 1025 *pcbReturned = pbDst - (uint8_t *)pv; 1026 if (ppszNext) 1027 *ppszNext = (const char *)pszSrc - 1; 1028 return VERR_BUFFER_OVERFLOW; 1029 } 1030 continue; 1031 } 1032 else 1033 break; 1034 } 1035 else 1036 { 1037 /* Got one digit, check what comes next: */ 1038 unsigned char const uchDigit2 = g_auchDigits[*pszSrc++]; 1039 if (uchDigit2 < 16) 1040 { 1041 if (cbDst > 0) 1042 { 1043 *pbDst++ = (uchDigit << 4) | uchDigit2; 1044 cbDst--; 1045 fPrevColon = false; 1046 } 1047 else 1048 { 1049 if (pcbReturned) 1050 *pcbReturned = pbDst - (uint8_t *)pv; 1051 if (ppszNext) 1052 *ppszNext = (const char *)pszSrc - 1; 1053 return VERR_BUFFER_OVERFLOW; 1054 } 1055 } 1056 /* Lone digits are only allowed if following a colon or at the very start, because 1057 if there is more than one byte it ambigious whether it is the lead or tail byte 1058 that only has one digit in it. 1059 Note! This also ensures better compatibility with the no-separator variant 1060 (except for single digit strings, which are accepted here but not below). */ 1061 else if (fPrevColon) 1062 { 1063 if (cbDst > 0) 1064 { 1065 *pbDst++ = uchDigit; 1066 cbDst--; 1067 } 1068 else 1069 { 1070 if (pcbReturned) 1071 *pcbReturned = pbDst - (uint8_t *)pv; 1072 if (ppszNext) 1073 *ppszNext = (const char *)pszSrc - 1; 1074 return VERR_BUFFER_OVERFLOW; 1075 } 1076 if (uchDigit2 == 253 /* colon */) 1077 { 1078 Assert(pszSrc[-1] == ':'); 1079 fPrevColon = true; 1080 } 1081 else 1082 { 1083 fPrevColon = false; 1084 uchDigit = uchDigit2; 1085 break; 1086 } 1087 } 1088 else 1089 { 1090 if (pcbReturned) 1091 *pcbReturned = pbDst - (uint8_t *)pv; 1092 if (ppszNext) 1093 *ppszNext = (const char *)pszSrc - 2; 1094 return VERR_UNEVEN_INPUT; 1095 } 1096 } 1097 } 1098 1099 /* Trailing colon means trailing zero byte: */ 1100 if (fPrevColon) 1101 { 1102 if (cbDst > 0) 1103 { 1104 *pbDst++ = 0; 1105 cbDst--; 1106 } 1107 else 1108 { 1109 if (pcbReturned) 1110 *pcbReturned = pbDst - (uint8_t *)pv; 1111 if (ppszNext) 1112 *ppszNext = (const char *)pszSrc - 1; 1113 return VERR_BUFFER_OVERFLOW; 1114 } 1115 } 1116 } 1117 else 1118 { 1119 /* 1120 * No separators. 1121 */ 1122 for (;;) 1123 { 1124 /* Pick the next two digit from the string. */ 1125 uchDigit = g_auchDigits[*pszSrc++]; 1126 if (uchDigit < 16) 1127 { 1128 unsigned char const uchDigit2 = g_auchDigits[*pszSrc++]; 1129 if (uchDigit2 < 16) 1130 { 1131 /* Add the byte to the output buffer. */ 1132 if (cbDst) 1133 { 1134 cbDst--; 1135 *pbDst++ = (uchDigit << 4) | uchDigit2; 1136 } 1137 else 1138 { 1139 if (pcbReturned) 1140 *pcbReturned = pbDst - (uint8_t *)pv; 1141 if (ppszNext) 1142 *ppszNext = (const char *)pszSrc - 2; 1143 return VERR_BUFFER_OVERFLOW; 1144 } 1145 } 1146 else 1147 { 1148 if (pcbReturned) 1149 *pcbReturned = pbDst - (uint8_t *)pv; 1150 if (ppszNext) 1151 *ppszNext = (const char *)pszSrc - 2; 1152 return VERR_UNEVEN_INPUT; 1153 } 1154 } 1155 else 1156 break; 1157 } 1158 } 1159 1160 /* 1161 * End of hex bytes, look what comes next and figure out what to return. 1162 */ 1163 if (pcbReturned) 1164 *pcbReturned = pbDst - (uint8_t *)pv; 1165 if (ppszNext) 1166 *ppszNext = (const char *)pszSrc - 1; 1167 1168 if (uchDigit == 254) 1169 { 1170 Assert(pszSrc[-1] == '\0'); 1171 if (cbDst == 0) 1172 return VINF_SUCCESS; 1173 return pcbReturned ? VINF_BUFFER_UNDERFLOW : VERR_BUFFER_UNDERFLOW; 1174 } 1175 Assert(pszSrc[-1] != '\0'); 1176 1177 if (cbDst != 0 && !pcbReturned) 1178 return VERR_BUFFER_UNDERFLOW; 1179 1180 while (uchDigit == 252) 1181 { 1182 Assert(pszSrc[-1] == ' ' || pszSrc[-1] == '\t'); 1183 uchDigit = g_auchDigits[*pszSrc++]; 1184 } 1185 1186 Assert(pszSrc[-1] == '\0' ? uchDigit == 254 : uchDigit != 254); 1187 return uchDigit == 254 ? VWRN_TRAILING_CHARS : VWRN_TRAILING_SPACES; 1188 1189 } 1190 RT_EXPORT_SYMBOL(RTStrConvertHexBytesEx); 1191 1192 975 1193 RTDECL(int) RTStrConvertHexBytes(char const *pszHex, void *pv, size_t cb, uint32_t fFlags) 976 1194 { 977 size_t cbDst; 978 uint8_t *pbDst; 979 const char *pszSrc; 980 981 AssertPtrReturn(pszHex, VERR_INVALID_POINTER); 982 AssertReturn(!fFlags, VERR_INVALID_PARAMETER); 983 984 cbDst = cb; 985 pbDst = (uint8_t *)pv; 986 pszSrc = pszHex; 987 for (;;) 988 { 989 /* Pick the next two digit from the string. */ 990 char ch = *pszSrc++; 991 unsigned char uchDigit1 = g_auchDigits[(unsigned char)ch]; 992 unsigned char uchDigit2; 993 if (uchDigit1 >= 16) 994 { 995 if (!ch) 996 return cbDst == 0 ? VINF_SUCCESS : VERR_BUFFER_UNDERFLOW; 997 998 while (ch == ' ' || ch == '\t') 999 ch = *pszSrc++; 1000 return ch ? VWRN_TRAILING_CHARS : VWRN_TRAILING_SPACES; 1001 } 1002 1003 ch = *pszSrc++; 1004 uchDigit2 = g_auchDigits[(unsigned char)ch]; 1005 if (uchDigit2 >= 16) 1006 return VERR_UNEVEN_INPUT; 1007 1008 /* Add the byte to the output buffer. */ 1009 if (!cbDst) 1010 return VERR_BUFFER_OVERFLOW; 1011 cbDst--; 1012 *pbDst++ = (uchDigit1 << 4) | uchDigit2; 1013 } 1195 return RTStrConvertHexBytesEx(pszHex, pv, cb, fFlags, NULL /*ppszNext*/, NULL /*pcbReturned*/); 1196 1014 1197 } 1015 1198 RT_EXPORT_SYMBOL(RTStrConvertHexBytes); -
trunk/src/VBox/Runtime/testcase/tstStrToNum.cpp
r76553 r79562 25 25 */ 26 26 27 #include <iprt/initterm.h> 27 28 /********************************************************************************************************************************* 29 * Header Files * 30 *********************************************************************************************************************************/ 31 #include <iprt/test.h> 28 32 #include <iprt/string.h> 29 33 #include <iprt/stream.h> … … 69 73 int rc = Fun(Test.psz, NULL, Test.uBase, &Result); \ 70 74 if (Result != Test.Result) \ 71 { \ 72 RTPrintf("failure: '%s' -> " Fmt " expected " Fmt ". (%s/%u)\n", Test.psz, Result, Test.Result, #Fun, iTest); \ 73 cErrors++; \ 74 } \ 75 RTTestIFailed("'%s' -> " Fmt " expected " Fmt ". (%s/%u)\n", Test.psz, Result, Test.Result, #Fun, iTest); \ 75 76 else if (rc != Test.rc) \ 76 { \ 77 RTPrintf("failure: '%s' -> rc=%Rrc expected %Rrc. (%s/%u)\n", Test.psz, rc, Test.rc, #Fun, iTest); \ 78 cErrors++; \ 79 } \ 77 RTTestIFailed("'%s' -> rc=%Rrc expected %Rrc. (%s/%u)\n", Test.psz, rc, Test.rc, #Fun, iTest); \ 80 78 } while (0) 81 79 … … 92 90 int main() 93 91 { 94 RTR3InitExeNoArguments(0); 95 96 int cErrors = 0; 92 RTTEST hTest; 93 RTEXITCODE rcExit = RTTestInitAndCreate("tstRTStrToNum", &hTest); 94 if (rcExit != RTEXITCODE_SUCCESS) 95 return rcExit; 96 97 97 static const struct TstU64 aTstU64[] = 98 98 { … … 159 159 160 160 161 162 161 static const struct TstI32 aTstI32[] = 163 162 { … … 223 222 RUN_TESTS(aTstU32, uint32_t, "%#x", RTStrToUInt32Ex); 224 223 224 225 /* 226 * Test the some hex stuff too. 227 */ 228 static const struct 229 { 230 const char *pszHex; 231 size_t cbOut; 232 size_t offNext; 233 uint8_t bLast; 234 bool fColon; 235 int rc; 236 } s_aConvertHexTests[] = 237 { 238 { "00", 1, 2, 0x00, true, VINF_SUCCESS }, 239 { "00", 1, 2, 0x00, false, VINF_SUCCESS }, 240 { "000102", 3, 6, 0x02, true, VINF_SUCCESS }, 241 { "00019", 2, 4, 0x01, false, VERR_UNEVEN_INPUT }, 242 { "00019", 2, 4, 0x01, true, VERR_UNEVEN_INPUT }, 243 { "0001:9", 3, 6, 0x09, true, VINF_SUCCESS}, 244 { "000102", 3, 6, 0x02, false, VINF_SUCCESS }, 245 { "0:1", 2, 3, 0x01, true, VINF_SUCCESS }, 246 { ":", 2, 1, 0x00, true, VINF_SUCCESS }, 247 { "0:01", 2, 4, 0x01, true, VINF_SUCCESS }, 248 { "00:01", 2, 5, 0x01, true, VINF_SUCCESS }, 249 { ":1:2:3:4:5", 6, 10, 0x05, true, VINF_SUCCESS }, 250 { ":1:2:3::5", 6, 9, 0x05, true, VINF_SUCCESS }, 251 { ":1:2:3:4:", 6, 9, 0x00, true, VINF_SUCCESS }, 252 }; 253 for (unsigned i = 0; i < RT_ELEMENTS(s_aConvertHexTests); i++) 254 { 255 uint8_t abBuf[1024]; 256 memset(abBuf, 0xf6, sizeof(abBuf)); 257 const char *pszExpectNext = &s_aConvertHexTests[i].pszHex[s_aConvertHexTests[i].offNext]; 258 const char *pszNext = ""; 259 size_t cbReturned = 77777; 260 int rc = RTStrConvertHexBytesEx(s_aConvertHexTests[i].pszHex, abBuf, s_aConvertHexTests[i].cbOut, 261 s_aConvertHexTests[i].fColon ? RTSTRCONVERTHEXBYTES_F_SEP_COLON : 0, 262 &pszNext, &cbReturned); 263 if ( rc != s_aConvertHexTests[i].rc 264 || pszNext != pszExpectNext 265 || abBuf[s_aConvertHexTests[i].cbOut - 1] != s_aConvertHexTests[i].bLast 266 ) 267 RTTestFailed(hTest, "RTStrConvertHexBytesEx/#%u %s -> %Rrc %p %#zx %#02x, expected %Rrc %p %#zx %#02x\n", 268 i, s_aConvertHexTests[i].pszHex, 269 rc, pszNext, cbReturned, abBuf[s_aConvertHexTests[i].cbOut - 1], 270 s_aConvertHexTests[i].rc, pszExpectNext, s_aConvertHexTests[i].cbOut, s_aConvertHexTests[i].bLast); 271 } 272 273 225 274 /* 226 275 * Summary. 227 276 */ 228 if (!cErrors) 229 RTPrintf("tstStrToNum: SUCCESS\n"); 230 else 231 RTPrintf("tstStrToNum: FAILURE - %d errors\n", cErrors); 232 return !!cErrors; 277 return RTTestSummaryAndDestroy(hTest); 233 278 }
Note:
See TracChangeset
for help on using the changeset viewer.