json_parser.c (44402B)
1 #include "flatcc_rtconfig.h" 2 #include "flatcc_json_parser.h" 3 #include "flatcc_assert.h" 4 5 #define uoffset_t flatbuffers_uoffset_t 6 #define soffset_t flatbuffers_soffset_t 7 #define voffset_t flatbuffers_voffset_t 8 #define utype_t flatbuffers_utype_t 9 10 #define uoffset_size sizeof(uoffset_t) 11 #define soffset_size sizeof(soffset_t) 12 #define voffset_size sizeof(voffset_t) 13 #define utype_size sizeof(utype_t) 14 15 #define offset_size uoffset_size 16 #if FLATCC_USE_GRISU3 && !defined(PORTABLE_USE_GRISU3) 17 #define PORTABLE_USE_GRISU3 1 18 #endif 19 #include "portable/pparsefp.h" 20 #include "portable/pbase64.h" 21 22 #if FLATCC_USE_SSE4_2 23 #ifdef __SSE4_2__ 24 #define USE_SSE4_2 25 #endif 26 #endif 27 28 #ifdef USE_SSE4_2 29 #include <nmmintrin.h> 30 #define cmpistri(end, haystack, needle, flags) \ 31 if (end - haystack >= 16) do { \ 32 int i; \ 33 __m128i a = _mm_loadu_si128((const __m128i *)(needle)); \ 34 do { \ 35 __m128i b = _mm_loadu_si128((const __m128i *)(haystack)); \ 36 i = _mm_cmpistri(a, b, flags); \ 37 haystack += i; \ 38 } while (i == 16 && end - haystack >= 16); \ 39 } while(0) 40 #endif 41 42 const char *flatcc_json_parser_error_string(int err) 43 { 44 switch (err) { 45 #define XX(no, str) \ 46 case flatcc_json_parser_error_##no: \ 47 return str; 48 FLATCC_JSON_PARSE_ERROR_MAP(XX) 49 #undef XX 50 default: 51 return "unknown"; 52 } 53 } 54 55 const char *flatcc_json_parser_set_error(flatcc_json_parser_t *ctx, const char *loc, const char *end, int err) 56 { 57 if (!ctx->error) { 58 ctx->error = err; 59 ctx->pos = (int)(loc - ctx->line_start + 1); 60 ctx->error_loc = loc; 61 } 62 return end; 63 } 64 65 const char *flatcc_json_parser_string_part(flatcc_json_parser_t *ctx, const char *buf, const char *end) 66 { 67 /* 68 * Disabled because it doesn't catch all control characters, but is 69 * useful for performance testing. 70 */ 71 #if 0 72 //#ifdef USE_SSE4_2 73 cmpistri(end, buf, "\"\\\0\r\n\t\v\f", _SIDD_POSITIVE_POLARITY); 74 #else 75 /* 76 * Testing for signed char >= 0x20 would also capture UTF-8 77 * encodings that we could verify, and also invalid encodings like 78 * 0xff, but we do not wan't to enforce strict UTF-8. 79 */ 80 while (buf != end && *buf != '\"' && ((unsigned char)*buf) >= 0x20 && *buf != '\\') { 81 ++buf; 82 } 83 #endif 84 if (buf == end) { 85 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unterminated_string); 86 } 87 if (*buf == '"') { 88 return buf; 89 } 90 if (*buf < 0x20) { 91 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_character); 92 } 93 return buf; 94 } 95 96 const char *flatcc_json_parser_space_ext(flatcc_json_parser_t *ctx, const char *buf, const char *end) 97 { 98 again: 99 #ifdef USE_SSE4_2 100 /* 101 * We can include line break, but then error reporting suffers and 102 * it really makes no big difference. 103 */ 104 //cmpistri(end, buf, "\x20\t\v\f\r\n", _SIDD_NEGATIVE_POLARITY); 105 cmpistri(end, buf, "\x20\t\v\f", _SIDD_NEGATIVE_POLARITY); 106 #else 107 #if FLATCC_ALLOW_UNALIGNED_ACCESS 108 while (end - buf >= 16) { 109 if (*buf > 0x20) { 110 return buf; 111 } 112 #if FLATCC_JSON_PARSE_WIDE_SPACE 113 if (((uint64_t *)buf)[0] != 0x2020202020202020) { 114 descend: 115 if (((uint32_t *)buf)[0] == 0x20202020) { 116 buf += 4; 117 } 118 #endif 119 if (((uint16_t *)buf)[0] == 0x2020) { 120 buf += 2; 121 } 122 if (*buf == 0x20) { 123 ++buf; 124 } 125 if (*buf > 0x20) { 126 return buf; 127 } 128 break; 129 #if FLATCC_JSON_PARSE_WIDE_SPACE 130 } 131 if (((uint64_t *)buf)[1] != 0x2020202020202020) { 132 buf += 8; 133 goto descend; 134 } 135 buf += 16; 136 #endif 137 } 138 #endif 139 #endif 140 while (buf != end && *buf == 0x20) { 141 ++buf; 142 } 143 while (buf != end && *buf <= 0x20) { 144 switch (*buf) { 145 case 0x0d: buf += (end - buf > 1 && buf[1] == 0x0a); 146 /* Consume following LF or treating CR as LF. */ 147 ++ctx->line; ctx->line_start = ++buf; continue; 148 case 0x0a: ++ctx->line; ctx->line_start = ++buf; continue; 149 case 0x09: ++buf; continue; 150 case 0x20: goto again; /* Don't consume here, sync with power of 2 spaces. */ 151 default: return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unexpected_character); 152 } 153 } 154 return buf; 155 } 156 157 static int decode_hex4(const char *buf, uint32_t *result) 158 { 159 uint32_t u, x; 160 char c; 161 162 u = 0; 163 c = buf[0]; 164 if (c >= '0' && c <= '9') { 165 x = (uint32_t)(c - '0'); 166 u = x << 12; 167 } else { 168 /* Lower case. */ 169 c |= 0x20; 170 if (c >= 'a' && c <= 'f') { 171 x = (uint32_t)(c - 'a' + 10); 172 u |= x << 12; 173 } else { 174 return -1; 175 } 176 } 177 c = buf[1]; 178 if (c >= '0' && c <= '9') { 179 x = (uint32_t)(c - '0'); 180 u |= x << 8; 181 } else { 182 /* Lower case. */ 183 c |= 0x20; 184 if (c >= 'a' && c <= 'f') { 185 x = (uint32_t)(c - 'a' + 10); 186 u |= x << 8; 187 } else { 188 return -1; 189 } 190 } 191 c = buf[2]; 192 if (c >= '0' && c <= '9') { 193 x = (uint32_t)(c - '0'); 194 u |= x << 4; 195 } else { 196 /* Lower case. */ 197 c |= 0x20; 198 if (c >= 'a' && c <= 'f') { 199 x = (uint32_t)(c - 'a' + 10); 200 u |= x << 4; 201 } else { 202 return -1; 203 } 204 } 205 c = buf[3]; 206 if (c >= '0' && c <= '9') { 207 x = (uint32_t)(c - '0'); 208 u |= x; 209 } else { 210 /* Lower case. */ 211 c |= 0x20; 212 if (c >= 'a' && c <= 'f') { 213 x = (uint32_t)(c - 'a' + 10); 214 u |= x; 215 } else { 216 return -1; 217 } 218 } 219 *result = u; 220 return 0; 221 } 222 223 static int decode_unicode_char(uint32_t u, char *code) 224 { 225 if (u <= 0x7f) { 226 code[0] = 1; 227 code[1] = (char)u; 228 } else if (u <= 0x7ff) { 229 code[0] = 2; 230 code[1] = (char)(0xc0 | (u >> 6)); 231 code[2] = (char)(0x80 | (u & 0x3f)); 232 } else if (u <= 0xffff) { 233 code[0] = 3; 234 code[1] = (char)(0xe0 | (u >> 12)); 235 code[2] = (char)(0x80 | ((u >> 6) & 0x3f)); 236 code[3] = (char)(0x80 | (u & 0x3f)); 237 } else if (u <= 0x10ffff) { 238 code[0] = 4; 239 code[1] = (char)(0xf0 | (u >> 18)); 240 code[2] = (char)(0x80 | ((u >> 12) & 0x3f)); 241 code[3] = (char)(0x80 | ((u >> 6) & 0x3f)); 242 code[4] = (char)(0x80 | (u & 0x3f)); 243 } else { 244 code[0] = 0; 245 return -1; 246 } 247 return 0; 248 } 249 250 static inline uint32_t combine_utf16_surrogate_pair(uint32_t high, uint32_t low) 251 { 252 return (high - 0xd800) * 0x400 + (low - 0xdc00) + 0x10000; 253 } 254 255 static inline int decode_utf16_surrogate_pair(uint32_t high, uint32_t low, char *code) 256 { 257 return decode_unicode_char(combine_utf16_surrogate_pair(high, low), code); 258 } 259 260 261 /* 262 * UTF-8 code points can have up to 4 bytes but JSON can only 263 * encode up to 3 bytes via the \uXXXX syntax. 264 * To handle the range U+10000..U+10FFFF two UTF-16 surrogate 265 * pairs must be used. If this is not detected, the pairs 266 * survive in the output which is not valid but often tolerated. 267 * Emojis generally require such a pair, unless encoded 268 * unescaped in UTF-8. 269 * 270 * If a high surrogate pair is detected and a low surrogate pair 271 * follows, the combined sequence is decoded as a 4 byte 272 * UTF-8 sequence. Unpaired surrogate halves are decoded as is 273 * despite being an invalid UTF-8 value. 274 */ 275 276 const char *flatcc_json_parser_string_escape(flatcc_json_parser_t *ctx, const char *buf, const char *end, flatcc_json_parser_escape_buffer_t code) 277 { 278 char c, v; 279 uint32_t u, u2; 280 281 if (end - buf < 2 || buf[0] != '\\') { 282 code[0] = 0; 283 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_escape); 284 } 285 switch (buf[1]) { 286 case 'x': 287 v = 0; 288 code[0] = 1; 289 if (end - buf < 4) { 290 code[0] = 0; 291 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_escape); 292 } 293 c = buf[2]; 294 if (c >= '0' && c <= '9') { 295 v |= (c - '0') << 4; 296 } else { 297 /* Lower case. */ 298 c |= 0x20; 299 if (c >= 'a' && c <= 'f') { 300 v |= (c - 'a' + 10) << 4; 301 } else { 302 code[0] = 0; 303 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_escape); 304 } 305 } 306 c = buf[3]; 307 if (c >= '0' && c <= '9') { 308 v |= c - '0'; 309 } else { 310 /* Lower case. */ 311 c |= 0x20; 312 if (c >= 'a' && c <= 'f') { 313 v |= c - 'a' + 10; 314 } else { 315 code[0] = 0; 316 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_escape); 317 } 318 } 319 code[1] = v; 320 return buf + 4; 321 case 'u': 322 if (end - buf < 6) { 323 code[0] = 0; 324 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_escape); 325 } 326 if (decode_hex4(buf + 2, &u)) { 327 code[0] = 0; 328 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_escape); 329 }; 330 /* If a high UTF-16 surrogate half pair was detected */ 331 if (u >= 0xd800 && u <= 0xdbff && 332 /* and there is space for a matching low half pair */ 333 end - buf >= 12 && 334 /* and there is a second escape following immediately */ 335 buf[6] == '\\' && buf[7] == 'u' && 336 /* and it is valid hex */ 337 decode_hex4(buf + 8, &u2) == 0 && 338 /* and it is a low UTF-16 surrogate pair */ 339 u2 >= 0xdc00 && u2 <= 0xdfff) { 340 /* then decode the pair into a single 4 byte utf-8 sequence. */ 341 if (decode_utf16_surrogate_pair(u, u2, code)) { 342 code[0] = 0; 343 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_escape); 344 } 345 return buf + 12; 346 /* 347 * Otherwise decode unmatched surrogate pairs as is any 348 * other UTF-8. Some systems might depend on these surviving. 349 * Leave ignored errors for the next parse step. 350 */ 351 } 352 decode_unicode_char(u, code); 353 return buf + 6; 354 case 't': 355 code[0] = 1; 356 code[1] = '\t'; 357 return buf + 2; 358 case 'n': 359 code[0] = 1; 360 code[1] = '\n'; 361 return buf + 2; 362 case 'r': 363 code[0] = 1; 364 code[1] = '\r'; 365 return buf + 2; 366 case 'b': 367 code[0] = 1; 368 code[1] = '\b'; 369 return buf + 2; 370 case 'f': 371 code[0] = 1; 372 code[1] = '\f'; 373 return buf + 2; 374 case '\"': 375 code[0] = 1; 376 code[1] = '\"'; 377 return buf + 2; 378 case '\\': 379 code[0] = 1; 380 code[1] = '\\'; 381 return buf + 2; 382 case '/': 383 code[0] = 1; 384 code[1] = '/'; 385 return buf + 2; 386 default: 387 code[0] = 0; 388 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_escape); 389 } 390 } 391 392 /* Only applies to unquoted constants during generic parsring, otherwise it is skipped as a string. */ 393 const char *flatcc_json_parser_skip_constant(flatcc_json_parser_t *ctx, const char *buf, const char *end) 394 { 395 char c; 396 const char *k; 397 398 while (buf != end) { 399 c = *buf; 400 if ((c & 0x80) || (c == '_') || (c >= '0' && c <= '9') || c == '.') { 401 ++buf; 402 continue; 403 } 404 /* Upper case. */ 405 c |= 0x20; 406 if (c >= 'a' && c <= 'z') { 407 ++buf; 408 continue; 409 } 410 buf = flatcc_json_parser_space(ctx, (k = buf), end); 411 if (buf == k) { 412 return buf; 413 } 414 } 415 return buf; 416 } 417 418 const char *flatcc_json_parser_match_constant(flatcc_json_parser_t *ctx, const char *buf, const char *end, int pos, int *more) 419 { 420 const char *mark = buf, *k = buf + pos; 421 422 if (end - buf <= pos) { 423 *more = 0; 424 return buf; 425 } 426 #if FLATCC_JSON_PARSE_ALLOW_UNQUOTED 427 if (ctx->unquoted) { 428 buf = flatcc_json_parser_space(ctx, k, end); 429 if (buf == end) { 430 /* 431 * We cannot make a decision on more. 432 * Just return end and let parser handle sync point in 433 * case it is able to resume parse later on. 434 * For the same reason we do not lower ctx->unquoted. 435 */ 436 *more = 0; 437 return buf; 438 } 439 if (buf != k) { 440 char c = *buf; 441 /* 442 * Space was seen - and thus we have a valid match. 443 * If the next char is an identifier start symbol 444 * we raise the more flag to support syntax like: 445 * 446 * `flags: Hungry Sleepy Awake, ...` 447 */ 448 if (c == '_' || (c & 0x80)) { 449 *more = 1; 450 return buf; 451 } 452 c |= 0x20; 453 if (c >= 'a' && c <= 'z') { 454 *more = 1; 455 return buf; 456 } 457 } 458 /* 459 * Space was not seen, so the match is only valid if followed 460 * by a JSON separator symbol, and there cannot be more values 461 * following so `more` is lowered. 462 */ 463 *more = 0; 464 if (*buf == ',' || *buf == '}' || *buf == ']') { 465 return buf; 466 } 467 return mark; 468 } 469 #endif 470 buf = k; 471 if (*buf == 0x20) { 472 ++buf; 473 while (buf != end && *buf == 0x20) { 474 ++buf; 475 } 476 if (buf == end) { 477 *more = 0; 478 return buf; 479 } 480 /* We accept untrimmed space like " Green Blue ". */ 481 if (*buf != '\"') { 482 *more = 1; 483 return buf; 484 } 485 } 486 switch (*buf) { 487 case '\\': 488 *more = 0; 489 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_escape); 490 case '\"': 491 buf = flatcc_json_parser_space(ctx, buf + 1, end); 492 *more = 0; 493 return buf; 494 } 495 *more = 0; 496 return mark; 497 } 498 499 const char *flatcc_json_parser_unmatched_symbol(flatcc_json_parser_t *ctx, const char *buf, const char *end) 500 { 501 if (ctx->flags & flatcc_json_parser_f_skip_unknown) { 502 buf = flatcc_json_parser_symbol_end(ctx, buf, end); 503 buf = flatcc_json_parser_space(ctx, buf, end); 504 if (buf != end && *buf == ':') { 505 ++buf; 506 buf = flatcc_json_parser_space(ctx, buf, end); 507 } else { 508 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_expected_colon); 509 } 510 return flatcc_json_parser_generic_json(ctx, buf, end); 511 } else { 512 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unknown_symbol); 513 } 514 } 515 516 static const char *__flatcc_json_parser_number(flatcc_json_parser_t *ctx, const char *buf, const char *end) 517 { 518 if (buf == end) { 519 return buf; 520 } 521 if (*buf == '-') { 522 ++buf; 523 if (buf == end) { 524 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_numeric); 525 } 526 } 527 if (*buf == '0') { 528 ++buf; 529 } else { 530 if (*buf < '1' || *buf > '9') { 531 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_numeric); 532 } 533 ++buf; 534 while (buf != end && *buf >= '0' && *buf <= '9') { 535 ++buf; 536 } 537 } 538 if (buf != end) { 539 if (*buf == '.') { 540 ++buf; 541 if (*buf < '0' || *buf > '9') { 542 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_numeric); 543 } 544 ++buf; 545 while (buf != end && *buf >= '0' && *buf <= '9') { 546 ++buf; 547 } 548 } 549 } 550 if (buf != end && (*buf == 'e' || *buf == 'E')) { 551 ++buf; 552 if (buf == end) { 553 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_numeric); 554 } 555 if (*buf == '+' || *buf == '-') { 556 ++buf; 557 } 558 if (buf == end || *buf < '0' || *buf > '9') { 559 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_numeric); 560 } 561 ++buf; 562 while (buf != end && *buf >= '0' && *buf <= '9') { 563 ++buf; 564 } 565 } 566 567 /* 568 * For strtod termination we must ensure the tail is not valid 569 * including non-json exponent types. The simplest approach is 570 * to accept anything that could be valid json successor 571 * characters and reject end of buffer since we expect a closing 572 * '}'. 573 * 574 * The ',' is actually not safe if strtod uses a non-POSIX locale. 575 */ 576 if (buf != end) { 577 switch (*buf) { 578 case ',': 579 case ':': 580 case ']': 581 case '}': 582 case ' ': 583 case '\r': 584 case '\t': 585 case '\n': 586 case '\v': 587 return buf; 588 } 589 } 590 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_numeric); 591 } 592 593 const char *flatcc_json_parser_double(flatcc_json_parser_t *ctx, const char *buf, const char *end, double *v) 594 { 595 const char *next, *k; 596 597 *v = 0.0; 598 if (buf == end) { 599 return buf; 600 } 601 k = buf; 602 if (*buf == '-') ++k; 603 if (end - k > 1 && (k[0] == '.' || (k[0] == '0' && k[1] == '0'))) { 604 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_numeric); 605 } 606 next = parse_double(buf, (size_t)(end - buf), v); 607 if (next == 0 || next == buf) { 608 if (parse_double_isinf(*v)) { 609 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_overflow); 610 } 611 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_numeric); 612 } 613 return next; 614 } 615 616 const char *flatcc_json_parser_float(flatcc_json_parser_t *ctx, const char *buf, const char *end, float *v) 617 { 618 const char *next, *k; 619 620 *v = 0.0; 621 if (buf == end) { 622 return buf; 623 } 624 k = buf; 625 if (*buf == '-') ++k; 626 if (end - k > 1 && (k[0] == '.' || (k[0] == '0' && k[1] == '0'))) { 627 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_numeric); 628 } 629 next = parse_float(buf, (size_t)(end - buf), v); 630 if (next == 0 || next == buf) { 631 if (parse_float_isinf(*v)) { 632 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_overflow); 633 } 634 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_numeric); 635 } 636 return next; 637 } 638 639 const char *flatcc_json_parser_generic_json(flatcc_json_parser_t *ctx, const char *buf, const char *end) 640 { 641 char stack[FLATCC_JSON_PARSE_GENERIC_MAX_NEST]; 642 char *sp, *spend; 643 const char *k; 644 flatcc_json_parser_escape_buffer_t code; 645 int more = 0; 646 647 sp = stack; 648 spend = sp + FLATCC_JSON_PARSE_GENERIC_MAX_NEST; 649 650 again: 651 if (buf == end) { 652 return buf; 653 } 654 if (sp != stack && sp[-1] == '}') { 655 /* Inside an object, about to read field name. */ 656 buf = flatcc_json_parser_symbol_start(ctx, buf, end); 657 buf = flatcc_json_parser_symbol_end(ctx, buf, end); 658 buf = flatcc_json_parser_space(ctx, buf, end); 659 if (buf == end) { 660 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unbalanced_object); 661 } 662 if (*buf != ':') { 663 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_expected_colon); 664 } 665 buf = flatcc_json_parser_space(ctx, buf + 1, end); 666 } 667 switch (*buf) { 668 case '\"': 669 buf = flatcc_json_parser_string_start(ctx, buf, end); 670 while (buf != end && *buf != '\"') { 671 buf = flatcc_json_parser_string_part(ctx, buf, end); 672 if (buf != end && *buf == '\"') { 673 break; 674 } 675 buf = flatcc_json_parser_string_escape(ctx, buf, end, code); 676 } 677 buf = flatcc_json_parser_string_end(ctx, buf, end); 678 break; 679 case '-': 680 case '0': case '1': case '2': case '3': case '4': 681 case '5': case '6': case '7': case '8': case '9': 682 buf = __flatcc_json_parser_number(ctx, buf, end); 683 break; 684 #if !FLATCC_JSON_PARSE_ALLOW_UNQUOTED 685 case 't': case 'f': 686 { 687 uint8_t v; 688 buf = flatcc_json_parser_bool(ctx, (k = buf), end, &v); 689 if (k == buf) { 690 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unexpected_character); 691 } 692 } 693 break; 694 case 'n': 695 buf = flatcc_json_parser_null((k = buf), end); 696 if (k == buf) { 697 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unexpected_character); 698 } 699 break; 700 #endif 701 case '[': 702 if (sp == spend) { 703 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_deep_nesting); 704 } 705 *sp++ = ']'; 706 buf = flatcc_json_parser_space(ctx, buf + 1, end); 707 if (buf != end && *buf == ']') { 708 break; 709 } 710 goto again; 711 case '{': 712 if (sp == spend) { 713 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_deep_nesting); 714 } 715 *sp++ = '}'; 716 buf = flatcc_json_parser_space(ctx, buf + 1, end); 717 if (buf != end && *buf == '}') { 718 break; 719 } 720 goto again; 721 722 default: 723 #if FLATCC_JSON_PARSE_ALLOW_UNQUOTED 724 buf = flatcc_json_parser_skip_constant(ctx, (k = buf), end); 725 if (k == buf) { 726 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unexpected_character); 727 } 728 break; 729 #else 730 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unexpected_character); 731 #endif 732 } 733 while (buf != end && sp != stack) { 734 --sp; 735 if (*sp == ']') { 736 buf = flatcc_json_parser_array_end(ctx, buf, end, &more); 737 } else { 738 buf = flatcc_json_parser_object_end(ctx, buf, end, &more); 739 } 740 if (more) { 741 ++sp; 742 goto again; 743 } 744 } 745 if (buf == end && sp != stack) { 746 return flatcc_json_parser_set_error(ctx, buf, end, sp[-1] == ']' ? 747 flatcc_json_parser_error_unbalanced_array : 748 flatcc_json_parser_error_unbalanced_object); 749 } 750 /* Any ',', ']', or '}' belongs to parent context. */ 751 return buf; 752 } 753 754 const char *flatcc_json_parser_integer(flatcc_json_parser_t *ctx, const char *buf, const char *end, 755 int *value_sign, uint64_t *value) 756 { 757 uint64_t x0, x = 0; 758 const char *k; 759 760 if (buf == end) { 761 return buf; 762 } 763 k = buf; 764 *value_sign = *buf == '-'; 765 buf += *value_sign; 766 while (buf != end && *buf >= '0' && *buf <= '9') { 767 x0 = x; 768 x = x * 10 + (uint64_t)(*buf - '0'); 769 if (x0 > x) { 770 return flatcc_json_parser_set_error(ctx, buf, end, value_sign ? 771 flatcc_json_parser_error_underflow : flatcc_json_parser_error_overflow); 772 } 773 ++buf; 774 } 775 if (buf == k) { 776 /* Give up, but don't fail the parse just yet, it might be a valid symbol. */ 777 return buf; 778 } 779 if (buf != end && (*buf == 'e' || *buf == 'E' || *buf == '.')) { 780 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_float_unexpected); 781 } 782 *value = x; 783 return buf; 784 } 785 786 /* Array Creation - depends on flatcc builder. */ 787 788 const char *flatcc_json_parser_build_uint8_vector_base64(flatcc_json_parser_t *ctx, 789 const char *buf, const char *end, flatcc_builder_ref_t *ref, int urlsafe) 790 { 791 const char *mark; 792 uint8_t *pval; 793 size_t max_len; 794 size_t decoded_len, src_len; 795 int mode; 796 int ret; 797 798 mode = urlsafe ? base64_mode_url : base64_mode_rfc4648; 799 buf = flatcc_json_parser_string_start(ctx, buf, end); 800 buf = flatcc_json_parser_string_part(ctx, (mark = buf), end); 801 if (buf == end || *buf != '\"') { 802 goto base64_failed; 803 } 804 max_len = base64_decoded_size((size_t)(buf - mark)); 805 if (flatcc_builder_start_vector(ctx->ctx, 1, 1, FLATBUFFERS_COUNT_MAX((utype_size)))) { 806 goto failed; 807 } 808 if (!(pval = flatcc_builder_extend_vector(ctx->ctx, max_len))) { 809 goto failed; 810 } 811 src_len = (size_t)(buf - mark); 812 decoded_len = max_len; 813 if ((ret = base64_decode(pval, (const uint8_t *)mark, &decoded_len, &src_len, mode))) { 814 buf = mark + src_len; 815 goto base64_failed; 816 } 817 if (src_len != (size_t)(buf - mark)) { 818 buf = mark + src_len; 819 goto base64_failed; 820 } 821 if (decoded_len < max_len) { 822 if (flatcc_builder_truncate_vector(ctx->ctx, max_len - decoded_len)) { 823 goto failed; 824 } 825 } 826 if (!(*ref = flatcc_builder_end_vector(ctx->ctx))) { 827 goto failed; 828 } 829 return flatcc_json_parser_string_end(ctx, buf, end); 830 831 failed: 832 *ref = 0; 833 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_runtime); 834 835 base64_failed: 836 *ref = 0; 837 return flatcc_json_parser_set_error(ctx, buf, end, 838 urlsafe ? flatcc_json_parser_error_base64url : flatcc_json_parser_error_base64); 839 } 840 841 const char *flatcc_json_parser_char_array(flatcc_json_parser_t *ctx, 842 const char *buf, const char *end, char *s, size_t n) 843 { 844 flatcc_json_parser_escape_buffer_t code; 845 const char *mark; 846 size_t k = 0; 847 848 buf = flatcc_json_parser_string_start(ctx, buf, end); 849 if (buf != end) 850 while (*buf != '\"') { 851 buf = flatcc_json_parser_string_part(ctx, (mark = buf), end); 852 if (buf == end) return end; 853 k = (size_t)(buf - mark); 854 if (k > n) { 855 if (!(ctx->flags & flatcc_json_parser_f_skip_array_overflow)) { 856 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_array_overflow); 857 } 858 k = n; /* Might truncate UTF-8. */ 859 } 860 memcpy(s, mark, k); 861 s += k; 862 n -= k; 863 if (*buf == '\"') break; 864 buf = flatcc_json_parser_string_escape(ctx, buf, end, code); 865 if (buf == end) return end; 866 k = (size_t)code[0]; 867 mark = code + 1; 868 if (k > n) { 869 if (!(ctx->flags & flatcc_json_parser_f_skip_array_overflow)) { 870 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_array_overflow); 871 } 872 k = n; /* Might truncate UTF-8. */ 873 } 874 memcpy(s, mark, k); 875 s += k; 876 n -= k; 877 } 878 if (n != 0) { 879 if (ctx->flags & flatcc_json_parser_f_reject_array_underflow) { 880 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_array_underflow); 881 } 882 memset(s, 0, n); 883 } 884 return flatcc_json_parser_string_end(ctx, buf, end); 885 } 886 887 888 /* String Creation - depends on flatcc builder. */ 889 890 const char *flatcc_json_parser_build_string(flatcc_json_parser_t *ctx, 891 const char *buf, const char *end, flatcc_builder_ref_t *ref) 892 { 893 flatcc_json_parser_escape_buffer_t code; 894 const char *mark; 895 896 buf = flatcc_json_parser_string_start(ctx, buf, end); 897 buf = flatcc_json_parser_string_part(ctx, (mark = buf), end); 898 if (buf != end && *buf == '\"') { 899 *ref = flatcc_builder_create_string(ctx->ctx, mark, (size_t)(buf - mark)); 900 } else { 901 if (flatcc_builder_start_string(ctx->ctx) || 902 0 == flatcc_builder_append_string(ctx->ctx, mark, (size_t)(buf - mark))) goto failed; 903 while (buf != end && *buf != '\"') { 904 buf = flatcc_json_parser_string_escape(ctx, buf, end, code); 905 if (0 == flatcc_builder_append_string(ctx->ctx, code + 1, (size_t)code[0])) goto failed; 906 if (end != (buf = flatcc_json_parser_string_part(ctx, (mark = buf), end))) { 907 if (0 == flatcc_builder_append_string(ctx->ctx, mark, (size_t)(buf - mark))) goto failed; 908 } 909 } 910 *ref = flatcc_builder_end_string(ctx->ctx); 911 } 912 return flatcc_json_parser_string_end(ctx, buf, end); 913 914 failed: 915 *ref = 0; 916 return buf; 917 } 918 919 /* UNIONS */ 920 921 /* 922 * Unions are difficult to parse because the type field may appear after 923 * the union table and because having two fields opens up for many more 924 * possible error scenarios. We must store each union of a table 925 * temporarily - this cannot be in the generated table parser function 926 * because there could be many unions (about 2^15 with default voffsets) 927 * although usually there will be only a few. We can also not store the 928 * data encoded in the existing table buffer in builder because we may 929 * have to remove it due to schema forwarding and removing it messes up 930 * the table layout. We also cannot naively allocate it dynamically for 931 * performance reasons. Instead we place the temporary union data in a 932 * separate frame from the table buffer, but on a similar stack. This is 933 * called the user stack and we manage one frame per table that is known 934 * to contain unions. 935 * 936 * Even the temporary structures in place we still cannot parse a union 937 * before we know its type. Due to JSON typically sorting fields 938 * alphabetically in various pretty printers, we are likely to receive 939 * the type late with (`<union_name>_type` following `<union_name>`. 940 * To deal with this we store a backtracking pointer and parses the 941 * table generically in a first pass and reparse the table once the type 942 * is known. This can happen recursively with nested tables containing 943 * unions which is why we need to have a stack frame. 944 * 945 * If the type field is stored first we just store the type in the 946 * custom frame and immediately parses the table with the right type 947 * once we see it. The parse will be much faster and we can strongly 948 * recommend that flatbuffer serializers do this, but we cannot require 949 * it. 950 * 951 * The actual overhead of dealing with the custom stack frame is fairly 952 * cheap once we get past the first custom stack allocation. 953 * 954 * We cannot update the builder before both the table and table type 955 * has been parsed because the the type might have to be ingored due 956 * to schema forwarding. Therefore the union type must be cached or 957 * reread. This happens trivially be calling the union parser with the 958 * type as argument, but it is important to be aware of before 959 * refactoring the code. 960 * 961 * The user frame is created at table start and remains valid until 962 * table exit, but we cannot assume the pointers to the frame remain 963 * valid. Specifically we cannot use frame pointers after calling 964 * the union parser. This means the union type must be cached or reread 965 * so it can be added to the table. Because the type is passed to 966 * the union parser this caching happens automatically but it is still 967 * important to be aware that it is required. 968 * 969 * The frame reserves temporary information for all unions the table 970 * holds, enumerated 0 <= `union_index` < `union_total` 971 * where the `union_total` is fixed type specific number. 972 * 973 * The `type_present` is needed because union types range from 0..255 974 * and we need an extra bit do distinguish not present from union type 975 * `NONE = 0`. 976 */ 977 978 typedef struct { 979 const char *backtrace; 980 const char *line_start; 981 int line; 982 uint8_t type_present; 983 uint8_t type; 984 /* Union vectors: */ 985 uoffset_t count; 986 size_t h_types; 987 } __flatcc_json_parser_union_entry_t; 988 989 typedef struct { 990 size_t union_total; 991 size_t union_count; 992 __flatcc_json_parser_union_entry_t unions[1]; 993 } __flatcc_json_parser_union_frame_t; 994 995 const char *flatcc_json_parser_prepare_unions(flatcc_json_parser_t *ctx, 996 const char *buf, const char *end, size_t union_total, size_t *handle) 997 { 998 __flatcc_json_parser_union_frame_t *f; 999 1000 if (!(*handle = flatcc_builder_enter_user_frame(ctx->ctx, 1001 sizeof(__flatcc_json_parser_union_frame_t) + (union_total - 1) * 1002 sizeof(__flatcc_json_parser_union_entry_t)))) { 1003 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_runtime); 1004 } 1005 f = flatcc_builder_get_user_frame_ptr(ctx->ctx, *handle); 1006 /* Frames have zeroed memory. */ 1007 f->union_total = union_total; 1008 return buf; 1009 } 1010 1011 const char *flatcc_json_parser_finalize_unions(flatcc_json_parser_t *ctx, 1012 const char *buf, const char *end, size_t handle) 1013 { 1014 __flatcc_json_parser_union_frame_t *f = flatcc_builder_get_user_frame_ptr(ctx->ctx, handle); 1015 1016 if (f->union_count) { 1017 buf = flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_union_incomplete); 1018 } 1019 flatcc_builder_exit_user_frame_at(ctx->ctx, handle); 1020 return buf; 1021 } 1022 1023 const char *flatcc_json_parser_union(flatcc_json_parser_t *ctx, 1024 const char *buf, const char *end, size_t union_index, 1025 flatbuffers_voffset_t id, size_t handle, flatcc_json_parser_union_f *union_parser) 1026 { 1027 __flatcc_json_parser_union_frame_t *f = flatcc_builder_get_user_frame_ptr(ctx->ctx, handle); 1028 __flatcc_json_parser_union_entry_t *e = &f->unions[union_index]; 1029 flatcc_builder_union_ref_t uref; 1030 1031 if (e->backtrace) { 1032 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_duplicate); 1033 } 1034 if (!e->type_present) { 1035 /* If we supported table: null, we should not count it, but we don't. */ 1036 ++f->union_count; 1037 e->line = ctx->line; 1038 e->line_start = ctx->line_start; 1039 buf = flatcc_json_parser_generic_json(ctx, (e->backtrace = buf), end); 1040 } else { 1041 uref.type = e->type; 1042 if (e->type == 0) { 1043 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_union_none_present); 1044 } 1045 --f->union_count; 1046 buf = union_parser(ctx, buf, end, e->type, &uref.value); 1047 if (buf != end) { 1048 if (flatcc_builder_table_add_union(ctx->ctx, id, uref)) { 1049 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_duplicate); 1050 } 1051 } 1052 } 1053 return buf; 1054 } 1055 1056 const char *flatcc_json_parser_union_type(flatcc_json_parser_t *ctx, 1057 const char *buf, const char *end, size_t union_index, flatbuffers_voffset_t id, 1058 size_t handle, 1059 flatcc_json_parser_integral_symbol_f *type_parsers[], 1060 flatcc_json_parser_union_f *union_parser) 1061 { 1062 __flatcc_json_parser_union_frame_t *f = flatcc_builder_get_user_frame_ptr(ctx->ctx, handle); 1063 __flatcc_json_parser_union_entry_t *e = f->unions + union_index; 1064 1065 flatcc_builder_union_ref_t uref; 1066 const char *mark; 1067 int line; 1068 const char *line_start; 1069 1070 if (e->type_present) { 1071 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_duplicate); 1072 } 1073 e->type_present = 1; 1074 buf = flatcc_json_parser_uint8(ctx, (mark = buf), end, &e->type); 1075 if (mark == buf) { 1076 buf = flatcc_json_parser_symbolic_uint8(ctx, buf, end, type_parsers, &e->type); 1077 } 1078 /* Only count the union if the type is not NONE. */ 1079 if (e->backtrace == 0) { 1080 f->union_count += e->type != 0; 1081 return buf; 1082 } 1083 FLATCC_ASSERT(f->union_count); 1084 --f->union_count; 1085 /* 1086 * IMPORTANT: we cannot access any value in the frame or entry 1087 * pointer after calling union parse because it might cause the 1088 * stack to reallocate. We should read the frame pointer again if 1089 * needed - we don't but remember it if refactoring code. 1090 * 1091 * IMPORTANT 2: Do not assign buf here. We are backtracking. 1092 */ 1093 line = ctx->line; 1094 line_start = ctx->line_start; 1095 ctx->line = e->line; 1096 ctx->line_start = e->line_start; 1097 uref.type = e->type; 1098 if (end == union_parser(ctx, e->backtrace, end, e->type, &uref.value)) { 1099 return end; 1100 } 1101 if (flatcc_builder_table_add_union(ctx->ctx, id, uref)) { 1102 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_duplicate); 1103 } 1104 ctx->line = line; 1105 ctx->line_start = line_start; 1106 return buf; 1107 } 1108 1109 static const char *_parse_union_vector(flatcc_json_parser_t *ctx, 1110 const char *buf, const char *end, size_t h_types, uoffset_t count, 1111 flatbuffers_voffset_t id, flatcc_json_parser_union_f *union_parser) 1112 { 1113 flatcc_builder_ref_t ref = 0, *pref; 1114 utype_t *types; 1115 int more; 1116 size_t i; 1117 1118 if (flatcc_builder_start_offset_vector(ctx->ctx)) goto failed; 1119 buf = flatcc_json_parser_array_start(ctx, buf, end, &more); 1120 i = 0; 1121 while (more) { 1122 if (i == count) { 1123 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_union_vector_length); 1124 } 1125 /* Frame must be restored between calls to table parser. */ 1126 types = flatcc_builder_get_user_frame_ptr(ctx->ctx, h_types); 1127 buf = union_parser(ctx, buf, end, types[i], &ref); 1128 if (buf == end) { 1129 return buf; 1130 } 1131 if (!(pref = flatcc_builder_extend_offset_vector(ctx->ctx, 1))) goto failed; 1132 *pref = ref; 1133 buf = flatcc_json_parser_array_end(ctx, buf, end, &more); 1134 ++i; 1135 } 1136 if (i != count) { 1137 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_union_vector_length); 1138 } 1139 /* Frame must be restored between calls to table parser. */ 1140 types = flatcc_builder_get_user_frame_ptr(ctx->ctx, h_types); 1141 if (!(ref = flatcc_builder_end_offset_vector_for_unions(ctx->ctx, types))) goto failed; 1142 if (!(pref = flatcc_builder_table_add_offset(ctx->ctx, id))) goto failed; 1143 *pref = ref; 1144 return buf; 1145 failed: 1146 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_runtime); 1147 } 1148 1149 const char *flatcc_json_parser_union_vector(flatcc_json_parser_t *ctx, 1150 const char *buf, const char *end, size_t union_index, 1151 flatbuffers_voffset_t id, size_t handle, flatcc_json_parser_union_f *union_parser) 1152 { 1153 __flatcc_json_parser_union_frame_t *f = flatcc_builder_get_user_frame_ptr(ctx->ctx, handle); 1154 __flatcc_json_parser_union_entry_t *e = f->unions + union_index; 1155 1156 if (e->backtrace) { 1157 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_duplicate); 1158 } 1159 if (!e->type_present) { 1160 ++f->union_count; 1161 e->line = ctx->line; 1162 e->line_start = ctx->line_start; 1163 buf = flatcc_json_parser_generic_json(ctx, (e->backtrace = buf), end); 1164 } else { 1165 --f->union_count; 1166 buf = _parse_union_vector(ctx, buf, end, e->h_types, e->count, id, union_parser); 1167 } 1168 return buf; 1169 } 1170 1171 const char *flatcc_json_parser_union_type_vector(flatcc_json_parser_t *ctx, 1172 const char *buf, const char *end, size_t union_index, flatbuffers_voffset_t id, 1173 size_t handle, 1174 flatcc_json_parser_integral_symbol_f *type_parsers[], 1175 flatcc_json_parser_union_f *union_parser, 1176 flatcc_json_parser_is_known_type_f accept_type) 1177 { 1178 __flatcc_json_parser_union_frame_t *f = flatcc_builder_get_user_frame_ptr(ctx->ctx, handle); 1179 __flatcc_json_parser_union_entry_t *e = f->unions + union_index; 1180 1181 const char *mark; 1182 int line; 1183 const char *line_start; 1184 int more; 1185 utype_t val; 1186 void *pval; 1187 flatcc_builder_ref_t ref, *pref; 1188 utype_t *types; 1189 size_t size; 1190 size_t h_types; 1191 uoffset_t count; 1192 1193 #if FLATBUFFERS_UTYPE_MAX != UINT8_MAX 1194 #error "Update union vector parser to support current union type definition." 1195 #endif 1196 1197 if (e->type_present) { 1198 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_duplicate); 1199 } 1200 e->type_present = 1; 1201 if (flatcc_builder_start_vector(ctx->ctx, 1, 1, FLATBUFFERS_COUNT_MAX((utype_size)))) goto failed; 1202 buf = flatcc_json_parser_array_start(ctx, buf, end, &more); 1203 while (more) { 1204 if (!(pval = flatcc_builder_extend_vector(ctx->ctx, 1))) goto failed; 1205 buf = flatcc_json_parser_uint8(ctx, (mark = buf), end, &val); 1206 if (mark == buf) { 1207 buf = flatcc_json_parser_symbolic_uint8(ctx, (mark = buf), end, type_parsers, &val); 1208 if (buf == mark || buf == end) goto failed; 1209 } 1210 /* Parse unknown types as NONE */ 1211 if (!accept_type(val)) { 1212 if (!(ctx->flags & flatcc_json_parser_f_skip_unknown)) { 1213 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_unknown_union); 1214 } 1215 val = 0; 1216 } 1217 flatbuffers_uint8_write_to_pe(pval, val); 1218 buf = flatcc_json_parser_array_end(ctx, buf, end, &more); 1219 } 1220 count = (uoffset_t)flatcc_builder_vector_count(ctx->ctx); 1221 e->count = count; 1222 size = count * utype_size; 1223 /* Store type vector so it is accessible to the table vector parser. */ 1224 h_types = flatcc_builder_enter_user_frame(ctx->ctx, size); 1225 types = flatcc_builder_get_user_frame_ptr(ctx->ctx, h_types); 1226 memcpy(types, flatcc_builder_vector_edit(ctx->ctx), size); 1227 if (!((ref = flatcc_builder_end_vector(ctx->ctx)))) goto failed; 1228 if (!(pref = flatcc_builder_table_add_offset(ctx->ctx, id - 1))) goto failed; 1229 *pref = ref; 1230 1231 /* Restore union frame after possible invalidation due to types frame allocation. */ 1232 f = flatcc_builder_get_user_frame_ptr(ctx->ctx, handle); 1233 e = f->unions + union_index; 1234 1235 e->h_types = h_types; 1236 if (e->backtrace == 0) { 1237 ++f->union_count; 1238 return buf; 1239 } 1240 FLATCC_ASSERT(f->union_count); 1241 --f->union_count; 1242 line = ctx->line; 1243 line_start = ctx->line_start; 1244 ctx->line = e->line; 1245 ctx->line_start = e->line_start; 1246 /* We must not assign buf here because we are backtracking. */ 1247 if (end == _parse_union_vector(ctx, e->backtrace, end, h_types, count, id, union_parser)) return end; 1248 /* 1249 * NOTE: We do not need the user frame anymore, but if we did, it 1250 * would have to be restored from its handle due to the above parse. 1251 */ 1252 ctx->line = line; 1253 ctx->line_start = line_start; 1254 return buf; 1255 failed: 1256 return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_runtime); 1257 } 1258 1259 int flatcc_json_parser_table_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx, 1260 const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags, const char *fid, 1261 flatcc_json_parser_table_f *parser) 1262 { 1263 flatcc_json_parser_t _ctx; 1264 flatcc_builder_ref_t root; 1265 flatcc_builder_buffer_flags_t builder_flags = flags & flatcc_json_parser_f_with_size ? flatcc_builder_with_size : 0; 1266 1267 ctx = ctx ? ctx : &_ctx; 1268 flatcc_json_parser_init(ctx, B, buf, buf + bufsiz, flags); 1269 if (flatcc_builder_start_buffer(B, fid, 0, builder_flags)) return -1; 1270 buf = parser(ctx, buf, buf + bufsiz, &root); 1271 if (ctx->error) { 1272 return ctx->error; 1273 } 1274 if (!flatcc_builder_end_buffer(B, root)) return -1; 1275 ctx->end_loc = buf; 1276 return 0; 1277 } 1278 1279 int flatcc_json_parser_struct_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx, 1280 const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags, const char *fid, 1281 flatcc_json_parser_table_f *parser) 1282 { 1283 flatcc_json_parser_t _ctx; 1284 flatcc_builder_ref_t root; 1285 flatcc_builder_buffer_flags_t builder_flags = flags & flatcc_json_parser_f_with_size ? flatcc_builder_with_size : 0; 1286 1287 ctx = ctx ? ctx : &_ctx; 1288 flatcc_json_parser_init(ctx, B, buf, buf + bufsiz, flags); 1289 if (flatcc_builder_start_buffer(B, fid, 0, builder_flags)) return -1; 1290 buf = parser(ctx, buf, buf + bufsiz, &root); 1291 if (ctx->error) { 1292 return ctx->error; 1293 } 1294 if (!flatcc_builder_end_buffer(B, root)) return -1; 1295 ctx->end_loc = buf; 1296 return 0; 1297 }