ucx/json.c

changeset 888
af685cc9d623
parent 854
1c8401ece69e
equal deleted inserted replaced
877:b60487c3ec36 888:af685cc9d623
30 30
31 #include <string.h> 31 #include <string.h>
32 #include <assert.h> 32 #include <assert.h>
33 #include <stdio.h> 33 #include <stdio.h>
34 #include <inttypes.h> 34 #include <inttypes.h>
35 #include <ctype.h>
35 36
36 /* 37 /*
37 * RFC 8259 38 * RFC 8259
38 * https://tools.ietf.org/html/rfc8259 39 * https://tools.ietf.org/html/rfc8259
39 */ 40 */
44 const CxJsonObjValue *left = l; 45 const CxJsonObjValue *left = l;
45 const CxJsonObjValue *right = r; 46 const CxJsonObjValue *right = r;
46 return cx_strcmp(cx_strcast(left->name), cx_strcast(right->name)); 47 return cx_strcmp(cx_strcast(left->name), cx_strcast(right->name));
47 } 48 }
48 49
49 static CxJsonObjValue *json_find_objvalue(const CxJsonValue *obj, cxstring name) { 50 static size_t json_find_objvalue(const CxJsonValue *obj, cxstring name) {
50 assert(obj->type == CX_JSON_OBJECT); 51 assert(obj->type == CX_JSON_OBJECT);
51 CxJsonObjValue kv_dummy; 52 CxJsonObjValue kv_dummy;
52 kv_dummy.name = cx_mutstrn((char*) name.ptr, name.length); 53 kv_dummy.name = cx_mutstrn((char*) name.ptr, name.length);
53 size_t index = cx_array_binary_search( 54 return cx_array_binary_search(
54 obj->value.object.values, 55 obj->value.object.values,
55 obj->value.object.values_size, 56 obj->value.object.values_size,
56 sizeof(CxJsonObjValue), 57 sizeof(CxJsonObjValue),
57 &kv_dummy, 58 &kv_dummy,
58 json_cmp_objvalue 59 json_cmp_objvalue
59 ); 60 );
60 if (index == obj->value.object.values_size) {
61 return NULL;
62 } else {
63 return &obj->value.object.values[index];
64 }
65 } 61 }
66 62
67 static int json_add_objvalue(CxJsonValue *objv, CxJsonObjValue member) { 63 static int json_add_objvalue(CxJsonValue *objv, CxJsonObjValue member) {
68 assert(objv->type == CX_JSON_OBJECT); 64 assert(objv->type == CX_JSON_OBJECT);
69 const CxAllocator * const al = objv->allocator; 65 const CxAllocator * const al = objv->allocator;
130 if (token->allocated) { 126 if (token->allocated) {
131 cx_strfree(&token->content); 127 cx_strfree(&token->content);
132 } 128 }
133 } 129 }
134 130
135 static bool json_isdigit(char c) {
136 // TODO: remove once UCX has public API for this
137 return c >= '0' && c <= '9';
138 }
139
140 static bool json_isspace(char c) {
141 // TODO: remove once UCX has public API for this
142 return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\v' || c == '\f';
143 }
144
145 static int num_isexp(const char *content, size_t length, size_t pos) { 131 static int num_isexp(const char *content, size_t length, size_t pos) {
146 if (pos >= length) { 132 if (pos >= length) {
147 return 0; 133 return 0;
148 } 134 }
149 135
150 int ok = 0; 136 int ok = 0;
151 for (size_t i = pos; i < length; i++) { 137 for (size_t i = pos; i < length; i++) {
152 char c = content[i]; 138 char c = content[i];
153 if (json_isdigit(c)) { 139 if (isdigit((unsigned char)c)) {
154 ok = 1; 140 ok = 1;
155 } else if (i == pos) { 141 } else if (i == pos) {
156 if (!(c == '+' || c == '-')) { 142 if (!(c == '+' || c == '-')) {
157 return 0; 143 return 0;
158 } 144 }
165 } 151 }
166 152
167 static CxJsonTokenType token_numbertype(const char *content, size_t length) { 153 static CxJsonTokenType token_numbertype(const char *content, size_t length) {
168 if (length == 0) return CX_JSON_TOKEN_ERROR; 154 if (length == 0) return CX_JSON_TOKEN_ERROR;
169 155
170 if (content[0] != '-' && !json_isdigit(content[0])) { 156 if (content[0] != '-' && !isdigit((unsigned char)content[0])) {
171 return CX_JSON_TOKEN_ERROR; 157 return CX_JSON_TOKEN_ERROR;
172 } 158 }
173 159
174 CxJsonTokenType type = CX_JSON_TOKEN_INTEGER; 160 CxJsonTokenType type = CX_JSON_TOKEN_INTEGER;
175 for (size_t i = 1; i < length; i++) { 161 for (size_t i = 1; i < length; i++) {
178 return CX_JSON_TOKEN_ERROR; // more than one decimal separator 164 return CX_JSON_TOKEN_ERROR; // more than one decimal separator
179 } 165 }
180 type = CX_JSON_TOKEN_NUMBER; 166 type = CX_JSON_TOKEN_NUMBER;
181 } else if (content[i] == 'e' || content[i] == 'E') { 167 } else if (content[i] == 'e' || content[i] == 'E') {
182 return num_isexp(content, length, i + 1) ? CX_JSON_TOKEN_NUMBER : CX_JSON_TOKEN_ERROR; 168 return num_isexp(content, length, i + 1) ? CX_JSON_TOKEN_NUMBER : CX_JSON_TOKEN_ERROR;
183 } else if (!json_isdigit(content[i])) { 169 } else if (!isdigit((unsigned char)content[i])) {
184 return CX_JSON_TOKEN_ERROR; // char is not a digit, decimal separator or exponent sep 170 return CX_JSON_TOKEN_ERROR; // char is not a digit, decimal separator or exponent sep
185 } 171 }
186 } 172 }
187 173
188 return type; 174 return type;
242 } 228 }
243 case '"': { 229 case '"': {
244 return CX_JSON_TOKEN_STRING; 230 return CX_JSON_TOKEN_STRING;
245 } 231 }
246 default: { 232 default: {
247 if (json_isspace(c)) { 233 if (isspace((unsigned char)c)) {
248 return CX_JSON_TOKEN_SPACE; 234 return CX_JSON_TOKEN_SPACE;
249 } 235 }
250 } 236 }
251 } 237 }
252 return CX_JSON_NO_TOKEN; 238 return CX_JSON_NO_TOKEN;
498 bool escape = c < 0x20 || c == '\\' || c == '"' 484 bool escape = c < 0x20 || c == '\\' || c == '"'
499 || (escape_slash && c == '/'); 485 || (escape_slash && c == '/');
500 486
501 if (all_printable && escape) { 487 if (all_printable && escape) {
502 size_t capa = str.length + 32; 488 size_t capa = str.length + 32;
503 char *space = malloc(capa); 489 char *space = cxMallocDefault(capa);
504 if (space == NULL) return cx_mutstrn(NULL, 0); 490 if (space == NULL) return cx_mutstrn(NULL, 0);
505 cxBufferInit(&buf, space, capa, NULL, CX_BUFFER_AUTO_EXTEND); 491 cxBufferInit(&buf, space, capa, NULL, CX_BUFFER_AUTO_EXTEND);
506 cxBufferWrite(str.ptr, 1, i, &buf); 492 cxBufferWrite(str.ptr, 1, i, &buf);
507 all_printable = false; 493 all_printable = false;
508 } 494 }
629 } 615 }
630 616
631 void cxJsonDestroy(CxJson *json) { 617 void cxJsonDestroy(CxJson *json) {
632 cxBufferDestroy(&json->buffer); 618 cxBufferDestroy(&json->buffer);
633 if (json->states != json->states_internal) { 619 if (json->states != json->states_internal) {
634 free(json->states); 620 cxFreeDefault(json->states);
635 } 621 }
636 if (json->vbuf != json->vbuf_internal) { 622 if (json->vbuf != json->vbuf_internal) {
637 free(json->vbuf); 623 cxFreeDefault(json->vbuf);
638 } 624 }
639 cxJsonValueFree(json->parsed); 625 cxJsonValueFree(json->parsed);
640 json->parsed = NULL; 626 json->parsed = NULL;
641 if (json->uncompleted_member.name.ptr != NULL) { 627 if (json->uncompleted_member.name.ptr != NULL) {
642 cx_strfree_a(json->allocator, &json->uncompleted_member.name); 628 cx_strfree_a(json->allocator, &json->uncompleted_member.name);
643 json->uncompleted_member = (CxJsonObjValue){{NULL, 0}, NULL}; 629 json->uncompleted_member = (CxJsonObjValue){{NULL, 0}, NULL};
644 } 630 }
631 }
632
633 void cxJsonReset(CxJson *json) {
634 const CxAllocator *allocator = json->allocator;
635 cxJsonDestroy(json);
636 cxJsonInit(json, allocator);
645 } 637 }
646 638
647 int cxJsonFilln(CxJson *json, const char *buf, size_t size) { 639 int cxJsonFilln(CxJson *json, const char *buf, size_t size) {
648 if (cxBufferEof(&json->buffer)) { 640 if (cxBufferEof(&json->buffer)) {
649 // reinitialize the buffer 641 // reinitialize the buffer
982 static void json_arr_free_temp(CxJsonValue** values, size_t count) { 974 static void json_arr_free_temp(CxJsonValue** values, size_t count) {
983 for (size_t i = 0; i < count; i++) { 975 for (size_t i = 0; i < count; i++) {
984 if (values[i] == NULL) break; 976 if (values[i] == NULL) break;
985 cxJsonValueFree(values[i]); 977 cxJsonValueFree(values[i]);
986 } 978 }
987 free(values); 979 cxFreeDefault(values);
988 } 980 }
989 // LCOV_EXCL_STOP 981 // LCOV_EXCL_STOP
990 982
991 int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count) { 983 int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count) {
992 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*)); 984 CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
993 if (values == NULL) return -1; 985 if (values == NULL) return -1;
994 for (size_t i = 0; i < count; i++) { 986 for (size_t i = 0; i < count; i++) {
995 values[i] = cxJsonCreateNumber(arr->allocator, num[i]); 987 values[i] = cxJsonCreateNumber(arr->allocator, num[i]);
996 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; } 988 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
997 } 989 }
998 int ret = cxJsonArrAddValues(arr, values, count); 990 int ret = cxJsonArrAddValues(arr, values, count);
999 free(values); 991 cxFreeDefault(values);
1000 return ret; 992 return ret;
1001 } 993 }
1002 994
1003 int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count) { 995 int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count) {
1004 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*)); 996 CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
1005 if (values == NULL) return -1; 997 if (values == NULL) return -1;
1006 for (size_t i = 0; i < count; i++) { 998 for (size_t i = 0; i < count; i++) {
1007 values[i] = cxJsonCreateInteger(arr->allocator, num[i]); 999 values[i] = cxJsonCreateInteger(arr->allocator, num[i]);
1008 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; } 1000 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
1009 } 1001 }
1010 int ret = cxJsonArrAddValues(arr, values, count); 1002 int ret = cxJsonArrAddValues(arr, values, count);
1011 free(values); 1003 cxFreeDefault(values);
1012 return ret; 1004 return ret;
1013 } 1005 }
1014 1006
1015 int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count) { 1007 int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count) {
1016 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*)); 1008 CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
1017 if (values == NULL) return -1; 1009 if (values == NULL) return -1;
1018 for (size_t i = 0; i < count; i++) { 1010 for (size_t i = 0; i < count; i++) {
1019 values[i] = cxJsonCreateString(arr->allocator, str[i]); 1011 values[i] = cxJsonCreateString(arr->allocator, str[i]);
1020 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; } 1012 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
1021 } 1013 }
1022 int ret = cxJsonArrAddValues(arr, values, count); 1014 int ret = cxJsonArrAddValues(arr, values, count);
1023 free(values); 1015 cxFreeDefault(values);
1024 return ret; 1016 return ret;
1025 } 1017 }
1026 1018
1027 int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count) { 1019 int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count) {
1028 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*)); 1020 CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
1029 if (values == NULL) return -1; 1021 if (values == NULL) return -1;
1030 for (size_t i = 0; i < count; i++) { 1022 for (size_t i = 0; i < count; i++) {
1031 values[i] = cxJsonCreateCxString(arr->allocator, str[i]); 1023 values[i] = cxJsonCreateCxString(arr->allocator, str[i]);
1032 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; } 1024 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
1033 } 1025 }
1034 int ret = cxJsonArrAddValues(arr, values, count); 1026 int ret = cxJsonArrAddValues(arr, values, count);
1035 free(values); 1027 cxFreeDefault(values);
1036 return ret; 1028 return ret;
1037 } 1029 }
1038 1030
1039 int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t count) { 1031 int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t count) {
1040 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*)); 1032 CxJsonValue** values = cxCallocDefault(count, sizeof(CxJsonValue*));
1041 if (values == NULL) return -1; 1033 if (values == NULL) return -1;
1042 for (size_t i = 0; i < count; i++) { 1034 for (size_t i = 0; i < count; i++) {
1043 values[i] = cxJsonCreateLiteral(arr->allocator, lit[i]); 1035 values[i] = cxJsonCreateLiteral(arr->allocator, lit[i]);
1044 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; } 1036 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; }
1045 } 1037 }
1046 int ret = cxJsonArrAddValues(arr, values, count); 1038 int ret = cxJsonArrAddValues(arr, values, count);
1047 free(values); 1039 cxFreeDefault(values);
1048 return ret; 1040 return ret;
1049 } 1041 }
1050 1042
1051 int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count) { 1043 int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count) {
1052 CxArrayReallocator value_realloc = cx_array_reallocator(arr->allocator, NULL); 1044 CxArrayReallocator value_realloc = cx_array_reallocator(arr->allocator, NULL);
1124 return &cx_json_value_nothing; 1116 return &cx_json_value_nothing;
1125 } 1117 }
1126 return value->value.array.array[index]; 1118 return value->value.array.array[index];
1127 } 1119 }
1128 1120
1121 CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) {
1122 if (index >= value->value.array.array_size) {
1123 return NULL;
1124 }
1125 CxJsonValue *ret = value->value.array.array[index];
1126 // TODO: replace with a low level cx_array_remove()
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;
1133 }
1134
1135 char *cxJsonAsString(const CxJsonValue *value) {
1136 return value->value.string.ptr;
1137 }
1138
1139 cxstring cxJsonAsCxString(const CxJsonValue *value) {
1140 return cx_strcast(value->value.string);
1141 }
1142
1143 cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value) {
1144 return value->value.string;
1145 }
1146
1147 double cxJsonAsDouble(const CxJsonValue *value) {
1148 if (value->type == CX_JSON_INTEGER) {
1149 return (double) value->value.integer;
1150 } else {
1151 return value->value.number;
1152 }
1153 }
1154
1155 int64_t cxJsonAsInteger(const CxJsonValue *value) {
1156 if (value->type == CX_JSON_INTEGER) {
1157 return value->value.integer;
1158 } else {
1159 return (int64_t) value->value.number;
1160 }
1161 }
1162
1129 CxIterator cxJsonArrIter(const CxJsonValue *value) { 1163 CxIterator cxJsonArrIter(const CxJsonValue *value) {
1130 return cxIteratorPtr( 1164 return cxIteratorPtr(
1131 value->value.array.array, 1165 value->value.array.array,
1132 value->value.array.array_size 1166 value->value.array.array_size,
1167 true // arrays need to keep order
1133 ); 1168 );
1134 } 1169 }
1135 1170
1136 CxIterator cxJsonObjIter(const CxJsonValue *value) { 1171 CxIterator cxJsonObjIter(const CxJsonValue *value) {
1137 return cxIterator( 1172 return cxIterator(
1138 value->value.object.values, 1173 value->value.object.values,
1139 sizeof(CxJsonObjValue), 1174 sizeof(CxJsonObjValue),
1140 value->value.object.values_size 1175 value->value.object.values_size,
1176 true // TODO: objects do not always need to keep order
1141 ); 1177 );
1142 } 1178 }
1143 1179
1144 CxJsonValue *cx_json_obj_get_cxstr(const CxJsonValue *value, cxstring name) { 1180 CxJsonValue *cx_json_obj_get(const CxJsonValue *value, cxstring name) {
1145 CxJsonObjValue *member = json_find_objvalue(value, name); 1181 size_t index = json_find_objvalue(value, name);
1146 if (member == NULL) { 1182 if (index >= value->value.object.values_size) {
1147 return &cx_json_value_nothing; 1183 return &cx_json_value_nothing;
1148 } else { 1184 } else {
1149 return member->value; 1185 return value->value.object.values[index].value;
1186 }
1187 }
1188
1189 CxJsonValue *cx_json_obj_remove(CxJsonValue *value, cxstring name) {
1190 size_t index = json_find_objvalue(value, name);
1191 if (index >= value->value.object.values_size) {
1192 return NULL;
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;
1150 } 1200 }
1151 } 1201 }
1152 1202
1153 CxJsonWriter cxJsonWriterCompact(void) { 1203 CxJsonWriter cxJsonWriterCompact(void) {
1154 return (CxJsonWriter) { 1204 return (CxJsonWriter) {

mercurial