1 /*
2  * Runtime support for printing flatbuffers to JSON.
3  */
4 
5 #include <stdio.h>
6 #include <assert.h>
7 #include <string.h>
8 #include <stdlib.h>
9 
10 #include "flatcc/flatcc_rtconfig.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 
flatcc_json_printer_error_string(int err)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 
read_uoffset_ptr(const void * p)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 
read_voffset(const void * p,uoffset_t base)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 
get_field_ptr(flatcc_json_printer_table_descriptor_t * td,int id)80 static inline const void *get_field_ptr(flatcc_json_printer_table_descriptor_t *td, int id)
81 {
82     int vo = (id + 2) * sizeof(voffset_t);
83 
84     if (vo >= 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 
flatcc_json_printer_fmt_float(char * buf,float n)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 
flatcc_json_printer_fmt_double(char * buf,double n)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 
flatcc_json_printer_fmt_bool(char * buf,int n)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 
print_ex(flatcc_json_printer_t * ctx,const char * s,size_t n)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 = 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 = ctx->pflush - ctx->p;
182     }
183     memcpy(ctx->p, s, n);
184     ctx->p += n;
185 }
186 
print(flatcc_json_printer_t * ctx,const char * s,size_t n)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 
print_escape(flatcc_json_printer_t * ctx,unsigned char c)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(x);
217         x = c & 15;
218         x += x < 10 ? '0' : 'a' - 10;
219         print_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  */
print_string(flatcc_json_printer_t * ctx,const char * s,size_t n)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 = *p;
245         while (c >= 0x20 && c != '\"' && c != '\\') {
246             c = *++p;
247         }
248         k = 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  */
print_char_array(flatcc_json_printer_t * ctx,const char * s,size_t n)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 = *p;
279             if (c < 0x20 || c == '\"' || c == '\\') break;
280             ++p;
281             --n;
282         }
283         k = 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 
print_uint8_vector_base64_object(flatcc_json_printer_t * ctx,const void * p,int mode)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 = (ctx->pflush - ctx->p) & ~(size_t)3;
315         n = k * 3 / 4;
316         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 
print_indent_ex(flatcc_json_printer_t * ctx,size_t n)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 = 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 = ctx->pflush - ctx->p;
344     }
345     memset(ctx->p, ' ', n);
346     ctx->p += n;
347 }
348 
print_indent(flatcc_json_printer_t * ctx)349 static inline void print_indent(flatcc_json_printer_t *ctx)
350 {
351     size_t n = 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  */
flatcc_json_printer_string(flatcc_json_printer_t * ctx,const char * s,int n)365 void flatcc_json_printer_string(flatcc_json_printer_t *ctx, const char *s, int n)
366 {
367     print_string(ctx, s, n);
368 }
369 
flatcc_json_printer_write(flatcc_json_printer_t * ctx,const char * s,int n)370 void flatcc_json_printer_write(flatcc_json_printer_t *ctx, const char *s, int n)
371 {
372     print(ctx, s, n);
373 }
374 
flatcc_json_printer_nl(flatcc_json_printer_t * ctx)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 
flatcc_json_printer_char(flatcc_json_printer_t * ctx,char c)381 void flatcc_json_printer_char(flatcc_json_printer_t *ctx, char c)
382 {
383     print_char(c);
384 }
385 
flatcc_json_printer_indent(flatcc_json_printer_t * ctx)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 
flatcc_json_printer_add_level(flatcc_json_printer_t * ctx,int n)395 void flatcc_json_printer_add_level(flatcc_json_printer_t *ctx, int n)
396 {
397     ctx->level += n;
398 }
399 
flatcc_json_printer_get_level(flatcc_json_printer_t * ctx)400 int flatcc_json_printer_get_level(flatcc_json_printer_t *ctx)
401 {
402     return ctx->level;
403 }
404 
print_symbol(flatcc_json_printer_t * ctx,const char * name,size_t len)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 
print_name(flatcc_json_printer_t * ctx,const char * name,size_t len)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 
__flatcc_define_json_printer_scalar(uint8,uint8_t)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, int len)
446 {
447     print_symbol(ctx, symbol, len);
448 }
449 
flatcc_json_printer_delimit_enum_flags(flatcc_json_printer_t * ctx,int multiple)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 
flatcc_json_printer_enum_flag(flatcc_json_printer_t * ctx,int count,const char * symbol,int len)461 void flatcc_json_printer_enum_flag(flatcc_json_printer_t *ctx, int count, const char *symbol, int len)
462 {
463     *ctx->p = ' ';
464     ctx->p += count > 0;
465     print(ctx, symbol, len);
466 }
467 
print_string_object(flatcc_json_printer_t * ctx,const void * p)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, int 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 
flatcc_json_printer_char_array_struct_field(flatcc_json_printer_t * ctx,int index,const void * p,size_t offset,const char * name,int len,size_t count)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, int 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, int 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, int 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, int 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, int 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_enum_field(TN, T)                                    \
623 void flatcc_json_printer_ ## TN ## _enum_field(flatcc_json_printer_t *ctx,  \
624         flatcc_json_printer_table_descriptor_t *td,                         \
625         int id, const char *name, int len, T v,                             \
626         flatcc_json_printer_ ## TN ##_enum_f *pf)                           \
627 {                                                                           \
628     T x;                                                                    \
629     const void *p = get_field_ptr(td, id);                                  \
630                                                                             \
631     if (p) {                                                                \
632         x = flatbuffers_ ## TN ## _read_from_pe(p);                         \
633         if (x == v && ctx->skip_default) {                                  \
634             return;                                                         \
635         }                                                                   \
636     } else {                                                                \
637         if (!ctx->force_default) {                                          \
638             return;                                                         \
639         }                                                                   \
640         x = v;                                                              \
641     }                                                                       \
642     if (td->count++) {                                                      \
643         print_char(',');                                                    \
644     }                                                                       \
645     print_name(ctx, name, len);                                             \
646     if (ctx->noenum) {                                                      \
647         ctx->p += print_ ## TN (x, ctx->p);                                 \
648     } else {                                                                \
649         pf(ctx, x);                                                         \
650     }                                                                       \
651 }
652 
print_table_object(flatcc_json_printer_t * ctx,const void * p,int ttl,flatcc_json_printer_table_f pf)653 static inline void print_table_object(flatcc_json_printer_t *ctx,
654         const void *p, int ttl, flatcc_json_printer_table_f pf)
655 {
656     flatcc_json_printer_table_descriptor_t td;
657 
658     if (!--ttl) {
659         flatcc_json_printer_set_error(ctx, flatcc_json_printer_error_deep_recursion);
660         return;
661     }
662     print_start('{');
663     td.count = 0;
664     td.ttl = ttl;
665     td.table = p;
666     td.vtable = (uint8_t *)p - __flatbuffers_soffset_read_from_pe(p);
667     td.vsize = __flatbuffers_voffset_read_from_pe(td.vtable);
668     pf(ctx, &td);
669     print_end('}');
670 }
671 
flatcc_json_printer_string_field(flatcc_json_printer_t * ctx,flatcc_json_printer_table_descriptor_t * td,int id,const char * name,int len)672 void flatcc_json_printer_string_field(flatcc_json_printer_t *ctx,
673         flatcc_json_printer_table_descriptor_t *td,
674         int id, const char *name, int len)
675 {
676     const void *p = get_field_ptr(td, id);
677 
678     if (p) {
679         if (td->count++) {
680             print_char(',');
681         }
682         print_name(ctx, name, len);
683         print_string_object(ctx, read_uoffset_ptr(p));
684     }
685 }
686 
flatcc_json_printer_uint8_vector_base64_field(flatcc_json_printer_t * ctx,flatcc_json_printer_table_descriptor_t * td,int id,const char * name,int len,int urlsafe)687 void flatcc_json_printer_uint8_vector_base64_field(flatcc_json_printer_t *ctx,
688         flatcc_json_printer_table_descriptor_t *td,
689         int id, const char *name, int len, int urlsafe)
690 {
691     const void *p = get_field_ptr(td, id);
692     int mode;
693 
694     mode = urlsafe ? base64_mode_url : base64_mode_rfc4648;
695     mode |= base64_enc_modifier_padding;
696 
697     if (p) {
698         if (td->count++) {
699             print_char(',');
700         }
701         print_name(ctx, name, len);
702         print_uint8_vector_base64_object(ctx, read_uoffset_ptr(p), mode);
703     }
704 }
705 
706 #define __define_print_scalar_vector_field(TN, T)                           \
707 void flatcc_json_printer_ ## TN ## _vector_field(                           \
708         flatcc_json_printer_t *ctx,                                         \
709         flatcc_json_printer_table_descriptor_t *td,                         \
710         int id, const char *name, int len)                                  \
711 {                                                                           \
712     const void *p = get_field_ptr(td, id);                                  \
713     uoffset_t count;                                                        \
714                                                                             \
715     if (p) {                                                                \
716         if (td->count++) {                                                  \
717             print_char(',');                                                \
718         }                                                                   \
719         p = read_uoffset_ptr(p);                                            \
720         count = __flatbuffers_uoffset_read_from_pe(p);                      \
721         p = (void *)((size_t)p + uoffset_size);                             \
722         print_name(ctx, name, len);                                         \
723         print_start('[');                                                   \
724         if (count) {                                                        \
725             print_nl();                                                     \
726             ctx->p += print_ ## TN (                                        \
727                     flatbuffers_ ## TN ## _read_from_pe(p),                 \
728                     ctx->p);                                                \
729             p = (void *)((size_t)p + sizeof(T));                            \
730             --count;                                                        \
731         }                                                                   \
732         while (count--) {                                                   \
733             print_char(',');                                                \
734             print_nl();                                                     \
735             ctx->p += print_ ## TN (                                        \
736                     flatbuffers_ ## TN ## _read_from_pe(p),                 \
737                     ctx->p);                                                \
738             p = (void *)((size_t)p + sizeof(T));                            \
739         }                                                                   \
740         print_end(']');                                                     \
741     }                                                                       \
742 }
743 
744 #define __define_print_enum_vector_field(TN, T)                             \
745 void flatcc_json_printer_ ## TN ## _enum_vector_field(                      \
746         flatcc_json_printer_t *ctx,                                         \
747         flatcc_json_printer_table_descriptor_t *td,                         \
748         int id, const char *name, int len,                                  \
749         flatcc_json_printer_ ## TN ##_enum_f *pf)                           \
750 {                                                                           \
751     const void *p;                                                          \
752     uoffset_t count;                                                        \
753                                                                             \
754     if (ctx->noenum) {                                                      \
755         flatcc_json_printer_ ## TN ## _vector_field(ctx, td, id, name, len);\
756         return;                                                             \
757     }                                                                       \
758     p = get_field_ptr(td, id);                                              \
759     if (p) {                                                                \
760         if (td->count++) {                                                  \
761             print_char(',');                                                \
762         }                                                                   \
763         p = read_uoffset_ptr(p);                                            \
764         count = __flatbuffers_uoffset_read_from_pe(p);                      \
765         p = (void *)((size_t)p + uoffset_size);                             \
766         print_name(ctx, name, len);                                         \
767         print_start('[');                                                   \
768         if (count) {                                                        \
769             print_nl();                                                     \
770             pf(ctx, flatbuffers_ ## TN ## _read_from_pe(p));                \
771             p = (void *)((size_t)p + sizeof(T));                            \
772             --count;                                                        \
773         }                                                                   \
774         while (count--) {                                                   \
775             print_char(',');                                                \
776             print_nl();                                                     \
777             pf(ctx, flatbuffers_ ## TN ## _read_from_pe(p));                \
778             p = (void *)((size_t)p + sizeof(T));                            \
779         }                                                                   \
780         print_end(']');                                                     \
781     }                                                                       \
782 }
783 
__define_print_scalar_field(uint8,uint8_t)784 __define_print_scalar_field(uint8, uint8_t)
785 __define_print_scalar_field(uint16, uint16_t)
786 __define_print_scalar_field(uint32, uint32_t)
787 __define_print_scalar_field(uint64, uint64_t)
788 __define_print_scalar_field(int8, int8_t)
789 __define_print_scalar_field(int16, int16_t)
790 __define_print_scalar_field(int32, int32_t)
791 __define_print_scalar_field(int64, int64_t)
792 __define_print_scalar_field(bool, flatbuffers_bool_t)
793 __define_print_scalar_field(float, float)
794 __define_print_scalar_field(double, double)
795 
796 __define_print_enum_field(uint8, uint8_t)
797 __define_print_enum_field(uint16, uint16_t)
798 __define_print_enum_field(uint32, uint32_t)
799 __define_print_enum_field(uint64, uint64_t)
800 __define_print_enum_field(int8, int8_t)
801 __define_print_enum_field(int16, int16_t)
802 __define_print_enum_field(int32, int32_t)
803 __define_print_enum_field(int64, int64_t)
804 __define_print_enum_field(bool, flatbuffers_bool_t)
805 
806 __define_print_scalar_struct_field(uint8, uint8_t)
807 __define_print_scalar_struct_field(uint16, uint16_t)
808 __define_print_scalar_struct_field(uint32, uint32_t)
809 __define_print_scalar_struct_field(uint64, uint64_t)
810 __define_print_scalar_struct_field(int8, int8_t)
811 __define_print_scalar_struct_field(int16, int16_t)
812 __define_print_scalar_struct_field(int32, int32_t)
813 __define_print_scalar_struct_field(int64, int64_t)
814 __define_print_scalar_struct_field(bool, flatbuffers_bool_t)
815 __define_print_scalar_struct_field(float, float)
816 __define_print_scalar_struct_field(double, double)
817 
818 __define_print_scalar_array_struct_field(uint8, uint8_t)
819 __define_print_scalar_array_struct_field(uint16, uint16_t)
820 __define_print_scalar_array_struct_field(uint32, uint32_t)
821 __define_print_scalar_array_struct_field(uint64, uint64_t)
822 __define_print_scalar_array_struct_field(int8, int8_t)
823 __define_print_scalar_array_struct_field(int16, int16_t)
824 __define_print_scalar_array_struct_field(int32, int32_t)
825 __define_print_scalar_array_struct_field(int64, int64_t)
826 __define_print_scalar_array_struct_field(bool, flatbuffers_bool_t)
827 __define_print_scalar_array_struct_field(float, float)
828 __define_print_scalar_array_struct_field(double, double)
829 
830 __define_print_enum_array_struct_field(uint8, uint8_t)
831 __define_print_enum_array_struct_field(uint16, uint16_t)
832 __define_print_enum_array_struct_field(uint32, uint32_t)
833 __define_print_enum_array_struct_field(uint64, uint64_t)
834 __define_print_enum_array_struct_field(int8, int8_t)
835 __define_print_enum_array_struct_field(int16, int16_t)
836 __define_print_enum_array_struct_field(int32, int32_t)
837 __define_print_enum_array_struct_field(int64, int64_t)
838 __define_print_enum_array_struct_field(bool, flatbuffers_bool_t)
839 
840 __define_print_enum_struct_field(uint8, uint8_t)
841 __define_print_enum_struct_field(uint16, uint16_t)
842 __define_print_enum_struct_field(uint32, uint32_t)
843 __define_print_enum_struct_field(uint64, uint64_t)
844 __define_print_enum_struct_field(int8, int8_t)
845 __define_print_enum_struct_field(int16, int16_t)
846 __define_print_enum_struct_field(int32, int32_t)
847 __define_print_enum_struct_field(int64, int64_t)
848 __define_print_enum_struct_field(bool, flatbuffers_bool_t)
849 
850 __define_print_scalar_vector_field(utype, flatbuffers_utype_t)
851 __define_print_scalar_vector_field(uint8, uint8_t)
852 __define_print_scalar_vector_field(uint16, uint16_t)
853 __define_print_scalar_vector_field(uint32, uint32_t)
854 __define_print_scalar_vector_field(uint64, uint64_t)
855 __define_print_scalar_vector_field(int8, int8_t)
856 __define_print_scalar_vector_field(int16, int16_t)
857 __define_print_scalar_vector_field(int32, int32_t)
858 __define_print_scalar_vector_field(int64, int64_t)
859 __define_print_scalar_vector_field(bool, flatbuffers_bool_t)
860 __define_print_scalar_vector_field(float, float)
861 __define_print_scalar_vector_field(double, double)
862 
863 __define_print_enum_vector_field(utype, flatbuffers_utype_t)
864 __define_print_enum_vector_field(uint8, uint8_t)
865 __define_print_enum_vector_field(uint16, uint16_t)
866 __define_print_enum_vector_field(uint32, uint32_t)
867 __define_print_enum_vector_field(uint64, uint64_t)
868 __define_print_enum_vector_field(int8, int8_t)
869 __define_print_enum_vector_field(int16, int16_t)
870 __define_print_enum_vector_field(int32, int32_t)
871 __define_print_enum_vector_field(int64, int64_t)
872 __define_print_enum_vector_field(bool, flatbuffers_bool_t)
873 
874 void flatcc_json_printer_struct_vector_field(flatcc_json_printer_t *ctx,
875         flatcc_json_printer_table_descriptor_t *td,
876         int id, const char *name, int len,
877         size_t size,
878         flatcc_json_printer_struct_f pf)
879 {
880     const uint8_t *p = get_field_ptr(td, id);
881     uoffset_t count;
882 
883     if (p) {
884         if (td->count++) {
885             print_char(',');
886         }
887         p = read_uoffset_ptr(p);
888         count = __flatbuffers_uoffset_read_from_pe(p);
889         p += uoffset_size;
890         print_name(ctx, name, len);
891         print_start('[');
892         if (count) {
893             print_nl();
894             print_start('{');
895             pf(ctx, p);
896             print_end('}');
897             --count;
898         }
899         while (count--) {
900             p += size;
901             print_char(',');
902             print_nl();
903             print_start('{');
904             pf(ctx, p);
905             print_end('}');
906         }
907         print_end(']');
908     }
909 }
910 
flatcc_json_printer_string_vector_field(flatcc_json_printer_t * ctx,flatcc_json_printer_table_descriptor_t * td,int id,const char * name,int len)911 void flatcc_json_printer_string_vector_field(flatcc_json_printer_t *ctx,
912         flatcc_json_printer_table_descriptor_t *td,
913         int id, const char *name, int len)
914 {
915     const uoffset_t *p = get_field_ptr(td, id);
916     uoffset_t count;
917 
918     if (p) {
919         if (td->count++) {
920             print_char(',');
921         }
922         p = read_uoffset_ptr(p);
923         count = __flatbuffers_uoffset_read_from_pe(p);
924         ++p;
925         print_name(ctx, name, len);
926         print_start('[');
927         if (count) {
928             print_nl();
929             print_string_object(ctx, read_uoffset_ptr(p));
930             --count;
931         }
932         while (count--) {
933             ++p;
934             print_char(',');
935             print_nl();
936             print_string_object(ctx, read_uoffset_ptr(p));
937         }
938         print_end(']');
939     }
940 }
941 
flatcc_json_printer_table_vector_field(flatcc_json_printer_t * ctx,flatcc_json_printer_table_descriptor_t * td,int id,const char * name,int len,flatcc_json_printer_table_f pf)942 void flatcc_json_printer_table_vector_field(flatcc_json_printer_t *ctx,
943         flatcc_json_printer_table_descriptor_t *td,
944         int id, const char *name, int len,
945         flatcc_json_printer_table_f pf)
946 {
947     const uoffset_t *p = get_field_ptr(td, id);
948     uoffset_t count;
949 
950     if (p) {
951         if (td->count++) {
952             print_char(',');
953         }
954         p = read_uoffset_ptr(p);
955         count = __flatbuffers_uoffset_read_from_pe(p);
956         ++p;
957         print_name(ctx, name, len);
958         print_start('[');
959         if (count) {
960             print_table_object(ctx, read_uoffset_ptr(p), td->ttl, pf);
961             --count;
962         }
963         while (count--) {
964             ++p;
965             print_char(',');
966             print_table_object(ctx, read_uoffset_ptr(p), td->ttl, pf);
967         }
968         print_end(']');
969     }
970 }
971 
flatcc_json_printer_union_vector_field(flatcc_json_printer_t * ctx,flatcc_json_printer_table_descriptor_t * td,int id,const char * name,int len,flatcc_json_printer_union_type_f ptf,flatcc_json_printer_union_f pf)972 void flatcc_json_printer_union_vector_field(flatcc_json_printer_t *ctx,
973         flatcc_json_printer_table_descriptor_t *td,
974         int id, const char *name, int len,
975         flatcc_json_printer_union_type_f ptf,
976         flatcc_json_printer_union_f pf)
977 {
978     const uoffset_t *pt = get_field_ptr(td, id - 1);
979     const uoffset_t *p = get_field_ptr(td, id);
980     utype_t *types, type;
981     uoffset_t count;
982     char type_name[FLATCC_JSON_PRINT_NAME_LEN_MAX + 5];
983     flatcc_json_printer_union_descriptor_t ud;
984 
985     ud.ttl = td->ttl;
986     if (len > FLATCC_JSON_PRINT_NAME_LEN_MAX) {
987         RAISE_ERROR(bad_input);
988         assert(0 && "identifier too long");
989         return;
990     }
991     memcpy(type_name, name, len);
992     memcpy(type_name + len, "_type", 5);
993     if (p && pt) {
994         flatcc_json_printer_utype_enum_vector_field(ctx, td, id - 1,
995                 type_name, len + 5, ptf);
996         if (td->count++) {
997             print_char(',');
998         }
999         p = read_uoffset_ptr(p);
1000         pt = read_uoffset_ptr(pt);
1001         count = __flatbuffers_uoffset_read_from_pe(p);
1002         ++p;
1003         ++pt;
1004         types = (utype_t *)pt;
1005         print_name(ctx, name, len);
1006         print_start('[');
1007 
1008         if (count) {
1009             type = __flatbuffers_utype_read_from_pe(types);
1010             if (type != 0) {
1011                 ud.type = type;
1012                 ud.member = p;
1013                 pf(ctx, &ud);
1014             } else {
1015                 print_null();
1016             }
1017             --count;
1018         }
1019         while (count--) {
1020             ++p;
1021             ++types;
1022             type = __flatbuffers_utype_read_from_pe(types);
1023             print_char(',');
1024             if (type != 0) {
1025                 ud.type = type;
1026                 ud.member = p;
1027                 pf(ctx, &ud);
1028             } else {
1029                 print_null();
1030             }
1031         }
1032         print_end(']');
1033     }
1034 }
1035 
flatcc_json_printer_table_field(flatcc_json_printer_t * ctx,flatcc_json_printer_table_descriptor_t * td,int id,const char * name,int len,flatcc_json_printer_table_f pf)1036 void flatcc_json_printer_table_field(flatcc_json_printer_t *ctx,
1037         flatcc_json_printer_table_descriptor_t *td,
1038         int id, const char *name, int len,
1039         flatcc_json_printer_table_f pf)
1040 {
1041     const void *p = get_field_ptr(td, id);
1042 
1043     if (p) {
1044         if (td->count++) {
1045             print_char(',');
1046         }
1047         print_name(ctx, name, len);
1048         print_table_object(ctx, read_uoffset_ptr(p), td->ttl, pf);
1049     }
1050 }
1051 
flatcc_json_printer_union_field(flatcc_json_printer_t * ctx,flatcc_json_printer_table_descriptor_t * td,int id,const char * name,int len,flatcc_json_printer_union_type_f ptf,flatcc_json_printer_union_f pf)1052 void flatcc_json_printer_union_field(flatcc_json_printer_t *ctx,
1053         flatcc_json_printer_table_descriptor_t *td,
1054         int id, const char *name, int len,
1055         flatcc_json_printer_union_type_f ptf,
1056         flatcc_json_printer_union_f pf)
1057 {
1058     const void *pt = get_field_ptr(td, id - 1);
1059     const void *p = get_field_ptr(td, id);
1060     utype_t type;
1061     flatcc_json_printer_union_descriptor_t ud;
1062 
1063     if (!p || !pt) {
1064         return;
1065     }
1066     type = __flatbuffers_utype_read_from_pe(pt);
1067     if (td->count++) {
1068         print_char(',');
1069     }
1070     print_nl();
1071     *ctx->p = '\"';
1072     ctx->p += !ctx->unquote;
1073     if (ctx->p + len < ctx->pflush) {
1074         memcpy(ctx->p, name, len);
1075         ctx->p += len;
1076     } else {
1077         print(ctx, name, len);
1078     }
1079     print(ctx, "_type", 5);
1080     *ctx->p = '\"';
1081     ctx->p += !ctx->unquote;
1082     print_char(':');
1083     print_space();
1084     if (ctx->noenum) {
1085         ctx->p += print_utype(type, ctx->p);
1086     } else {
1087         ptf(ctx, type);
1088     }
1089     if (type != 0) {
1090         print_char(',');
1091         print_name(ctx, name, len);
1092         ud.ttl = td->ttl;
1093         ud.type = type;
1094         ud.member = p;
1095         pf(ctx, &ud);
1096     }
1097 }
1098 
flatcc_json_printer_union_table(flatcc_json_printer_t * ctx,flatcc_json_printer_union_descriptor_t * ud,flatcc_json_printer_table_f pf)1099 void flatcc_json_printer_union_table(flatcc_json_printer_t *ctx,
1100         flatcc_json_printer_union_descriptor_t *ud,
1101         flatcc_json_printer_table_f pf)
1102 {
1103     print_table_object(ctx, read_uoffset_ptr(ud->member), ud->ttl, pf);
1104 }
1105 
flatcc_json_printer_union_struct(flatcc_json_printer_t * ctx,flatcc_json_printer_union_descriptor_t * ud,flatcc_json_printer_struct_f pf)1106 void flatcc_json_printer_union_struct(flatcc_json_printer_t *ctx,
1107         flatcc_json_printer_union_descriptor_t *ud,
1108         flatcc_json_printer_struct_f pf)
1109 {
1110     print_start('{');
1111     pf(ctx, read_uoffset_ptr(ud->member));
1112     print_end('}');
1113 }
1114 
flatcc_json_printer_union_string(flatcc_json_printer_t * ctx,flatcc_json_printer_union_descriptor_t * ud)1115 void flatcc_json_printer_union_string(flatcc_json_printer_t *ctx,
1116         flatcc_json_printer_union_descriptor_t *ud)
1117 {
1118     print_string_object(ctx, read_uoffset_ptr(ud->member));
1119 }
1120 
flatcc_json_printer_embedded_struct_field(flatcc_json_printer_t * ctx,int index,const void * p,size_t offset,const char * name,int len,flatcc_json_printer_struct_f pf)1121 void flatcc_json_printer_embedded_struct_field(flatcc_json_printer_t *ctx,
1122         int index, const void *p, size_t offset,
1123         const char *name, int len,
1124         flatcc_json_printer_struct_f pf)
1125 {
1126     if (index) {
1127         print_char(',');
1128     }
1129     print_name(ctx, name, len);
1130     print_start('{');
1131     pf(ctx, (uint8_t *)p + offset);
1132     print_end('}');
1133 }
1134 
flatcc_json_printer_embedded_struct_array_field(flatcc_json_printer_t * ctx,int index,const void * p,size_t offset,const char * name,int len,size_t size,size_t count,flatcc_json_printer_struct_f pf)1135 void flatcc_json_printer_embedded_struct_array_field(flatcc_json_printer_t *ctx,
1136         int index, const void *p, size_t offset,
1137         const char *name, int len,
1138         size_t size, size_t count,
1139         flatcc_json_printer_struct_f pf)
1140 {
1141     size_t i;
1142     if (index) {
1143         print_char(',');
1144     }
1145     print_name(ctx, name, len);
1146     print_start('[');
1147     for (i = 0; i < count; ++i) {
1148         if (i > 0) {
1149             print_char(',');
1150         }
1151         print_start('{');                                                   \
1152         pf(ctx, (uint8_t *)p + offset + i * size);
1153         print_end('}');
1154     }
1155     print_end(']');
1156 }
1157 
flatcc_json_printer_struct_field(flatcc_json_printer_t * ctx,flatcc_json_printer_table_descriptor_t * td,int id,const char * name,int len,flatcc_json_printer_struct_f * pf)1158 void flatcc_json_printer_struct_field(flatcc_json_printer_t *ctx,
1159         flatcc_json_printer_table_descriptor_t *td,
1160         int id, const char *name, int len,
1161         flatcc_json_printer_struct_f *pf)
1162 {
1163     const void *p = get_field_ptr(td, id);
1164 
1165     if (p) {
1166         if (td->count++) {
1167             print_char(',');
1168         }
1169         print_name(ctx, name, len);
1170         print_start('{');
1171         pf(ctx, p);
1172         print_end('}');
1173     }
1174 }
1175 
1176 /*
1177  * Make sure the buffer identifier is valid before assuming the rest of
1178  * the buffer is sane.
1179  * NOTE: this won't work with type hashes because these can contain
1180  * nulls in the fid string. In this case use null as fid to disable
1181  * check.
1182  */
accept_header(flatcc_json_printer_t * ctx,const void * buf,size_t bufsiz,const char * fid)1183 static int accept_header(flatcc_json_printer_t * ctx,
1184         const void *buf, size_t bufsiz, const char *fid)
1185 {
1186     flatbuffers_thash_t id, id2 = 0;
1187 
1188     if (buf == 0 || bufsiz < offset_size + FLATBUFFERS_IDENTIFIER_SIZE) {
1189         RAISE_ERROR(bad_input);
1190         assert(0 && "buffer header too small");
1191         return 0;
1192     }
1193     if (fid != 0) {
1194         id2 = flatbuffers_type_hash_from_string(fid);
1195         id = __flatbuffers_thash_read_from_pe((uint8_t *)buf + offset_size);
1196         if (!(id2 == 0 || id == id2)) {
1197             RAISE_ERROR(bad_input);
1198             assert(0 && "identifier mismatch");
1199             return 0;
1200         }
1201     }
1202     return 1;
1203 }
1204 
flatcc_json_printer_struct_as_root(flatcc_json_printer_t * ctx,const void * buf,size_t bufsiz,const char * fid,flatcc_json_printer_struct_f * pf)1205 int flatcc_json_printer_struct_as_root(flatcc_json_printer_t *ctx,
1206         const void *buf, size_t bufsiz, const char *fid,
1207         flatcc_json_printer_struct_f *pf)
1208 {
1209     if (!accept_header(ctx, buf, bufsiz, fid)) {
1210         return -1;
1211     }
1212     print_start('{');
1213     pf(ctx, read_uoffset_ptr(buf));
1214     print_end('}');
1215     print_last_nl();
1216     return flatcc_json_printer_get_error(ctx) ? -1 : (int)(ctx->total + (ctx->p - ctx->buf));
1217 }
1218 
flatcc_json_printer_table_as_root(flatcc_json_printer_t * ctx,const void * buf,size_t bufsiz,const char * fid,flatcc_json_printer_table_f * pf)1219 int flatcc_json_printer_table_as_root(flatcc_json_printer_t *ctx,
1220         const void *buf, size_t bufsiz, const char *fid, flatcc_json_printer_table_f *pf)
1221 {
1222     if (!accept_header(ctx, buf, bufsiz, fid)) {
1223         return -1;
1224     }
1225     print_table_object(ctx, read_uoffset_ptr(buf), FLATCC_JSON_PRINT_MAX_LEVELS, pf);
1226     print_last_nl();
1227     return flatcc_json_printer_get_error(ctx) ? -1 : (int)(ctx->total + (ctx->p - ctx->buf));
1228 }
1229 
flatcc_json_printer_struct_as_nested_root(flatcc_json_printer_t * ctx,flatcc_json_printer_table_descriptor_t * td,int id,const char * name,int len,const char * fid,flatcc_json_printer_struct_f * pf)1230 void flatcc_json_printer_struct_as_nested_root(flatcc_json_printer_t *ctx,
1231         flatcc_json_printer_table_descriptor_t *td,
1232         int id, const char *name, int len,
1233         const char *fid,
1234         flatcc_json_printer_struct_f *pf)
1235 {
1236     const uoffset_t *buf;
1237     uoffset_t bufsiz;
1238 
1239     if (0 == (buf = get_field_ptr(td, id))) {
1240         return;
1241     }
1242     buf = (const uoffset_t *)((size_t)buf + __flatbuffers_uoffset_read_from_pe(buf));
1243     bufsiz = __flatbuffers_uoffset_read_from_pe(buf);
1244     if (!accept_header(ctx, buf, bufsiz, fid)) {
1245         return;
1246     }
1247     if (td->count++) {
1248         print_char(',');
1249     }
1250     print_name(ctx, name, len);
1251     print_start('{');
1252     pf(ctx, read_uoffset_ptr(buf));
1253     print_end('}');
1254 }
1255 
flatcc_json_printer_table_as_nested_root(flatcc_json_printer_t * ctx,flatcc_json_printer_table_descriptor_t * td,int id,const char * name,int len,const char * fid,flatcc_json_printer_table_f pf)1256 void flatcc_json_printer_table_as_nested_root(flatcc_json_printer_t *ctx,
1257         flatcc_json_printer_table_descriptor_t *td,
1258         int id, const char *name, int len,
1259         const char *fid,
1260         flatcc_json_printer_table_f pf)
1261 {
1262     const uoffset_t *buf;
1263     uoffset_t bufsiz;
1264 
1265     if (0 == (buf = get_field_ptr(td, id))) {
1266         return;
1267     }
1268     buf = (const uoffset_t *)((size_t)buf + __flatbuffers_uoffset_read_from_pe(buf));
1269     bufsiz = __flatbuffers_uoffset_read_from_pe(buf);
1270     ++buf;
1271     if (!accept_header(ctx, buf, bufsiz, fid)) {
1272         return;
1273     }
1274     if (td->count++) {
1275         print_char(',');
1276     }
1277     print_name(ctx, name, len);
1278     print_table_object(ctx, read_uoffset_ptr(buf), td->ttl, pf);
1279 }
1280 
__flatcc_json_printer_flush(flatcc_json_printer_t * ctx,int all)1281 static void __flatcc_json_printer_flush(flatcc_json_printer_t *ctx, int all)
1282 {
1283     if (!all && ctx->p >= ctx->pflush) {
1284         size_t spill = ctx->p - ctx->pflush;
1285 
1286         fwrite(ctx->buf, ctx->flush_size, 1, ctx->fp);
1287         memcpy(ctx->buf, ctx->buf + ctx->flush_size, spill);
1288         ctx->p = ctx->buf + spill;
1289         ctx->total += ctx->flush_size;
1290     } else {
1291         size_t len = ctx->p - ctx->buf;
1292 
1293         fwrite(ctx->buf, len, 1, ctx->fp);
1294         ctx->p = ctx->buf;
1295         ctx->total += len;
1296     }
1297     *ctx->p = '\0';
1298 }
1299 
flatcc_json_printer_init(flatcc_json_printer_t * ctx,void * fp)1300 int flatcc_json_printer_init(flatcc_json_printer_t *ctx, void *fp)
1301 {
1302     memset(ctx, 0, sizeof(*ctx));
1303     ctx->fp = fp ? fp : stdout;
1304     ctx->flush = __flatcc_json_printer_flush;
1305     if (!(ctx->buf = FLATCC_JSON_PRINTER_ALLOC(FLATCC_JSON_PRINT_BUFFER_SIZE))) {
1306         return -1;
1307     }
1308     ctx->own_buffer = 1;
1309     ctx->size = FLATCC_JSON_PRINT_BUFFER_SIZE;
1310     ctx->flush_size = FLATCC_JSON_PRINT_FLUSH_SIZE;
1311     ctx->p = ctx->buf;
1312     ctx->pflush = ctx->buf + ctx->flush_size;
1313     /*
1314      * Make sure we have space for primitive operations such as printing numbers
1315      * without having to flush.
1316      */
1317     assert(ctx->flush_size + FLATCC_JSON_PRINT_RESERVE <= ctx->size);
1318     return 0;
1319 }
1320 
__flatcc_json_printer_flush_buffer(flatcc_json_printer_t * ctx,int all)1321 static void __flatcc_json_printer_flush_buffer(flatcc_json_printer_t *ctx, int all)
1322 {
1323     (void)all;
1324 
1325     if (ctx->p >= ctx->pflush) {
1326         RAISE_ERROR(overflow);
1327         ctx->total += ctx->p - ctx->buf;
1328         ctx->p = ctx->buf;
1329     }
1330     *ctx->p = '\0';
1331 }
1332 
flatcc_json_printer_init_buffer(flatcc_json_printer_t * ctx,char * buffer,size_t buffer_size)1333 int flatcc_json_printer_init_buffer(flatcc_json_printer_t *ctx, char *buffer, size_t buffer_size)
1334 {
1335     assert(buffer_size >= FLATCC_JSON_PRINT_RESERVE);
1336     if (buffer_size < FLATCC_JSON_PRINT_RESERVE) {
1337         return -1;
1338     }
1339     memset(ctx, 0, sizeof(*ctx));
1340     ctx->buf = buffer;
1341     ctx->size = buffer_size;
1342     ctx->flush_size = ctx->size - FLATCC_JSON_PRINT_RESERVE;
1343     ctx->p = ctx->buf;
1344     ctx->pflush = ctx->buf + ctx->flush_size;
1345     ctx->flush = __flatcc_json_printer_flush_buffer;
1346     return 0;
1347 }
1348 
__flatcc_json_printer_flush_dynamic_buffer(flatcc_json_printer_t * ctx,int all)1349 static void __flatcc_json_printer_flush_dynamic_buffer(flatcc_json_printer_t *ctx, int all)
1350 {
1351     size_t len = ctx->p - ctx->buf;
1352     char *p;
1353 
1354     (void)all;
1355 
1356     *ctx->p = '\0';
1357     if (ctx->p < ctx->pflush) {
1358         return;
1359     }
1360     p = FLATCC_JSON_PRINTER_REALLOC(ctx->buf, ctx->size * 2);
1361     if (!p) {
1362         RAISE_ERROR(overflow);
1363         ctx->total += len;
1364         ctx->p = ctx->buf;
1365     } else {
1366         ctx->size *= 2;
1367         ctx->flush_size = ctx->size - FLATCC_JSON_PRINT_RESERVE;
1368         ctx->buf = p;
1369         ctx->p = p + len;
1370         ctx->pflush = p + ctx->flush_size;
1371     }
1372     *ctx->p = '\0';
1373 }
1374 
flatcc_json_printer_init_dynamic_buffer(flatcc_json_printer_t * ctx,size_t buffer_size)1375 int flatcc_json_printer_init_dynamic_buffer(flatcc_json_printer_t *ctx, size_t buffer_size)
1376 {
1377     if (buffer_size == 0) {
1378         buffer_size = FLATCC_JSON_PRINT_DYN_BUFFER_SIZE;
1379     }
1380     if (buffer_size < FLATCC_JSON_PRINT_RESERVE) {
1381         buffer_size = FLATCC_JSON_PRINT_RESERVE;
1382     }
1383     memset(ctx, 0, sizeof(*ctx));
1384     ctx->buf = FLATCC_JSON_PRINTER_ALLOC(buffer_size);
1385     ctx->own_buffer = 1;
1386     ctx->size = buffer_size;
1387     ctx->flush_size = ctx->size - FLATCC_JSON_PRINT_RESERVE;
1388     ctx->p = ctx->buf;
1389     ctx->pflush = ctx->buf + ctx->flush_size;
1390     ctx->flush = __flatcc_json_printer_flush_dynamic_buffer;
1391     if (!ctx->buf) {
1392         RAISE_ERROR(overflow);
1393         return -1;
1394     }
1395     return 0;
1396 }
1397 
flatcc_json_printer_get_buffer(flatcc_json_printer_t * ctx,size_t * buffer_size)1398 void *flatcc_json_printer_get_buffer(flatcc_json_printer_t *ctx, size_t *buffer_size)
1399 {
1400     ctx->flush(ctx, 0);
1401     if (buffer_size) {
1402         *buffer_size = ctx->p - ctx->buf;
1403     }
1404     return ctx->buf;
1405 }
1406 
flatcc_json_printer_finalize_dynamic_buffer(flatcc_json_printer_t * ctx,size_t * buffer_size)1407 void *flatcc_json_printer_finalize_dynamic_buffer(flatcc_json_printer_t *ctx, size_t *buffer_size)
1408 {
1409     void *buffer;
1410 
1411     buffer = flatcc_json_printer_get_buffer(ctx, buffer_size);
1412     memset(ctx, 0, sizeof(*ctx));
1413     return buffer;
1414 }
1415 
flatcc_json_printer_clear(flatcc_json_printer_t * ctx)1416 void flatcc_json_printer_clear(flatcc_json_printer_t *ctx)
1417 {
1418     if (ctx->own_buffer && ctx->buf) {
1419         FLATCC_JSON_PRINTER_FREE(ctx->buf);
1420     }
1421     memset(ctx, 0, sizeof(*ctx));
1422 }
1423