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