ucx/json.c

changeset 31
287484519844
parent 30
d33eaaec15da
equal deleted inserted replaced
30:d33eaaec15da 31:287484519844
109 CxJsonTokenType ttype; 109 CxJsonTokenType ttype;
110 if (isstring) { 110 if (isstring) {
111 ttype = CX_JSON_TOKEN_STRING; 111 ttype = CX_JSON_TOKEN_STRING;
112 } else { 112 } else {
113 cxstring s = cx_strcast(str); 113 cxstring s = cx_strcast(str);
114 if (!cx_strcmp(s, CX_STR("true")) || !cx_strcmp(s, CX_STR("false")) 114 if (!cx_strcmp(s, "true") || !cx_strcmp(s, "false")
115 || !cx_strcmp(s, CX_STR("null"))) { 115 || !cx_strcmp(s, "null")) {
116 ttype = CX_JSON_TOKEN_LITERAL; 116 ttype = CX_JSON_TOKEN_LITERAL;
117 } else { 117 } else {
118 ttype = token_numbertype(str.ptr, str.length); 118 ttype = token_numbertype(str.ptr, str.length);
119 } 119 }
120 } 120 }
408 408
409 if (all_printable && escape) { 409 if (all_printable && escape) {
410 size_t capa = str.length + 32; 410 size_t capa = str.length + 32;
411 char *space = cxMallocDefault(capa); 411 char *space = cxMallocDefault(capa);
412 if (space == NULL) return cx_mutstrn(NULL, 0); 412 if (space == NULL) return cx_mutstrn(NULL, 0);
413 cxBufferInit(&buf, space, capa, NULL, CX_BUFFER_AUTO_EXTEND); 413 cxBufferInit(&buf, NULL, space, capa, CX_BUFFER_AUTO_EXTEND);
414 cxBufferWrite(str.ptr, 1, i, &buf); 414 cxBufferWrite(str.ptr, 1, i, &buf);
415 all_printable = false; 415 all_printable = false;
416 } 416 }
417 if (escape) { 417 if (escape) {
418 cxBufferPut(&buf, '\\'); 418 cxBufferPut(&buf, '\\');
451 cxBufferDestroy(&buf); 451 cxBufferDestroy(&buf);
452 return ret; 452 return ret;
453 } 453 }
454 454
455 static CxJsonObject json_create_object_map(const CxAllocator *allocator) { 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 456 CxMap *map = cxKvListCreateAsMap(allocator, CX_STORE_POINTERS);
457 CxMap *map = cxKvListCreateAsMap(allocator, NULL, CX_STORE_POINTERS);
458 if (map == NULL) return NULL; // LCOV_EXCL_LINE 457 if (map == NULL) return NULL; // LCOV_EXCL_LINE
459 cxDefineDestructor(map, cxJsonValueFree); 458 cxSetCompareFunc(map, cxJsonCompare);
459 cxSetDestructor(map, cxJsonValueFree);
460 return map; 460 return map;
461 } 461 }
462 462
463 static void json_free_object_map(CxJsonObject obj) { 463 static void json_free_object_map(CxJsonObject obj) {
464 cxMapFree(obj); 464 cxMapFree(obj);
470 470
471 // initialize the value 471 // initialize the value
472 v->type = type; 472 v->type = type;
473 v->allocator = json->allocator; 473 v->allocator = json->allocator;
474 if (type == CX_JSON_ARRAY) { 474 if (type == CX_JSON_ARRAY) {
475 cx_array_initialize_a(json->allocator, v->array.data, 16); 475 if (cx_array_init_a(json->allocator, v->array, 16)) {
476 if (v->array.data == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE 476 goto create_json_value_exit_error; // LCOV_EXCL_LINE
477 }
477 } else if (type == CX_JSON_OBJECT) { 478 } else if (type == CX_JSON_OBJECT) {
478 v->object = json_create_object_map(json->allocator); 479 v->object = json_create_object_map(json->allocator);
479 if (v->object == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE 480 if (v->object == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE
480 } 481 }
481 482
482 // add the new value to a possible parent 483 // add the new value to a possible parent
483 if (json->vbuf_size > 0) { 484 if (json->vbuf.size > 0) {
484 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1]; 485 CxJsonValue *parent = json->vbuf.data[json->vbuf.size - 1];
485 assert(parent != NULL); 486 assert(parent != NULL);
486 if (parent->type == CX_JSON_ARRAY) { 487 if (parent->type == CX_JSON_ARRAY) {
487 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL); 488 if (cx_array_add_a(json->allocator, parent->array, v)) {
488 if (cx_array_simple_add_a(&value_realloc, parent->array.data, v)) {
489 goto create_json_value_exit_error; // LCOV_EXCL_LINE 489 goto create_json_value_exit_error; // LCOV_EXCL_LINE
490 } 490 }
491 } else if (parent->type == CX_JSON_OBJECT) { 491 } else if (parent->type == CX_JSON_OBJECT) {
492 // the member was already created after parsing the name 492 // the member was already created after parsing the name
493 // store the pointer of the uncompleted value in the map 493 // store the pointer of the uncompleted value in the map
501 } 501 }
502 } 502 }
503 503
504 // 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
505 if (type == CX_JSON_ARRAY || type == CX_JSON_OBJECT) { 505 if (type == CX_JSON_ARRAY || type == CX_JSON_OBJECT) {
506 CxArrayReallocator vbuf_realloc = cx_array_reallocator(NULL, json->vbuf_internal); 506 if (json->vbuf.size >= json->vbuf.capacity) {
507 if (cx_array_simple_add_a(&vbuf_realloc, json->vbuf, v)) { 507 int alloc_error;
508 goto create_json_value_exit_error; // LCOV_EXCL_LINE 508 if (json->vbuf.data == json->vbuf_internal) {
509 } 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++;
510 } 519 }
511 520
512 // 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
513 if (json->parsed == NULL) { 522 if (json->parsed == NULL) {
514 json->parsed = v; 523 json->parsed = v;
538 } 547 }
539 548
540 memset(json, 0, sizeof(CxJson)); 549 memset(json, 0, sizeof(CxJson));
541 json->allocator = allocator; 550 json->allocator = allocator;
542 551
543 json->states = json->states_internal; 552 cx_array_init_fixed(json->states, json->states_internal, 1);
544 json->states_capacity = cx_nmemb(json->states_internal); 553 json->states.data[0] = JP_STATE_VALUE_BEGIN;
545 json->states[0] = JP_STATE_VALUE_BEGIN; 554 cx_array_init_fixed(json->vbuf, json->vbuf_internal, 0);
546 json->states_size = 1;
547
548 json->vbuf = json->vbuf_internal;
549 json->vbuf_capacity = cx_nmemb(json->vbuf_internal);
550 } 555 }
551 556
552 void cxJsonDestroy(CxJson *json) { 557 void cxJsonDestroy(CxJson *json) {
553 cxBufferDestroy(&json->buffer); 558 cxBufferDestroy(&json->buffer);
554 if (json->states != json->states_internal) { 559 if (json->states.data != json->states_internal) {
555 cxFreeDefault(json->states); 560 cx_array_free(json->states);
556 } 561 }
557 if (json->vbuf != json->vbuf_internal) { 562 if (json->vbuf.data != json->vbuf_internal) {
558 cxFreeDefault(json->vbuf); 563 cx_array_free(json->vbuf);
559 } 564 }
560 cxJsonValueFree(json->parsed); 565 cxJsonValueFree(json->parsed);
561 json->parsed = NULL; 566 json->parsed = NULL;
562 token_destroy(&json->uncompleted); 567 token_destroy(&json->uncompleted);
563 cx_strfree_a(json->allocator, &json->uncompleted_member_name); 568 cx_strfree_a(json->allocator, &json->uncompleted_member_name);
572 int cxJsonFilln(CxJson *json, const char *buf, size_t size) { 577 int cxJsonFilln(CxJson *json, const char *buf, size_t size) {
573 if (cxBufferEof(&json->buffer)) { 578 if (cxBufferEof(&json->buffer)) {
574 // reinitialize the buffer 579 // reinitialize the buffer
575 cxBufferDestroy(&json->buffer); 580 cxBufferDestroy(&json->buffer);
576 if (buf == NULL) buf = ""; // buffer must not be initialized with NULL 581 if (buf == NULL) buf = ""; // buffer must not be initialized with NULL
577 cxBufferInit(&json->buffer, (char*) buf, size, 582 cxBufferInit(&json->buffer, NULL, (char*) buf,
578 NULL, CX_BUFFER_AUTO_EXTEND | CX_BUFFER_COPY_ON_WRITE); 583 size, CX_BUFFER_AUTO_EXTEND | CX_BUFFER_COPY_ON_WRITE);
579 json->buffer.size = size; 584 json->buffer.size = size;
580 return 0; 585 return 0;
581 } else { 586 } else {
582 return size != cxBufferAppend(buf, 1, size, &json->buffer); 587 return size != cxBufferAppend(buf, 1, size, &json->buffer);
583 } 588 }
584 } 589 }
585 590
586 static void json_add_state(CxJson *json, int state) { 591 static void json_add_state(CxJson *json, int state) {
587 // we have guaranteed the necessary space with cx_array_simple_reserve() 592 // we have guaranteed the necessary space
588 // 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
589 json->states[json->states_size++] = state; 594 json->states.data[json->states.size++] = state;
590 } 595 }
591 596
592 #define return_rec(code) \ 597 #define return_rec(code) \
593 token_destroy(&token); \ 598 token_destroy(&token); \
594 return code 599 return code
605 return ret; 610 return ret;
606 } 611 }
607 } 612 }
608 613
609 // pop the current state 614 // pop the current state
610 assert(json->states_size > 0); 615 assert(json->states.size > 0);
611 int state = json->states[--json->states_size]; 616 int state = json->states.data[--json->states.size];
612 617
613 // guarantee that at least two more states fit on the stack 618 // guarantee that at least two more states fit into the array
614 CxArrayReallocator state_realloc = cx_array_reallocator(NULL, json->states_internal); 619 const size_t required_states_depth = json->states.size + 2;
615 if (cx_array_simple_reserve_a(&state_realloc, json->states, 2)) { 620 if (required_states_depth >= json->states.capacity) {
616 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 }
617 } 630 }
618 631
619 632
620 // 0 JP_STATE_VALUE_BEGIN value begin 633 // 0 JP_STATE_VALUE_BEGIN value begin
621 // 10 JP_STATE_VALUE_END expect value end 634 // 10 JP_STATE_VALUE_END expect value end
643 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 656 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
644 } 657 }
645 json_add_state(json, JP_STATE_OBJ_NAME_OR_CLOSE); 658 json_add_state(json, JP_STATE_OBJ_NAME_OR_CLOSE);
646 return_rec(CX_JSON_NO_ERROR); 659 return_rec(CX_JSON_NO_ERROR);
647 } 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 }
648 case CX_JSON_TOKEN_STRING: { 671 case CX_JSON_TOKEN_STRING: {
649 if ((vbuf = json_create_value(json, CX_JSON_STRING)) == NULL) { 672 if ((vbuf = json_create_value(json, CX_JSON_STRING)) == NULL) {
650 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 673 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
651 } 674 }
652 cxmutstr str = unescape_string(json->allocator, token.content); 675 cxmutstr str = unescape_string(json->allocator, token.content);
676 } 699 }
677 case CX_JSON_TOKEN_LITERAL: { 700 case CX_JSON_TOKEN_LITERAL: {
678 if ((vbuf = json_create_value(json, CX_JSON_LITERAL)) == NULL) { 701 if ((vbuf = json_create_value(json, CX_JSON_LITERAL)) == NULL) {
679 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 702 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
680 } 703 }
681 if (0 == cx_strcmp(cx_strcast(token.content), cx_str("true"))) { 704 if (0 == cx_strcmp(token.content, "true")) {
682 vbuf->literal = CX_JSON_TRUE; 705 vbuf->literal = CX_JSON_TRUE;
683 } else if (0 == cx_strcmp(cx_strcast(token.content), cx_str("false"))) { 706 } else if (0 == cx_strcmp(token.content, "false")) {
684 vbuf->literal = CX_JSON_FALSE; 707 vbuf->literal = CX_JSON_FALSE;
685 } else { 708 } else {
686 vbuf->literal = CX_JSON_NULL; 709 vbuf->literal = CX_JSON_NULL;
687 } 710 }
688 return_rec(CX_JSON_NO_ERROR); 711 return_rec(CX_JSON_NO_ERROR);
696 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) { 719 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) {
697 json_add_state(json, JP_STATE_VALUE_BEGIN_AR); 720 json_add_state(json, JP_STATE_VALUE_BEGIN_AR);
698 return_rec(CX_JSON_NO_ERROR); 721 return_rec(CX_JSON_NO_ERROR);
699 } else if (token.tokentype == CX_JSON_TOKEN_END_ARRAY) { 722 } else if (token.tokentype == CX_JSON_TOKEN_END_ARRAY) {
700 // discard the array from the value buffer 723 // discard the array from the value buffer
701 json->vbuf_size--; 724 json->vbuf.size--;
702 return_rec(CX_JSON_NO_ERROR); 725 return_rec(CX_JSON_NO_ERROR);
703 } else { 726 } else {
704 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); 727 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
705 } 728 }
706 } 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) {
707 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) {
708 // discard the obj from the value buffer 731 // discard the obj from the value buffer
709 json->vbuf_size--; 732 json->vbuf.size--;
710 return_rec(CX_JSON_NO_ERROR); 733 return_rec(CX_JSON_NO_ERROR);
711 } else { 734 } else {
712 // expect string 735 // expect string
713 if (token.tokentype != CX_JSON_TOKEN_STRING) { 736 if (token.tokentype != CX_JSON_TOKEN_STRING) {
714 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); 737 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
719 if (name.ptr == NULL) { 742 if (name.ptr == NULL) {
720 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE 743 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
721 } 744 }
722 assert(json->uncompleted_member_name.ptr == NULL); 745 assert(json->uncompleted_member_name.ptr == NULL);
723 json->uncompleted_member_name = name; 746 json->uncompleted_member_name = name;
724 assert(json->vbuf_size > 0); 747 assert(json->vbuf.size > 0);
725 748
726 // next state 749 // next state
727 json_add_state(json, JP_STATE_OBJ_COLON); 750 json_add_state(json, JP_STATE_OBJ_COLON);
728 return_rec(CX_JSON_NO_ERROR); 751 return_rec(CX_JSON_NO_ERROR);
729 } 752 }
740 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) { 763 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) {
741 json_add_state(json, JP_STATE_OBJ_NAME); 764 json_add_state(json, JP_STATE_OBJ_NAME);
742 return_rec(CX_JSON_NO_ERROR); 765 return_rec(CX_JSON_NO_ERROR);
743 } else if (token.tokentype == CX_JSON_TOKEN_END_OBJECT) { 766 } else if (token.tokentype == CX_JSON_TOKEN_END_OBJECT) {
744 // discard the obj from the value buffer 767 // discard the obj from the value buffer
745 json->vbuf_size--; 768 json->vbuf.size--;
746 return_rec(CX_JSON_NO_ERROR); 769 return_rec(CX_JSON_NO_ERROR);
747 } else { 770 } else {
748 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); 771 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
749 } 772 }
750 } else { 773 } else {
765 788
766 // parse data 789 // parse data
767 CxJsonStatus result; 790 CxJsonStatus result;
768 do { 791 do {
769 result = json_parse(json); 792 result = json_parse(json);
770 if (result == CX_JSON_NO_ERROR && json->states_size == 1) { 793 if (result == CX_JSON_NO_ERROR && json->states.size == 1) {
771 // final state reached 794 // final state reached
772 assert(json->states[0] == JP_STATE_VALUE_END); 795 assert(json->states.data[0] == JP_STATE_VALUE_END);
773 assert(json->vbuf_size == 0); 796 assert(json->vbuf.size == 0);
774 797
775 // write output value 798 // write output value
776 *value = json->parsed; 799 *value = json->parsed;
777 json->parsed = NULL; 800 json->parsed = NULL;
778 801
779 // re-initialize state machine 802 // re-initialize state machine
780 json->states[0] = JP_STATE_VALUE_BEGIN; 803 json->states.data[0] = JP_STATE_VALUE_BEGIN;
781 804
782 return CX_JSON_NO_ERROR; 805 return CX_JSON_NO_ERROR;
783 } 806 }
784 } while (result == CX_JSON_NO_ERROR); 807 } while (result == CX_JSON_NO_ERROR);
785 808
786 // the parser might think there is no data 809 // the parser might think there is no data
787 // but when we did not reach the final state, 810 // but when we did not reach the final state,
788 // we know that there must be more to come 811 // we know that there must be more to come
789 if (result == CX_JSON_NO_DATA && json->states_size > 1) { 812 if (result == CX_JSON_NO_DATA && json->states.size > 1) {
790 return CX_JSON_INCOMPLETE_DATA; 813 return CX_JSON_INCOMPLETE_DATA;
791 } 814 }
792 815
793 return result; 816 return result;
794 } 817 }
830 case CX_JSON_OBJECT: { 853 case CX_JSON_OBJECT: {
831 json_free_object_map(value->object); 854 json_free_object_map(value->object);
832 break; 855 break;
833 } 856 }
834 case CX_JSON_ARRAY: { 857 case CX_JSON_ARRAY: {
835 CxJsonArray array = value->array; 858 for (size_t i = 0; i < value->array.size; i++) {
836 for (size_t i = 0; i < array.data_size; i++) { 859 cxJsonValueFree(value->array.data[i]);
837 cxJsonValueFree(array.data[i]); 860 }
838 } 861 cx_array_free_a(value->allocator, value->array);
839 cxFree(value->allocator, array.data);
840 break; 862 break;
841 } 863 }
842 case CX_JSON_STRING: { 864 case CX_JSON_STRING: {
843 cxFree(value->allocator, value->string.ptr); 865 cxFree(value->allocator, value->string.ptr);
844 break; 866 break;
863 // LCOV_EXCL_STOP 885 // LCOV_EXCL_STOP
864 } 886 }
865 return v; 887 return v;
866 } 888 }
867 889
868 CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator) { 890 CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator, size_t capacity) {
869 if (allocator == NULL) allocator = cxDefaultAllocator; 891 if (allocator == NULL) allocator = cxDefaultAllocator;
870 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); 892 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue));
871 if (v == NULL) return NULL; 893 if (v == NULL) return NULL;
872 v->allocator = allocator; 894 v->allocator = allocator;
873 v->type = CX_JSON_ARRAY; 895 v->type = CX_JSON_ARRAY;
874 cx_array_initialize_a(allocator, v->array.data, 16); 896 if (capacity > 0) {
875 if (v->array.data == 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 }
876 return v; 907 return v;
877 } 908 }
878 909
879 CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num) { 910 CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num) {
880 if (allocator == NULL) allocator = cxDefaultAllocator; 911 if (allocator == NULL) allocator = cxDefaultAllocator;
988 cxFreeDefault(values); 1019 cxFreeDefault(values);
989 return ret; 1020 return ret;
990 } 1021 }
991 1022
992 int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count) { 1023 int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count) {
993 CxArrayReallocator value_realloc = cx_array_reallocator(arr->allocator, NULL);
994 assert(arr->type == CX_JSON_ARRAY); 1024 assert(arr->type == CX_JSON_ARRAY);
995 return cx_array_simple_copy_a(&value_realloc, 1025 return cx_array_add_array_a(arr->allocator, arr->array, val, count);
996 arr->array.data,
997 arr->array.data_size,
998 val, count
999 );
1000 } 1026 }
1001 1027
1002 int cx_json_obj_put(CxJsonValue* obj, cxstring name, CxJsonValue* child) { 1028 int cx_json_obj_put(CxJsonValue* obj, cxstring name, CxJsonValue* child) {
1003 return cxMapPut(obj->object, name, child); 1029 return cxMapPut(obj->object, name, child);
1004 } 1030 }
1008 if (v == NULL) return NULL; 1034 if (v == NULL) return NULL;
1009 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; } 1035 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; }
1010 return v; 1036 return v;
1011 } 1037 }
1012 1038
1013 CxJsonValue* cx_json_obj_put_arr(CxJsonValue* obj, cxstring name) { 1039 CxJsonValue* cx_json_obj_put_arr(CxJsonValue* obj, cxstring name, size_t capacity) {
1014 CxJsonValue* v = cxJsonCreateArr(obj->allocator); 1040 CxJsonValue* v = cxJsonCreateArr(obj->allocator, capacity);
1015 if (v == NULL) return NULL; 1041 if (v == NULL) return NULL;
1016 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; } 1042 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL; }
1017 return v; 1043 return v;
1018 } 1044 }
1019 1045
1044 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL;} 1070 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL;}
1045 return v; 1071 return v;
1046 } 1072 }
1047 1073
1048 CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index) { 1074 CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index) {
1049 if (index >= value->array.data_size) { 1075 if (index >= value->array.size) {
1050 return &cx_json_value_nothing; 1076 return &cx_json_value_nothing;
1051 } 1077 }
1052 return value->array.data[index]; 1078 return value->array.data[index];
1053 } 1079 }
1054 1080
1055 CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) { 1081 CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) {
1056 if (index >= value->array.data_size) { 1082 if (index >= value->array.size) {
1057 return NULL; 1083 return NULL;
1058 } 1084 }
1059 CxJsonValue *ret = value->array.data[index]; 1085 CxJsonValue *ret = value->array.data[index];
1060 // TODO: replace with a low level cx_array_remove() 1086 cx_array_remove(value->array, index);
1061 size_t count = value->array.data_size - index - 1;
1062 if (count > 0) {
1063 memmove(value->array.data + index, value->array.data + index + 1, count * sizeof(CxJsonValue*));
1064 }
1065 value->array.data_size--;
1066 return ret; 1087 return ret;
1067 } 1088 }
1068 1089
1069 char *cxJsonAsString(const CxJsonValue *value) { 1090 char *cxJsonAsString(const CxJsonValue *value) {
1070 return value->string.ptr; 1091 return value->string.ptr;
1093 return (int64_t) value->number; 1114 return (int64_t) value->number;
1094 } 1115 }
1095 } 1116 }
1096 1117
1097 CxIterator cxJsonArrIter(const CxJsonValue *value) { 1118 CxIterator cxJsonArrIter(const CxJsonValue *value) {
1098 return cxIteratorPtr( 1119 return cx_array_iterator_ptr(value->array);
1099 value->array.data,
1100 value->array.data_size,
1101 true // arrays need to keep order
1102 );
1103 } 1120 }
1104 1121
1105 CxMapIterator cxJsonObjIter(const CxJsonValue *value) { 1122 CxMapIterator cxJsonObjIter(const CxJsonValue *value) {
1106 return cxMapIterator(value->object); 1123 return cxMapIterator(value->object);
1107 } 1124 }
1407 if (settings == NULL) { 1424 if (settings == NULL) {
1408 settings = &writer_default; 1425 settings = &writer_default;
1409 } 1426 }
1410 return cx_json_write_rec(target, value, wfunc, settings, 0); 1427 return cx_json_write_rec(target, value, wfunc, settings, 0);
1411 } 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