| 50 static size_t json_find_objvalue(const CxJsonValue *obj, cxstring name) { |
50 static size_t json_find_objvalue(const CxJsonValue *obj, cxstring name) { |
| 51 assert(obj->type == CX_JSON_OBJECT); |
51 assert(obj->type == CX_JSON_OBJECT); |
| 52 CxJsonObjValue kv_dummy; |
52 CxJsonObjValue kv_dummy; |
| 53 kv_dummy.name = cx_mutstrn((char*) name.ptr, name.length); |
53 kv_dummy.name = cx_mutstrn((char*) name.ptr, name.length); |
| 54 return cx_array_binary_search( |
54 return cx_array_binary_search( |
| 55 obj->value.object.values, |
55 obj->object.values, |
| 56 obj->value.object.values_size, |
56 obj->object.values_size, |
| 57 sizeof(CxJsonObjValue), |
57 sizeof(CxJsonObjValue), |
| 58 &kv_dummy, |
58 &kv_dummy, |
| 59 json_cmp_objvalue |
59 json_cmp_objvalue |
| 60 ); |
60 ); |
| 61 } |
61 } |
| 62 |
62 |
| 63 static int json_add_objvalue(CxJsonValue *objv, CxJsonObjValue member) { |
63 static int json_add_objvalue(CxJsonValue *objv, CxJsonObjValue member) { |
| 64 assert(objv->type == CX_JSON_OBJECT); |
64 assert(objv->type == CX_JSON_OBJECT); |
| 65 const CxAllocator * const al = objv->allocator; |
65 const CxAllocator * const al = objv->allocator; |
| 66 CxJsonObject *obj = &(objv->value.object); |
66 CxJsonObject *obj = &(objv->object); |
| 67 |
67 |
| 68 // determine the index where we need to insert the new member |
68 // determine the index where we need to insert the new member |
| 69 size_t index = cx_array_binary_search_sup( |
69 size_t index = cx_array_binary_search_sup( |
| 70 obj->values, |
70 obj->values, |
| 71 obj->values_size, |
71 obj->values_size, |
| 532 |
532 |
| 533 // initialize the value |
533 // initialize the value |
| 534 v->type = type; |
534 v->type = type; |
| 535 v->allocator = json->allocator; |
535 v->allocator = json->allocator; |
| 536 if (type == CX_JSON_ARRAY) { |
536 if (type == CX_JSON_ARRAY) { |
| 537 cx_array_initialize_a(json->allocator, v->value.array.array, 16); |
537 cx_array_initialize_a(json->allocator, v->array.array, 16); |
| 538 if (v->value.array.array == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE |
538 if (v->array.array == NULL) goto create_json_value_exit_error; // LCOV_EXCL_LINE |
| 539 } else if (type == CX_JSON_OBJECT) { |
539 } else if (type == CX_JSON_OBJECT) { |
| 540 cx_array_initialize_a(json->allocator, v->value.object.values, 16); |
540 cx_array_initialize_a(json->allocator, v->object.values, 16); |
| 541 v->value.object.indices = cxCalloc(json->allocator, 16, sizeof(size_t)); |
541 v->object.indices = cxCalloc(json->allocator, 16, sizeof(size_t)); |
| 542 if (v->value.object.values == NULL || |
542 if (v->object.values == NULL || |
| 543 v->value.object.indices == NULL) |
543 v->object.indices == NULL) |
| 544 goto create_json_value_exit_error; // LCOV_EXCL_LINE |
544 goto create_json_value_exit_error; // LCOV_EXCL_LINE |
| 545 } |
545 } |
| 546 |
546 |
| 547 // add the new value to a possible parent |
547 // add the new value to a possible parent |
| 548 if (json->vbuf_size > 0) { |
548 if (json->vbuf_size > 0) { |
| 549 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1]; |
549 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1]; |
| 550 assert(parent != NULL); |
550 assert(parent != NULL); |
| 551 if (parent->type == CX_JSON_ARRAY) { |
551 if (parent->type == CX_JSON_ARRAY) { |
| 552 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL); |
552 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL); |
| 553 if (cx_array_simple_add_a(&value_realloc, parent->value.array.array, v)) { |
553 if (cx_array_simple_add_a(&value_realloc, parent->array.array, v)) { |
| 554 goto create_json_value_exit_error; // LCOV_EXCL_LINE |
554 goto create_json_value_exit_error; // LCOV_EXCL_LINE |
| 555 } |
555 } |
| 556 } else if (parent->type == CX_JSON_OBJECT) { |
556 } else if (parent->type == CX_JSON_OBJECT) { |
| 557 // the member was already created after parsing the name |
557 // the member was already created after parsing the name |
| 558 assert(json->uncompleted_member.name.ptr != NULL); |
558 assert(json->uncompleted_member.name.ptr != NULL); |
| 718 } |
718 } |
| 719 cxmutstr str = unescape_string(json->allocator, token.content); |
719 cxmutstr str = unescape_string(json->allocator, token.content); |
| 720 if (str.ptr == NULL) { |
720 if (str.ptr == NULL) { |
| 721 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
721 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
| 722 } |
722 } |
| 723 vbuf->value.string = str; |
723 vbuf->string = str; |
| 724 return_rec(CX_JSON_NO_ERROR); |
724 return_rec(CX_JSON_NO_ERROR); |
| 725 } |
725 } |
| 726 case CX_JSON_TOKEN_INTEGER: |
726 case CX_JSON_TOKEN_INTEGER: |
| 727 case CX_JSON_TOKEN_NUMBER: { |
727 case CX_JSON_TOKEN_NUMBER: { |
| 728 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER; |
728 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER; |
| 729 if (NULL == (vbuf = json_create_value(json, type))) { |
729 if (NULL == (vbuf = json_create_value(json, type))) { |
| 730 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
730 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
| 731 } |
731 } |
| 732 if (type == CX_JSON_INTEGER) { |
732 if (type == CX_JSON_INTEGER) { |
| 733 if (cx_strtoi64(token.content, &vbuf->value.integer, 10)) { |
733 if (cx_strtoi64(token.content, &vbuf->integer, 10)) { |
| 734 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); |
734 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); |
| 735 } |
735 } |
| 736 } else { |
736 } else { |
| 737 if (cx_strtod(token.content, &vbuf->value.number)) { |
737 if (cx_strtod(token.content, &vbuf->number)) { |
| 738 // TODO: at the moment this is unreachable, because the tokenizer is already stricter than cx_strtod() |
738 // 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 |
739 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); // LCOV_EXCL_LINE |
| 740 } |
740 } |
| 741 } |
741 } |
| 742 return_rec(CX_JSON_NO_ERROR); |
742 return_rec(CX_JSON_NO_ERROR); |
| 744 case CX_JSON_TOKEN_LITERAL: { |
744 case CX_JSON_TOKEN_LITERAL: { |
| 745 if ((vbuf = json_create_value(json, CX_JSON_LITERAL)) == NULL) { |
745 if ((vbuf = json_create_value(json, CX_JSON_LITERAL)) == NULL) { |
| 746 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
746 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
| 747 } |
747 } |
| 748 if (0 == cx_strcmp(cx_strcast(token.content), cx_str("true"))) { |
748 if (0 == cx_strcmp(cx_strcast(token.content), cx_str("true"))) { |
| 749 vbuf->value.literal = CX_JSON_TRUE; |
749 vbuf->literal = CX_JSON_TRUE; |
| 750 } else if (0 == cx_strcmp(cx_strcast(token.content), cx_str("false"))) { |
750 } else if (0 == cx_strcmp(cx_strcast(token.content), cx_str("false"))) { |
| 751 vbuf->value.literal = CX_JSON_FALSE; |
751 vbuf->literal = CX_JSON_FALSE; |
| 752 } else { |
752 } else { |
| 753 vbuf->value.literal = CX_JSON_NULL; |
753 vbuf->literal = CX_JSON_NULL; |
| 754 } |
754 } |
| 755 return_rec(CX_JSON_NO_ERROR); |
755 return_rec(CX_JSON_NO_ERROR); |
| 756 } |
756 } |
| 757 default: { |
757 default: { |
| 758 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); |
758 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN); |
| 862 |
862 |
| 863 void cxJsonValueFree(CxJsonValue *value) { |
863 void cxJsonValueFree(CxJsonValue *value) { |
| 864 if (value == NULL || value->type == CX_JSON_NOTHING) return; |
864 if (value == NULL || value->type == CX_JSON_NOTHING) return; |
| 865 switch (value->type) { |
865 switch (value->type) { |
| 866 case CX_JSON_OBJECT: { |
866 case CX_JSON_OBJECT: { |
| 867 CxJsonObject obj = value->value.object; |
867 CxJsonObject obj = value->object; |
| 868 for (size_t i = 0; i < obj.values_size; i++) { |
868 for (size_t i = 0; i < obj.values_size; i++) { |
| 869 cxJsonValueFree(obj.values[i].value); |
869 cxJsonValueFree(obj.values[i].value); |
| 870 cx_strfree_a(value->allocator, &obj.values[i].name); |
870 cx_strfree_a(value->allocator, &obj.values[i].name); |
| 871 } |
871 } |
| 872 cxFree(value->allocator, obj.values); |
872 cxFree(value->allocator, obj.values); |
| 873 cxFree(value->allocator, obj.indices); |
873 cxFree(value->allocator, obj.indices); |
| 874 break; |
874 break; |
| 875 } |
875 } |
| 876 case CX_JSON_ARRAY: { |
876 case CX_JSON_ARRAY: { |
| 877 CxJsonArray array = value->value.array; |
877 CxJsonArray array = value->array; |
| 878 for (size_t i = 0; i < array.array_size; i++) { |
878 for (size_t i = 0; i < array.array_size; i++) { |
| 879 cxJsonValueFree(array.array[i]); |
879 cxJsonValueFree(array.array[i]); |
| 880 } |
880 } |
| 881 cxFree(value->allocator, array.array); |
881 cxFree(value->allocator, array.array); |
| 882 break; |
882 break; |
| 883 } |
883 } |
| 884 case CX_JSON_STRING: { |
884 case CX_JSON_STRING: { |
| 885 cxFree(value->allocator, value->value.string.ptr); |
885 cxFree(value->allocator, value->string.ptr); |
| 886 break; |
886 break; |
| 887 } |
887 } |
| 888 default: { |
888 default: { |
| 889 break; |
889 break; |
| 890 } |
890 } |
| 896 if (allocator == NULL) allocator = cxDefaultAllocator; |
896 if (allocator == NULL) allocator = cxDefaultAllocator; |
| 897 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); |
897 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); |
| 898 if (v == NULL) return NULL; |
898 if (v == NULL) return NULL; |
| 899 v->allocator = allocator; |
899 v->allocator = allocator; |
| 900 v->type = CX_JSON_OBJECT; |
900 v->type = CX_JSON_OBJECT; |
| 901 cx_array_initialize_a(allocator, v->value.object.values, 16); |
901 cx_array_initialize_a(allocator, v->object.values, 16); |
| 902 if (v->value.object.values == NULL) { // LCOV_EXCL_START |
902 if (v->object.values == NULL) { // LCOV_EXCL_START |
| 903 cxFree(allocator, v); |
903 cxFree(allocator, v); |
| 904 return NULL; |
904 return NULL; |
| 905 // LCOV_EXCL_STOP |
905 // LCOV_EXCL_STOP |
| 906 } |
906 } |
| 907 v->value.object.indices = cxCalloc(allocator, 16, sizeof(size_t)); |
907 v->object.indices = cxCalloc(allocator, 16, sizeof(size_t)); |
| 908 if (v->value.object.indices == NULL) { // LCOV_EXCL_START |
908 if (v->object.indices == NULL) { // LCOV_EXCL_START |
| 909 cxFree(allocator, v->value.object.values); |
909 cxFree(allocator, v->object.values); |
| 910 cxFree(allocator, v); |
910 cxFree(allocator, v); |
| 911 return NULL; |
911 return NULL; |
| 912 // LCOV_EXCL_STOP |
912 // LCOV_EXCL_STOP |
| 913 } |
913 } |
| 914 return v; |
914 return v; |
| 918 if (allocator == NULL) allocator = cxDefaultAllocator; |
918 if (allocator == NULL) allocator = cxDefaultAllocator; |
| 919 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); |
919 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); |
| 920 if (v == NULL) return NULL; |
920 if (v == NULL) return NULL; |
| 921 v->allocator = allocator; |
921 v->allocator = allocator; |
| 922 v->type = CX_JSON_ARRAY; |
922 v->type = CX_JSON_ARRAY; |
| 923 cx_array_initialize_a(allocator, v->value.array.array, 16); |
923 cx_array_initialize_a(allocator, v->array.array, 16); |
| 924 if (v->value.array.array == NULL) { cxFree(allocator, v); return NULL; } |
924 if (v->array.array == NULL) { cxFree(allocator, v); return NULL; } |
| 925 return v; |
925 return v; |
| 926 } |
926 } |
| 927 |
927 |
| 928 CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num) { |
928 CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num) { |
| 929 if (allocator == NULL) allocator = cxDefaultAllocator; |
929 if (allocator == NULL) allocator = cxDefaultAllocator; |
| 930 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); |
930 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); |
| 931 if (v == NULL) return NULL; |
931 if (v == NULL) return NULL; |
| 932 v->allocator = allocator; |
932 v->allocator = allocator; |
| 933 v->type = CX_JSON_NUMBER; |
933 v->type = CX_JSON_NUMBER; |
| 934 v->value.number = num; |
934 v->number = num; |
| 935 return v; |
935 return v; |
| 936 } |
936 } |
| 937 |
937 |
| 938 CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num) { |
938 CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num) { |
| 939 if (allocator == NULL) allocator = cxDefaultAllocator; |
939 if (allocator == NULL) allocator = cxDefaultAllocator; |
| 940 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); |
940 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); |
| 941 if (v == NULL) return NULL; |
941 if (v == NULL) return NULL; |
| 942 v->allocator = allocator; |
942 v->allocator = allocator; |
| 943 v->type = CX_JSON_INTEGER; |
943 v->type = CX_JSON_INTEGER; |
| 944 v->value.integer = num; |
944 v->integer = num; |
| 945 return v; |
945 return v; |
| 946 } |
946 } |
| 947 |
947 |
| 948 CxJsonValue* cx_json_create_string(const CxAllocator* allocator, cxstring str) { |
948 CxJsonValue* cx_json_create_string(const CxAllocator* allocator, cxstring str) { |
| 949 if (allocator == NULL) allocator = cxDefaultAllocator; |
949 if (allocator == NULL) allocator = cxDefaultAllocator; |
| 951 if (v == NULL) return NULL; |
951 if (v == NULL) return NULL; |
| 952 v->allocator = allocator; |
952 v->allocator = allocator; |
| 953 v->type = CX_JSON_STRING; |
953 v->type = CX_JSON_STRING; |
| 954 cxmutstr s = cx_strdup_a(allocator, str); |
954 cxmutstr s = cx_strdup_a(allocator, str); |
| 955 if (s.ptr == NULL) { cxFree(allocator, v); return NULL; } |
955 if (s.ptr == NULL) { cxFree(allocator, v); return NULL; } |
| 956 v->value.string = s; |
956 v->string = s; |
| 957 return v; |
957 return v; |
| 958 } |
958 } |
| 959 |
959 |
| 960 CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit) { |
960 CxJsonValue* cxJsonCreateLiteral(const CxAllocator* allocator, CxJsonLiteral lit) { |
| 961 if (allocator == NULL) allocator = cxDefaultAllocator; |
961 if (allocator == NULL) allocator = cxDefaultAllocator; |
| 962 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); |
962 CxJsonValue* v = cxMalloc(allocator, sizeof(CxJsonValue)); |
| 963 if (v == NULL) return NULL; |
963 if (v == NULL) return NULL; |
| 964 v->allocator = allocator; |
964 v->allocator = allocator; |
| 965 v->type = CX_JSON_LITERAL; |
965 v->type = CX_JSON_LITERAL; |
| 966 v->value.literal = lit; |
966 v->literal = lit; |
| 967 return v; |
967 return v; |
| 968 } |
968 } |
| 969 |
969 |
| 970 // LCOV_EXCL_START |
970 // LCOV_EXCL_START |
| 971 // never called as long as malloc() does not return NULL |
971 // never called as long as malloc() does not return NULL |
| 1103 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL;} |
1103 if (cxJsonObjPut(obj, name, v)) { cxJsonValueFree(v); return NULL;} |
| 1104 return v; |
1104 return v; |
| 1105 } |
1105 } |
| 1106 |
1106 |
| 1107 CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index) { |
1107 CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index) { |
| 1108 if (index >= value->value.array.array_size) { |
1108 if (index >= value->array.array_size) { |
| 1109 return &cx_json_value_nothing; |
1109 return &cx_json_value_nothing; |
| 1110 } |
1110 } |
| 1111 return value->value.array.array[index]; |
1111 return value->array.array[index]; |
| 1112 } |
1112 } |
| 1113 |
1113 |
| 1114 CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) { |
1114 CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) { |
| 1115 if (index >= value->value.array.array_size) { |
1115 if (index >= value->array.array_size) { |
| 1116 return NULL; |
1116 return NULL; |
| 1117 } |
1117 } |
| 1118 CxJsonValue *ret = value->value.array.array[index]; |
1118 CxJsonValue *ret = value->array.array[index]; |
| 1119 // TODO: replace with a low level cx_array_remove() |
1119 // TODO: replace with a low level cx_array_remove() |
| 1120 size_t count = value->value.array.array_size - index - 1; |
1120 size_t count = value->array.array_size - index - 1; |
| 1121 if (count > 0) { |
1121 if (count > 0) { |
| 1122 memmove(value->value.array.array + index, value->value.array.array + index + 1, count * sizeof(CxJsonValue*)); |
1122 memmove(value->array.array + index, value->array.array + index + 1, count * sizeof(CxJsonValue*)); |
| 1123 } |
1123 } |
| 1124 value->value.array.array_size--; |
1124 value->array.array_size--; |
| 1125 return ret; |
1125 return ret; |
| 1126 } |
1126 } |
| 1127 |
1127 |
| 1128 char *cxJsonAsString(const CxJsonValue *value) { |
1128 char *cxJsonAsString(const CxJsonValue *value) { |
| 1129 return value->value.string.ptr; |
1129 return value->string.ptr; |
| 1130 } |
1130 } |
| 1131 |
1131 |
| 1132 cxstring cxJsonAsCxString(const CxJsonValue *value) { |
1132 cxstring cxJsonAsCxString(const CxJsonValue *value) { |
| 1133 return cx_strcast(value->value.string); |
1133 return cx_strcast(value->string); |
| 1134 } |
1134 } |
| 1135 |
1135 |
| 1136 cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) { |
1136 cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) { |
| 1137 return value->value.string; |
1137 return value->string; |
| 1138 } |
1138 } |
| 1139 |
1139 |
| 1140 double cxJsonAsDouble(const CxJsonValue *value) { |
1140 double cxJsonAsDouble(const CxJsonValue *value) { |
| 1141 if (value->type == CX_JSON_INTEGER) { |
1141 if (value->type == CX_JSON_INTEGER) { |
| 1142 return (double) value->value.integer; |
1142 return (double) value->integer; |
| 1143 } else { |
1143 } else { |
| 1144 return value->value.number; |
1144 return value->number; |
| 1145 } |
1145 } |
| 1146 } |
1146 } |
| 1147 |
1147 |
| 1148 int64_t cxJsonAsInteger(const CxJsonValue *value) { |
1148 int64_t cxJsonAsInteger(const CxJsonValue *value) { |
| 1149 if (value->type == CX_JSON_INTEGER) { |
1149 if (value->type == CX_JSON_INTEGER) { |
| 1150 return value->value.integer; |
1150 return value->integer; |
| 1151 } else { |
1151 } else { |
| 1152 return (int64_t) value->value.number; |
1152 return (int64_t) value->number; |
| 1153 } |
1153 } |
| 1154 } |
1154 } |
| 1155 |
1155 |
| 1156 CxIterator cxJsonArrIter(const CxJsonValue *value) { |
1156 CxIterator cxJsonArrIter(const CxJsonValue *value) { |
| 1157 return cxIteratorPtr( |
1157 return cxIteratorPtr( |
| 1158 value->value.array.array, |
1158 value->array.array, |
| 1159 value->value.array.array_size, |
1159 value->array.array_size, |
| 1160 true // arrays need to keep order |
1160 true // arrays need to keep order |
| 1161 ); |
1161 ); |
| 1162 } |
1162 } |
| 1163 |
1163 |
| 1164 CxIterator cxJsonObjIter(const CxJsonValue *value) { |
1164 CxIterator cxJsonObjIter(const CxJsonValue *value) { |
| 1165 return cxIterator( |
1165 return cxIterator( |
| 1166 value->value.object.values, |
1166 value->object.values, |
| 1167 sizeof(CxJsonObjValue), |
1167 sizeof(CxJsonObjValue), |
| 1168 value->value.object.values_size, |
1168 value->object.values_size, |
| 1169 true // TODO: objects do not always need to keep order |
1169 true // TODO: objects do not always need to keep order |
| 1170 ); |
1170 ); |
| 1171 } |
1171 } |
| 1172 |
1172 |
| 1173 CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name) { |
1173 CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name) { |
| 1174 size_t index = json_find_objvalue(value, name); |
1174 size_t index = json_find_objvalue(value, name); |
| 1175 if (index >= value->value.object.values_size) { |
1175 if (index >= value->object.values_size) { |
| 1176 return &cx_json_value_nothing; |
1176 return &cx_json_value_nothing; |
| 1177 } else { |
1177 } else { |
| 1178 return value->value.object.values[index].value; |
1178 return value->object.values[index].value; |
| 1179 } |
1179 } |
| 1180 } |
1180 } |
| 1181 |
1181 |
| 1182 CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name) { |
1182 CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name) { |
| 1183 size_t index = json_find_objvalue(value, name); |
1183 size_t index = json_find_objvalue(value, name); |
| 1184 if (index >= value->value.object.values_size) { |
1184 if (index >= value->object.values_size) { |
| 1185 return NULL; |
1185 return NULL; |
| 1186 } else { |
1186 } else { |
| 1187 CxJsonObjValue kv = value->value.object.values[index]; |
1187 CxJsonObjValue kv = value->object.values[index]; |
| 1188 cx_strfree_a(value->allocator, &kv.name); |
1188 cx_strfree_a(value->allocator, &kv.name); |
| 1189 // TODO: replace with cx_array_remove() / cx_array_remove_fast() |
1189 // TODO: replace with cx_array_remove() / cx_array_remove_fast() |
| 1190 value->value.object.values_size--; |
1190 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)); |
1191 memmove(value->object.values + index, value->object.values + index + 1, (value->object.values_size - index) * sizeof(CxJsonObjValue)); |
| 1192 return kv.value; |
1192 return kv.value; |
| 1193 } |
1193 } |
| 1194 } |
1194 } |
| 1195 |
1195 |
| 1196 CxJsonWriter cxJsonWriterCompact(void) { |
1196 CxJsonWriter cxJsonWriterCompact(void) { |
| 1270 } else { |
1270 } else { |
| 1271 actual += wfunc(begin_obj, 1, 1, target); |
1271 actual += wfunc(begin_obj, 1, 1, target); |
| 1272 expected++; |
1272 expected++; |
| 1273 } |
1273 } |
| 1274 depth++; |
1274 depth++; |
| 1275 size_t elem_count = value->value.object.values_size; |
1275 size_t elem_count = value->object.values_size; |
| 1276 for (size_t look_idx = 0; look_idx < elem_count; look_idx++) { |
1276 for (size_t look_idx = 0; look_idx < elem_count; look_idx++) { |
| 1277 // get the member either via index array or directly |
1277 // get the member either via index array or directly |
| 1278 size_t elem_idx = settings->sort_members |
1278 size_t elem_idx = settings->sort_members |
| 1279 ? look_idx |
1279 ? look_idx |
| 1280 : value->value.object.indices[look_idx]; |
1280 : value->object.indices[look_idx]; |
| 1281 CxJsonObjValue *member = &value->value.object.values[elem_idx]; |
1281 CxJsonObjValue *member = &value->object.values[elem_idx]; |
| 1282 |
1282 |
| 1283 // possible indentation |
1283 // possible indentation |
| 1284 if (settings->pretty) { |
1284 if (settings->pretty) { |
| 1285 if (cx_json_writer_indent(target, wfunc, settings, depth)) { |
1285 if (cx_json_writer_indent(target, wfunc, settings, depth)) { |
| 1286 return 1; // LCOV_EXCL_LINE |
1286 return 1; // LCOV_EXCL_LINE |
| 1359 expected++; |
1359 expected++; |
| 1360 break; |
1360 break; |
| 1361 } |
1361 } |
| 1362 case CX_JSON_STRING: { |
1362 case CX_JSON_STRING: { |
| 1363 actual += wfunc("\"", 1, 1, target); |
1363 actual += wfunc("\"", 1, 1, target); |
| 1364 cxmutstr str = escape_string(value->value.string, settings->escape_slash); |
1364 cxmutstr str = escape_string(value->string, settings->escape_slash); |
| 1365 actual += wfunc(str.ptr, 1, str.length, target); |
1365 actual += wfunc(str.ptr, 1, str.length, target); |
| 1366 if (str.ptr != value->value.string.ptr) { |
1366 if (str.ptr != value->string.ptr) { |
| 1367 cx_strfree(&str); |
1367 cx_strfree(&str); |
| 1368 } |
1368 } |
| 1369 actual += wfunc("\"", 1, 1, target); |
1369 actual += wfunc("\"", 1, 1, target); |
| 1370 expected += 2 + value->value.string.length; |
1370 expected += 2 + value->string.length; |
| 1371 break; |
1371 break; |
| 1372 } |
1372 } |
| 1373 case CX_JSON_NUMBER: { |
1373 case CX_JSON_NUMBER: { |
| 1374 int precision = settings->frac_max_digits; |
1374 int precision = settings->frac_max_digits; |
| 1375 // because of the way how %g is defined, we need to |
1375 // because of the way how %g is defined, we need to |
| 1376 // double the precision and truncate ourselves |
1376 // double the precision and truncate ourselves |
| 1377 precision = 1 + (precision > 15 ? 30 : 2 * precision); |
1377 precision = 1 + (precision > 15 ? 30 : 2 * precision); |
| 1378 snprintf(numbuf, 40, "%.*g", precision, value->value.number); |
1378 snprintf(numbuf, 40, "%.*g", precision, value->number); |
| 1379 char *dot, *exp; |
1379 char *dot, *exp; |
| 1380 unsigned char max_digits; |
1380 unsigned char max_digits; |
| 1381 // find the decimal separator and hope that it's one of . or , |
1381 // find the decimal separator and hope that it's one of . or , |
| 1382 dot = strchr(numbuf, '.'); |
1382 dot = strchr(numbuf, '.'); |
| 1383 if (dot == NULL) { |
1383 if (dot == NULL) { |
| 1437 expected += len; |
1437 expected += len; |
| 1438 } |
1438 } |
| 1439 break; |
1439 break; |
| 1440 } |
1440 } |
| 1441 case CX_JSON_INTEGER: { |
1441 case CX_JSON_INTEGER: { |
| 1442 snprintf(numbuf, 32, "%" PRIi64, value->value.integer); |
1442 snprintf(numbuf, 32, "%" PRIi64, value->integer); |
| 1443 size_t len = strlen(numbuf); |
1443 size_t len = strlen(numbuf); |
| 1444 actual += wfunc(numbuf, 1, len, target); |
1444 actual += wfunc(numbuf, 1, len, target); |
| 1445 expected += len; |
1445 expected += len; |
| 1446 break; |
1446 break; |
| 1447 } |
1447 } |
| 1448 case CX_JSON_LITERAL: { |
1448 case CX_JSON_LITERAL: { |
| 1449 if (value->value.literal == CX_JSON_TRUE) { |
1449 if (value->literal == CX_JSON_TRUE) { |
| 1450 actual += wfunc("true", 1, 4, target); |
1450 actual += wfunc("true", 1, 4, target); |
| 1451 expected += 4; |
1451 expected += 4; |
| 1452 } else if (value->value.literal == CX_JSON_FALSE) { |
1452 } else if (value->literal == CX_JSON_FALSE) { |
| 1453 actual += wfunc("false", 1, 5, target); |
1453 actual += wfunc("false", 1, 5, target); |
| 1454 expected += 5; |
1454 expected += 5; |
| 1455 } else { |
1455 } else { |
| 1456 actual += wfunc("null", 1, 4, target); |
1456 actual += wfunc("null", 1, 4, target); |
| 1457 expected += 4; |
1457 expected += 4; |