ucx/json.c

branch
dav-2
changeset 891
4d58cbcc9efa
parent 889
42cdbf9bbd49
equal deleted inserted replaced
890:e77ccf1c4bb3 891:4d58cbcc9efa
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29 #include "cx/json.h" 29 #include "cx/json.h"
30 #include "cx/kv_list.h"
30 31
31 #include <string.h> 32 #include <string.h>
32 #include <assert.h> 33 #include <assert.h>
33 #include <stdio.h> 34 #include <stdio.h>
34 #include <inttypes.h> 35 #include <inttypes.h>
39 * https://tools.ietf.org/html/rfc8259 40 * https://tools.ietf.org/html/rfc8259
40 */ 41 */
41 42
42 static CxJsonValue cx_json_value_nothing = {.type = CX_JSON_NOTHING}; 43 static CxJsonValue cx_json_value_nothing = {.type = CX_JSON_NOTHING};
43 44
44 static int json_cmp_objvalue(const void *l, const void *r) {
45 const CxJsonObjValue *left = l;
46 const CxJsonObjValue *right = r;
47 return cx_strcmp(cx_strcast(left->name), cx_strcast(right->name));
48 }
49
50 static size_t json_find_objvalue(const CxJsonValue *obj, cxstring name) {
51 assert(obj->type == CX_JSON_OBJECT);
52 CxJsonObjValue kv_dummy;
53 kv_dummy.name = cx_mutstrn((char*) name.ptr, name.length);
54 return cx_array_binary_search(
55 obj->value.object.values,
56 obj->value.object.values_size,
57 sizeof(CxJsonObjValue),
58 &kv_dummy,
59 json_cmp_objvalue
60 );
61 }
62
63 static int json_add_objvalue(CxJsonValue *objv, CxJsonObjValue member) {
64 assert(objv->type == CX_JSON_OBJECT);
65 const CxAllocator * const al = objv->allocator;
66 CxJsonObject *obj = &(objv->value.object);
67
68 // determine the index where we need to insert the new member
69 size_t index = cx_array_binary_search_sup(
70 obj->values,
71 obj->values_size,
72 sizeof(CxJsonObjValue),
73 &member, json_cmp_objvalue
74 );
75
76 // is the name already present?
77 if (index < obj->values_size && 0 == json_cmp_objvalue(&member, &obj->values[index])) {
78 // free the original value
79 cx_strfree_a(al, &obj->values[index].name);
80 cxJsonValueFree(obj->values[index].value);
81 // replace the item
82 obj->values[index] = member;
83
84 // nothing more to do
85 return 0;
86 }
87
88 // determine the old capacity and reserve for one more element
89 CxArrayReallocator arealloc = cx_array_reallocator(al, NULL);
90 size_t oldcap = obj->values_capacity;
91 if (cx_array_simple_reserve_a(&arealloc, obj->values, 1)) return 1;
92
93 // check the new capacity, if we need to realloc the index array
94 size_t newcap = obj->values_capacity;
95 if (newcap > oldcap) {
96 if (cxReallocateArray(al, &obj->indices, newcap, sizeof(size_t))) {
97 return 1;
98 }
99 }
100
101 // check if append or insert
102 if (index < obj->values_size) {
103 // move the other elements
104 memmove(
105 &obj->values[index+1],
106 &obj->values[index],
107 (obj->values_size - index) * sizeof(CxJsonObjValue)
108 );
109 // increase indices for the moved elements
110 for (size_t i = 0; i < obj->values_size ; i++) {
111 if (obj->indices[i] >= index) {
112 obj->indices[i]++;
113 }
114 }
115 }
116
117 // insert the element and set the index
118 obj->values[index] = member;
119 obj->indices[obj->values_size] = index;
120 obj->values_size++;
121
122 return 0;
123 }
124
125 static void token_destroy(CxJsonToken *token) { 45 static void token_destroy(CxJsonToken *token) {
126 if (token->allocated) { 46 if (token->allocated) {
127 cx_strfree(&token->content); 47 cx_strfree(&token->content);
48 token->allocated = false;
128 } 49 }
129 } 50 }
130 51
131 static int num_isexp(const char *content, size_t length, size_t pos) { 52 static int num_isexp(const char *content, size_t length, size_t pos) {
132 if (pos >= length) { 53 if (pos >= length) {
188 CxJsonTokenType ttype; 109 CxJsonTokenType ttype;
189 if (isstring) { 110 if (isstring) {
190 ttype = CX_JSON_TOKEN_STRING; 111 ttype = CX_JSON_TOKEN_STRING;
191 } else { 112 } else {
192 cxstring s = cx_strcast(str); 113 cxstring s = cx_strcast(str);
193 if (!cx_strcmp(s, CX_STR("true")) || !cx_strcmp(s, CX_STR("false")) 114 if (!cx_strcmp(s, "true") || !cx_strcmp(s, "false")
194 || !cx_strcmp(s, CX_STR("null"))) { 115 || !cx_strcmp(s, "null")) {
195 ttype = CX_JSON_TOKEN_LITERAL; 116 ttype = CX_JSON_TOKEN_LITERAL;
196 } else { 117 } else {
197 ttype = token_numbertype(str.ptr, str.length); 118 ttype = token_numbertype(str.ptr, str.length);
198 } 119 }
199 } 120 }
305 } 226 }
306 } 227 }
307 } 228 }
308 } 229 }
309 230
310 if (ttype != CX_JSON_NO_TOKEN) { 231 if (ttype == CX_JSON_NO_TOKEN) {
232 return CX_JSON_NO_DATA;
233 } else {
311 // uncompleted token 234 // uncompleted token
312 size_t uncompleted_len = json->buffer.size - token_part_start; 235 size_t uncompleted_len = json->buffer.size - token_part_start;
313 if (json->uncompleted.tokentype == CX_JSON_NO_TOKEN) { 236 if (json->uncompleted.tokentype == CX_JSON_NO_TOKEN) {
314 // current token is uncompleted 237 // current token is uncompleted
315 // save current token content 238 // save current token content
332 } 255 }
333 json->uncompleted.content = str; 256 json->uncompleted.content = str;
334 } 257 }
335 // advance the buffer position - we saved the stuff in the uncompleted token 258 // advance the buffer position - we saved the stuff in the uncompleted token
336 json->buffer.pos += uncompleted_len; 259 json->buffer.pos += uncompleted_len;
337 } 260 return CX_JSON_INCOMPLETE_DATA;
338 261 }
339 return CX_JSON_INCOMPLETE_DATA;
340 } 262 }
341 263
342 // converts a Unicode codepoint to utf8 264 // converts a Unicode codepoint to utf8
343 static unsigned codepoint_to_utf8(uint32_t codepoint, char *output_buf) { 265 static unsigned codepoint_to_utf8(uint32_t codepoint, char *output_buf) {
344 if (codepoint <= 0x7F) { 266 if (codepoint <= 0x7F) {
435 } else if (c == 'b') { 357 } else if (c == 'b') {
436 c = '\b'; 358 c = '\b';
437 } else if (c == 'u') { 359 } else if (c == 'u') {
438 char utf8buf[4]; 360 char utf8buf[4];
439 unsigned utf8len = unescape_unicode_string( 361 unsigned utf8len = unescape_unicode_string(
440 cx_strn(str.ptr + i - 1, str.length + 1 - i), 362 cx_strn(str.ptr + i - 1, str.length - i),
441 utf8buf 363 utf8buf
442 ); 364 );
443 if(utf8len > 0) { 365 if(utf8len > 0) {
444 i += utf8len < 4 ? 4 : 10; 366 i += utf8len < 4 ? 4 : 10;
445 // add all bytes from utf8buf except the last char 367 // add all bytes from utf8buf except the last char
454 result.ptr[result.length++] = '\\'; 376 result.ptr[result.length++] = '\\';
455 } 377 }
456 } else { 378 } else {
457 // TODO: discuss the behavior for unrecognized escape sequences 379 // TODO: discuss the behavior for unrecognized escape sequences
458 // most parsers throw an error here - we just ignore it 380 // most parsers throw an error here - we just ignore it
459 result.ptr[result.length++] = '\\'; 381 result.ptr[result.length++] = '\\'; // LCOV_EXCL_LINE
460 } 382 }
461 383
462 result.ptr[result.length++] = c; 384 result.ptr[result.length++] = c;
463 } else { 385 } else {
464 if (c == '\\') { 386 if (c == '\\') {
471 result.ptr[result.length] = 0; 393 result.ptr[result.length] = 0;
472 394
473 return result; 395 return result;
474 } 396 }
475 397
476 static cxmutstr escape_string(cxmutstr str, bool escape_slash) { 398 static cxmutstr escape_string(cxstring str, bool escape_slash) {
477 // note: this function produces the string without enclosing quotes 399 // note: this function produces the string without enclosing quotes
478 // the reason is that we don't want to allocate memory just for that 400 // the reason is that we don't want to allocate memory just for that
479 CxBuffer buf = {0}; 401 CxBuffer buf = {0};
480 402
481 bool all_printable = true; 403 bool all_printable = true;
486 408
487 if (all_printable && escape) { 409 if (all_printable && escape) {
488 size_t capa = str.length + 32; 410 size_t capa = str.length + 32;
489 char *space = cxMallocDefault(capa); 411 char *space = cxMallocDefault(capa);
490 if (space == NULL) return cx_mutstrn(NULL, 0); 412 if (space == NULL) return cx_mutstrn(NULL, 0);
491 cxBufferInit(&buf, space, capa, NULL, CX_BUFFER_AUTO_EXTEND); 413 cxBufferInit(&buf, NULL, space, capa, CX_BUFFER_AUTO_EXTEND);
492 cxBufferWrite(str.ptr, 1, i, &buf); 414 cxBufferWrite(str.ptr, 1, i, &buf);
493 all_printable = false; 415 all_printable = false;
494 } 416 }
495 if (escape) { 417 if (escape) {
496 cxBufferPut(&buf, '\\'); 418 cxBufferPut(&buf, '\\');
517 } 439 }
518 } else if (!all_printable) { 440 } else if (!all_printable) {
519 cxBufferPut(&buf, c); 441 cxBufferPut(&buf, c);
520 } 442 }
521 } 443 }
522 if (!all_printable) { 444 cxmutstr ret;
523 str = cx_mutstrn(buf.space, buf.size); 445 if (all_printable) {
446 // don't copy the string when we don't need to escape anything
447 ret = cx_mutstrn((char*)str.ptr, str.length);
448 } else {
449 ret = cx_mutstrn(buf.space, buf.size);
524 } 450 }
525 cxBufferDestroy(&buf); 451 cxBufferDestroy(&buf);
526 return str; 452 return ret;
453 }
454
455 static CxJsonObject json_create_object_map(const CxAllocator *allocator) {
456 CxMap *map = cxKvListCreateAsMap(allocator, CX_STORE_POINTERS);
457 if (map == NULL) return NULL; // LCOV_EXCL_LINE
458 cxSetCompareFunc(map, cxJsonCompare);
459 cxSetDestructor(map, cxJsonValueFree);
460 return map;
461 }
462
463 static void json_free_object_map(CxJsonObject obj) {
464 cxMapFree(obj);
527 } 465 }
528 466
529 static CxJsonValue* json_create_value(CxJson *json, CxJsonValueType type) { 467 static CxJsonValue* json_create_value(CxJson *json, CxJsonValueType type) {
530 CxJsonValue *v = cxCalloc(json->allocator, 1, sizeof(CxJsonValue)); 468 CxJsonValue *v = cxCalloc(json->allocator, 1, sizeof(CxJsonValue));
531 if (v == NULL) return NULL; // LCOV_EXCL_LINE 469 if (v == NULL) return NULL; // LCOV_EXCL_LINE
532 470
533 // initialize the value 471 // initialize the value
534 v->type = type; 472 v->type = type;
535 v->allocator = json->allocator; 473 v->allocator = json->allocator;
536 if (type == CX_JSON_ARRAY) { 474 if (type == CX_JSON_ARRAY) {
537 cx_array_initialize_a(json->allocator, v->value.array.array, 16); 475 if (cx_array_init_a(json->allocator, v->array, 16)) {
538 if (v->value.array.array == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE 476 goto create_json_value_exit_error; // LCOV_EXCL_LINE
477 }
539 } else if (type == CX_JSON_OBJECT) { 478 } else if (type == CX_JSON_OBJECT) {
540 cx_array_initialize_a(json->allocator, v->value.object.values, 16); 479 v->object = json_create_object_map(json->allocator);
541 v->value.object.indices = cxCalloc(json->allocator, 16, sizeof(size_t)); 480 if (v->object == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE
542 if (v->value.object.values == NULL ||
543 v->value.object.indices == NULL)
544 goto create_json_value_exit_error; // LCOV_EXCL_LINE
545 } 481 }
546 482
547 // add the new value to a possible parent 483 // add the new value to a possible parent
548 if (json->vbuf_size > 0) { 484 if (json->vbuf.size > 0) {
549 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1]; 485 CxJsonValue *parent = json->vbuf.data[json->vbuf.size - 1];
550 assert(parent != NULL); 486 assert(parent != NULL);
551 if (parent->type == CX_JSON_ARRAY) { 487 if (parent->type == CX_JSON_ARRAY) {
552 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL); 488 if (cx_array_add_a(json->allocator, parent->array, v)) {
553 if (cx_array_simple_add_a(&value_realloc, parent->value.array.array, v)) {
554 goto create_json_value_exit_error; // LCOV_EXCL_LINE 489 goto create_json_value_exit_error; // LCOV_EXCL_LINE
555 } 490 }
556 } else if (parent->type == CX_JSON_OBJECT) { 491 } else if (parent->type == CX_JSON_OBJECT) {
557 // the member was already created after parsing the name 492 // the member was already created after parsing the name
558 assert(json->uncompleted_member.name.ptr != NULL); 493 // store the pointer of the uncompleted value in the map
559 json->uncompleted_member.value = v; 494 assert(json->uncompleted_member_name.ptr != NULL);
560 if (json_add_objvalue(parent, json->uncompleted_member)) { 495 if (cxMapPut(parent->object, json->uncompleted_member_name, v)) {
561 goto create_json_value_exit_error; // LCOV_EXCL_LINE 496 goto create_json_value_exit_error; // LCOV_EXCL_LINE
562 } 497 }
563 json->uncompleted_member.name = (cxmutstr) {NULL, 0}; 498 cx_strfree_a(json->allocator, &json->uncompleted_member_name);
564 } else { 499 } else {
565 assert(false); // LCOV_EXCL_LINE 500 assert(false); // LCOV_EXCL_LINE
566 } 501 }
567 } 502 }
568 503
569 // add the new value to the stack, if it is an array or object 504 // add the new value to the stack, if it is an array or object
570 if (type == CX_JSON_ARRAY || type == CX_JSON_OBJECT) { 505 if (type == CX_JSON_ARRAY || type == CX_JSON_OBJECT) {
571 CxArrayReallocator vbuf_realloc = cx_array_reallocator(NULL, json->vbuf_internal); 506 if (json->vbuf.size >= json->vbuf.capacity) {
572 if (cx_array_simple_add_a(&vbuf_realloc, json->vbuf, v)) { 507 int alloc_error;
573 goto create_json_value_exit_error; // LCOV_EXCL_LINE 508 if (json->vbuf.data == json->vbuf_internal) {
574 } 509 alloc_error = cx_array_copy_to_new(json->vbuf, json->vbuf.size+1);
510 } else {
511 alloc_error = cx_array_reserve(json->vbuf, json->vbuf.size+1);
512 }
513 if (alloc_error) {
514 goto create_json_value_exit_error; // LCOV_EXCL_LINE
515 }
516 }
517 json->vbuf.data[json->vbuf.size] = v;
518 json->vbuf.size++;
575 } 519 }
576 520
577 // if currently no value is parsed, this is now the value of interest 521 // if currently no value is parsed, this is now the value of interest
578 if (json->parsed == NULL) { 522 if (json->parsed == NULL) {
579 json->parsed = v; 523 json->parsed = v;
603 } 547 }
604 548
605 memset(json, 0, sizeof(CxJson)); 549 memset(json, 0, sizeof(CxJson));
606 json->allocator = allocator; 550 json->allocator = allocator;
607 551
608 json->states = json->states_internal; 552 cx_array_init_fixed(json->states, json->states_internal, 1);
609 json->states_capacity = cx_nmemb(json->states_internal); 553 json->states.data[0] = JP_STATE_VALUE_BEGIN;
610 json->states[0] = JP_STATE_VALUE_BEGIN; 554 cx_array_init_fixed(json->vbuf, json->vbuf_internal, 0);
611 json->states_size = 1;
612
613 json->vbuf = json->vbuf_internal;
614 json->vbuf_capacity = cx_nmemb(json->vbuf_internal);
615 } 555 }
616 556
617 void cxJsonDestroy(CxJson *json) { 557 void cxJsonDestroy(CxJson *json) {
618 cxBufferDestroy(&json->buffer); 558 cxBufferDestroy(&json->buffer);
619 if (json->states != json->states_internal) { 559 if (json->states.data != json->states_internal) {
620 cxFreeDefault(json->states); 560 cx_array_free(json->states);
621 } 561 }
622 if (json->vbuf != json->vbuf_internal) { 562 if (json->vbuf.data != json->vbuf_internal) {
623 cxFreeDefault(json->vbuf); 563 cx_array_free(json->vbuf);
624 } 564 }
625 cxJsonValueFree(json->parsed); 565 cxJsonValueFree(json->parsed);
626 json->parsed = NULL; 566 json->parsed = NULL;
627 if (json->uncompleted_member.name.ptr != NULL) { 567 token_destroy(&json->uncompleted);
628 cx_strfree_a(json->allocator, &json->uncompleted_member.name); 568 cx_strfree_a(json->allocator, &json->uncompleted_member_name);
629 json->uncompleted_member = (CxJsonObjValue){{NULL, 0}, NULL};
630 }
631 } 569 }
632 570
633 void cxJsonReset(CxJson *json) { 571 void cxJsonReset(CxJson *json) {
634 const CxAllocator *allocator = json->allocator; 572 const CxAllocator *allocator = json->allocator;
635 cxJsonDestroy(json); 573 cxJsonDestroy(json);
638 576
639 int cxJsonFilln(CxJson *json, const char *buf, size_t size) { 577 int cxJsonFilln(CxJson *json, const char *buf, size_t size) {
640 if (cxBufferEof(&json->buffer)) { 578 if (cxBufferEof(&json->buffer)) {
641 // reinitialize the buffer 579 // reinitialize the buffer
642 cxBufferDestroy(&json->buffer); 580 cxBufferDestroy(&json->buffer);
643 cxBufferInit(&json->buffer, (char*) buf, size, 581 if (buf == NULL) buf = ""; // buffer must not be initialized with NULL
644 NULL, CX_BUFFER_AUTO_EXTEND | CX_BUFFER_COPY_ON_WRITE); 582 cxBufferInit(&json->buffer, NULL, (char*) buf,
583 size, CX_BUFFER_AUTO_EXTEND | CX_BUFFER_COPY_ON_WRITE);
645 json->buffer.size = size; 584 json->buffer.size = size;
646 return 0; 585 return 0;
647 } else { 586 } else {
648 return size != cxBufferAppend(buf, 1, size, &json->buffer); 587 return size != cxBufferAppend(buf, 1, size, &json->buffer);
649 } 588 }
650 } 589 }
651 590
652 static void json_add_state(CxJson *json, int state) { 591 static void json_add_state(CxJson *json, int state) {
653 // we have guaranteed the necessary space with cx_array_simple_reserve() 592 // we have guaranteed the necessary space
654 // therefore, we can safely add the state in the simplest way possible 593 // therefore, we can safely add the state in the simplest way possible
655 json->states[json->states_size++] = state; 594 json->states.data[json->states.size++] = state;
656 } 595 }
657 596
658 #define return_rec(code) \ 597 #define return_rec(code) \
659 token_destroy(&token); \ 598 token_destroy(&token); \
660 return code 599 return code
671 return ret; 610 return ret;
672 } 611 }
673 } 612 }
674 613
675 // pop the current state 614 // pop the current state
676 assert(json->states_size > 0); 615 assert(json->states.size > 0);
677 int state = json->states[--json->states_size]; 616 int state = json->states.data[--json->states.size];
678 617
679 // guarantee that at least two more states fit on the stack 618 // guarantee that at least two more states fit into the array
680 CxArrayReallocator state_realloc = cx_array_reallocator(NULL, json->states_internal); 619 const size_t required_states_depth = json->states.size + 2;
681 if (cx_array_simple_reserve_a(&state_realloc, json->states, 2)) { 620 if (required_states_depth >= json->states.capacity) {
682 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE 621 int alloc_error;
622 if (json->states.data == json->states_internal) {
623 alloc_error = cx_array_copy_to_new(json->states, required_states_depth);
624 } else {
625 alloc_error = cx_array_reserve(json->states, required_states_depth);
626 }
627 if (alloc_error) {
628 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE
629 }
683 } 630 }
684 631
685 632
686 // 0 JP_STATE_VALUE_BEGIN value begin 633 // 0 JP_STATE_VALUE_BEGIN value begin
687 // 10 JP_STATE_VALUE_END expect value end 634 // 10 JP_STATE_VALUE_END expect value end
709 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 656 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
710 } 657 }
711 json_add_state(json, JP_STATE_OBJ_NAME_OR_CLOSE); 658 json_add_state(json, JP_STATE_OBJ_NAME_OR_CLOSE);
712 return_rec(CX_JSON_NO_ERROR); 659 return_rec(CX_JSON_NO_ERROR);
713 } 660 }
661 case CX_JSON_TOKEN_END_ARRAY: {
662 if (state == JP_STATE_VALUE_BEGIN_AR) {
663 // discard the array from the value buffer
664 json->vbuf.size--;
665 json->states.size--;
666 return_rec(CX_JSON_NO_ERROR);
667 } else {
668 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
669 }
670 }
714 case CX_JSON_TOKEN_STRING: { 671 case CX_JSON_TOKEN_STRING: {
715 if ((vbuf = json_create_value(json, CX_JSON_STRING)) == NULL) { 672 if ((vbuf = json_create_value(json, CX_JSON_STRING)) == NULL) {
716 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 673 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
717 } 674 }
718 cxmutstr str = unescape_string(json->allocator, token.content); 675 cxmutstr str = unescape_string(json->allocator, token.content);
719 if (str.ptr == NULL) { 676 if (str.ptr == NULL) {
720 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 677 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
721 } 678 }
722 vbuf->value.string = str; 679 vbuf->string = str;
723 return_rec(CX_JSON_NO_ERROR); 680 return_rec(CX_JSON_NO_ERROR);
724 } 681 }
725 case CX_JSON_TOKEN_INTEGER: 682 case CX_JSON_TOKEN_INTEGER:
726 case CX_JSON_TOKEN_NUMBER: { 683 case CX_JSON_TOKEN_NUMBER: {
727 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER; 684 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER;
728 if (NULL == (vbuf = json_create_value(json, type))) { 685 if (NULL == (vbuf = json_create_value(json, type))) {
729 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 686 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
730 } 687 }
731 if (type == CX_JSON_INTEGER) { 688 if (type == CX_JSON_INTEGER) {
732 if (cx_strtoi64(token.content, &vbuf->value.integer, 10)) { 689 if (cx_strtoi64(token.content, &vbuf->integer, 10)) {
733 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); 690 return_rec(CX_JSON_FORMAT_ERROR_NUMBER);
734 } 691 }
735 } else { 692 } else {
736 if (cx_strtod(token.content, &vbuf->value.number)) { 693 if (cx_strtod(token.content, &vbuf->number)) {
737 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); 694 // TODO: at the moment this is unreachable, because the tokenizer is already stricter than cx_strtod()
695 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); // LCOV_EXCL_LINE
738 } 696 }
739 } 697 }
740 return_rec(CX_JSON_NO_ERROR); 698 return_rec(CX_JSON_NO_ERROR);
741 } 699 }
742 case CX_JSON_TOKEN_LITERAL: { 700 case CX_JSON_TOKEN_LITERAL: {
743 if ((vbuf = json_create_value(json, CX_JSON_LITERAL)) == NULL) { 701 if ((vbuf = json_create_value(json, CX_JSON_LITERAL)) == NULL) {
744 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 702 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
745 } 703 }
746 if (0 == cx_strcmp(cx_strcast(token.content), cx_str("true"))) { 704 if (0 == cx_strcmp(token.content, "true")) {
747 vbuf->value.literal = CX_JSON_TRUE; 705 vbuf->literal = CX_JSON_TRUE;
748 } else if (0 == cx_strcmp(cx_strcast(token.content), cx_str("false"))) { 706 } else if (0 == cx_strcmp(token.content, "false")) {
749 vbuf->value.literal = CX_JSON_FALSE; 707 vbuf->literal = CX_JSON_FALSE;
750 } else { 708 } else {
751 vbuf->value.literal = CX_JSON_NULL; 709 vbuf->literal = CX_JSON_NULL;
752 } 710 }
753 return_rec(CX_JSON_NO_ERROR); 711 return_rec(CX_JSON_NO_ERROR);
754 } 712 }
755 default: { 713 default: {
756 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); 714 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
761 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) { 719 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) {
762 json_add_state(json, JP_STATE_VALUE_BEGIN_AR); 720 json_add_state(json, JP_STATE_VALUE_BEGIN_AR);
763 return_rec(CX_JSON_NO_ERROR); 721 return_rec(CX_JSON_NO_ERROR);
764 } else if (token.tokentype == CX_JSON_TOKEN_END_ARRAY) { 722 } else if (token.tokentype == CX_JSON_TOKEN_END_ARRAY) {
765 // discard the array from the value buffer 723 // discard the array from the value buffer
766 json->vbuf_size--; 724 json->vbuf.size--;
767 return_rec(CX_JSON_NO_ERROR); 725 return_rec(CX_JSON_NO_ERROR);
768 } else { 726 } else {
769 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); 727 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
770 } 728 }
771 } else if (state == JP_STATE_OBJ_NAME_OR_CLOSE || state == JP_STATE_OBJ_NAME) { 729 } else if (state == JP_STATE_OBJ_NAME_OR_CLOSE || state == JP_STATE_OBJ_NAME) {
772 if (state == JP_STATE_OBJ_NAME_OR_CLOSE && token.tokentype == CX_JSON_TOKEN_END_OBJECT) { 730 if (state == JP_STATE_OBJ_NAME_OR_CLOSE && token.tokentype == CX_JSON_TOKEN_END_OBJECT) {
773 // discard the obj from the value buffer 731 // discard the obj from the value buffer
774 json->vbuf_size--; 732 json->vbuf.size--;
775 return_rec(CX_JSON_NO_ERROR); 733 return_rec(CX_JSON_NO_ERROR);
776 } else { 734 } else {
777 // expect string 735 // expect string
778 if (token.tokentype != CX_JSON_TOKEN_STRING) { 736 if (token.tokentype != CX_JSON_TOKEN_STRING) {
779 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); 737 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
782 // add new entry 740 // add new entry
783 cxmutstr name = unescape_string(json->allocator, token.content); 741 cxmutstr name = unescape_string(json->allocator, token.content);
784 if (name.ptr == NULL) { 742 if (name.ptr == NULL) {
785 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 743 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
786 } 744 }
787 assert(json->uncompleted_member.name.ptr == NULL); 745 assert(json->uncompleted_member_name.ptr == NULL);
788 json->uncompleted_member.name = name; 746 json->uncompleted_member_name = name;
789 assert(json->vbuf_size > 0); 747 assert(json->vbuf.size > 0);
790 748
791 // next state 749 // next state
792 json_add_state(json, JP_STATE_OBJ_COLON); 750 json_add_state(json, JP_STATE_OBJ_COLON);
793 return_rec(CX_JSON_NO_ERROR); 751 return_rec(CX_JSON_NO_ERROR);
794 } 752 }
805 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) { 763 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) {
806 json_add_state(json, JP_STATE_OBJ_NAME); 764 json_add_state(json, JP_STATE_OBJ_NAME);
807 return_rec(CX_JSON_NO_ERROR); 765 return_rec(CX_JSON_NO_ERROR);
808 } else if (token.tokentype == CX_JSON_TOKEN_END_OBJECT) { 766 } else if (token.tokentype == CX_JSON_TOKEN_END_OBJECT) {
809 // discard the obj from the value buffer 767 // discard the obj from the value buffer
810 json->vbuf_size--; 768 json->vbuf.size--;
811 return_rec(CX_JSON_NO_ERROR); 769 return_rec(CX_JSON_NO_ERROR);
812 } else { 770 } else {
813 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); 771 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
814 } 772 }
815 } else { 773 } else {
816 // should be unreachable 774 // should be unreachable
817 assert(false); 775 assert(false);
818 return_rec(-1); 776 return_rec(-1); // LCOV_EXCL_LINE
819 } 777 }
820 } 778 }
821 779
822 CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value) { 780 CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value) {
823 // check if buffer has been filled 781 // initialize output value
782 *value = &cx_json_value_nothing;
783
784 // check if the buffer has been filled
824 if (json->buffer.space == NULL) { 785 if (json->buffer.space == NULL) {
825 return CX_JSON_NULL_DATA; 786 return CX_JSON_NULL_DATA;
826 } 787 }
827
828 // initialize output value
829 *value = &cx_json_value_nothing;
830 788
831 // parse data 789 // parse data
832 CxJsonStatus result; 790 CxJsonStatus result;
833 do { 791 do {
834 result = json_parse(json); 792 result = json_parse(json);
835 if (result == CX_JSON_NO_ERROR && json->states_size == 1) { 793 if (result == CX_JSON_NO_ERROR && json->states.size == 1) {
836 // final state reached 794 // final state reached
837 assert(json->states[0] == JP_STATE_VALUE_END); 795 assert(json->states.data[0] == JP_STATE_VALUE_END);
838 assert(json->vbuf_size == 0); 796 assert(json->vbuf.size == 0);
839 797
840 // write output value 798 // write output value
841 *value = json->parsed; 799 *value = json->parsed;
842 json->parsed = NULL; 800 json->parsed = NULL;
843 801
844 // re-initialize state machine 802 // re-initialize state machine
845 json->states[0] = JP_STATE_VALUE_BEGIN; 803 json->states.data[0] = JP_STATE_VALUE_BEGIN;
846 804
847 return CX_JSON_NO_ERROR; 805 return CX_JSON_NO_ERROR;
848 } 806 }
849 } while (result == CX_JSON_NO_ERROR); 807 } while (result == CX_JSON_NO_ERROR);
850 808
851 // the parser might think there is no data 809 // the parser might think there is no data
852 // but when we did not reach the final state, 810 // but when we did not reach the final state,
853 // we know that there must be more to come 811 // we know that there must be more to come
854 if (result == CX_JSON_NO_DATA && json->states_size > 1) { 812 if (result == CX_JSON_NO_DATA && json->states.size > 1) {
855 return CX_JSON_INCOMPLETE_DATA; 813 return CX_JSON_INCOMPLETE_DATA;
856 } 814 }
857 815
858 return result; 816 return result;
817 }
818
819 CxJsonStatus cx_json_from_string(const CxAllocator *allocator,
820 cxstring str, CxJsonValue **value) {
821 *value = &cx_json_value_nothing;
822 CxJson parser;
823 cxJsonInit(&parser, allocator);
824 if (cxJsonFill(&parser, str)) {
825 // LCOV_EXCL_START
826 cxJsonDestroy(&parser);
827 return CX_JSON_BUFFER_ALLOC_FAILED;
828 // LCOV_EXCL_STOP
829 }
830 CxJsonStatus status = cxJsonNext(&parser, value);
831 // check if we consume the total string
832 CxJsonValue *chk_value = NULL;
833 CxJsonStatus chk_status = CX_JSON_NO_DATA;
834 if (status == CX_JSON_NO_ERROR) {
835 chk_status = cxJsonNext(&parser, &chk_value);
836 }
837 cxJsonDestroy(&parser);
838 if (chk_status == CX_JSON_NO_DATA) {
839 return status;
840 } else {
841 cxJsonValueFree(*value);
842 // if chk_value is nothing, the free is harmless
843 cxJsonValueFree(chk_value);
844 *value = &cx_json_value_nothing;
845 return CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN;
846 }
847
859 } 848 }
860 849
861 void cxJsonValueFree(CxJsonValue *value) { 850 void cxJsonValueFree(CxJsonValue *value) {
862 if (value == NULL || value->type == CX_JSON_NOTHING) return; 851 if (value == NULL || value->type == CX_JSON_NOTHING) return;
863 switch (value->type) { 852 switch (value->type) {
864 case CX_JSON_OBJECT: { 853 case CX_JSON_OBJECT: {
865 CxJsonObject obj = value->value.object; 854 json_free_object_map(value->object);
866 for (size_t i = 0; i < obj.values_size; i++) {
867 cxJsonValueFree(obj.values[i].value);
868 cx_strfree_a(value->allocator, &obj.values[i].name);
869 }
870 cxFree(value->allocator, obj.values);
871 cxFree(value->allocator, obj.indices);
872 break; 855 break;
873 } 856 }
874 case CX_JSON_ARRAY: { 857 case CX_JSON_ARRAY: {
875 CxJsonArray array = value->value.array; 858 for (size_t i = 0; i < value->array.size; i++) {
876 for (size_t i = 0; i < array.array_size; i++) { 859 cxJsonValueFree(value->array.data[i]);
877 cxJsonValueFree(array.array[i]); 860 }
878 } 861 cx_array_free_a(value->allocator, value->array);
879 cxFree(value->allocator, array.array);
880 break; 862 break;
881 } 863 }
882 case CX_JSON_STRING: { 864 case CX_JSON_STRING: {
883 cxFree(value->allocator, value->value.string.ptr); 865 cxFree(value->allocator, value->string.ptr);
884 break; 866 break;
885 } 867 }
886 default: { 868 default: {
887 break; 869 break;
888 } 870 }
894 if (allocator == NULL) allocator = cxDefaultAllocator; 876 if (allocator == NULL) allocator = cxDefaultAllocator;
895 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 877 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
896 if (v == NULL) return NULL; 878 if (v == NULL) return NULL;
897 v->allocator = allocator; 879 v->allocator = allocator;
898 v->type = CX_JSON_OBJECT; 880 v->type = CX_JSON_OBJECT;
899 cx_array_initialize_a(allocator, v->value.object.values, 16); 881 v->object = json_create_object_map(allocator);
900 if (v->value.object.values == NULL) { // LCOV_EXCL_START 882 if (v->object == NULL) { // LCOV_EXCL_START
901 cxFree(allocator, v); 883 cxFree(allocator, v);
902 return NULL; 884 return NULL;
903 // LCOV_EXCL_STOP 885 // LCOV_EXCL_STOP
904 } 886 }
905 v->value.object.indices = cxCalloc(allocator, 16, sizeof(size_t));
906 if (v->value.object.indices == NULL) { // LCOV_EXCL_START
907 cxFree(allocator, v->value.object.values);
908 cxFree(allocator, v);
909 return NULL;
910 // LCOV_EXCL_STOP
911 }
912 return v; 887 return v;
913 } 888 }
914 889
915 CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator) { 890 CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator, size_t capacity) {
916 if (allocator == NULL) allocator = cxDefaultAllocator; 891 if (allocator == NULL) allocator = cxDefaultAllocator;
917 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 892 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
918 if (v == NULL) return NULL; 893 if (v == NULL) return NULL;
919 v->allocator = allocator; 894 v->allocator = allocator;
920 v->type = CX_JSON_ARRAY; 895 v->type = CX_JSON_ARRAY;
921 cx_array_initialize_a(allocator, v->value.array.array, 16); 896 if (capacity > 0) {
922 if (v->value.array.array == NULL) { cxFree(allocator, v); return NULL; } 897 if (cx_array_init_a(allocator, v->array, capacity)) {
898 // LCOV_EXCL_START
899 cxFree(allocator, v);
900 return NULL;
901 // LCOV_EXCL_STOP
902 }
903 } else {
904 v->array.data = NULL;
905 v->array.size = v->array.capacity = 0;
906 }
923 return v; 907 return v;
924 } 908 }
925 909
926 CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num) { 910 CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num) {
927 if (allocator == NULL) allocator = cxDefaultAllocator; 911 if (allocator == NULL) allocator = cxDefaultAllocator;
928 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 912 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
929 if (v == NULL) return NULL; 913 if (v == NULL) return NULL;
930 v->allocator = allocator; 914 v->allocator = allocator;
931 v->type = CX_JSON_NUMBER; 915 v->type = CX_JSON_NUMBER;
932 v->value.number = num; 916 v->number = num;
933 return v; 917 return v;
934 } 918 }
935 919
936 CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num) { 920 CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num) {
937 if (allocator == NULL) allocator = cxDefaultAllocator; 921 if (allocator == NULL) allocator = cxDefaultAllocator;
938 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 922 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
939 if (v == NULL) return NULL; 923 if (v == NULL) return NULL;
940 v->allocator = allocator; 924 v->allocator = allocator;
941 v->type = CX_JSON_INTEGER; 925 v->type = CX_JSON_INTEGER;
942 v->value.integer = num; 926 v->integer = num;
943 return v; 927 return v;
944 } 928 }
945 929
946 CxJsonValue* cxJsonCreateString(const CxAllocator* allocator, const char* str) { 930 CxJsonValue* cx_json_create_string(const CxAllocator* allocator, cxstring str) {
947 return cxJsonCreateCxString(allocator, cx_str(str));
948 }
949
950 CxJsonValue* cxJsonCreateCxString(const CxAllocator* allocator, cxstring str) {
951 if (allocator == NULL) allocator = cxDefaultAllocator; 931 if (allocator == NULL) allocator = cxDefaultAllocator;
952 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 932 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
953 if (v == NULL) return NULL; 933 if (v == NULL) return NULL;
954 v->allocator = allocator; 934 v->allocator = allocator;
955 v->type = CX_JSON_STRING; 935 v->type = CX_JSON_STRING;
956 cxmutstr s = cx_strdup_a(allocator, str); 936 cxmutstr s = cx_strdup_a(allocator, str);
957 if (s.ptr == NULL) { cxFree(allocator, v); return NULL; } 937 if (s.ptr == NULL) { cxFree(allocator, v); return NULL; }
958 v->value.string = s; 938 v->string = s;
959 return v; 939 return v;
960 } 940 }
961 941
962 CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit) { 942 CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit) {
963 if (allocator == NULL) allocator = cxDefaultAllocator; 943 if (allocator == NULL) allocator = cxDefaultAllocator;
964 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 944 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
965 if (v == NULL) return NULL; 945 if (v == NULL) return NULL;
966 v->allocator = allocator; 946 v->allocator = allocator;
967 v->type = CX_JSON_LITERAL; 947 v->type = CX_JSON_LITERAL;
968 v->value.literal = lit; 948 v->literal = lit;
969 return v; 949 return v;
970 } 950 }
971 951
972 // LCOV_EXCL_START 952 // LCOV_EXCL_START
973 // never called as long as malloc() does not return NULL 953 // never called as long as malloc() does not return NULL
1018 998
1019 int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count) { 999 int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count) {
1020 CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*)); 1000 CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
1021 if (values == NULL) return -1; 1001 if (values == NULL) return -1;
1022 for (size_t i = 0; i < count; i++) { 1002 for (size_t i = 0; i < count; i++) {
1023 values[i] = cxJsonCreateCxString(arr->allocator, str[i]); 1003 values[i] = cxJsonCreateString(arr->allocator, str[i]);
1024 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; } 1004 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
1025 } 1005 }
1026 int ret = cxJsonArrAddValues(arr, values, count); 1006 int ret = cxJsonArrAddValues(arr, values, count);
1027 cxFreeDefault(values); 1007 cxFreeDefault(values);
1028 return ret; 1008 return ret;
1039 cxFreeDefault(values); 1019 cxFreeDefault(values);
1040 return ret; 1020 return ret;
1041 } 1021 }
1042 1022
1043 int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count) { 1023 int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count) {
1044 CxArrayReallocator value_realloc = cx_array_reallocator(arr->allocator, NULL);
1045 assert(arr->type == CX_JSON_ARRAY); 1024 assert(arr->type == CX_JSON_ARRAY);
1046 return cx_array_simple_copy_a(&value_realloc, 1025 return cx_array_add_array_a(arr->allocator, arr->array, val, count);
1047 arr->value.array.array, 1026 }
1048 arr->value.array.array_size, 1027
1049 val, count 1028 int cx_json_obj_put(CxJsonValue* obj, cxstring name, CxJsonValue* child) {
1050 ); 1029 return cxMapPut(obj->object, name, child);
1051 } 1030 }
1052 1031
1053 int cxJsonObjPut(CxJsonValue* obj, cxstring name, CxJsonValue* child) { 1032 CxJsonValue* cx_json_obj_put_obj(CxJsonValue* obj, cxstring name) {
1054 cxmutstr k = cx_strdup_a(obj->allocator, name);
1055 if (k.ptr == NULL) return -1;
1056 CxJsonObjValue kv = {k, child};
1057 if (json_add_objvalue(obj, kv)) {
1058 cx_strfree_a(obj->allocator, &k);
1059 return 1;
1060 } else {
1061 return 0;
1062 }
1063 }
1064
1065 CxJsonValue* cxJsonObjPutObj(CxJsonValue* obj, cxstring name) {
1066 CxJsonValue* v = cxJsonCreateObj(obj->allocator); 1033 CxJsonValue* v = cxJsonCreateObj(obj->allocator);
1067 if (v == NULL) return NULL; 1034 if (v == NULL) return NULL;
1068 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; } 1035 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; }
1069 return v; 1036 return v;
1070 } 1037 }
1071 1038
1072 CxJsonValue* cxJsonObjPutArr(CxJsonValue* obj, cxstring name) { 1039 CxJsonValue* cx_json_obj_put_arr(CxJsonValue* obj, cxstring name, size_t capacity) {
1073 CxJsonValue* v = cxJsonCreateArr(obj->allocator); 1040 CxJsonValue* v = cxJsonCreateArr(obj->allocator, capacity);
1074 if (v == NULL) return NULL; 1041 if (v == NULL) return NULL;
1075 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; } 1042 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; }
1076 return v; 1043 return v;
1077 } 1044 }
1078 1045
1079 CxJsonValue* cxJsonObjPutNumber(CxJsonValue* obj, cxstring name, double num) { 1046 CxJsonValue* cx_json_obj_put_number(CxJsonValue* obj, cxstring name, double num) {
1080 CxJsonValue* v = cxJsonCreateNumber(obj->allocator, num); 1047 CxJsonValue* v = cxJsonCreateNumber(obj->allocator, num);
1081 if (v == NULL) return NULL; 1048 if (v == NULL) return NULL;
1082 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; } 1049 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; }
1083 return v; 1050 return v;
1084 } 1051 }
1085 1052
1086 CxJsonValue* cxJsonObjPutInteger(CxJsonValue* obj, cxstring name, int64_t num) { 1053 CxJsonValue* cx_json_obj_put_integer(CxJsonValue* obj, cxstring name, int64_t num) {
1087 CxJsonValue* v = cxJsonCreateInteger(obj->allocator, num); 1054 CxJsonValue* v = cxJsonCreateInteger(obj->allocator, num);
1088 if (v == NULL) return NULL; 1055 if (v == NULL) return NULL;
1089 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; } 1056 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; }
1090 return v; 1057 return v;
1091 } 1058 }
1092 1059
1093 CxJsonValue* cxJsonObjPutString(CxJsonValue* obj, cxstring name, const char* str) { 1060 CxJsonValue* cx_json_obj_put_string(CxJsonValue* obj, cxstring name, cxstring str) {
1094 CxJsonValue* v = cxJsonCreateString(obj->allocator, str); 1061 CxJsonValue* v = cxJsonCreateString(obj->allocator, str);
1095 if (v == NULL) return NULL; 1062 if (v == NULL) return NULL;
1096 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; } 1063 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; }
1097 return v; 1064 return v;
1098 } 1065 }
1099 1066
1100 CxJsonValue* cxJsonObjPutCxString(CxJsonValue* obj, cxstring name, cxstring str) { 1067 CxJsonValue* cx_json_obj_put_literal(CxJsonValue* obj, cxstring name, CxJsonLiteral lit) {
1101 CxJsonValue* v = cxJsonCreateCxString(obj->allocator, str);
1102 if (v == NULL) return NULL;
1103 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; }
1104 return v;
1105 }
1106
1107 CxJsonValue* cxJsonObjPutLiteral(CxJsonValue* obj, cxstring name, CxJsonLiteral lit) {
1108 CxJsonValue* v = cxJsonCreateLiteral(obj->allocator, lit); 1068 CxJsonValue* v = cxJsonCreateLiteral(obj->allocator, lit);
1109 if (v == NULL) return NULL; 1069 if (v == NULL) return NULL;
1110 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL;} 1070 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL;}
1111 return v; 1071 return v;
1112 } 1072 }
1113 1073
1114 CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index) { 1074 CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index) {
1115 if (index >= value->value.array.array_size) { 1075 if (index >= value->array.size) {
1116 return &cx_json_value_nothing; 1076 return &cx_json_value_nothing;
1117 } 1077 }
1118 return value->value.array.array[index]; 1078 return value->array.data[index];
1119 } 1079 }
1120 1080
1121 CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) { 1081 CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) {
1122 if (index >= value->value.array.array_size) { 1082 if (index >= value->array.size) {
1123 return NULL; 1083 return NULL;
1124 } 1084 }
1125 CxJsonValue *ret = value->value.array.array[index]; 1085 CxJsonValue *ret = value->array.data[index];
1126 // TODO: replace with a low level cx_array_remove() 1086 cx_array_remove(value->array, index);
1127 size_t count = value->value.array.array_size - index - 1;
1128 if (count > 0) {
1129 memmove(value->value.array.array + index, value->value.array.array + index + 1, count * sizeof(CxJsonValue*));
1130 }
1131 value->value.array.array_size--;
1132 return ret; 1087 return ret;
1133 } 1088 }
1134 1089
1135 char *cxJsonAsString(const CxJsonValue *value) { 1090 char *cxJsonAsString(const CxJsonValue *value) {
1136 return value->value.string.ptr; 1091 return value->string.ptr;
1137 } 1092 }
1138 1093
1139 cxstring cxJsonAsCxString(const CxJsonValue *value) { 1094 cxstring cxJsonAsCxString(const CxJsonValue *value) {
1140 return cx_strcast(value->value.string); 1095 return cx_strcast(value->string);
1141 } 1096 }
1142 1097
1143 cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) { 1098 cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) {
1144 return value->value.string; 1099 return value->string;
1145 } 1100 }
1146 1101
1147 double cxJsonAsDouble(const CxJsonValue *value) { 1102 double cxJsonAsDouble(const CxJsonValue *value) {
1148 if (value->type == CX_JSON_INTEGER) { 1103 if (value->type == CX_JSON_INTEGER) {
1149 return (double) value->value.integer; 1104 return (double) value->integer;
1150 } else { 1105 } else {
1151 return value->value.number; 1106 return value->number;
1152 } 1107 }
1153 } 1108 }
1154 1109
1155 int64_t cxJsonAsInteger(const CxJsonValue *value) { 1110 int64_t cxJsonAsInteger(const CxJsonValue *value) {
1156 if (value->type == CX_JSON_INTEGER) { 1111 if (value->type == CX_JSON_INTEGER) {
1157 return value->value.integer; 1112 return value->integer;
1158 } else { 1113 } else {
1159 return (int64_t) value->value.number; 1114 return (int64_t) value->number;
1160 } 1115 }
1161 } 1116 }
1162 1117
1163 CxIterator cxJsonArrIter(const CxJsonValue *value) { 1118 CxIterator cxJsonArrIter(const CxJsonValue *value) {
1164 return cxIteratorPtr( 1119 return cx_array_iterator_ptr(value->array);
1165 value->value.array.array, 1120 }
1166 value->value.array.array_size, 1121
1167 true // arrays need to keep order 1122 CxMapIterator cxJsonObjIter(const CxJsonValue *value) {
1168 ); 1123 return cxMapIterator(value->object);
1169 }
1170
1171 CxIterator cxJsonObjIter(const CxJsonValue *value) {
1172 return cxIterator(
1173 value->value.object.values,
1174 sizeof(CxJsonObjValue),
1175 value->value.object.values_size,
1176 true // TODO: objects do not always need to keep order
1177 );
1178 } 1124 }
1179 1125
1180 CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name) { 1126 CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name) {
1181 size_t index = json_find_objvalue(value, name); 1127 CxJsonValue *v = cxMapGet(value->object, name);
1182 if (index >= value->value.object.values_size) { 1128 if (v == NULL) {
1183 return &cx_json_value_nothing; 1129 return &cx_json_value_nothing;
1184 } else { 1130 } else {
1185 return value->value.object.values[index].value; 1131 return v;
1186 } 1132 }
1187 } 1133 }
1188 1134
1189 CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name) { 1135 CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name) {
1190 size_t index = json_find_objvalue(value, name); 1136 CxJsonValue *v = NULL;
1191 if (index >= value->value.object.values_size) { 1137 cxMapRemoveAndGet(value->object, name, &v);
1192 return NULL; 1138 return v;
1193 } else {
1194 CxJsonObjValue kv = value->value.object.values[index];
1195 cx_strfree_a(value->allocator, &kv.name);
1196 // TODO: replace with cx_array_remove() / cx_array_remove_fast()
1197 value->value.object.values_size--;
1198 memmove(value->value.object.values + index, value->value.object.values + index + 1, (value->value.object.values_size - index) * sizeof(CxJsonObjValue));
1199 return kv.value;
1200 }
1201 } 1139 }
1202 1140
1203 CxJsonWriter cxJsonWriterCompact(void) { 1141 CxJsonWriter cxJsonWriterCompact(void) {
1204 return (CxJsonWriter) { 1142 return (CxJsonWriter) {
1205 false, 1143 false,
1206 true,
1207 6, 1144 6,
1208 false, 1145 false,
1209 4, 1146 4,
1210 false 1147 false
1211 }; 1148 };
1212 } 1149 }
1213 1150
1214 CxJsonWriter cxJsonWriterPretty(bool use_spaces) { 1151 CxJsonWriter cxJsonWriterPretty(bool use_spaces) {
1215 return (CxJsonWriter) { 1152 return (CxJsonWriter) {
1216 true,
1217 true, 1153 true,
1218 6, 1154 6,
1219 use_spaces, 1155 use_spaces,
1220 4, 1156 4,
1221 false 1157 false
1277 } else { 1213 } else {
1278 actual += wfunc(begin_obj, 1, 1, target); 1214 actual += wfunc(begin_obj, 1, 1, target);
1279 expected++; 1215 expected++;
1280 } 1216 }
1281 depth++; 1217 depth++;
1282 size_t elem_count = value->value.object.values_size; 1218 CxMapIterator member_iter = cxJsonObjIter(value);
1283 for (size_t look_idx = 0; look_idx < elem_count; look_idx++) { 1219 cx_foreach(const CxMapEntry *, member, member_iter) {
1284 // get the member either via index array or directly
1285 size_t elem_idx = settings->sort_members
1286 ? look_idx
1287 : value->value.object.indices[look_idx];
1288 CxJsonObjValue *member = &value->value.object.values[elem_idx];
1289 if (settings->sort_members) {
1290 depth++;depth--;
1291 }
1292
1293 // possible indentation 1220 // possible indentation
1294 if (settings->pretty) { 1221 if (settings->pretty) {
1295 if (cx_json_writer_indent(target, wfunc, settings, depth)) { 1222 if (cx_json_writer_indent(target, wfunc, settings, depth)) {
1296 return 1; // LCOV_EXCL_LINE 1223 return 1; // LCOV_EXCL_LINE
1297 } 1224 }
1298 } 1225 }
1299 1226
1300 // the name 1227 // the name
1301 actual += wfunc("\"", 1, 1, target); 1228 actual += wfunc("\"", 1, 1, target);
1302 cxmutstr name = escape_string(member->name, settings->escape_slash); 1229 cxstring key = cx_strn(member->key->data, member->key->len);
1230 cxmutstr name = escape_string(key, settings->escape_slash);
1303 actual += wfunc(name.ptr, 1, name.length, target); 1231 actual += wfunc(name.ptr, 1, name.length, target);
1304 if (name.ptr != member->name.ptr) {
1305 cx_strfree(&name);
1306 }
1307 actual += wfunc("\"", 1, 1, target); 1232 actual += wfunc("\"", 1, 1, target);
1308 const char *obj_name_sep = ": "; 1233 const char *obj_name_sep = ": ";
1309 if (settings->pretty) { 1234 if (settings->pretty) {
1310 actual += wfunc(obj_name_sep, 1, 2, target); 1235 actual += wfunc(obj_name_sep, 1, 2, target);
1311 expected += 4 + member->name.length; 1236 expected += 4 + name.length;
1312 } else { 1237 } else {
1313 actual += wfunc(obj_name_sep, 1, 1, target); 1238 actual += wfunc(obj_name_sep, 1, 1, target);
1314 expected += 3 + member->name.length; 1239 expected += 3 + name.length;
1240 }
1241 if (name.ptr != key.ptr) {
1242 cx_strfree(&name);
1315 } 1243 }
1316 1244
1317 // the value 1245 // the value
1318 if (cx_json_write_rec(target, member->value, wfunc, settings, depth)) return 1; 1246 if (cx_json_write_rec(target, member->value, wfunc, settings, depth)) return 1;
1319 1247
1320 // end of object-value 1248 // end of object-value
1321 if (look_idx < elem_count - 1) { 1249 if (member_iter.index < member_iter.elem_count - 1) {
1322 const char *obj_value_sep = ",\n"; 1250 const char *obj_value_sep = ",\n";
1323 if (settings->pretty) { 1251 if (settings->pretty) {
1324 actual += wfunc(obj_value_sep, 1, 2, target); 1252 actual += wfunc(obj_value_sep, 1, 2, target);
1325 expected += 2; 1253 expected += 2;
1326 } else { 1254 } else {
1348 CxIterator iter = cxJsonArrIter(value); 1276 CxIterator iter = cxJsonArrIter(value);
1349 cx_foreach(CxJsonValue*, element, iter) { 1277 cx_foreach(CxJsonValue*, element, iter) {
1350 if (cx_json_write_rec( 1278 if (cx_json_write_rec(
1351 target, element, 1279 target, element,
1352 wfunc, settings, depth) 1280 wfunc, settings, depth)
1353 ) return 1; 1281 ) {
1282 return 1; // LCOV_EXCL_LINE
1283 }
1354 1284
1355 if (iter.index < iter.elem_count - 1) { 1285 if (iter.index < iter.elem_count - 1) {
1356 const char *arr_value_sep = ", "; 1286 const char *arr_value_sep = ", ";
1357 if (settings->pretty) { 1287 if (settings->pretty) {
1358 actual += wfunc(arr_value_sep, 1, 2, target); 1288 actual += wfunc(arr_value_sep, 1, 2, target);
1367 expected++; 1297 expected++;
1368 break; 1298 break;
1369 } 1299 }
1370 case CX_JSON_STRING: { 1300 case CX_JSON_STRING: {
1371 actual += wfunc("\"", 1, 1, target); 1301 actual += wfunc("\"", 1, 1, target);
1372 cxmutstr str = escape_string(value->value.string, settings->escape_slash); 1302 cxmutstr str = escape_string(cx_strcast(value->string),
1303 settings->escape_slash);
1373 actual += wfunc(str.ptr, 1, str.length, target); 1304 actual += wfunc(str.ptr, 1, str.length, target);
1374 if (str.ptr != value->value.string.ptr) { 1305 actual += wfunc("\"", 1, 1, target);
1306 expected += 2 + str.length;
1307 if (str.ptr != value->string.ptr) {
1375 cx_strfree(&str); 1308 cx_strfree(&str);
1376 } 1309 }
1377 actual += wfunc("\"", 1, 1, target);
1378 expected += 2 + value->value.string.length;
1379 break; 1310 break;
1380 } 1311 }
1381 case CX_JSON_NUMBER: { 1312 case CX_JSON_NUMBER: {
1382 int precision = settings->frac_max_digits; 1313 int precision = settings->frac_max_digits;
1383 // because of the way how %g is defined, we need to 1314 // because of the way how %g is defined, we need to
1384 // double the precision and truncate ourselves 1315 // double the precision and truncate ourselves
1385 precision = 1 + (precision > 15 ? 30 : 2 * precision); 1316 precision = 1 + (precision > 15 ? 30 : 2 * precision);
1386 snprintf(numbuf, 40, "%.*g", precision, value->value.number); 1317 snprintf(numbuf, 40, "%.*g", precision, value->number);
1387 char *dot, *exp; 1318 char *dot, *exp;
1388 unsigned char max_digits; 1319 unsigned char max_digits;
1389 // find the decimal separator and hope that it's one of . or , 1320 // find the decimal separator and hope that it's one of . or ,
1390 dot = strchr(numbuf, '.'); 1321 dot = strchr(numbuf, '.');
1391 if (dot == NULL) { 1322 if (dot == NULL) {
1445 expected += len; 1376 expected += len;
1446 } 1377 }
1447 break; 1378 break;
1448 } 1379 }
1449 case CX_JSON_INTEGER: { 1380 case CX_JSON_INTEGER: {
1450 snprintf(numbuf, 32, "%" PRIi64, value->value.integer); 1381 snprintf(numbuf, 32, "%" PRIi64, value->integer);
1451 size_t len = strlen(numbuf); 1382 size_t len = strlen(numbuf);
1452 actual += wfunc(numbuf, 1, len, target); 1383 actual += wfunc(numbuf, 1, len, target);
1453 expected += len; 1384 expected += len;
1454 break; 1385 break;
1455 } 1386 }
1456 case CX_JSON_LITERAL: { 1387 case CX_JSON_LITERAL: {
1457 if (value->value.literal == CX_JSON_TRUE) { 1388 if (value->literal == CX_JSON_TRUE) {
1458 actual += wfunc("true", 1, 4, target); 1389 actual += wfunc("true", 1, 4, target);
1459 expected += 4; 1390 expected += 4;
1460 } else if (value->value.literal == CX_JSON_FALSE) { 1391 } else if (value->literal == CX_JSON_FALSE) {
1461 actual += wfunc("false", 1, 5, target); 1392 actual += wfunc("false", 1, 5, target);
1462 expected += 5; 1393 expected += 5;
1463 } else { 1394 } else {
1464 actual += wfunc("null", 1, 4, target); 1395 actual += wfunc("null", 1, 4, target);
1465 expected += 4; 1396 expected += 4;
1493 if (settings == NULL) { 1424 if (settings == NULL) {
1494 settings = &writer_default; 1425 settings = &writer_default;
1495 } 1426 }
1496 return cx_json_write_rec(target, value, wfunc, settings, 0); 1427 return cx_json_write_rec(target, value, wfunc, settings, 0);
1497 } 1428 }
1429
1430 static cxmutstr cx_json_to_string(CxJsonValue *value, const CxAllocator *allocator, CxJsonWriter *writer) {
1431 if (allocator == NULL) allocator = cxDefaultAllocator;
1432 CxBuffer buffer;
1433 if (cxBufferInit(&buffer, allocator, NULL, 128,
1434 CX_BUFFER_AUTO_EXTEND | CX_BUFFER_DO_NOT_FREE)) {
1435 return (cxmutstr){NULL, 0};
1436 }
1437 if (cx_json_write_rec(&buffer, value, cxBufferWriteFunc, writer, 0)
1438 || cxBufferTerminate(&buffer)) {
1439 // LCOV_EXCL_START
1440 buffer.flags &= ~CX_BUFFER_DO_NOT_FREE;
1441 cxBufferDestroy(&buffer);
1442 return (cxmutstr){NULL, 0};
1443 // LCOV_EXCL_STOP
1444 } else {
1445 cxmutstr str = cx_mutstrn(buffer.space, buffer.size);
1446 cxBufferDestroy(&buffer);
1447 return str;
1448 }
1449
1450 }
1451
1452 cxmutstr cxJsonToString(const CxAllocator *allocator, CxJsonValue *value) {
1453 CxJsonWriter writer = cxJsonWriterCompact();
1454 return cx_json_to_string(value, allocator, &writer);
1455 }
1456
1457 cxmutstr cxJsonToPrettyString(const CxAllocator *allocator, CxJsonValue *value) {
1458 CxJsonWriter writer = cxJsonWriterPretty(true);
1459 return cx_json_to_string(value, allocator, &writer);
1460 }
1461
1462 int cxJsonCompare(const CxJsonValue *json, const CxJsonValue *other) {
1463 if (json == other) return 0;
1464 if (json == NULL || other == NULL) return -1;
1465 if (json->type != other->type) {
1466 if (!cxJsonIsNumber(json)) return -1;
1467 if (!cxJsonIsNumber(other)) return -1;
1468 }
1469 switch (json->type) {
1470 case CX_JSON_NOTHING:
1471 return 0;
1472 case CX_JSON_OBJECT:
1473 return cxMapCompare(json->object, other->object);
1474 case CX_JSON_ARRAY:
1475 if (json->array.size != other->array.size) return -1;
1476 for (size_t i = 0; i < json->array.size; i++) {
1477 const int d = cxJsonCompare(json->array.data[i], other->array.data[i]);
1478 if (d != 0) return d;
1479 }
1480 return 0;
1481 case CX_JSON_STRING:
1482 return cx_strcmp(json->string, other->string);
1483 case CX_JSON_INTEGER:
1484 if (other->type == CX_JSON_INTEGER) {
1485 return cx_vcmp_int64(json->integer, other->integer);
1486 } else {
1487 return cx_vcmp_double(cxJsonAsDouble(json), other->number);
1488 }
1489 case CX_JSON_NUMBER:
1490 return cx_vcmp_double(json->number, cxJsonAsDouble(other));
1491 case CX_JSON_LITERAL:
1492 return json->literal == other->literal ? 0 : -1;
1493 default:
1494 // LCOV_EXCL_START
1495 // unreachable
1496 assert(false);
1497 return -1;
1498 // LCOV_EXCL_STOP
1499 }
1500 }
1501
1502 CxJsonValue* cxJsonClone(const CxJsonValue* value, const CxAllocator* allocator) {
1503 return cx_json_clone_func(NULL, value, allocator, NULL);
1504 }
1505
1506 CxJsonValue* cx_json_clone_func(CxJsonValue* target, const CxJsonValue* source,
1507 const CxAllocator* allocator, cx_attr_unused void *data) {
1508 if (source == NULL || source->type == CX_JSON_NOTHING) {
1509 return &cx_json_value_nothing;
1510 }
1511 if (allocator == NULL) allocator = cxDefaultAllocator;
1512
1513 #define return_value(v) { \
1514 CxJsonValue *ret = v; \
1515 if (target == NULL) { \
1516 return ret; \
1517 } else { \
1518 *target = *ret; \
1519 cxFree(allocator, ret); \
1520 return target; \
1521 } \
1522 }
1523
1524 switch (source->type) {
1525 case CX_JSON_OBJECT: {
1526 CxJsonValue *obj = cxJsonCreateObj(allocator);
1527 if (obj == NULL) return NULL; // LCOV_EXCL_LINE
1528 if (cxMapClone(obj->object, source->object, cxJsonCloneFunc, allocator, NULL)) {
1529 // LCOV_EXCL_START
1530 cxJsonValueFree(obj);
1531 return NULL;
1532 // LCOV_EXCL_STOP
1533 }
1534 return_value(obj);
1535 }
1536 case CX_JSON_ARRAY: {
1537 const size_t elem_count = source->array.size;
1538 CxJsonValue *arr = cxJsonCreateArr(allocator, elem_count);
1539 if (arr == NULL) return NULL; // LCOV_EXCL_LINE
1540 arr->array.size = elem_count;
1541 for (size_t i = 0 ; i < elem_count ; i++) {
1542 CxJsonValue *e = cx_json_clone_func(NULL, source->array.data[i], allocator, NULL);
1543 if (e == NULL) {
1544 // LCOV_EXCL_START
1545 cxJsonValueFree(arr);
1546 return NULL;
1547 // LCOV_EXCL_STOP
1548 }
1549 arr->array.data[i] = e;
1550 }
1551 return_value(arr);
1552 }
1553 case CX_JSON_STRING:
1554 return_value(cxJsonCreateString(allocator, source->string));
1555 case CX_JSON_INTEGER:
1556 return_value(cxJsonCreateInteger(allocator, source->integer));
1557 case CX_JSON_NUMBER:
1558 return_value(cxJsonCreateNumber(allocator, source->number));
1559 case CX_JSON_LITERAL:
1560 return_value(cxJsonCreateLiteral(allocator, source->literal));
1561 default:
1562 // LCOV_EXCL_START
1563 // unreachable
1564 assert(false);
1565 return NULL;
1566 // LCOV_EXCL_STOP
1567 }
1568 #undef return_value
1569 }

mercurial