ucx/json.c

changeset 30
d33eaaec15da
parent 23
b26390e77237
equal deleted inserted replaced
29:b8c826c720f3 30:d33eaaec15da
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; // LCOV_EXCL_LINE
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) {
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) {
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;
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 // TODO: we might want to add a comparator that is sorting the elements by their key
457 CxMap *map = cxKvListCreateAsMap(allocator, NULL, CX_STORE_POINTERS);
458 if (map == NULL) return NULL; // LCOV_EXCL_LINE
459 cxDefineDestructor(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 cx_array_initialize_a(json->allocator, v->array.data, 16);
538 if (v->value.array.array == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE 476 if (v->array.data == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE
539 } else if (type == CX_JSON_OBJECT) { 477 } else if (type == CX_JSON_OBJECT) {
540 cx_array_initialize_a(json->allocator, v->value.object.values, 16); 478 v->object = json_create_object_map(json->allocator);
541 v->value.object.indices = cxCalloc(json->allocator, 16, sizeof(size_t)); 479 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 } 480 }
546 481
547 // add the new value to a possible parent 482 // add the new value to a possible parent
548 if (json->vbuf_size > 0) { 483 if (json->vbuf_size > 0) {
549 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1]; 484 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1];
550 assert(parent != NULL); 485 assert(parent != NULL);
551 if (parent->type == CX_JSON_ARRAY) { 486 if (parent->type == CX_JSON_ARRAY) {
552 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL); 487 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL);
553 if (cx_array_simple_add_a(&value_realloc, parent->value.array.array, v)) { 488 if (cx_array_simple_add_a(&value_realloc, parent->array.data, 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
622 if (json->vbuf != json->vbuf_internal) { 557 if (json->vbuf != json->vbuf_internal) {
623 cxFreeDefault(json->vbuf); 558 cxFreeDefault(json->vbuf);
624 } 559 }
625 cxJsonValueFree(json->parsed); 560 cxJsonValueFree(json->parsed);
626 json->parsed = NULL; 561 json->parsed = NULL;
627 if (json->uncompleted_member.name.ptr != NULL) { 562 token_destroy(&json->uncompleted);
628 cx_strfree_a(json->allocator, &json->uncompleted_member.name); 563 cx_strfree_a(json->allocator, &json->uncompleted_member_name);
629 json->uncompleted_member = (CxJsonObjValue){{NULL, 0}, NULL};
630 }
631 } 564 }
632 565
633 void cxJsonReset(CxJson *json) { 566 void cxJsonReset(CxJson *json) {
634 const CxAllocator *allocator = json->allocator; 567 const CxAllocator *allocator = json->allocator;
635 cxJsonDestroy(json); 568 cxJsonDestroy(json);
718 } 651 }
719 cxmutstr str = unescape_string(json->allocator, token.content); 652 cxmutstr str = unescape_string(json->allocator, token.content);
720 if (str.ptr == NULL) { 653 if (str.ptr == NULL) {
721 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 654 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
722 } 655 }
723 vbuf->value.string = str; 656 vbuf->string = str;
724 return_rec(CX_JSON_NO_ERROR); 657 return_rec(CX_JSON_NO_ERROR);
725 } 658 }
726 case CX_JSON_TOKEN_INTEGER: 659 case CX_JSON_TOKEN_INTEGER:
727 case CX_JSON_TOKEN_NUMBER: { 660 case CX_JSON_TOKEN_NUMBER: {
728 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER; 661 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER;
729 if (NULL == (vbuf = json_create_value(json, type))) { 662 if (NULL == (vbuf = json_create_value(json, type))) {
730 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 663 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
731 } 664 }
732 if (type == CX_JSON_INTEGER) { 665 if (type == CX_JSON_INTEGER) {
733 if (cx_strtoi64(token.content, &vbuf->value.integer, 10)) { 666 if (cx_strtoi64(token.content, &vbuf->integer, 10)) {
734 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); 667 return_rec(CX_JSON_FORMAT_ERROR_NUMBER);
735 } 668 }
736 } else { 669 } else {
737 if (cx_strtod(token.content, &vbuf->value.number)) { 670 if (cx_strtod(token.content, &vbuf->number)) {
738 // TODO: at the moment this is unreachable, because the tokenizer is already stricter than cx_strtod() 671 // TODO: at the moment this is unreachable, because the tokenizer is already stricter than cx_strtod()
739 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); // LCOV_EXCL_LINE 672 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); // LCOV_EXCL_LINE
740 } 673 }
741 } 674 }
742 return_rec(CX_JSON_NO_ERROR); 675 return_rec(CX_JSON_NO_ERROR);
744 case CX_JSON_TOKEN_LITERAL: { 677 case CX_JSON_TOKEN_LITERAL: {
745 if ((vbuf = json_create_value(json, CX_JSON_LITERAL)) == NULL) { 678 if ((vbuf = json_create_value(json, CX_JSON_LITERAL)) == NULL) {
746 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 679 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
747 } 680 }
748 if (0 == cx_strcmp(cx_strcast(token.content), cx_str("true"))) { 681 if (0 == cx_strcmp(cx_strcast(token.content), cx_str("true"))) {
749 vbuf->value.literal = CX_JSON_TRUE; 682 vbuf->literal = CX_JSON_TRUE;
750 } else if (0 == cx_strcmp(cx_strcast(token.content), cx_str("false"))) { 683 } else if (0 == cx_strcmp(cx_strcast(token.content), cx_str("false"))) {
751 vbuf->value.literal = CX_JSON_FALSE; 684 vbuf->literal = CX_JSON_FALSE;
752 } else { 685 } else {
753 vbuf->value.literal = CX_JSON_NULL; 686 vbuf->literal = CX_JSON_NULL;
754 } 687 }
755 return_rec(CX_JSON_NO_ERROR); 688 return_rec(CX_JSON_NO_ERROR);
756 } 689 }
757 default: { 690 default: {
758 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); 691 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
784 // add new entry 717 // add new entry
785 cxmutstr name = unescape_string(json->allocator, token.content); 718 cxmutstr name = unescape_string(json->allocator, token.content);
786 if (name.ptr == NULL) { 719 if (name.ptr == NULL) {
787 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 720 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
788 } 721 }
789 assert(json->uncompleted_member.name.ptr == NULL); 722 assert(json->uncompleted_member_name.ptr == NULL);
790 json->uncompleted_member.name = name; 723 json->uncompleted_member_name = name;
791 assert(json->vbuf_size > 0); 724 assert(json->vbuf_size > 0);
792 725
793 // next state 726 // next state
794 json_add_state(json, JP_STATE_OBJ_COLON); 727 json_add_state(json, JP_STATE_OBJ_COLON);
795 return_rec(CX_JSON_NO_ERROR); 728 return_rec(CX_JSON_NO_ERROR);
858 } 791 }
859 792
860 return result; 793 return result;
861 } 794 }
862 795
796 CxJsonStatus cx_json_from_string(const CxAllocator *allocator,
797 cxstring str, CxJsonValue **value) {
798 *value = &cx_json_value_nothing;
799 CxJson parser;
800 cxJsonInit(&parser, allocator);
801 if (cxJsonFill(&parser, str)) {
802 // LCOV_EXCL_START
803 cxJsonDestroy(&parser);
804 return CX_JSON_BUFFER_ALLOC_FAILED;
805 // LCOV_EXCL_STOP
806 }
807 CxJsonStatus status = cxJsonNext(&parser, value);
808 // check if we consume the total string
809 CxJsonValue *chk_value = NULL;
810 CxJsonStatus chk_status = CX_JSON_NO_DATA;
811 if (status == CX_JSON_NO_ERROR) {
812 chk_status = cxJsonNext(&parser, &chk_value);
813 }
814 cxJsonDestroy(&parser);
815 if (chk_status == CX_JSON_NO_DATA) {
816 return status;
817 } else {
818 cxJsonValueFree(*value);
819 // if chk_value is nothing, the free is harmless
820 cxJsonValueFree(chk_value);
821 *value = &cx_json_value_nothing;
822 return CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN;
823 }
824
825 }
826
863 void cxJsonValueFree(CxJsonValue *value) { 827 void cxJsonValueFree(CxJsonValue *value) {
864 if (value == NULL || value->type == CX_JSON_NOTHING) return; 828 if (value == NULL || value->type == CX_JSON_NOTHING) return;
865 switch (value->type) { 829 switch (value->type) {
866 case CX_JSON_OBJECT: { 830 case CX_JSON_OBJECT: {
867 CxJsonObject obj = value->value.object; 831 json_free_object_map(value->object);
868 for (size_t i = 0; i < obj.values_size; i++) {
869 cxJsonValueFree(obj.values[i].value);
870 cx_strfree_a(value->allocator, &obj.values[i].name);
871 }
872 cxFree(value->allocator, obj.values);
873 cxFree(value->allocator, obj.indices);
874 break; 832 break;
875 } 833 }
876 case CX_JSON_ARRAY: { 834 case CX_JSON_ARRAY: {
877 CxJsonArray array = value->value.array; 835 CxJsonArray array = value->array;
878 for (size_t i = 0; i < array.array_size; i++) { 836 for (size_t i = 0; i < array.data_size; i++) {
879 cxJsonValueFree(array.array[i]); 837 cxJsonValueFree(array.data[i]);
880 } 838 }
881 cxFree(value->allocator, array.array); 839 cxFree(value->allocator, array.data);
882 break; 840 break;
883 } 841 }
884 case CX_JSON_STRING: { 842 case CX_JSON_STRING: {
885 cxFree(value->allocator, value->value.string.ptr); 843 cxFree(value->allocator, value->string.ptr);
886 break; 844 break;
887 } 845 }
888 default: { 846 default: {
889 break; 847 break;
890 } 848 }
896 if (allocator == NULL) allocator = cxDefaultAllocator; 854 if (allocator == NULL) allocator = cxDefaultAllocator;
897 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 855 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
898 if (v == NULL) return NULL; 856 if (v == NULL) return NULL;
899 v->allocator = allocator; 857 v->allocator = allocator;
900 v->type = CX_JSON_OBJECT; 858 v->type = CX_JSON_OBJECT;
901 cx_array_initialize_a(allocator, v->value.object.values, 16); 859 v->object = json_create_object_map(allocator);
902 if (v->value.object.values == NULL) { // LCOV_EXCL_START 860 if (v->object == NULL) { // LCOV_EXCL_START
903 cxFree(allocator, v);
904 return NULL;
905 // LCOV_EXCL_STOP
906 }
907 v->value.object.indices = cxCalloc(allocator, 16, sizeof(size_t));
908 if (v->value.object.indices == NULL) { // LCOV_EXCL_START
909 cxFree(allocator, v->value.object.values);
910 cxFree(allocator, v); 861 cxFree(allocator, v);
911 return NULL; 862 return NULL;
912 // LCOV_EXCL_STOP 863 // LCOV_EXCL_STOP
913 } 864 }
914 return v; 865 return v;
918 if (allocator == NULL) allocator = cxDefaultAllocator; 869 if (allocator == NULL) allocator = cxDefaultAllocator;
919 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 870 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
920 if (v == NULL) return NULL; 871 if (v == NULL) return NULL;
921 v->allocator = allocator; 872 v->allocator = allocator;
922 v->type = CX_JSON_ARRAY; 873 v->type = CX_JSON_ARRAY;
923 cx_array_initialize_a(allocator, v->value.array.array, 16); 874 cx_array_initialize_a(allocator, v->array.data, 16);
924 if (v->value.array.array == NULL) { cxFree(allocator, v); return NULL; } 875 if (v->array.data == NULL) { cxFree(allocator, v); return NULL; }
925 return v; 876 return v;
926 } 877 }
927 878
928 CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num) { 879 CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num) {
929 if (allocator == NULL) allocator = cxDefaultAllocator; 880 if (allocator == NULL) allocator = cxDefaultAllocator;
930 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 881 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
931 if (v == NULL) return NULL; 882 if (v == NULL) return NULL;
932 v->allocator = allocator; 883 v->allocator = allocator;
933 v->type = CX_JSON_NUMBER; 884 v->type = CX_JSON_NUMBER;
934 v->value.number = num; 885 v->number = num;
935 return v; 886 return v;
936 } 887 }
937 888
938 CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num) { 889 CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num) {
939 if (allocator == NULL) allocator = cxDefaultAllocator; 890 if (allocator == NULL) allocator = cxDefaultAllocator;
940 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 891 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
941 if (v == NULL) return NULL; 892 if (v == NULL) return NULL;
942 v->allocator = allocator; 893 v->allocator = allocator;
943 v->type = CX_JSON_INTEGER; 894 v->type = CX_JSON_INTEGER;
944 v->value.integer = num; 895 v->integer = num;
945 return v; 896 return v;
946 } 897 }
947 898
948 CxJsonValue* cx_json_create_string(const CxAllocator* allocator, cxstring str) { 899 CxJsonValue* cx_json_create_string(const CxAllocator* allocator, cxstring str) {
949 if (allocator == NULL) allocator = cxDefaultAllocator; 900 if (allocator == NULL) allocator = cxDefaultAllocator;
951 if (v == NULL) return NULL; 902 if (v == NULL) return NULL;
952 v->allocator = allocator; 903 v->allocator = allocator;
953 v->type = CX_JSON_STRING; 904 v->type = CX_JSON_STRING;
954 cxmutstr s = cx_strdup_a(allocator, str); 905 cxmutstr s = cx_strdup_a(allocator, str);
955 if (s.ptr == NULL) { cxFree(allocator, v); return NULL; } 906 if (s.ptr == NULL) { cxFree(allocator, v); return NULL; }
956 v->value.string = s; 907 v->string = s;
957 return v; 908 return v;
958 } 909 }
959 910
960 CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit) { 911 CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit) {
961 if (allocator == NULL) allocator = cxDefaultAllocator; 912 if (allocator == NULL) allocator = cxDefaultAllocator;
962 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 913 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
963 if (v == NULL) return NULL; 914 if (v == NULL) return NULL;
964 v->allocator = allocator; 915 v->allocator = allocator;
965 v->type = CX_JSON_LITERAL; 916 v->type = CX_JSON_LITERAL;
966 v->value.literal = lit; 917 v->literal = lit;
967 return v; 918 return v;
968 } 919 }
969 920
970 // LCOV_EXCL_START 921 // LCOV_EXCL_START
971 // never called as long as malloc() does not return NULL 922 // never called as long as malloc() does not return NULL
1040 991
1041 int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count) { 992 int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count) {
1042 CxArrayReallocator value_realloc = cx_array_reallocator(arr->allocator, NULL); 993 CxArrayReallocator value_realloc = cx_array_reallocator(arr->allocator, NULL);
1043 assert(arr->type == CX_JSON_ARRAY); 994 assert(arr->type == CX_JSON_ARRAY);
1044 return cx_array_simple_copy_a(&value_realloc, 995 return cx_array_simple_copy_a(&value_realloc,
1045 arr->value.array.array, 996 arr->array.data,
1046 arr->value.array.array_size, 997 arr->array.data_size,
1047 val, count 998 val, count
1048 ); 999 );
1049 } 1000 }
1050 1001
1051 int cx_json_obj_put(CxJsonValue* obj, cxstring name, CxJsonValue* child) { 1002 int cx_json_obj_put(CxJsonValue* obj, cxstring name, CxJsonValue* child) {
1052 cxmutstr k = cx_strdup_a(obj->allocator, name); 1003 return cxMapPut(obj->object, name, child);
1053 if (k.ptr == NULL) return -1;
1054 CxJsonObjValue kv = {k, child};
1055 if (json_add_objvalue(obj, kv)) {
1056 // LCOV_EXCL_START
1057 cx_strfree_a(obj->allocator, &k);
1058 return 1;
1059 // LCOV_EXCL_STOP
1060 } else {
1061 return 0;
1062 }
1063 } 1004 }
1064 1005
1065 CxJsonValue* cx_json_obj_put_obj(CxJsonValue* obj, cxstring name) { 1006 CxJsonValue* cx_json_obj_put_obj(CxJsonValue* obj, cxstring name) {
1066 CxJsonValue* v = cxJsonCreateObj(obj->allocator); 1007 CxJsonValue* v = cxJsonCreateObj(obj->allocator);
1067 if (v == NULL) return NULL; 1008 if (v == NULL) return NULL;
1103 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL;} 1044 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL;}
1104 return v; 1045 return v;
1105 } 1046 }
1106 1047
1107 CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index) { 1048 CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index) {
1108 if (index >= value->value.array.array_size) { 1049 if (index >= value->array.data_size) {
1109 return &cx_json_value_nothing; 1050 return &cx_json_value_nothing;
1110 } 1051 }
1111 return value->value.array.array[index]; 1052 return value->array.data[index];
1112 } 1053 }
1113 1054
1114 CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) { 1055 CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) {
1115 if (index >= value->value.array.array_size) { 1056 if (index >= value->array.data_size) {
1116 return NULL; 1057 return NULL;
1117 } 1058 }
1118 CxJsonValue *ret = value->value.array.array[index]; 1059 CxJsonValue *ret = value->array.data[index];
1119 // TODO: replace with a low level cx_array_remove() 1060 // TODO: replace with a low level cx_array_remove()
1120 size_t count = value->value.array.array_size - index - 1; 1061 size_t count = value->array.data_size - index - 1;
1121 if (count > 0) { 1062 if (count > 0) {
1122 memmove(value->value.array.array + index, value->value.array.array + index + 1, count * sizeof(CxJsonValue*)); 1063 memmove(value->array.data + index, value->array.data + index + 1, count * sizeof(CxJsonValue*));
1123 } 1064 }
1124 value->value.array.array_size--; 1065 value->array.data_size--;
1125 return ret; 1066 return ret;
1126 } 1067 }
1127 1068
1128 char *cxJsonAsString(const CxJsonValue *value) { 1069 char *cxJsonAsString(const CxJsonValue *value) {
1129 return value->value.string.ptr; 1070 return value->string.ptr;
1130 } 1071 }
1131 1072
1132 cxstring cxJsonAsCxString(const CxJsonValue *value) { 1073 cxstring cxJsonAsCxString(const CxJsonValue *value) {
1133 return cx_strcast(value->value.string); 1074 return cx_strcast(value->string);
1134 } 1075 }
1135 1076
1136 cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) { 1077 cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) {
1137 return value->value.string; 1078 return value->string;
1138 } 1079 }
1139 1080
1140 double cxJsonAsDouble(const CxJsonValue *value) { 1081 double cxJsonAsDouble(const CxJsonValue *value) {
1141 if (value->type == CX_JSON_INTEGER) { 1082 if (value->type == CX_JSON_INTEGER) {
1142 return (double) value->value.integer; 1083 return (double) value->integer;
1143 } else { 1084 } else {
1144 return value->value.number; 1085 return value->number;
1145 } 1086 }
1146 } 1087 }
1147 1088
1148 int64_t cxJsonAsInteger(const CxJsonValue *value) { 1089 int64_t cxJsonAsInteger(const CxJsonValue *value) {
1149 if (value->type == CX_JSON_INTEGER) { 1090 if (value->type == CX_JSON_INTEGER) {
1150 return value->value.integer; 1091 return value->integer;
1151 } else { 1092 } else {
1152 return (int64_t) value->value.number; 1093 return (int64_t) value->number;
1153 } 1094 }
1154 } 1095 }
1155 1096
1156 CxIterator cxJsonArrIter(const CxJsonValue *value) { 1097 CxIterator cxJsonArrIter(const CxJsonValue *value) {
1157 return cxIteratorPtr( 1098 return cxIteratorPtr(
1158 value->value.array.array, 1099 value->array.data,
1159 value->value.array.array_size, 1100 value->array.data_size,
1160 true // arrays need to keep order 1101 true // arrays need to keep order
1161 ); 1102 );
1162 } 1103 }
1163 1104
1164 CxIterator cxJsonObjIter(const CxJsonValue *value) { 1105 CxMapIterator cxJsonObjIter(const CxJsonValue *value) {
1165 return cxIterator( 1106 return cxMapIterator(value->object);
1166 value->value.object.values,
1167 sizeof(CxJsonObjValue),
1168 value->value.object.values_size,
1169 true // TODO: objects do not always need to keep order
1170 );
1171 } 1107 }
1172 1108
1173 CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name) { 1109 CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name) {
1174 size_t index = json_find_objvalue(value, name); 1110 CxJsonValue *v = cxMapGet(value->object, name);
1175 if (index >= value->value.object.values_size) { 1111 if (v == NULL) {
1176 return &cx_json_value_nothing; 1112 return &cx_json_value_nothing;
1177 } else { 1113 } else {
1178 return value->value.object.values[index].value; 1114 return v;
1179 } 1115 }
1180 } 1116 }
1181 1117
1182 CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name) { 1118 CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name) {
1183 size_t index = json_find_objvalue(value, name); 1119 CxJsonValue *v = NULL;
1184 if (index >= value->value.object.values_size) { 1120 cxMapRemoveAndGet(value->object, name, &v);
1185 return NULL; 1121 return v;
1186 } else {
1187 CxJsonObjValue kv = value->value.object.values[index];
1188 cx_strfree_a(value->allocator, &kv.name);
1189 // TODO: replace with cx_array_remove() / cx_array_remove_fast()
1190 value->value.object.values_size--;
1191 memmove(value->value.object.values + index, value->value.object.values + index + 1, (value->value.object.values_size - index) * sizeof(CxJsonObjValue));
1192 return kv.value;
1193 }
1194 } 1122 }
1195 1123
1196 CxJsonWriter cxJsonWriterCompact(void) { 1124 CxJsonWriter cxJsonWriterCompact(void) {
1197 return (CxJsonWriter) { 1125 return (CxJsonWriter) {
1198 false, 1126 false,
1199 true,
1200 6, 1127 6,
1201 false, 1128 false,
1202 4, 1129 4,
1203 false 1130 false
1204 }; 1131 };
1205 } 1132 }
1206 1133
1207 CxJsonWriter cxJsonWriterPretty(bool use_spaces) { 1134 CxJsonWriter cxJsonWriterPretty(bool use_spaces) {
1208 return (CxJsonWriter) { 1135 return (CxJsonWriter) {
1209 true,
1210 true, 1136 true,
1211 6, 1137 6,
1212 use_spaces, 1138 use_spaces,
1213 4, 1139 4,
1214 false 1140 false
1270 } else { 1196 } else {
1271 actual += wfunc(begin_obj, 1, 1, target); 1197 actual += wfunc(begin_obj, 1, 1, target);
1272 expected++; 1198 expected++;
1273 } 1199 }
1274 depth++; 1200 depth++;
1275 size_t elem_count = value->value.object.values_size; 1201 CxMapIterator member_iter = cxJsonObjIter(value);
1276 for (size_t look_idx = 0; look_idx < elem_count; look_idx++) { 1202 cx_foreach(const CxMapEntry *, member, member_iter) {
1277 // get the member either via index array or directly
1278 size_t elem_idx = settings->sort_members
1279 ? look_idx
1280 : value->value.object.indices[look_idx];
1281 CxJsonObjValue *member = &value->value.object.values[elem_idx];
1282
1283 // possible indentation 1203 // possible indentation
1284 if (settings->pretty) { 1204 if (settings->pretty) {
1285 if (cx_json_writer_indent(target, wfunc, settings, depth)) { 1205 if (cx_json_writer_indent(target, wfunc, settings, depth)) {
1286 return 1; // LCOV_EXCL_LINE 1206 return 1; // LCOV_EXCL_LINE
1287 } 1207 }
1288 } 1208 }
1289 1209
1290 // the name 1210 // the name
1291 actual += wfunc("\"", 1, 1, target); 1211 actual += wfunc("\"", 1, 1, target);
1292 cxmutstr name = escape_string(member->name, settings->escape_slash); 1212 cxstring key = cx_strn(member->key->data, member->key->len);
1213 cxmutstr name = escape_string(key, settings->escape_slash);
1293 actual += wfunc(name.ptr, 1, name.length, target); 1214 actual += wfunc(name.ptr, 1, name.length, target);
1294 if (name.ptr != member->name.ptr) {
1295 cx_strfree(&name);
1296 }
1297 actual += wfunc("\"", 1, 1, target); 1215 actual += wfunc("\"", 1, 1, target);
1298 const char *obj_name_sep = ": "; 1216 const char *obj_name_sep = ": ";
1299 if (settings->pretty) { 1217 if (settings->pretty) {
1300 actual += wfunc(obj_name_sep, 1, 2, target); 1218 actual += wfunc(obj_name_sep, 1, 2, target);
1301 expected += 4 + member->name.length; 1219 expected += 4 + name.length;
1302 } else { 1220 } else {
1303 actual += wfunc(obj_name_sep, 1, 1, target); 1221 actual += wfunc(obj_name_sep, 1, 1, target);
1304 expected += 3 + member->name.length; 1222 expected += 3 + name.length;
1223 }
1224 if (name.ptr != key.ptr) {
1225 cx_strfree(&name);
1305 } 1226 }
1306 1227
1307 // the value 1228 // the value
1308 if (cx_json_write_rec(target, member->value, wfunc, settings, depth)) return 1; 1229 if (cx_json_write_rec(target, member->value, wfunc, settings, depth)) return 1;
1309 1230
1310 // end of object-value 1231 // end of object-value
1311 if (look_idx < elem_count - 1) { 1232 if (member_iter.index < member_iter.elem_count - 1) {
1312 const char *obj_value_sep = ",\n"; 1233 const char *obj_value_sep = ",\n";
1313 if (settings->pretty) { 1234 if (settings->pretty) {
1314 actual += wfunc(obj_value_sep, 1, 2, target); 1235 actual += wfunc(obj_value_sep, 1, 2, target);
1315 expected += 2; 1236 expected += 2;
1316 } else { 1237 } else {
1359 expected++; 1280 expected++;
1360 break; 1281 break;
1361 } 1282 }
1362 case CX_JSON_STRING: { 1283 case CX_JSON_STRING: {
1363 actual += wfunc("\"", 1, 1, target); 1284 actual += wfunc("\"", 1, 1, target);
1364 cxmutstr str = escape_string(value->value.string, settings->escape_slash); 1285 cxmutstr str = escape_string(cx_strcast(value->string),
1286 settings->escape_slash);
1365 actual += wfunc(str.ptr, 1, str.length, target); 1287 actual += wfunc(str.ptr, 1, str.length, target);
1366 if (str.ptr != value->value.string.ptr) { 1288 actual += wfunc("\"", 1, 1, target);
1289 expected += 2 + str.length;
1290 if (str.ptr != value->string.ptr) {
1367 cx_strfree(&str); 1291 cx_strfree(&str);
1368 } 1292 }
1369 actual += wfunc("\"", 1, 1, target);
1370 expected += 2 + value->value.string.length;
1371 break; 1293 break;
1372 } 1294 }
1373 case CX_JSON_NUMBER: { 1295 case CX_JSON_NUMBER: {
1374 int precision = settings->frac_max_digits; 1296 int precision = settings->frac_max_digits;
1375 // because of the way how %g is defined, we need to 1297 // because of the way how %g is defined, we need to
1376 // double the precision and truncate ourselves 1298 // double the precision and truncate ourselves
1377 precision = 1 + (precision > 15 ? 30 : 2 * precision); 1299 precision = 1 + (precision > 15 ? 30 : 2 * precision);
1378 snprintf(numbuf, 40, "%.*g", precision, value->value.number); 1300 snprintf(numbuf, 40, "%.*g", precision, value->number);
1379 char *dot, *exp; 1301 char *dot, *exp;
1380 unsigned char max_digits; 1302 unsigned char max_digits;
1381 // find the decimal separator and hope that it's one of . or , 1303 // find the decimal separator and hope that it's one of . or ,
1382 dot = strchr(numbuf, '.'); 1304 dot = strchr(numbuf, '.');
1383 if (dot == NULL) { 1305 if (dot == NULL) {
1437 expected += len; 1359 expected += len;
1438 } 1360 }
1439 break; 1361 break;
1440 } 1362 }
1441 case CX_JSON_INTEGER: { 1363 case CX_JSON_INTEGER: {
1442 snprintf(numbuf, 32, "%" PRIi64, value->value.integer); 1364 snprintf(numbuf, 32, "%" PRIi64, value->integer);
1443 size_t len = strlen(numbuf); 1365 size_t len = strlen(numbuf);
1444 actual += wfunc(numbuf, 1, len, target); 1366 actual += wfunc(numbuf, 1, len, target);
1445 expected += len; 1367 expected += len;
1446 break; 1368 break;
1447 } 1369 }
1448 case CX_JSON_LITERAL: { 1370 case CX_JSON_LITERAL: {
1449 if (value->value.literal == CX_JSON_TRUE) { 1371 if (value->literal == CX_JSON_TRUE) {
1450 actual += wfunc("true", 1, 4, target); 1372 actual += wfunc("true", 1, 4, target);
1451 expected += 4; 1373 expected += 4;
1452 } else if (value->value.literal == CX_JSON_FALSE) { 1374 } else if (value->literal == CX_JSON_FALSE) {
1453 actual += wfunc("false", 1, 5, target); 1375 actual += wfunc("false", 1, 5, target);
1454 expected += 5; 1376 expected += 5;
1455 } else { 1377 } else {
1456 actual += wfunc("null", 1, 4, target); 1378 actual += wfunc("null", 1, 4, target);
1457 expected += 4; 1379 expected += 4;

mercurial