Changeset 61704 in vbox for trunk/src/VBox/Runtime/common/misc/json.cpp
- Timestamp:
- Jun 15, 2016 9:54:26 AM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/misc/json.cpp
r61695 r61704 35 35 #include <iprt/json.h> 36 36 #include <iprt/mem.h> 37 #include <iprt/stream.h> 37 38 #include <iprt/string.h> 38 39 … … 124 125 125 126 /** 127 * Tokenizer read input callback. 128 * 129 * @returns IPRT status code. 130 * @param pvUser Opaque user data for the callee. 131 * @param offInput Start offset from the start of the input stream to read from. 132 * @param pvBuf Where to store the read data. 133 * @param cbBuf How much to read. 134 * @param pcbRead Where to store the amount of data read on succcess. 135 */ 136 typedef DECLCALLBACK(int) FNRTJSONTOKENIZERREAD(void *pvUser, uint32_t offInput, void *pvBuf, size_t cbBuf, 137 size_t *pcbRead); 138 /** Pointer to a tokenizer read buffer callback. */ 139 typedef FNRTJSONTOKENIZERREAD *PFNRTJSONTOKENIZERREAD; 140 141 /** 126 142 * Tokenizer state. 127 143 */ 128 144 typedef struct RTJSONTOKENIZER 129 145 { 130 /** Char buffer to read from. */ 131 const char *pszInput; 146 /** Read callback. */ 147 PFNRTJSONTOKENIZERREAD pfnRead; 148 /** Opaque user data. */ 149 void *pvUser; 150 /** Current offset into the input stream. */ 151 uint32_t offInput; 152 /** Number of valid bytes in the input buffer. */ 153 size_t cbBuf; 154 /* Current offset into the input buffer. */ 155 uint32_t offBuf; 156 /** Input cache buffer. */ 157 char achBuf[512]; 132 158 /** Current position into the input stream. */ 133 159 RTJSONPOS Pos; … … 205 231 typedef RTJSONITINT *PRTJSONITINT; 206 232 233 /** 234 * Passing arguments for the read callbacks. 235 */ 236 typedef struct RTJSONREADERARGS 237 { 238 /** Buffer/File size */ 239 size_t cbData; 240 /** Data specific for one callback. */ 241 union 242 { 243 PRTSTREAM hStream; 244 const uint8_t *pbBuf; 245 } u; 246 } RTJSONREADERARGS; 247 /** Pointer to a readers argument. */ 248 typedef RTJSONREADERARGS *PRTJSONREADERARGS; 249 207 250 /********************************************************************************************************************************* 208 251 * Global variables * … … 213 256 214 257 /** 258 * Fill the input buffer from the input stream. 259 * 260 * @returns IPRT status code. 261 * @param pTokenizer The tokenizer state. 262 */ 263 static int rtJsonTokenizerRead(PRTJSONTOKENIZER pTokenizer) 264 { 265 size_t cbRead = 0; 266 int rc = pTokenizer->pfnRead(pTokenizer->pvUser, pTokenizer->offInput, &pTokenizer->achBuf[0], 267 sizeof(pTokenizer->achBuf), &cbRead); 268 if (RT_SUCCESS(rc)) 269 { 270 pTokenizer->cbBuf = cbRead; 271 pTokenizer->offInput += cbRead; 272 pTokenizer->offBuf = 0; 273 /* Validate UTF-8 encoding. */ 274 rc = RTStrValidateEncodingEx(&pTokenizer->achBuf[0], cbRead, 0 /* fFlags */); 275 /* If we read less than requested we reached the end and fill the remainder with terminators. */ 276 if (cbRead < sizeof(pTokenizer->achBuf)) 277 memset(&pTokenizer->achBuf[cbRead], 0, sizeof(pTokenizer->achBuf) - cbRead); 278 } 279 280 return rc; 281 } 282 283 /** 284 * Skips the given amount of characters in the input stream. 285 * 286 * @returns IPRT status code. 287 * @param pTokenizer The tokenizer state. 288 * @param cchSkip The amount of characters to skip. 289 */ 290 static int rtJsonTokenizerSkip(PRTJSONTOKENIZER pTokenizer, unsigned cchSkip) 291 { 292 int rc = VINF_SUCCESS; 293 294 /* 295 * In case we reached the end of the stream don't even attempt to read new data. 296 * Safety precaution for possible bugs in the parser causing out of bounds reads 297 */ 298 if (pTokenizer->achBuf[pTokenizer->offBuf] == '\0') 299 return rc; 300 301 while ( cchSkip > 0 302 && pTokenizer->offBuf < pTokenizer->cbBuf 303 && RT_SUCCESS(rc)) 304 { 305 unsigned cchThisSkip = RT_MIN(cchSkip, pTokenizer->cbBuf - pTokenizer->offBuf); 306 307 pTokenizer->offBuf += cchThisSkip; 308 /* Read new data if required and we didn't reach the end yet. */ 309 if ( pTokenizer->offBuf == pTokenizer->cbBuf 310 && pTokenizer->cbBuf == sizeof(pTokenizer->achBuf)) 311 rc = rtJsonTokenizerRead(pTokenizer); 312 313 cchSkip -= cchThisSkip; 314 } 315 316 return rc; 317 } 318 319 320 /** 215 321 * Returns whether the tokenizer reached the end of the stream. 216 322 * … … 221 327 DECLINLINE(bool) rtJsonTokenizerIsEos(PRTJSONTOKENIZER pTokenizer) 222 328 { 223 return *pTokenizer->pszInput== '\0';329 return pTokenizer->achBuf[pTokenizer->offBuf] == '\0'; 224 330 } 225 331 … … 232 338 DECLINLINE(void) rtJsonTokenizerSkipCh(PRTJSONTOKENIZER pTokenizer) 233 339 { 234 pTokenizer->pszInput++;340 rtJsonTokenizerSkip(pTokenizer, 1); 235 341 pTokenizer->Pos.iChStart++; 236 342 pTokenizer->Pos.iChEnd++; … … 247 353 return rtJsonTokenizerIsEos(pTokenizer) 248 354 ? '\0' 249 : *(pTokenizer->pszInput + 1);355 : pTokenizer->achBuf[pTokenizer->offBuf + 1]; /** @todo: Read out of bounds */ 250 356 } 251 357 … … 264 370 ch = '\0'; 265 371 else 266 ch = *pTokenizer->pszInput;372 ch = pTokenizer->achBuf[pTokenizer->offBuf]; 267 373 268 374 return ch; … … 277 383 DECLINLINE(void) rtJsonTokenizerNewLine(PRTJSONTOKENIZER pTokenizer, unsigned cSkip) 278 384 { 279 pTokenizer->pszInput += cSkip;385 rtJsonTokenizerSkip(pTokenizer, cSkip); 280 386 pTokenizer->Pos.iLine++; 281 387 pTokenizer->Pos.iChStart = 1; … … 384 490 unsigned uBase = 10; 385 491 char *pszNext = NULL; 386 387 Assert(RT_C_IS_DIGIT(rtJsonTokenizerGetCh(pTokenizer)));388 389 /* Let RTStrToInt64Ex() do all the work, looks compliant. */ 492 size_t cchNum = 0; 493 char aszTmp[128]; /* Everything larger is not possible to display in signed 64bit. */ 494 RT_ZERO(aszTmp); 495 390 496 pToken->enmClass = RTJSONTOKENCLASS_NUMBER; 391 int rc = RTStrToInt64Ex(pTokenizer->pszInput, &pszNext, 0, &pToken->Class.Number.i64Num); 392 Assert(RT_SUCCESS(rc) || rc == VWRN_TRAILING_CHARS || rc == VWRN_TRAILING_SPACES); 393 /** @todo: Handle number to big, throw a warning */ 394 395 unsigned cchNumber = pszNext - pTokenizer->pszInput; 396 for (unsigned i = 0; i < cchNumber; i++) 497 498 char ch = rtJsonTokenizerGetCh(pTokenizer); 499 while ( RT_C_IS_DIGIT(ch) 500 && cchNum < sizeof(aszTmp) - 1) 501 { 502 aszTmp[cchNum] = ch; 503 cchNum++; 397 504 rtJsonTokenizerSkipCh(pTokenizer); 398 399 return VINF_SUCCESS; 505 ch = rtJsonTokenizerGetCh(pTokenizer); 506 } 507 508 int rc = VINF_SUCCESS; 509 if (RT_C_IS_DIGIT(ch) && cchNum == sizeof(aszTmp) - 1) 510 rc = VERR_NUMBER_TOO_BIG; 511 else 512 { 513 rc = RTStrToInt64Ex(&aszTmp[0], NULL, 0, &pToken->Class.Number.i64Num); 514 Assert(RT_SUCCESS(rc) || rc == VWRN_NUMBER_TOO_BIG); 515 if (rc == VWRN_NUMBER_TOO_BIG) 516 rc = VERR_NUMBER_TOO_BIG; 517 } 518 519 return rc; 400 520 } 401 521 … … 422 542 char ch = rtJsonTokenizerGetCh(pTokenizer); 423 543 while ( ch != '\"' 424 && ch != '\0') 544 && ch != '\0' 545 && cchStr < sizeof(aszTmp) - 1) 425 546 { 426 547 if (ch == '\\') … … 545 666 * @returns IPRT status code. 546 667 * @param pTokenizer The tokenizer state to initialize. 547 * @param pszInput The input to create the tokenizer for. 548 */ 549 static int rtJsonTokenizerInit(PRTJSONTOKENIZER pTokenizer, const char *pszInput) 550 { 551 pTokenizer->pszInput = pszInput; 668 * @param pfnRead Read callback for the input stream. 669 * @param pvUser Opaque user data to pass to the callback. 670 */ 671 static int rtJsonTokenizerInit(PRTJSONTOKENIZER pTokenizer, PFNRTJSONTOKENIZERREAD pfnRead, void *pvUser) 672 { 673 pTokenizer->pfnRead = pfnRead; 674 pTokenizer->pvUser = pvUser; 675 pTokenizer->offInput = 0; 676 pTokenizer->cbBuf = 0; 677 pTokenizer->offBuf = 0; 552 678 pTokenizer->Pos.iLine = 1; 553 679 pTokenizer->Pos.iChStart = 1; … … 555 681 pTokenizer->pTokenCurr = &pTokenizer->Token1; 556 682 pTokenizer->pTokenNext = &pTokenizer->Token2; 683 684 RT_ZERO(pTokenizer->achBuf); 685 686 /* Fill the input buffer. */ 687 int rc = rtJsonTokenizerRead(pTokenizer); 688 557 689 /* Fill the tokenizer with two first tokens. */ 558 int rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenCurr); 690 if (RT_SUCCESS(rc)) 691 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenCurr); 559 692 if (RT_SUCCESS(rc)) 560 693 rc = rtJsonTokenizerReadNextToken(pTokenizer, pTokenizer->pTokenNext); … … 846 979 } 847 980 981 /** 982 * Entry point to parse a JSON document. 983 * 984 * @returns IPRT status code. 985 * @param pTokenizer The tokenizer state. 986 * @param ppJsonVal Where to store the root JSON value on success. 987 * @param pErrInfo Where to store extended error info. Optional. 988 */ 989 static int rtJsonParse(PRTJSONTOKENIZER pTokenizer, PRTJSONVALINT *ppJsonVal, 990 PRTERRINFO pErrInfo) 991 { 992 PRTJSONTOKEN pToken = NULL; 993 int rc = rtJsonTokenizerGetToken(pTokenizer, &pToken); 994 if (RT_SUCCESS(rc)) 995 rc = rtJsonParseValue(pTokenizer, pToken, ppJsonVal, pErrInfo); 996 997 return rc; 998 } 999 1000 /** 1001 * Read callback for RTJsonParseFromBuf(). 1002 */ 1003 static DECLCALLBACK(int) rtJsonTokenizerParseFromBuf(void *pvUser, uint32_t offInput, 1004 void *pvBuf, size_t cbBuf, 1005 size_t *pcbRead) 1006 { 1007 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser; 1008 size_t cbLeft = offInput < pArgs->cbData ? pArgs->cbData - offInput : 0; 1009 1010 if (cbLeft) 1011 memcpy(pvBuf, &pArgs->u.pbBuf[offInput], RT_MIN(cbLeft, cbBuf)); 1012 1013 *pcbRead = RT_MIN(cbLeft, cbBuf); 1014 1015 return VINF_SUCCESS; 1016 } 1017 1018 /** 1019 * Read callback for RTJsonParseFromString(). 1020 */ 1021 static DECLCALLBACK(int) rtJsonTokenizerParseFromString(void *pvUser, uint32_t offInput, 1022 void *pvBuf, size_t cbBuf, 1023 size_t *pcbRead) 1024 { 1025 const char *pszStr = (const char *)pvUser; 1026 size_t cchStr = strlen(pszStr) + 1; /* Include zero terminator. */ 1027 size_t cbLeft = offInput < cchStr ? cchStr - offInput : 0; 1028 1029 if (cbLeft) 1030 memcpy(pvBuf, &pszStr[offInput], RT_MIN(cbLeft, cbBuf)); 1031 1032 *pcbRead = RT_MIN(cbLeft, cbBuf); 1033 1034 return VINF_SUCCESS; 1035 } 1036 1037 /** 1038 * Read callback for RTJsonParseFromFile(). 1039 */ 1040 static DECLCALLBACK(int) rtJsonTokenizerParseFromFile(void *pvUser, uint32_t offInput, 1041 void *pvBuf, size_t cbBuf, 1042 size_t *pcbRead) 1043 { 1044 int rc = VINF_SUCCESS; 1045 PRTJSONREADERARGS pArgs = (PRTJSONREADERARGS)pvUser; 1046 size_t cbRead = 0; 1047 1048 rc = RTStrmReadEx(pArgs->u.hStream, pvBuf, cbBuf, &cbRead); 1049 if (RT_SUCCESS(rc)) 1050 *pcbRead = cbRead; 1051 1052 return rc; 1053 } 848 1054 849 1055 RTDECL(int) RTJsonParseFromBuf(PRTJSONVAL phJsonVal, const uint8_t *pbBuf, size_t cbBuf, 850 1056 PRTERRINFO pErrInfo) 851 1057 { 852 return VERR_NOT_IMPLEMENTED; 1058 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER); 1059 AssertPtrReturn(pbBuf, VERR_INVALID_POINTER); 1060 AssertReturn(cbBuf > 0, VERR_INVALID_PARAMETER); 1061 1062 int rc = VINF_SUCCESS; 1063 RTJSONREADERARGS Args; 1064 RTJSONTOKENIZER Tokenizer; 1065 1066 Args.cbData = cbBuf; 1067 Args.u.pbBuf = pbBuf; 1068 1069 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromBuf, &Args); 1070 if (RT_SUCCESS(rc)) 1071 { 1072 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo); 1073 rtJsonTokenizerDestroy(&Tokenizer); 1074 } 1075 1076 return rc; 853 1077 } 854 1078 855 1079 RTDECL(int) RTJsonParseFromString(PRTJSONVAL phJsonVal, const char *pszStr, PRTERRINFO pErrInfo) 856 1080 { 857 return VERR_NOT_IMPLEMENTED; 1081 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER); 1082 AssertPtrReturn(pszStr, VERR_INVALID_POINTER); 1083 1084 int rc = VINF_SUCCESS; 1085 RTJSONTOKENIZER Tokenizer; 1086 1087 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromString, (void *)pszStr); 1088 if (RT_SUCCESS(rc)) 1089 { 1090 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo); 1091 rtJsonTokenizerDestroy(&Tokenizer); 1092 } 1093 1094 return rc; 858 1095 } 859 1096 860 1097 RTDECL(int) RTJsonParseFromFile(PRTJSONVAL phJsonVal, const char *pszFilename, PRTERRINFO pErrInfo) 861 1098 { 862 return VERR_NOT_IMPLEMENTED; 1099 AssertPtrReturn(phJsonVal, VERR_INVALID_POINTER); 1100 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER); 1101 1102 int rc = VINF_SUCCESS; 1103 RTJSONREADERARGS Args; 1104 1105 Args.cbData = 0; 1106 rc = RTStrmOpen(pszFilename, "r", &Args.u.hStream); 1107 if (RT_SUCCESS(rc)) 1108 { 1109 RTJSONTOKENIZER Tokenizer; 1110 1111 rc = rtJsonTokenizerInit(&Tokenizer, rtJsonTokenizerParseFromFile, &Args); 1112 if (RT_SUCCESS(rc)) 1113 { 1114 rc = rtJsonParse(&Tokenizer, phJsonVal, pErrInfo); 1115 rtJsonTokenizerDestroy(&Tokenizer); 1116 } 1117 RTStrmClose(Args.u.hStream); 1118 } 1119 1120 return rc; 863 1121 } 864 1122
Note:
See TracChangeset
for help on using the changeset viewer.