nostrdb

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

json_printer.c (56842B)


      1 /*
      2  * Runtime support for printing flatbuffers to JSON.
      3  */
      4 
      5 #include <stdio.h>
      6 #include <string.h>
      7 #include <stdlib.h>
      8 
      9 #include "flatcc/flatcc_rtconfig.h"
     10 #include "flatcc/flatcc_assert.h"
     11 
     12 /*
     13  * Grisu significantly improves printing speed of floating point values
     14  * and also the overall printing speed when floating point values are
     15  * present in non-trivial amounts. (Also applies to parsing).
     16  */
     17 #if FLATCC_USE_GRISU3 && !defined(PORTABLE_USE_GRISU3)
     18 #define PORTABLE_USE_GRISU3 1
     19 #endif
     20 
     21 #include "flatcc/flatcc_flatbuffers.h"
     22 #include "flatcc/flatcc_json_printer.h"
     23 #include "flatcc/flatcc_identifier.h"
     24 
     25 #include "flatcc/portable/pprintint.h"
     26 #include "flatcc/portable/pprintfp.h"
     27 #include "flatcc/portable/pbase64.h"
     28 
     29 
     30 #define RAISE_ERROR(err) flatcc_json_printer_set_error(ctx, flatcc_json_printer_error_##err)
     31 
     32 const char *flatcc_json_printer_error_string(int err)
     33 {
     34     switch (err) {
     35 #define XX(no, str)                                                         \
     36     case flatcc_json_printer_error_##no:                                    \
     37         return str;
     38         FLATCC_JSON_PRINT_ERROR_MAP(XX)
     39 #undef XX
     40     default:
     41         return "unknown";
     42     }
     43 }
     44 
     45 #define flatcc_json_printer_utype_enum_f flatcc_json_printer_union_type_f
     46 #define flatbuffers_utype_read_from_pe __flatbuffers_utype_read_from_pe
     47 
     48 #define uoffset_t flatbuffers_uoffset_t
     49 #define soffset_t flatbuffers_soffset_t
     50 #define voffset_t flatbuffers_voffset_t
     51 #define utype_t flatbuffers_utype_t
     52 
     53 #define uoffset_size sizeof(uoffset_t)
     54 #define soffset_size sizeof(soffset_t)
     55 #define voffset_size sizeof(voffset_t)
     56 #define utype_size sizeof(utype_t)
     57 
     58 #define offset_size uoffset_size
     59 
     60 #if FLATBUFFERS_UTYPE_MAX == UINT8_MAX
     61 #define print_utype print_uint8
     62 #else
     63 #ifdef FLATBUFFERS_UTYPE_MIN
     64 #define print_utype print_int64
     65 #else
     66 #define print_utype print_uint64
     67 #endif
     68 #endif
     69 
     70 static inline const void *read_uoffset_ptr(const void *p)
     71 {
     72     return (uint8_t *)p + __flatbuffers_uoffset_read_from_pe(p);
     73 }
     74 
     75 static inline voffset_t read_voffset(const void *p, uoffset_t base)
     76 {
     77     return __flatbuffers_voffset_read_from_pe((uint8_t *)p + base);
     78 }
     79 
     80 static inline const void *get_field_ptr(flatcc_json_printer_table_descriptor_t *td, int id)
     81 {
     82     uoffset_t vo = (uoffset_t)(id + 2) * (uoffset_t)sizeof(voffset_t);
     83 
     84     if (vo >= (uoffset_t)td->vsize) {
     85         return 0;
     86     }
     87     vo = read_voffset(td->vtable, vo);
     88     if (vo == 0) {
     89         return 0;
     90     }
     91     return (uint8_t *)td->table + vo;
     92 }
     93 
     94 #define print_char(c) *ctx->p++ = (c)
     95 
     96 #define print_null() do {                                                   \
     97     print_char('n');                                                        \
     98     print_char('u');                                                        \
     99     print_char('l');                                                        \
    100     print_char('l');                                                        \
    101 } while (0)
    102 
    103 #define print_start(c) do {                                                 \
    104     ++ctx->level;                                                           \
    105     *ctx->p++ = c;                                                          \
    106 } while (0)
    107 
    108 #define print_end(c) do {                                                   \
    109     if (ctx->indent) {                                                      \
    110         *ctx->p++ = '\n';                                                   \
    111         --ctx->level;                                                       \
    112         print_indent(ctx);                                                  \
    113     }                                                                       \
    114     *ctx->p++ = c;                                                          \
    115 } while (0)
    116 
    117 #define print_space() do {                                                  \
    118     *ctx->p = ' ';                                                          \
    119     ctx->p += !!ctx->indent;                                                \
    120 } while (0)
    121 
    122 #define print_nl() do {                                                     \
    123     if (ctx->indent) {                                                      \
    124         *ctx->p++ = '\n';                                                   \
    125         print_indent(ctx);                                                  \
    126     } else {                                                                \
    127         flatcc_json_printer_flush_partial(ctx);                             \
    128     }                                                                       \
    129 } while (0)
    130 
    131 /* Call at the end so print_end does not have to check for level. */
    132 #define print_last_nl() do {                                                \
    133     if (ctx->indent && ctx->level == 0) {                                   \
    134         *ctx->p++ = '\n';                                                   \
    135     }                                                                       \
    136     ctx->flush(ctx, 1);                                                     \
    137 } while (0)
    138 
    139 int flatcc_json_printer_fmt_float(char *buf, float n)
    140 {
    141 #if FLATCC_JSON_PRINT_HEX_FLOAT
    142     return print_hex_float(buf, n);
    143 #else
    144     return print_float(n, buf);
    145 #endif
    146 }
    147 
    148 int flatcc_json_printer_fmt_double(char *buf, double n)
    149 {
    150 #if FLATCC_JSON_PRINT_HEX_FLOAT
    151     return print_hex_double(buf, n);
    152 #else
    153     return print_double(n, buf);
    154 #endif
    155 }
    156 
    157 int flatcc_json_printer_fmt_bool(char *buf, int n)
    158 {
    159     if (n) {
    160         memcpy(buf, "true", 4);
    161         return 4;
    162     }
    163     memcpy(buf, "false", 5);
    164     return 5;
    165 }
    166 
    167 static void print_ex(flatcc_json_printer_t *ctx, const char *s, size_t n)
    168 {
    169     size_t k;
    170 
    171     if (ctx->p >= ctx->pflush) {
    172         ctx->flush(ctx, 0);
    173     }
    174     k = (size_t)(ctx->pflush - ctx->p);
    175     while (n > k) {
    176         memcpy(ctx->p, s, k);
    177         ctx->p += k;
    178         s += k;
    179         n -= k;
    180         ctx->flush(ctx, 0);
    181         k = (size_t)(ctx->pflush - ctx->p);
    182     }
    183     memcpy(ctx->p, s, n);
    184     ctx->p += n;
    185 }
    186 
    187 static inline void print(flatcc_json_printer_t *ctx, const char *s, size_t n)
    188 {
    189     if (ctx->p + n >= ctx->pflush) {
    190         print_ex(ctx, s, n);
    191     } else {
    192         memcpy(ctx->p, s, n);
    193         ctx->p += n;
    194     }
    195 }
    196 
    197 static void print_escape(flatcc_json_printer_t *ctx, unsigned char c)
    198 {
    199     unsigned char x;
    200 
    201     print_char('\\');
    202     switch (c) {
    203     case '"': print_char('\"'); break;
    204     case '\\': print_char('\\'); break;
    205     case '\t' : print_char('t'); break;
    206     case '\f' : print_char('f'); break;
    207     case '\r' : print_char('r'); break;
    208     case '\n' : print_char('n'); break;
    209     case '\b' : print_char('b'); break;
    210     default:
    211         print_char('u');
    212         print_char('0');
    213         print_char('0');
    214         x = c >> 4;
    215         x += x < 10 ? '0' : 'a' - 10;
    216         print_char((char)x);
    217         x = c & 15;
    218         x += x < 10 ? '0' : 'a' - 10;
    219         print_char((char)x);
    220         break;
    221     }
    222 }
    223 
    224 /*
    225  * Even though we know the the string length, we need to scan for escape
    226  * characters. There may be embedded zeroes. Because FlatBuffer strings
    227  * are always zero terminated, we assume and optimize for this.
    228  *
    229  * We enforce \u00xx for control characters, but not for invalid
    230  * characters like 0xff - this makes it possible to handle some other
    231  * codepages transparently while formally not valid.  (Formally JSON
    232  * also supports UTF-16/32 little/big endian but flatbuffers only
    233  * support UTF-8 and we expect this in JSON input/output too).
    234  */
    235 static void print_string(flatcc_json_printer_t *ctx, const char *s, size_t n)
    236 {
    237     const char *p = s;
    238     /* Unsigned is important. */
    239     unsigned char c;
    240     size_t k;
    241 
    242     print_char('\"');
    243     for (;;) {
    244         c = (unsigned char)*p;
    245         while (c >= 0x20 && c != '\"' && c != '\\') {
    246             c = (unsigned char)*++p;
    247         }
    248         k = (size_t)(p - s);
    249         /* Even if k == 0, print ensures buffer flush. */
    250         print(ctx, s, k);
    251         n -= k;
    252         if (n == 0) break;
    253         s += k;
    254         print_escape(ctx, c);
    255         ++p;
    256         --n;
    257         ++s;
    258     }
    259     print_char('\"');
    260 }
    261 
    262 /*
    263  * Similar to print_string, but null termination is not guaranteed, and
    264  * trailing nulls are stripped.
    265  */
    266 static void print_char_array(flatcc_json_printer_t *ctx, const char *s, size_t n)
    267 {
    268     const char *p = s;
    269     /* Unsigned is important. */
    270     unsigned char c = 0;
    271     size_t k;
    272 
    273     while (n > 0 && s[n - 1] == '\0') --n;
    274 
    275     print_char('\"');
    276     for (;;) {
    277         while (n) {
    278             c = (unsigned char)*p;
    279             if (c < 0x20 || c == '\"' || c == '\\') break;
    280             ++p;
    281             --n;
    282         }
    283         k = (size_t)(p - s);
    284         /* Even if k == 0, print ensures buffer flush. */
    285         print(ctx, s, k);
    286         if (n == 0) break;
    287         s += k;
    288         print_escape(ctx, c);
    289         ++p;
    290         --n;
    291         ++s;
    292     }
    293     print_char('\"');
    294 }
    295 
    296 static void print_uint8_vector_base64_object(flatcc_json_printer_t *ctx, const void *p, int mode)
    297 {
    298     const int unpadded_mode = mode & ~base64_enc_modifier_padding;
    299     size_t k, n, len;
    300     const uint8_t *data;
    301     size_t data_len, src_len;
    302 
    303     data_len = (size_t)__flatbuffers_uoffset_read_from_pe(p);
    304     data = (const uint8_t *)p + uoffset_size;
    305 
    306     print_char('\"');
    307 
    308     len = base64_encoded_size(data_len, mode);
    309     if (ctx->p + len >= ctx->pflush) {
    310         ctx->flush(ctx, 0);
    311     }
    312     while (ctx->p + len > ctx->pflush) {
    313         /* Multiples of 4 output chars consumes exactly 3 bytes before final padding. */
    314         k = (size_t)(ctx->pflush - ctx->p) & ~(size_t)3;
    315         n = k * 3 / 4;
    316         FLATCC_ASSERT(n > 0);
    317         src_len = k * 3 / 4;
    318         base64_encode((uint8_t *)ctx->p, data, 0, &src_len, unpadded_mode);
    319         ctx->p += k;
    320         data += n;
    321         data_len -= n;
    322         ctx->flush(ctx, 0);
    323         len = base64_encoded_size(data_len, mode);
    324     }
    325     base64_encode((uint8_t *)ctx->p, data, 0, &data_len, mode);
    326     ctx->p += len;
    327     print_char('\"');
    328 }
    329 
    330 static void print_indent_ex(flatcc_json_printer_t *ctx, size_t n)
    331 {
    332     size_t k;
    333 
    334     if (ctx->p >= ctx->pflush) {
    335         ctx->flush(ctx, 0);
    336     }
    337     k = (size_t)(ctx->pflush - ctx->p);
    338     while (n > k) {
    339         memset(ctx->p, ' ', k);
    340         ctx->p += k;
    341         n -= k;
    342         ctx->flush(ctx, 0);
    343         k = (size_t)(ctx->pflush - ctx->p);
    344     }
    345     memset(ctx->p, ' ', n);
    346     ctx->p += n;
    347 }
    348 
    349 static inline void print_indent(flatcc_json_printer_t *ctx)
    350 {
    351     size_t n = (size_t)(ctx->level * ctx->indent);
    352 
    353     if (ctx->p + n > ctx->pflush) {
    354         print_indent_ex(ctx, n);
    355     } else {
    356         memset(ctx->p, ' ', n);
    357         ctx->p += n;
    358     }
    359 }
    360 
    361 /*
    362  * Helpers for external use - does not do autmatic pretty printing, but
    363  * does escape strings.
    364  */
    365 void flatcc_json_printer_string(flatcc_json_printer_t *ctx, const char *s, size_t n)
    366 {
    367     print_string(ctx, s, n);
    368 }
    369 
    370 void flatcc_json_printer_write(flatcc_json_printer_t *ctx, const char *s, size_t n)
    371 {
    372     print(ctx, s, n);
    373 }
    374 
    375 void flatcc_json_printer_nl(flatcc_json_printer_t *ctx)
    376 {
    377     print_char('\n');
    378     flatcc_json_printer_flush_partial(ctx);
    379 }
    380 
    381 void flatcc_json_printer_char(flatcc_json_printer_t *ctx, char c)
    382 {
    383     print_char(c);
    384 }
    385 
    386 void flatcc_json_printer_indent(flatcc_json_printer_t *ctx)
    387 {
    388     /*
    389      * This is only needed when indent is 0 but helps external users
    390      * to avoid flushing when indenting.
    391      */
    392     print_indent(ctx);
    393 }
    394 
    395 void flatcc_json_printer_add_level(flatcc_json_printer_t *ctx, int n)
    396 {
    397     ctx->level += n;
    398 }
    399 
    400 int flatcc_json_printer_get_level(flatcc_json_printer_t *ctx)
    401 {
    402     return ctx->level;
    403 }
    404 
    405 static inline void print_symbol(flatcc_json_printer_t *ctx, const char *name, size_t len)
    406 {
    407     *ctx->p = '\"';
    408     ctx->p += !ctx->unquote;
    409     if (ctx->p + len < ctx->pflush) {
    410         memcpy(ctx->p, name, len);
    411         ctx->p += len;
    412     } else {
    413         print(ctx, name, len);
    414     }
    415     *ctx->p = '\"';
    416     ctx->p += !ctx->unquote;
    417 }
    418 
    419 static inline void print_name(flatcc_json_printer_t *ctx, const char *name, size_t len)
    420 {
    421     print_nl();
    422     print_symbol(ctx, name, len);
    423     print_char(':');
    424     print_space();
    425 }
    426 
    427 #define __flatcc_define_json_printer_scalar(TN, T)                          \
    428 void flatcc_json_printer_ ## TN(                                            \
    429         flatcc_json_printer_t *ctx, T v)                                    \
    430 {                                                                           \
    431     ctx->p += print_ ## TN(v, ctx->p);                                      \
    432 }
    433 
    434 __flatcc_define_json_printer_scalar(uint8, uint8_t)
    435 __flatcc_define_json_printer_scalar(uint16, uint16_t)
    436 __flatcc_define_json_printer_scalar(uint32, uint32_t)
    437 __flatcc_define_json_printer_scalar(uint64, uint64_t)
    438 __flatcc_define_json_printer_scalar(int8, int8_t)
    439 __flatcc_define_json_printer_scalar(int16, int16_t)
    440 __flatcc_define_json_printer_scalar(int32, int32_t)
    441 __flatcc_define_json_printer_scalar(int64, int64_t)
    442 __flatcc_define_json_printer_scalar(float, float)
    443 __flatcc_define_json_printer_scalar(double, double)
    444 
    445 void flatcc_json_printer_enum(flatcc_json_printer_t *ctx, const char *symbol, size_t len)
    446 {
    447     print_symbol(ctx, symbol, len);
    448 }
    449 
    450 void flatcc_json_printer_delimit_enum_flags(flatcc_json_printer_t *ctx, int multiple)
    451 {
    452 #if FLATCC_JSON_PRINT_ALWAYS_QUOTE_MULTIPLE_FLAGS
    453     int quote = !ctx->unquote || multiple;
    454 #else
    455     int quote = !ctx->unquote;
    456 #endif
    457     *ctx->p = '"';
    458     ctx->p += quote;
    459 }
    460 
    461 void flatcc_json_printer_enum_flag(flatcc_json_printer_t *ctx, int count, const char *symbol, size_t len)
    462 {
    463     *ctx->p = ' ';
    464     ctx->p += count > 0;
    465     print(ctx, symbol, len);
    466 }
    467 
    468 static inline void print_string_object(flatcc_json_printer_t *ctx, const void *p)
    469 {
    470     size_t len;
    471     const char *s;
    472 
    473     len = (size_t)__flatbuffers_uoffset_read_from_pe(p);
    474     s = (const char *)p + uoffset_size;
    475     print_string(ctx, s, len);
    476 }
    477 
    478 #define __define_print_scalar_struct_field(TN, T)                           \
    479 void flatcc_json_printer_ ## TN ## _struct_field(flatcc_json_printer_t *ctx,\
    480         int index, const void *p, size_t offset,                            \
    481         const char *name, size_t len)                                       \
    482 {                                                                           \
    483     T x = flatbuffers_ ## TN ## _read_from_pe((uint8_t *)p + offset);       \
    484                                                                             \
    485     if (index) {                                                            \
    486         print_char(',');                                                    \
    487     }                                                                       \
    488     print_name(ctx, name, len);                                             \
    489     ctx->p += print_ ## TN (x, ctx->p);                                     \
    490 }
    491 
    492 void flatcc_json_printer_char_array_struct_field(
    493         flatcc_json_printer_t *ctx,
    494         int index, const void *p, size_t offset,
    495         const char *name, size_t len, size_t count)
    496 {
    497     p = (void *)((size_t)p + offset);
    498     if (index) {
    499         print_char(',');
    500     }
    501     print_name(ctx, name, len);
    502     print_char_array(ctx, p, count);
    503 }
    504 
    505 #define __define_print_scalar_array_struct_field(TN, T)                     \
    506 void flatcc_json_printer_ ## TN ## _array_struct_field(                     \
    507         flatcc_json_printer_t *ctx,                                         \
    508         int index, const void *p, size_t offset,                            \
    509         const char *name, size_t len, size_t count)                         \
    510 {                                                                           \
    511     p = (void *)((size_t)p + offset);                                       \
    512     if (index) {                                                            \
    513         print_char(',');                                                    \
    514     }                                                                       \
    515     print_name(ctx, name, len);                                             \
    516     print_start('[');                                                       \
    517     if (count) {                                                            \
    518         print_nl();                                                         \
    519         ctx->p += print_ ## TN (                                            \
    520                 flatbuffers_ ## TN ## _read_from_pe(p),                     \
    521                 ctx->p);                                                    \
    522         p = (void *)((size_t)p + sizeof(T));                                \
    523         --count;                                                            \
    524     }                                                                       \
    525     while (count--) {                                                       \
    526         print_char(',');                                                    \
    527         print_nl();                                                         \
    528         ctx->p += print_ ## TN (                                            \
    529                 flatbuffers_ ## TN ## _read_from_pe(p),                     \
    530                 ctx->p);                                                    \
    531         p = (void *)((size_t)p + sizeof(T));                                \
    532     }                                                                       \
    533     print_end(']');                                                         \
    534 }
    535 
    536 #define __define_print_enum_array_struct_field(TN, T)                       \
    537 void flatcc_json_printer_ ## TN ## _enum_array_struct_field(                \
    538         flatcc_json_printer_t *ctx,                                         \
    539         int index, const void *p, size_t offset,                            \
    540         const char *name, size_t len, size_t count,                         \
    541         flatcc_json_printer_ ## TN ##_enum_f *pf)                           \
    542 {                                                                           \
    543     T x;                                                                    \
    544                                                                             \
    545     p = (void *)((size_t)p + offset);                                       \
    546     if (index) {                                                            \
    547         print_char(',');                                                    \
    548     }                                                                       \
    549     print_name(ctx, name, len);                                             \
    550     print_start('[');                                                       \
    551     if (count) {                                                            \
    552         print_nl();                                                         \
    553         x = flatbuffers_ ## TN ## _read_from_pe(p);                         \
    554         if (ctx->noenum) {                                                  \
    555             ctx->p += print_ ## TN (x, ctx->p);                             \
    556         } else {                                                            \
    557             pf(ctx, x);                                                     \
    558         }                                                                   \
    559         p = (void *)((size_t)p + sizeof(T));                                \
    560         --count;                                                            \
    561     }                                                                       \
    562     while (count--) {                                                       \
    563         print_char(',');                                                    \
    564         print_nl();                                                         \
    565         x = flatbuffers_ ## TN ## _read_from_pe(p);                         \
    566         if (ctx->noenum) {                                                  \
    567             ctx->p += print_ ## TN (x, ctx->p);                             \
    568         } else {                                                            \
    569             pf(ctx, x);                                                     \
    570         }                                                                   \
    571         p = (void *)((size_t)p + sizeof(T));                                \
    572     }                                                                       \
    573     print_end(']');                                                         \
    574 }
    575 
    576 #define __define_print_enum_struct_field(TN, T)                             \
    577 void flatcc_json_printer_ ## TN ## _enum_struct_field(                      \
    578         flatcc_json_printer_t *ctx,                                         \
    579         int index, const void *p, size_t offset,                            \
    580         const char *name, size_t len,                                       \
    581         flatcc_json_printer_ ## TN ##_enum_f *pf)                           \
    582 {                                                                           \
    583     T x = flatbuffers_ ## TN ## _read_from_pe((uint8_t *)p + offset);       \
    584                                                                             \
    585     if (index) {                                                            \
    586         print_char(',');                                                    \
    587     }                                                                       \
    588     print_name(ctx, name, len);                                             \
    589     if (ctx->noenum) {                                                      \
    590         ctx->p += print_ ## TN (x, ctx->p);                                 \
    591     } else {                                                                \
    592         pf(ctx, x);                                                         \
    593     }                                                                       \
    594 }
    595 
    596 #define __define_print_scalar_field(TN, T)                                  \
    597 void flatcc_json_printer_ ## TN ## _field(flatcc_json_printer_t *ctx,       \
    598         flatcc_json_printer_table_descriptor_t *td,                         \
    599         int id, const char *name, size_t len, T v)                          \
    600 {                                                                           \
    601     T x;                                                                    \
    602     const void *p = get_field_ptr(td, id);                                  \
    603                                                                             \
    604     if (p) {                                                                \
    605         x = flatbuffers_ ## TN ## _read_from_pe(p);                         \
    606         if (x == v && ctx->skip_default) {                                  \
    607             return;                                                         \
    608         }                                                                   \
    609     } else {                                                                \
    610         if (!ctx->force_default) {                                          \
    611             return;                                                         \
    612         }                                                                   \
    613         x = v;                                                              \
    614     }                                                                       \
    615     if (td->count++) {                                                      \
    616         print_char(',');                                                    \
    617     }                                                                       \
    618     print_name(ctx, name, len);                                             \
    619     ctx->p += print_ ## TN (x, ctx->p);                                     \
    620 }
    621 
    622 #define __define_print_scalar_optional_field(TN, T)                         \
    623 void flatcc_json_printer_ ## TN ## _optional_field(                         \
    624         flatcc_json_printer_t *ctx,                                         \
    625         flatcc_json_printer_table_descriptor_t *td,                         \
    626         int id, const char *name, size_t len)                               \
    627 {                                                                           \
    628     T x;                                                                    \
    629     const void *p = get_field_ptr(td, id);                                  \
    630                                                                             \
    631     if (!p) return;                                                         \
    632     x = flatbuffers_ ## TN ## _read_from_pe(p);                             \
    633     if (td->count++) {                                                      \
    634         print_char(',');                                                    \
    635     }                                                                       \
    636     print_name(ctx, name, len);                                             \
    637     ctx->p += print_ ## TN (x, ctx->p);                                     \
    638 }
    639 
    640 
    641 #define __define_print_enum_field(TN, T)                                    \
    642 void flatcc_json_printer_ ## TN ## _enum_field(flatcc_json_printer_t *ctx,  \
    643         flatcc_json_printer_table_descriptor_t *td,                         \
    644         int id, const char *name, size_t len, T v,                          \
    645         flatcc_json_printer_ ## TN ##_enum_f *pf)                           \
    646 {                                                                           \
    647     T x;                                                                    \
    648     const void *p = get_field_ptr(td, id);                                  \
    649                                                                             \
    650     if (p) {                                                                \
    651         x = flatbuffers_ ## TN ## _read_from_pe(p);                         \
    652         if (x == v && ctx->skip_default) {                                  \
    653             return;                                                         \
    654         }                                                                   \
    655     } else {                                                                \
    656         if (!ctx->force_default) {                                          \
    657             return;                                                         \
    658         }                                                                   \
    659         x = v;                                                              \
    660     }                                                                       \
    661     if (td->count++) {                                                      \
    662         print_char(',');                                                    \
    663     }                                                                       \
    664     print_name(ctx, name, len);                                             \
    665     if (ctx->noenum) {                                                      \
    666         ctx->p += print_ ## TN (x, ctx->p);                                 \
    667     } else {                                                                \
    668         pf(ctx, x);                                                         \
    669     }                                                                       \
    670 }
    671 
    672 #define __define_print_enum_optional_field(TN, T)                           \
    673 void flatcc_json_printer_ ## TN ## _enum_optional_field(                    \
    674         flatcc_json_printer_t *ctx,                                         \
    675         flatcc_json_printer_table_descriptor_t *td,                         \
    676         int id, const char *name, size_t len,                               \
    677         flatcc_json_printer_ ## TN ##_enum_f *pf)                           \
    678 {                                                                           \
    679     T x;                                                                    \
    680     const void *p = get_field_ptr(td, id);                                  \
    681                                                                             \
    682     if (!p) return;                                                         \
    683     x = flatbuffers_ ## TN ## _read_from_pe(p);                             \
    684     if (td->count++) {                                                      \
    685         print_char(',');                                                    \
    686     }                                                                       \
    687     print_name(ctx, name, len);                                             \
    688     if (ctx->noenum) {                                                      \
    689         ctx->p += print_ ## TN (x, ctx->p);                                 \
    690     } else {                                                                \
    691         pf(ctx, x);                                                         \
    692     }                                                                       \
    693 }
    694 
    695 static inline void print_table_object(flatcc_json_printer_t *ctx,
    696         const void *p, int ttl, flatcc_json_printer_table_f pf)
    697 {
    698     flatcc_json_printer_table_descriptor_t td;
    699 
    700     if (!--ttl) {
    701         flatcc_json_printer_set_error(ctx, flatcc_json_printer_error_deep_recursion);
    702         return;
    703     }
    704     print_start('{');
    705     td.count = 0;
    706     td.ttl = ttl;
    707     td.table = p;
    708     td.vtable = (uint8_t *)p - __flatbuffers_soffset_read_from_pe(p);
    709     td.vsize = __flatbuffers_voffset_read_from_pe(td.vtable);
    710     pf(ctx, &td);
    711     print_end('}');
    712 }
    713 
    714 void flatcc_json_printer_string_field(flatcc_json_printer_t *ctx,
    715         flatcc_json_printer_table_descriptor_t *td,
    716         int id, const char *name, size_t len)
    717 {
    718     const void *p = get_field_ptr(td, id);
    719 
    720     if (p) {
    721         if (td->count++) {
    722             print_char(',');
    723         }
    724         print_name(ctx, name, len);
    725         print_string_object(ctx, read_uoffset_ptr(p));
    726     }
    727 }
    728 
    729 void flatcc_json_printer_uint8_vector_base64_field(flatcc_json_printer_t *ctx,
    730         flatcc_json_printer_table_descriptor_t *td,
    731         int id, const char *name, size_t len, int urlsafe)
    732 {
    733     const void *p = get_field_ptr(td, id);
    734     int mode;
    735 
    736     mode = urlsafe ? base64_mode_url : base64_mode_rfc4648;
    737     mode |= base64_enc_modifier_padding;
    738 
    739     if (p) {
    740         if (td->count++) {
    741             print_char(',');
    742         }
    743         print_name(ctx, name, len);
    744         print_uint8_vector_base64_object(ctx, read_uoffset_ptr(p), mode);
    745     }
    746 }
    747 
    748 #define __define_print_scalar_vector_field(TN, T)                           \
    749 void flatcc_json_printer_ ## TN ## _vector_field(                           \
    750         flatcc_json_printer_t *ctx,                                         \
    751         flatcc_json_printer_table_descriptor_t *td,                         \
    752         int id, const char *name, size_t len)                               \
    753 {                                                                           \
    754     const void *p = get_field_ptr(td, id);                                  \
    755     uoffset_t count;                                                        \
    756                                                                             \
    757     if (p) {                                                                \
    758         if (td->count++) {                                                  \
    759             print_char(',');                                                \
    760         }                                                                   \
    761         p = read_uoffset_ptr(p);                                            \
    762         count = __flatbuffers_uoffset_read_from_pe(p);                      \
    763         p = (void *)((size_t)p + uoffset_size);                             \
    764         print_name(ctx, name, len);                                         \
    765         print_start('[');                                                   \
    766         if (count) {                                                        \
    767             print_nl();                                                     \
    768             ctx->p += print_ ## TN (                                        \
    769                     flatbuffers_ ## TN ## _read_from_pe(p),                 \
    770                     ctx->p);                                                \
    771             p = (void *)((size_t)p + sizeof(T));                            \
    772             --count;                                                        \
    773         }                                                                   \
    774         while (count--) {                                                   \
    775             print_char(',');                                                \
    776             print_nl();                                                     \
    777             ctx->p += print_ ## TN (                                        \
    778                     flatbuffers_ ## TN ## _read_from_pe(p),                 \
    779                     ctx->p);                                                \
    780             p = (void *)((size_t)p + sizeof(T));                            \
    781         }                                                                   \
    782         print_end(']');                                                     \
    783     }                                                                       \
    784 }
    785 
    786 #define __define_print_enum_vector_field(TN, T)                             \
    787 void flatcc_json_printer_ ## TN ## _enum_vector_field(                      \
    788         flatcc_json_printer_t *ctx,                                         \
    789         flatcc_json_printer_table_descriptor_t *td,                         \
    790         int id, const char *name, size_t len,                               \
    791         flatcc_json_printer_ ## TN ##_enum_f *pf)                           \
    792 {                                                                           \
    793     const void *p;                                                          \
    794     uoffset_t count;                                                        \
    795                                                                             \
    796     if (ctx->noenum) {                                                      \
    797         flatcc_json_printer_ ## TN ## _vector_field(ctx, td, id, name, len);\
    798         return;                                                             \
    799     }                                                                       \
    800     p = get_field_ptr(td, id);                                              \
    801     if (p) {                                                                \
    802         if (td->count++) {                                                  \
    803             print_char(',');                                                \
    804         }                                                                   \
    805         p = read_uoffset_ptr(p);                                            \
    806         count = __flatbuffers_uoffset_read_from_pe(p);                      \
    807         p = (void *)((size_t)p + uoffset_size);                             \
    808         print_name(ctx, name, len);                                         \
    809         print_start('[');                                                   \
    810         if (count) {                                                        \
    811             print_nl();                                                     \
    812             pf(ctx, flatbuffers_ ## TN ## _read_from_pe(p));                \
    813             p = (void *)((size_t)p + sizeof(T));                            \
    814             --count;                                                        \
    815         }                                                                   \
    816         while (count--) {                                                   \
    817             print_char(',');                                                \
    818             print_nl();                                                     \
    819             pf(ctx, flatbuffers_ ## TN ## _read_from_pe(p));                \
    820             p = (void *)((size_t)p + sizeof(T));                            \
    821         }                                                                   \
    822         print_end(']');                                                     \
    823     }                                                                       \
    824 }
    825 
    826 __define_print_scalar_field(uint8, uint8_t)
    827 __define_print_scalar_field(uint16, uint16_t)
    828 __define_print_scalar_field(uint32, uint32_t)
    829 __define_print_scalar_field(uint64, uint64_t)
    830 __define_print_scalar_field(int8, int8_t)
    831 __define_print_scalar_field(int16, int16_t)
    832 __define_print_scalar_field(int32, int32_t)
    833 __define_print_scalar_field(int64, int64_t)
    834 __define_print_scalar_field(bool, flatbuffers_bool_t)
    835 __define_print_scalar_field(float, float)
    836 __define_print_scalar_field(double, double)
    837 
    838 __define_print_enum_field(uint8, uint8_t)
    839 __define_print_enum_field(uint16, uint16_t)
    840 __define_print_enum_field(uint32, uint32_t)
    841 __define_print_enum_field(uint64, uint64_t)
    842 __define_print_enum_field(int8, int8_t)
    843 __define_print_enum_field(int16, int16_t)
    844 __define_print_enum_field(int32, int32_t)
    845 __define_print_enum_field(int64, int64_t)
    846 __define_print_enum_field(bool, flatbuffers_bool_t)
    847 
    848 __define_print_scalar_optional_field(uint8, uint8_t)
    849 __define_print_scalar_optional_field(uint16, uint16_t)
    850 __define_print_scalar_optional_field(uint32, uint32_t)
    851 __define_print_scalar_optional_field(uint64, uint64_t)
    852 __define_print_scalar_optional_field(int8, int8_t)
    853 __define_print_scalar_optional_field(int16, int16_t)
    854 __define_print_scalar_optional_field(int32, int32_t)
    855 __define_print_scalar_optional_field(int64, int64_t)
    856 __define_print_scalar_optional_field(bool, flatbuffers_bool_t)
    857 __define_print_scalar_optional_field(float, float)
    858 __define_print_scalar_optional_field(double, double)
    859 
    860 __define_print_enum_optional_field(uint8, uint8_t)
    861 __define_print_enum_optional_field(uint16, uint16_t)
    862 __define_print_enum_optional_field(uint32, uint32_t)
    863 __define_print_enum_optional_field(uint64, uint64_t)
    864 __define_print_enum_optional_field(int8, int8_t)
    865 __define_print_enum_optional_field(int16, int16_t)
    866 __define_print_enum_optional_field(int32, int32_t)
    867 __define_print_enum_optional_field(int64, int64_t)
    868 __define_print_enum_optional_field(bool, flatbuffers_bool_t)
    869 
    870 __define_print_scalar_struct_field(uint8, uint8_t)
    871 __define_print_scalar_struct_field(uint16, uint16_t)
    872 __define_print_scalar_struct_field(uint32, uint32_t)
    873 __define_print_scalar_struct_field(uint64, uint64_t)
    874 __define_print_scalar_struct_field(int8, int8_t)
    875 __define_print_scalar_struct_field(int16, int16_t)
    876 __define_print_scalar_struct_field(int32, int32_t)
    877 __define_print_scalar_struct_field(int64, int64_t)
    878 __define_print_scalar_struct_field(bool, flatbuffers_bool_t)
    879 __define_print_scalar_struct_field(float, float)
    880 __define_print_scalar_struct_field(double, double)
    881 
    882 __define_print_scalar_array_struct_field(uint8, uint8_t)
    883 __define_print_scalar_array_struct_field(uint16, uint16_t)
    884 __define_print_scalar_array_struct_field(uint32, uint32_t)
    885 __define_print_scalar_array_struct_field(uint64, uint64_t)
    886 __define_print_scalar_array_struct_field(int8, int8_t)
    887 __define_print_scalar_array_struct_field(int16, int16_t)
    888 __define_print_scalar_array_struct_field(int32, int32_t)
    889 __define_print_scalar_array_struct_field(int64, int64_t)
    890 __define_print_scalar_array_struct_field(bool, flatbuffers_bool_t)
    891 __define_print_scalar_array_struct_field(float, float)
    892 __define_print_scalar_array_struct_field(double, double)
    893 
    894 __define_print_enum_array_struct_field(uint8, uint8_t)
    895 __define_print_enum_array_struct_field(uint16, uint16_t)
    896 __define_print_enum_array_struct_field(uint32, uint32_t)
    897 __define_print_enum_array_struct_field(uint64, uint64_t)
    898 __define_print_enum_array_struct_field(int8, int8_t)
    899 __define_print_enum_array_struct_field(int16, int16_t)
    900 __define_print_enum_array_struct_field(int32, int32_t)
    901 __define_print_enum_array_struct_field(int64, int64_t)
    902 __define_print_enum_array_struct_field(bool, flatbuffers_bool_t)
    903 
    904 __define_print_enum_struct_field(uint8, uint8_t)
    905 __define_print_enum_struct_field(uint16, uint16_t)
    906 __define_print_enum_struct_field(uint32, uint32_t)
    907 __define_print_enum_struct_field(uint64, uint64_t)
    908 __define_print_enum_struct_field(int8, int8_t)
    909 __define_print_enum_struct_field(int16, int16_t)
    910 __define_print_enum_struct_field(int32, int32_t)
    911 __define_print_enum_struct_field(int64, int64_t)
    912 __define_print_enum_struct_field(bool, flatbuffers_bool_t)
    913 
    914 __define_print_scalar_vector_field(utype, flatbuffers_utype_t)
    915 __define_print_scalar_vector_field(uint8, uint8_t)
    916 __define_print_scalar_vector_field(uint16, uint16_t)
    917 __define_print_scalar_vector_field(uint32, uint32_t)
    918 __define_print_scalar_vector_field(uint64, uint64_t)
    919 __define_print_scalar_vector_field(int8, int8_t)
    920 __define_print_scalar_vector_field(int16, int16_t)
    921 __define_print_scalar_vector_field(int32, int32_t)
    922 __define_print_scalar_vector_field(int64, int64_t)
    923 __define_print_scalar_vector_field(bool, flatbuffers_bool_t)
    924 __define_print_scalar_vector_field(float, float)
    925 __define_print_scalar_vector_field(double, double)
    926 
    927 __define_print_enum_vector_field(utype, flatbuffers_utype_t)
    928 __define_print_enum_vector_field(uint8, uint8_t)
    929 __define_print_enum_vector_field(uint16, uint16_t)
    930 __define_print_enum_vector_field(uint32, uint32_t)
    931 __define_print_enum_vector_field(uint64, uint64_t)
    932 __define_print_enum_vector_field(int8, int8_t)
    933 __define_print_enum_vector_field(int16, int16_t)
    934 __define_print_enum_vector_field(int32, int32_t)
    935 __define_print_enum_vector_field(int64, int64_t)
    936 __define_print_enum_vector_field(bool, flatbuffers_bool_t)
    937 
    938 void flatcc_json_printer_struct_vector_field(flatcc_json_printer_t *ctx,
    939         flatcc_json_printer_table_descriptor_t *td,
    940         int id, const char *name, size_t len,
    941         size_t size,
    942         flatcc_json_printer_struct_f pf)
    943 {
    944     const uint8_t *p = get_field_ptr(td, id);
    945     uoffset_t count;
    946 
    947     if (p) {
    948         if (td->count++) {
    949             print_char(',');
    950         }
    951         p = read_uoffset_ptr(p);
    952         count = __flatbuffers_uoffset_read_from_pe(p);
    953         p += uoffset_size;
    954         print_name(ctx, name, len);
    955         print_start('[');
    956         if (count) {
    957             print_nl();
    958             print_start('{');
    959             pf(ctx, p);
    960             print_end('}');
    961             --count;
    962         }
    963         while (count--) {
    964             p += size;
    965             print_char(',');
    966             print_nl();
    967             print_start('{');
    968             pf(ctx, p);
    969             print_end('}');
    970         }
    971         print_end(']');
    972     }
    973 }
    974 
    975 void flatcc_json_printer_string_vector_field(flatcc_json_printer_t *ctx,
    976         flatcc_json_printer_table_descriptor_t *td,
    977         int id, const char *name, size_t len)
    978 {
    979     const uoffset_t *p = get_field_ptr(td, id);
    980     uoffset_t count;
    981 
    982     if (p) {
    983         if (td->count++) {
    984             print_char(',');
    985         }
    986         p = read_uoffset_ptr(p);
    987         count = __flatbuffers_uoffset_read_from_pe(p);
    988         ++p;
    989         print_name(ctx, name, len);
    990         print_start('[');
    991         if (count) {
    992             print_nl();
    993             print_string_object(ctx, read_uoffset_ptr(p));
    994             --count;
    995         }
    996         while (count--) {
    997             ++p;
    998             print_char(',');
    999             print_nl();
   1000             print_string_object(ctx, read_uoffset_ptr(p));
   1001         }
   1002         print_end(']');
   1003     }
   1004 }
   1005 
   1006 void flatcc_json_printer_table_vector_field(flatcc_json_printer_t *ctx,
   1007         flatcc_json_printer_table_descriptor_t *td,
   1008         int id, const char *name, size_t len,
   1009         flatcc_json_printer_table_f pf)
   1010 {
   1011     const uoffset_t *p = get_field_ptr(td, id);
   1012     uoffset_t count;
   1013 
   1014     if (p) {
   1015         if (td->count++) {
   1016             print_char(',');
   1017         }
   1018         p = read_uoffset_ptr(p);
   1019         count = __flatbuffers_uoffset_read_from_pe(p);
   1020         ++p;
   1021         print_name(ctx, name, len);
   1022         print_start('[');
   1023         if (count) {
   1024             print_table_object(ctx, read_uoffset_ptr(p), td->ttl, pf);
   1025             --count;
   1026         }
   1027         while (count--) {
   1028             ++p;
   1029             print_char(',');
   1030             print_table_object(ctx, read_uoffset_ptr(p), td->ttl, pf);
   1031         }
   1032         print_end(']');
   1033     }
   1034 }
   1035 
   1036 void flatcc_json_printer_union_vector_field(flatcc_json_printer_t *ctx,
   1037         flatcc_json_printer_table_descriptor_t *td,
   1038         int id, const char *name, size_t len,
   1039         flatcc_json_printer_union_type_f ptf,
   1040         flatcc_json_printer_union_f pf)
   1041 {
   1042     const uoffset_t *pt = get_field_ptr(td, id - 1);
   1043     const uoffset_t *p = get_field_ptr(td, id);
   1044     utype_t *types, type;
   1045     uoffset_t count;
   1046     char type_name[FLATCC_JSON_PRINT_NAME_LEN_MAX + 5];
   1047     flatcc_json_printer_union_descriptor_t ud;
   1048 
   1049     ud.ttl = td->ttl;
   1050     if (len > FLATCC_JSON_PRINT_NAME_LEN_MAX) {
   1051         RAISE_ERROR(bad_input);
   1052         FLATCC_ASSERT(0 && "identifier too long");
   1053         return;
   1054     }
   1055     memcpy(type_name, name, len);
   1056     memcpy(type_name + len, "_type", 5);
   1057     if (p && pt) {
   1058         flatcc_json_printer_utype_enum_vector_field(ctx, td, id - 1,
   1059                 type_name, len + 5, ptf);
   1060         if (td->count++) {
   1061             print_char(',');
   1062         }
   1063         p = read_uoffset_ptr(p);
   1064         pt = read_uoffset_ptr(pt);
   1065         count = __flatbuffers_uoffset_read_from_pe(p);
   1066         ++p;
   1067         ++pt;
   1068         types = (utype_t *)pt;
   1069         print_name(ctx, name, len);
   1070         print_start('[');
   1071 
   1072         if (count) {
   1073             type = __flatbuffers_utype_read_from_pe(types);
   1074             if (type != 0) {
   1075                 ud.type = type;
   1076                 ud.member = p;
   1077                 pf(ctx, &ud);
   1078             } else {
   1079                 print_null();
   1080             }
   1081             --count;
   1082         }
   1083         while (count--) {
   1084             ++p;
   1085             ++types;
   1086             type = __flatbuffers_utype_read_from_pe(types);
   1087             print_char(',');
   1088             if (type != 0) {
   1089                 ud.type = type;
   1090                 ud.member = p;
   1091                 pf(ctx, &ud);
   1092             } else {
   1093                 print_null();
   1094             }
   1095         }
   1096         print_end(']');
   1097     }
   1098 }
   1099 
   1100 void flatcc_json_printer_table_field(flatcc_json_printer_t *ctx,
   1101         flatcc_json_printer_table_descriptor_t *td,
   1102         int id, const char *name, size_t len,
   1103         flatcc_json_printer_table_f pf)
   1104 {
   1105     const void *p = get_field_ptr(td, id);
   1106 
   1107     if (p) {
   1108         if (td->count++) {
   1109             print_char(',');
   1110         }
   1111         print_name(ctx, name, len);
   1112         print_table_object(ctx, read_uoffset_ptr(p), td->ttl, pf);
   1113     }
   1114 }
   1115 
   1116 void flatcc_json_printer_union_field(flatcc_json_printer_t *ctx,
   1117         flatcc_json_printer_table_descriptor_t *td,
   1118         int id, const char *name, size_t len,
   1119         flatcc_json_printer_union_type_f ptf,
   1120         flatcc_json_printer_union_f pf)
   1121 {
   1122     const void *pt = get_field_ptr(td, id - 1);
   1123     const void *p = get_field_ptr(td, id);
   1124     utype_t type;
   1125     flatcc_json_printer_union_descriptor_t ud;
   1126 
   1127     if (!p || !pt) {
   1128         return;
   1129     }
   1130     type = __flatbuffers_utype_read_from_pe(pt);
   1131     if (td->count++) {
   1132         print_char(',');
   1133     }
   1134     print_nl();
   1135     *ctx->p = '\"';
   1136     ctx->p += !ctx->unquote;
   1137     if (ctx->p + len < ctx->pflush) {
   1138         memcpy(ctx->p, name, len);
   1139         ctx->p += len;
   1140     } else {
   1141         print(ctx, name, len);
   1142     }
   1143     print(ctx, "_type", 5);
   1144     *ctx->p = '\"';
   1145     ctx->p += !ctx->unquote;
   1146     print_char(':');
   1147     print_space();
   1148     if (ctx->noenum) {
   1149         ctx->p += print_utype(type, ctx->p);
   1150     } else {
   1151         ptf(ctx, type);
   1152     }
   1153     if (type != 0) {
   1154         print_char(',');
   1155         print_name(ctx, name, len);
   1156         ud.ttl = td->ttl;
   1157         ud.type = type;
   1158         ud.member = p;
   1159         pf(ctx, &ud);
   1160     }
   1161 }
   1162 
   1163 void flatcc_json_printer_union_table(flatcc_json_printer_t *ctx,
   1164         flatcc_json_printer_union_descriptor_t *ud,
   1165         flatcc_json_printer_table_f pf)
   1166 {
   1167     print_table_object(ctx, read_uoffset_ptr(ud->member), ud->ttl, pf);
   1168 }
   1169 
   1170 void flatcc_json_printer_union_struct(flatcc_json_printer_t *ctx,
   1171         flatcc_json_printer_union_descriptor_t *ud,
   1172         flatcc_json_printer_struct_f pf)
   1173 {
   1174     print_start('{');
   1175     pf(ctx, read_uoffset_ptr(ud->member));
   1176     print_end('}');
   1177 }
   1178 
   1179 void flatcc_json_printer_union_string(flatcc_json_printer_t *ctx,
   1180         flatcc_json_printer_union_descriptor_t *ud)
   1181 {
   1182     print_string_object(ctx, read_uoffset_ptr(ud->member));
   1183 }
   1184 
   1185 void flatcc_json_printer_embedded_struct_field(flatcc_json_printer_t *ctx,
   1186         int index, const void *p, size_t offset,
   1187         const char *name, size_t len,
   1188         flatcc_json_printer_struct_f pf)
   1189 {
   1190     if (index) {
   1191         print_char(',');
   1192     }
   1193     print_name(ctx, name, len);
   1194     print_start('{');
   1195     pf(ctx, (uint8_t *)p + offset);
   1196     print_end('}');
   1197 }
   1198 
   1199 void flatcc_json_printer_embedded_struct_array_field(flatcc_json_printer_t *ctx,
   1200         int index, const void *p, size_t offset,
   1201         const char *name, size_t len,
   1202         size_t size, size_t count,
   1203         flatcc_json_printer_struct_f pf)
   1204 {
   1205     size_t i;
   1206     if (index) {
   1207         print_char(',');
   1208     }
   1209     print_name(ctx, name, len);
   1210     print_start('[');
   1211     for (i = 0; i < count; ++i) {
   1212         if (i > 0) {
   1213             print_char(',');
   1214         }
   1215         print_start('{');                                                   \
   1216         pf(ctx, (uint8_t *)p + offset + i * size);
   1217         print_end('}');
   1218     }
   1219     print_end(']');
   1220 }
   1221 
   1222 void flatcc_json_printer_struct_field(flatcc_json_printer_t *ctx,
   1223         flatcc_json_printer_table_descriptor_t *td,
   1224         int id, const char *name, size_t len,
   1225         flatcc_json_printer_struct_f *pf)
   1226 {
   1227     const void *p = get_field_ptr(td, id);
   1228 
   1229     if (p) {
   1230         if (td->count++) {
   1231             print_char(',');
   1232         }
   1233         print_name(ctx, name, len);
   1234         print_start('{');
   1235         pf(ctx, p);
   1236         print_end('}');
   1237     }
   1238 }
   1239 
   1240 /*
   1241  * Make sure the buffer identifier is valid before assuming the rest of
   1242  * the buffer is sane.
   1243  * NOTE: this won't work with type hashes because these can contain
   1244  * nulls in the fid string. In this case use null as fid to disable
   1245  * check.
   1246  */
   1247 static int accept_header(flatcc_json_printer_t * ctx,
   1248         const void *buf, size_t bufsiz, const char *fid)
   1249 {
   1250     flatbuffers_thash_t id, id2 = 0;
   1251 
   1252     if (buf == 0 || bufsiz < offset_size + FLATBUFFERS_IDENTIFIER_SIZE) {
   1253         RAISE_ERROR(bad_input);
   1254         FLATCC_ASSERT(0 && "buffer header too small");
   1255         return 0;
   1256     }
   1257     if (fid != 0) {
   1258         id2 = flatbuffers_type_hash_from_string(fid);
   1259         id = __flatbuffers_thash_read_from_pe((uint8_t *)buf + offset_size);
   1260         if (!(id2 == 0 || id == id2)) {
   1261             RAISE_ERROR(bad_input);
   1262             FLATCC_ASSERT(0 && "identifier mismatch");
   1263             return 0;
   1264         }
   1265     }
   1266     return 1;
   1267 }
   1268 
   1269 int flatcc_json_printer_struct_as_root(flatcc_json_printer_t *ctx,
   1270         const void *buf, size_t bufsiz, const char *fid,
   1271         flatcc_json_printer_struct_f *pf)
   1272 {
   1273     if (!accept_header(ctx, buf, bufsiz, fid)) {
   1274         return -1;
   1275     }
   1276     print_start('{');
   1277     pf(ctx, read_uoffset_ptr(buf));
   1278     print_end('}');
   1279     print_last_nl();
   1280     return flatcc_json_printer_get_error(ctx) ? -1 : (int)ctx->total + (int)(ctx->p - ctx->buf);
   1281 }
   1282 
   1283 int flatcc_json_printer_table_as_root(flatcc_json_printer_t *ctx,
   1284         const void *buf, size_t bufsiz, const char *fid, flatcc_json_printer_table_f *pf)
   1285 {
   1286     if (!accept_header(ctx, buf, bufsiz, fid)) {
   1287         return -1;
   1288     }
   1289     print_table_object(ctx, read_uoffset_ptr(buf), FLATCC_JSON_PRINT_MAX_LEVELS, pf);
   1290     print_last_nl();
   1291     return flatcc_json_printer_get_error(ctx) ? -1 : (int)ctx->total + (int)(ctx->p - ctx->buf);
   1292 }
   1293 
   1294 void flatcc_json_printer_struct_as_nested_root(flatcc_json_printer_t *ctx,
   1295         flatcc_json_printer_table_descriptor_t *td,
   1296         int id, const char *name, size_t len,
   1297         const char *fid,
   1298         flatcc_json_printer_struct_f *pf)
   1299 {
   1300     const uoffset_t *buf;
   1301     uoffset_t bufsiz;
   1302 
   1303     if (0 == (buf = get_field_ptr(td, id))) {
   1304         return;
   1305     }
   1306     buf = (const uoffset_t *)((size_t)buf + __flatbuffers_uoffset_read_from_pe(buf));
   1307     bufsiz = __flatbuffers_uoffset_read_from_pe(buf);
   1308     if (!accept_header(ctx, buf, bufsiz, fid)) {
   1309         return;
   1310     }
   1311     if (td->count++) {
   1312         print_char(',');
   1313     }
   1314     print_name(ctx, name, len);
   1315     print_start('{');
   1316     pf(ctx, read_uoffset_ptr(buf));
   1317     print_end('}');
   1318 }
   1319 
   1320 void flatcc_json_printer_table_as_nested_root(flatcc_json_printer_t *ctx,
   1321         flatcc_json_printer_table_descriptor_t *td,
   1322         int id, const char *name, size_t len,
   1323         const char *fid,
   1324         flatcc_json_printer_table_f pf)
   1325 {
   1326     const uoffset_t *buf;
   1327     uoffset_t bufsiz;
   1328 
   1329     if (0 == (buf = get_field_ptr(td, id))) {
   1330         return;
   1331     }
   1332     buf = (const uoffset_t *)((size_t)buf + __flatbuffers_uoffset_read_from_pe(buf));
   1333     bufsiz = __flatbuffers_uoffset_read_from_pe(buf);
   1334     ++buf;
   1335     if (!accept_header(ctx, buf, bufsiz, fid)) {
   1336         return;
   1337     }
   1338     if (td->count++) {
   1339         print_char(',');
   1340     }
   1341     print_name(ctx, name, len);
   1342     print_table_object(ctx, read_uoffset_ptr(buf), td->ttl, pf);
   1343 }
   1344 
   1345 static void __flatcc_json_printer_flush(flatcc_json_printer_t *ctx, int all)
   1346 {
   1347     if (!all && ctx->p >= ctx->pflush) {
   1348         size_t spill = (size_t)(ctx->p - ctx->pflush);
   1349 
   1350         fwrite(ctx->buf, ctx->flush_size, 1, ctx->fp);
   1351         memcpy(ctx->buf, ctx->buf + ctx->flush_size, spill);
   1352         ctx->p = ctx->buf + spill;
   1353         ctx->total += ctx->flush_size;
   1354     } else {
   1355         size_t len = (size_t)(ctx->p - ctx->buf);
   1356 
   1357         fwrite(ctx->buf, len, 1, ctx->fp);
   1358         ctx->p = ctx->buf;
   1359         ctx->total += len;
   1360     }
   1361     *ctx->p = '\0';
   1362 }
   1363 
   1364 int flatcc_json_printer_init(flatcc_json_printer_t *ctx, void *fp)
   1365 {
   1366     memset(ctx, 0, sizeof(*ctx));
   1367     ctx->fp = fp ? fp : stdout;
   1368     ctx->flush = __flatcc_json_printer_flush;
   1369     if (!(ctx->buf = FLATCC_JSON_PRINTER_ALLOC(FLATCC_JSON_PRINT_BUFFER_SIZE))) {
   1370         return -1;
   1371     }
   1372     ctx->own_buffer = 1;
   1373     ctx->size = FLATCC_JSON_PRINT_BUFFER_SIZE;
   1374     ctx->flush_size = FLATCC_JSON_PRINT_FLUSH_SIZE;
   1375     ctx->p = ctx->buf;
   1376     ctx->pflush = ctx->buf + ctx->flush_size;
   1377     /*
   1378      * Make sure we have space for primitive operations such as printing numbers
   1379      * without having to flush.
   1380      */
   1381     FLATCC_ASSERT(ctx->flush_size + FLATCC_JSON_PRINT_RESERVE <= ctx->size);
   1382     return 0;
   1383 }
   1384 
   1385 static void __flatcc_json_printer_flush_buffer(flatcc_json_printer_t *ctx, int all)
   1386 {
   1387     (void)all;
   1388 
   1389     if (ctx->p >= ctx->pflush) {
   1390         RAISE_ERROR(overflow);
   1391         ctx->total += (size_t)(ctx->p - ctx->buf);
   1392         ctx->p = ctx->buf;
   1393     }
   1394     *ctx->p = '\0';
   1395 }
   1396 
   1397 int flatcc_json_printer_init_buffer(flatcc_json_printer_t *ctx, char *buffer, size_t buffer_size)
   1398 {
   1399     FLATCC_ASSERT(buffer_size >= FLATCC_JSON_PRINT_RESERVE);
   1400     if (buffer_size < FLATCC_JSON_PRINT_RESERVE) {
   1401         return -1;
   1402     }
   1403     memset(ctx, 0, sizeof(*ctx));
   1404     ctx->buf = buffer;
   1405     ctx->size = buffer_size;
   1406     ctx->flush_size = ctx->size - FLATCC_JSON_PRINT_RESERVE;
   1407     ctx->p = ctx->buf;
   1408     ctx->pflush = ctx->buf + ctx->flush_size;
   1409     ctx->flush = __flatcc_json_printer_flush_buffer;
   1410     return 0;
   1411 }
   1412 
   1413 static void __flatcc_json_printer_flush_dynamic_buffer(flatcc_json_printer_t *ctx, int all)
   1414 {
   1415     size_t len = (size_t)(ctx->p - ctx->buf);
   1416     char *p;
   1417 
   1418     (void)all;
   1419 
   1420     *ctx->p = '\0';
   1421     if (ctx->p < ctx->pflush) {
   1422         return;
   1423     }
   1424     p = FLATCC_JSON_PRINTER_REALLOC(ctx->buf, ctx->size * 2);
   1425     if (!p) {
   1426         RAISE_ERROR(overflow);
   1427         ctx->total += len;
   1428         ctx->p = ctx->buf;
   1429     } else {
   1430         ctx->size *= 2;
   1431         ctx->flush_size = ctx->size - FLATCC_JSON_PRINT_RESERVE;
   1432         ctx->buf = p;
   1433         ctx->p = p + len;
   1434         ctx->pflush = p + ctx->flush_size;
   1435     }
   1436     *ctx->p = '\0';
   1437 }
   1438 
   1439 int flatcc_json_printer_init_dynamic_buffer(flatcc_json_printer_t *ctx, size_t buffer_size)
   1440 {
   1441     if (buffer_size == 0) {
   1442         buffer_size = FLATCC_JSON_PRINT_DYN_BUFFER_SIZE;
   1443     }
   1444     if (buffer_size < FLATCC_JSON_PRINT_RESERVE) {
   1445         buffer_size = FLATCC_JSON_PRINT_RESERVE;
   1446     }
   1447     memset(ctx, 0, sizeof(*ctx));
   1448     ctx->buf = FLATCC_JSON_PRINTER_ALLOC(buffer_size);
   1449     ctx->own_buffer = 1;
   1450     ctx->size = buffer_size;
   1451     ctx->flush_size = ctx->size - FLATCC_JSON_PRINT_RESERVE;
   1452     ctx->p = ctx->buf;
   1453     ctx->pflush = ctx->buf + ctx->flush_size;
   1454     ctx->flush = __flatcc_json_printer_flush_dynamic_buffer;
   1455     if (!ctx->buf) {
   1456         RAISE_ERROR(overflow);
   1457         return -1;
   1458     }
   1459     return 0;
   1460 }
   1461 
   1462 void *flatcc_json_printer_get_buffer(flatcc_json_printer_t *ctx, size_t *buffer_size)
   1463 {
   1464     ctx->flush(ctx, 0);
   1465     if (buffer_size) {
   1466         *buffer_size = (size_t)(ctx->p - ctx->buf);
   1467     }
   1468     return ctx->buf;
   1469 }
   1470 
   1471 void *flatcc_json_printer_finalize_dynamic_buffer(flatcc_json_printer_t *ctx, size_t *buffer_size)
   1472 {
   1473     void *buffer;
   1474 
   1475     buffer = flatcc_json_printer_get_buffer(ctx, buffer_size);
   1476     memset(ctx, 0, sizeof(*ctx));
   1477     return buffer;
   1478 }
   1479 
   1480 void flatcc_json_printer_clear(flatcc_json_printer_t *ctx)
   1481 {
   1482     if (ctx->own_buffer && ctx->buf) {
   1483         FLATCC_JSON_PRINTER_FREE(ctx->buf);
   1484     }
   1485     memset(ctx, 0, sizeof(*ctx));
   1486 }