17#define JSONB_API static
19#define JSONB_API extern
22#ifndef JSONB_MAX_DEPTH
30#define JSONB_MAX_DEPTH 128
80#define jsonb_reset(builder) ((builder)->pos = 0)
146 jsonb *builder,
char buf[],
size_t bufsize,
const char key[],
size_t len);
303 jsonb *builder,
char buf[],
size_t bufsize,
const char str[],
size_t len);
353#define TRACE(prev, next) next
368 default:
return "unknown";
371#define TRACE(prev, next) \
373 enum jsonbstate _prev = prev, _next = next; \
374 fprintf(stderr, "%s():L%d | %s -> %s\n", __func__, __LINE__, \
375 _jsonb_eval_state(_prev), _jsonb_eval_state(_next)); \
377#define DECORATOR(d) d
380#define STACK_HEAD(b, state) *(b)->top = (state)
381#define STACK_PUSH(b, state) TRACE(*(b)->top, *++(b)->top = (state))
382#define STACK_POP(b) TRACE(*(b)->top, DECORATOR(*)--(b)->top)
384#define BUFFER_COPY_CHAR_STATIC(b, c, _pos, buf, bufsize) \
386 if ((b)->pos + (_pos) + 1 + 1 > (bufsize)) { \
387 (buf)[(b)->pos] = '\0'; \
388 return JSONB_ERROR_NOMEM; \
390 (buf)[(b)->pos + (_pos)++] = (c); \
391 (buf)[(b)->pos + (_pos)] = '\0'; \
393#define BUFFER_COPY_STATIC(b, value, len, _pos, buf, bufsize) \
396 if ((b)->pos + (_pos) + (len) + 1 > (bufsize)) { \
397 (buf)[(b)->pos] = '\0'; \
398 return JSONB_ERROR_NOMEM; \
400 for (i = 0; i < (len); ++i) \
401 (buf)[(b)->pos + (_pos) + i] = (value)[i]; \
403 (buf)[(b)->pos + (_pos)] = '\0'; \
405#define BUFFER_COPY_CHAR_REALLOC(b, c, _pos, p_buf, p_bufsize) \
407 if ((b)->pos + (_pos) + 1 + 1 > *p_bufsize) { \
408 char *new_buf = NULL; \
409 const size_t needed = (b)->pos + (_pos) + 1 + 1; \
410 size_t new_size = *p_bufsize + (*p_bufsize >> 1); \
411 if (new_size < needed) new_size = needed; \
412 if (new_size < *p_bufsize) return JSONB_ERROR_OVERFLOW; \
413 new_buf = realloc(*p_buf, new_size); \
414 if (!new_buf) return JSONB_ERROR_NOMEM; \
416 *p_bufsize = new_size; \
418 (*p_buf)[(b)->pos + (_pos)++] = (c); \
419 (*p_buf)[(b)->pos + (_pos)] = '\0'; \
421#define BUFFER_COPY_REALLOC(b, value, len, _pos, p_buf, p_bufsize) \
424 if ((b)->pos + (_pos) + (len) + 1 > *p_bufsize) { \
425 char *new_buf = NULL; \
426 const size_t needed = (b)->pos + (_pos) + (len) + 1; \
427 size_t new_size = *p_bufsize + (*p_bufsize >> 1); \
428 if (new_size < needed) new_size = needed; \
429 if (new_size < *p_bufsize) return JSONB_ERROR_OVERFLOW; \
430 new_buf = realloc(*p_buf, new_size); \
431 if (!new_buf) return JSONB_ERROR_NOMEM; \
433 *p_bufsize = new_size; \
435 for (i = 0; i < (len); ++i) \
436 (*p_buf)[(b)->pos + (_pos) + i] = (value)[i]; \
438 (*p_buf)[(b)->pos + (_pos)] = '\0'; \
444 static jsonb empty_builder;
449#define JSONB_OBJECT_EXEC(_type, buf, bufsize) \
450 enum jsonbstate new_state; \
452 if (b->top - b->stack >= JSONB_MAX_DEPTH) return JSONB_ERROR_STACK; \
454 case JSONB_ARRAY_NEXT_VALUE_OR_CLOSE: \
455 BUFFER_COPY_CHAR_##_type(b, ',', pos, buf, bufsize); \
457 case JSONB_ARRAY_VALUE_OR_CLOSE: \
458 new_state = JSONB_ARRAY_NEXT_VALUE_OR_CLOSE; \
460 case JSONB_OBJECT_VALUE: \
461 new_state = JSONB_OBJECT_NEXT_KEY_OR_CLOSE; \
463 case JSONB_ARRAY_OR_OBJECT_OR_VALUE: \
464 new_state = JSONB_DONE; \
467 STACK_HEAD(b, JSONB_ERROR); \
471 return JSONB_ERROR_INPUT; \
473 BUFFER_COPY_CHAR_##_type(b, '{', pos, buf, bufsize); \
474 STACK_HEAD(b, new_state); \
475 STACK_PUSH(b, JSONB_OBJECT_KEY_OR_CLOSE); \
491#define JSONB_OBJECT_POP_EXEC(_type, buf, bufsize) \
492 enum jsonbcode code; \
495 case JSONB_OBJECT_KEY_OR_CLOSE: \
496 case JSONB_OBJECT_NEXT_KEY_OR_CLOSE: \
497 code = b->stack == b->top - 1 ? JSONB_END : JSONB_OK; \
500 STACK_HEAD(b, JSONB_ERROR); \
504 return JSONB_ERROR_INPUT; \
506 BUFFER_COPY_CHAR_##_type(b, '}', pos, buf, bufsize); \
524_jsonb_escape_STATIC(
size_t *pos,
531 char *esc_tok = NULL, _esc_tok[8] =
"\\u00";
532 char *esc_buf = NULL;
541 for (i = 0; i < len; ++i) {
542 unsigned char c = str[i];
545 case 0x22: esc_tok =
"\\\"";
break;
546 case 0x5C: esc_tok =
"\\\\";
break;
547 case '\b': esc_tok =
"\\b";
break;
548 case '\f': esc_tok =
"\\f";
break;
549 case '\n': esc_tok =
"\\n";
break;
550 case '\r': esc_tok =
"\\r";
break;
551 case '\t': esc_tok =
"\\t";
break;
552 default:
if (c <= 0x1F) {
553 static const char tohex[] =
"0123456789abcdef";
554 _esc_tok[4] = tohex[c >> 4];
555 _esc_tok[5] = tohex[c & 0xF];
562 for (j = 0; esc_tok[j]; j++) {
565 *esc_buf++ = esc_tok[j];
567 extra_bytes += j - 1;
574 if (*pos + len + extra_bytes > bufsize) {
580 *pos += len + extra_bytes;
585 for (j = 0; j < len; ++j)
586 buf[*pos + j] = str[j];
590 esc_buf = buf + *pos;
596_jsonb_escape_REALLOC(
size_t *pos,
603 char *esc_tok = NULL, _esc_tok[8] =
"\\u00";
604 char *esc_buf = NULL;
609 ptrdiff_t esc_buf_offset = 0;
614 buf = *p_buf + offset;
615 bufsize = *p_bufsize - offset;
617 if (second_pass && esc_buf) esc_buf = buf + esc_buf_offset;
622 for (i = 0; i < len; ++i) {
623 unsigned char c = str[i];
625 switch (c) {
case 0x22: esc_tok =
"\\\"";
break;
626 case 0x5C: esc_tok =
"\\\\";
break;
627 case '\b': esc_tok =
"\\b";
break;
628 case '\f': esc_tok =
"\\f";
break;
629 case '\n': esc_tok =
"\\n";
break;
630 case '\r': esc_tok =
"\\r";
break;
631 case '\t': esc_tok =
"\\t";
break;
632 default:
if (c <= 0x1F) {
633 static const char tohex[] =
"0123456789abcdef";
634 _esc_tok[4] = tohex[c >> 4];
635 _esc_tok[5] = tohex[c & 0xF];
642 for (j = 0; esc_tok[j]; j++) {
645 *esc_buf++ = esc_tok[j];
647 extra_bytes += j - 1;
654 if (*pos + len + extra_bytes + 1 > bufsize) {
655 char *new_buf = NULL;
656 const size_t needed = *pos + len + extra_bytes + 1;
657 size_t new_size = *p_bufsize + (*p_bufsize >> 1);
658 if (new_size < needed) new_size = needed;
660 new_buf = realloc(*p_buf, new_size);
662 if (esc_buf) esc_buf_offset = esc_buf - buf;
664 *p_bufsize = new_size;
670 *pos += len + extra_bytes;
675 for (j = 0; j < len; ++j)
676 buf[*pos + j] = str[j];
680 esc_buf = buf + *pos;
685#define JSONB_KEY_EXEC(_type, buf, bufsize, key, len) \
688 case JSONB_OBJECT_NEXT_KEY_OR_CLOSE: \
689 BUFFER_COPY_CHAR_##_type(b, ',', pos, buf, bufsize); \
691 case JSONB_OBJECT_KEY_OR_CLOSE: { \
692 enum jsonbcode ret; \
693 BUFFER_COPY_CHAR_##_type(b, '"', pos, buf, bufsize); \
694 ret = _jsonb_escape_##_type(&pos, buf, bufsize, b->pos, key, len); \
695 if (ret != JSONB_OK) return ret; \
696 BUFFER_COPY_##_type(b, "\":", 2, pos, buf, bufsize); \
697 STACK_HEAD(b, JSONB_OBJECT_VALUE); \
700 STACK_HEAD(b, JSONB_ERROR); \
703 return JSONB_ERROR_INPUT; \
716 jsonb *b,
char *p_buf[],
size_t *p_bufsize,
const char key[],
size_t len)
721#define JSONB_ARRAY_EXEC(_type, buf, bufsize) \
722 enum jsonbstate new_state; \
724 if (b->top - b->stack >= JSONB_MAX_DEPTH) return JSONB_ERROR_STACK; \
726 case JSONB_ARRAY_NEXT_VALUE_OR_CLOSE: \
727 BUFFER_COPY_CHAR_##_type(b, ',', pos, buf, bufsize); \
729 case JSONB_ARRAY_VALUE_OR_CLOSE: \
730 new_state = JSONB_ARRAY_NEXT_VALUE_OR_CLOSE; \
732 case JSONB_OBJECT_VALUE: \
733 new_state = JSONB_OBJECT_NEXT_KEY_OR_CLOSE; \
735 case JSONB_ARRAY_OR_OBJECT_OR_VALUE: \
736 new_state = JSONB_DONE; \
739 STACK_HEAD(b, JSONB_ERROR); \
743 return JSONB_ERROR_INPUT; \
745 BUFFER_COPY_CHAR_##_type(b, '[', pos, buf, bufsize); \
746 STACK_HEAD(b, new_state); \
747 STACK_PUSH(b, JSONB_ARRAY_VALUE_OR_CLOSE); \
763#define JSONB_ARRAY_POP_EXEC(_type, buf, bufsize) \
764 enum jsonbcode code; \
767 case JSONB_ARRAY_VALUE_OR_CLOSE: \
768 case JSONB_ARRAY_NEXT_VALUE_OR_CLOSE: \
769 code = b->stack == b->top - 1 ? JSONB_END : JSONB_OK; \
772 STACK_HEAD(b, JSONB_ERROR); \
776 return JSONB_ERROR_INPUT; \
778 BUFFER_COPY_CHAR_##_type(b, ']', pos, buf, bufsize); \
795#define JSONB_TOKEN_EXEC(_type, buf, bufsize, token, len) \
796 enum jsonbstate next_state; \
797 enum jsonbcode code; \
800 case JSONB_ARRAY_OR_OBJECT_OR_VALUE: \
801 next_state = JSONB_DONE; \
804 case JSONB_ARRAY_NEXT_VALUE_OR_CLOSE: \
805 BUFFER_COPY_CHAR_##_type(b, ',', pos, buf, bufsize); \
807 case JSONB_ARRAY_VALUE_OR_CLOSE: \
808 next_state = JSONB_ARRAY_NEXT_VALUE_OR_CLOSE; \
811 case JSONB_OBJECT_VALUE: \
812 next_state = JSONB_OBJECT_NEXT_KEY_OR_CLOSE; \
816 STACK_HEAD(b, JSONB_ERROR); \
820 return JSONB_ERROR_INPUT; \
822 BUFFER_COPY_##_type(b, token, len, pos, buf, bufsize); \
823 STACK_HEAD(b, next_state); \
829 jsonb *b,
char buf[],
size_t bufsize,
const char token[],
size_t len)
836 jsonb *b,
char *p_buf[],
size_t *p_bufsize,
const char token[],
size_t len)
844 return boolean ?
jsonb_token(b, buf, bufsize,
"true", 4)
867#define JSONB_STRING_EXEC(_type, buf, bufsize, str, len) \
868 enum jsonbstate next_state; \
869 enum jsonbcode code, ret; \
872 case JSONB_ARRAY_OR_OBJECT_OR_VALUE: \
873 next_state = JSONB_DONE; \
876 case JSONB_ARRAY_NEXT_VALUE_OR_CLOSE: \
877 BUFFER_COPY_CHAR_##_type(b, ',', pos, buf, bufsize); \
879 case JSONB_ARRAY_VALUE_OR_CLOSE: \
880 next_state = JSONB_ARRAY_NEXT_VALUE_OR_CLOSE; \
883 case JSONB_OBJECT_VALUE: \
884 next_state = JSONB_OBJECT_NEXT_KEY_OR_CLOSE; \
888 STACK_HEAD(b, JSONB_ERROR); \
892 return JSONB_ERROR_INPUT; \
894 BUFFER_COPY_CHAR_##_type(b, '"', pos, buf, bufsize); \
895 ret = _jsonb_escape_##_type(&pos, buf, bufsize, b->pos, str, len); \
896 if (ret != JSONB_OK) return ret; \
897 BUFFER_COPY_CHAR_##_type(b, '"', pos, buf, bufsize); \
898 STACK_HEAD(b, next_state); \
904 jsonb *b,
char buf[],
size_t bufsize,
const char str[],
size_t len)
911 jsonb *b,
char *p_buf[],
size_t *p_bufsize,
const char str[],
size_t len)
920 const long len = sprintf(token,
"%.17G", number);
929 const long len = sprintf(token,
"%.17G", number);
939#undef BUFFER_COPY_CHAR_STATIC
940#undef BUFFER_COPY_STATIC
941#undef BUFFER_COPY_CHAR_REALLOC
942#undef BUFFER_COPY_REALLOC
943#undef JSONB_OBJECT_EXEC
944#undef JSONB_OBJECT_POP_EXEC
946#undef JSONB_ARRAY_EXEC
947#undef JSONB_ARRAY_POP_EXEC
948#undef JSONB_TOKEN_EXEC
949#undef JSONB_STRING_EXEC
struct jsonb jsonb
Handle for building a JSON string.
jsonbcode jsonb_array(jsonb *builder, char buf[], size_t bufsize)
Push an array to the builder.
Definition: json-build.h:752
jsonbstate
json-builder serializing state
Definition: json-build.h:50
@ JSONB_OBJECT_VALUE
Definition: json-build.h:54
@ JSONB_INIT
Definition: json-build.h:51
@ JSONB_ARRAY_VALUE_OR_CLOSE
Definition: json-build.h:56
@ JSONB_OBJECT_NEXT_KEY_OR_CLOSE
Definition: json-build.h:55
@ JSONB_ARRAY_NEXT_VALUE_OR_CLOSE
Definition: json-build.h:57
@ JSONB_ERROR
Definition: json-build.h:58
@ JSONB_DONE
Definition: json-build.h:59
@ JSONB_OBJECT_KEY_OR_CLOSE
Definition: json-build.h:53
@ JSONB_ARRAY_OR_OBJECT_OR_VALUE
Definition: json-build.h:52
#define JSONB_MAX_DEPTH
Definition: json-build.h:30
jsonbcode jsonb_bool_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize, int boolean)
jsonb_bool() with dynamic buffer
Definition: json-build.h:849
jsonbcode jsonb_key(jsonb *builder, char buf[], size_t bufsize, const char key[], size_t len)
Push a key to the builder.
Definition: json-build.h:709
jsonbcode jsonb_token(jsonb *builder, char buf[], size_t bufsize, const char token[], size_t len)
Push a raw JSON token to the builder.
Definition: json-build.h:828
jsonbcode jsonb_string(jsonb *builder, char buf[], size_t bufsize, const char str[], size_t len)
Push a string token to the builder.
Definition: json-build.h:903
#define JSONB_ARRAY_POP_EXEC(_type, buf, bufsize)
Definition: json-build.h:763
#define JSONB_STRING_EXEC(_type, buf, bufsize, str, len)
Definition: json-build.h:867
jsonbcode jsonb_string_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize, const char str[], size_t len)
jsonb_string() with dynamic buffer
Definition: json-build.h:910
jsonbcode jsonb_object(jsonb *builder, char buf[], size_t bufsize)
Push an object to the builder.
Definition: json-build.h:480
jsonbcode jsonb_array_pop_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize)
jsonb_array_pop() with dynamic buffer
Definition: json-build.h:790
jsonbcode jsonb_token_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize, const char token[], size_t len)
jsonb_token() with dynamic buffer
Definition: json-build.h:835
jsonbcode jsonb_object_pop_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize)
jsonb_object_pop() with dynamic buffer
Definition: json-build.h:518
#define JSONB_KEY_EXEC(_type, buf, bufsize, key, len)
Definition: json-build.h:685
jsonbcode jsonb_bool(jsonb *builder, char buf[], size_t bufsize, int boolean)
Push a boolean token to the builder.
Definition: json-build.h:842
jsonbcode jsonb_array_pop(jsonb *builder, char buf[], size_t bufsize)
Pop an array from the builder.
Definition: json-build.h:784
#define JSONB_TOKEN_EXEC(_type, buf, bufsize, token, len)
Definition: json-build.h:795
#define JSONB_OBJECT_EXEC(_type, buf, bufsize)
Definition: json-build.h:449
jsonbcode jsonb_null_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize)
jsonb_null() with dynamic buffer
Definition: json-build.h:862
jsonbcode jsonb_null(jsonb *builder, char buf[], size_t bufsize)
Push a null token to the builder.
Definition: json-build.h:856
jsonbcode jsonb_number(jsonb *builder, char buf[], size_t bufsize, double number)
Push a number token to the builder.
Definition: json-build.h:917
void jsonb_init(jsonb *builder)
Initialize a jsonb handle.
Definition: json-build.h:442
jsonbcode jsonb_object_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize)
jsonb_object() with dynamic buffer
Definition: json-build.h:486
jsonbcode jsonb_number_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize, double number)
jsonb_number() with dynamic buffer
Definition: json-build.h:926
jsonbcode jsonb_array_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize)
jsonb_array() with dynamic buffer
Definition: json-build.h:758
jsonbcode
json-builder return codes
Definition: json-build.h:34
@ JSONB_ERROR_OVERFLOW
Definition: json-build.h:46
@ JSONB_END
Definition: json-build.h:38
@ JSONB_ERROR_INPUT
Definition: json-build.h:42
@ JSONB_ERROR_STACK
Definition: json-build.h:44
@ JSONB_ERROR_NOMEM
Definition: json-build.h:40
@ JSONB_OK
Definition: json-build.h:36
#define JSONB_ARRAY_EXEC(_type, buf, bufsize)
Definition: json-build.h:721
jsonbcode jsonb_object_pop(jsonb *builder, char buf[], size_t bufsize)
Pop an object from the builder.
Definition: json-build.h:512
jsonbcode jsonb_key_auto(jsonb *builder, char *p_buf[], size_t *p_bufsize, const char key[], size_t len)
jsonb_key() with dynamic buffer
Definition: json-build.h:715
#define JSONB_API
Definition: json-build.h:19
#define JSONB_OBJECT_POP_EXEC(_type, buf, bufsize)
Definition: json-build.h:491
Handle for building a JSON string.
Definition: json-build.h:63
enum jsonbstate * top
Definition: json-build.h:67
size_t pos
Definition: json-build.h:69
enum jsonbstate stack[128+1]
Definition: json-build.h:65