nostrdb

an unfairly fast embedded nostr database backed by lmdb
git clone git://jb55.com/nostrdb
Log | Files | Refs | Submodules | README | LICENSE

json_parser.c (44437B)


      1 #include "flatcc/flatcc_rtconfig.h"
      2 #include "flatcc/flatcc_json_parser.h"
      3 #include "flatcc/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 "flatcc/portable/pparsefp.h"
     20 #include "flatcc/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 }