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