ucx/json.c

changeset 1040
473d8cb58a6c
parent 1035
86d3a45dc928
equal deleted inserted replaced
1039:6691e007cef7 1040:473d8cb58a6c
96 } 96 }
97 97
98 static CxJsonToken token_create(CxJson *json, bool isstring, size_t start, size_t end) { 98 static CxJsonToken token_create(CxJson *json, bool isstring, size_t start, size_t end) {
99 cxmutstr str = cx_mutstrn(json->buffer.space + start, end - start); 99 cxmutstr str = cx_mutstrn(json->buffer.space + start, end - start);
100 bool allocated = false; 100 bool allocated = false;
101 if (json->uncompleted.tokentype != CX_JSON_NO_TOKEN) { 101 if (json->uncompleted_tokentype != CX_JSON_NO_TOKEN) {
102 allocated = true; 102 allocated = true;
103 str = cx_strcat_m(json->uncompleted.content, 1, str); 103 str = cx_strcat(json->uncompleted_content, 1, str);
104 if (str.ptr == NULL) { // LCOV_EXCL_START 104 if (str.ptr == NULL) {
105 return (CxJsonToken){CX_JSON_NO_TOKEN, false, {NULL, 0}}; 105 return (CxJsonToken){CX_JSON_NO_TOKEN, false, CX_NULLSTR}; // LCOV_EXCL_LINE
106 } // LCOV_EXCL_STOP 106 }
107 } 107 json->uncompleted_content = CX_NULLSTR;
108 json->uncompleted = (CxJsonToken){0}; 108 json->uncompleted_tokentype = CX_JSON_NO_TOKEN;
109 }
109 CxJsonTokenType ttype; 110 CxJsonTokenType ttype;
110 if (isstring) { 111 if (isstring) {
111 ttype = CX_JSON_TOKEN_STRING; 112 ttype = CX_JSON_TOKEN_STRING;
112 } else { 113 } else {
113 cxstring s = cx_strcast(str); 114 if (!cx_strcmp(str, "true") || !cx_strcmp(str, "false")
114 if (!cx_strcmp(s, "true") || !cx_strcmp(s, "false") 115 || !cx_strcmp(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 }
121 if (ttype == CX_JSON_TOKEN_ERROR) { 121 if (ttype == CX_JSON_TOKEN_ERROR) {
122 if (allocated) { 122 if (allocated) {
123 cx_strfree(&str); 123 cx_strfree(&str);
124 } 124 }
125 return (CxJsonToken){CX_JSON_TOKEN_ERROR, false, {NULL, 0}}; 125 return (CxJsonToken){CX_JSON_TOKEN_ERROR, false, CX_NULLSTR};
126 } 126 }
127 return (CxJsonToken){ttype, allocated, str}; 127 return (CxJsonToken){ttype, allocated, str};
128 } 128 }
129 129
130 static CxJsonTokenType char2ttype(char c) { 130 static CxJsonTokenType char2ttype(char c) {
160 } 160 }
161 161
162 static enum cx_json_status token_parse_next(CxJson *json, CxJsonToken *result) { 162 static enum cx_json_status token_parse_next(CxJson *json, CxJsonToken *result) {
163 // check if there is data in the buffer 163 // check if there is data in the buffer
164 if (cxBufferEof(&json->buffer)) { 164 if (cxBufferEof(&json->buffer)) {
165 return json->uncompleted.tokentype == CX_JSON_NO_TOKEN ? 165 return json->uncompleted_tokentype == CX_JSON_NO_TOKEN ?
166 CX_JSON_NO_DATA : CX_JSON_INCOMPLETE_DATA; 166 CX_JSON_NO_DATA : CX_JSON_INCOMPLETE_DATA;
167 } 167 }
168 168
169 // current token type and start index 169 // current token type and start index
170 CxJsonTokenType ttype = json->uncompleted.tokentype; 170 CxJsonTokenType ttype = json->uncompleted_tokentype;
171 size_t token_part_start = json->buffer.pos; 171 size_t token_part_start = json->buffer.pos;
172 172
173 bool escape_end_of_string = ttype == CX_JSON_TOKEN_STRING 173 bool escape_end_of_string = ttype == CX_JSON_TOKEN_STRING
174 && json->uncompleted.content.ptr[json->uncompleted.content.length-1] == '\\'; 174 && cx_strat(json->uncompleted_content, -1) == '\\';
175 175
176 for (size_t i = json->buffer.pos; i < json->buffer.size; i++) { 176 for (size_t i = json->buffer.pos; i < json->buffer.size; i++) {
177 char c = json->buffer.space[i]; 177 char c = json->buffer.space[i];
178 if (ttype != CX_JSON_TOKEN_STRING) { 178 if (ttype != CX_JSON_TOKEN_STRING) {
179 // currently non-string token 179 // currently non-string token
187 ttype = CX_JSON_TOKEN_STRING; 187 ttype = CX_JSON_TOKEN_STRING;
188 token_part_start = i; 188 token_part_start = i;
189 } else if (ctype != CX_JSON_NO_TOKEN) { 189 } else if (ctype != CX_JSON_NO_TOKEN) {
190 // single-char token 190 // single-char token
191 json->buffer.pos = i + 1; 191 json->buffer.pos = i + 1;
192 *result = (CxJsonToken){ctype, false, {NULL, 0}}; 192 *result = (CxJsonToken){ctype, false, CX_NULLSTR};
193 return CX_JSON_NO_ERROR; 193 return CX_JSON_NO_ERROR;
194 } else { 194 } else {
195 ttype = CX_JSON_TOKEN_LITERAL; // number or literal 195 ttype = CX_JSON_TOKEN_LITERAL; // number or literal
196 token_part_start = i; 196 token_part_start = i;
197 } 197 }
230 230
231 if (ttype == CX_JSON_NO_TOKEN) { 231 if (ttype == CX_JSON_NO_TOKEN) {
232 return CX_JSON_NO_DATA; 232 return CX_JSON_NO_DATA;
233 } else { 233 } else {
234 // uncompleted token 234 // uncompleted token
235 size_t uncompleted_len = json->buffer.size - token_part_start; 235 cxstring uncompleted = cx_strn(json->buffer.space + token_part_start, json->buffer.size - token_part_start);
236 if (json->uncompleted.tokentype == CX_JSON_NO_TOKEN) { 236 if (json->uncompleted_tokentype == CX_JSON_NO_TOKEN) {
237 // current token is uncompleted 237 assert(json->uncompleted_content.ptr == NULL);
238 // save current token content 238 json->uncompleted_content = cx_strdup(uncompleted);
239 CxJsonToken uncompleted = { 239 if (json->uncompleted_content.ptr == NULL) {
240 ttype, true,
241 cx_strdup(cx_strn(json->buffer.space + token_part_start, uncompleted_len))
242 };
243 if (uncompleted.content.ptr == NULL) {
244 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE 240 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE
245 } 241 }
246 json->uncompleted = uncompleted; 242 json->uncompleted_tokentype = ttype;
247 } else { 243 } else {
248 // previously we also had an uncompleted token 244 // previously we already had an uncompleted token
249 // combine the uncompleted token with the current token 245 // combine the uncompleted token with the current token
250 assert(json->uncompleted.allocated); 246 cxmutstr s = cx_strcat(json->uncompleted_content, 1, uncompleted);
251 cxmutstr str = cx_strcat_m(json->uncompleted.content, 1, 247 if (s.ptr == NULL) {
252 cx_strn(json->buffer.space + token_part_start, uncompleted_len));
253 if (str.ptr == NULL) {
254 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE 248 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE
255 } 249 }
256 json->uncompleted.content = str; 250 json->uncompleted_content = s;
257 } 251 }
258 // advance the buffer position - we saved the stuff in the uncompleted token 252 // advance the buffer position - we saved the stuff in the uncompleted token
259 json->buffer.pos += uncompleted_len; 253 json->buffer.pos += uncompleted.length;
260 return CX_JSON_INCOMPLETE_DATA; 254 return CX_JSON_INCOMPLETE_DATA;
261 } 255 }
262 } 256 }
263 257
264 // converts a Unicode codepoint to utf8 258 // converts a Unicode codepoint to utf8
562 if (json->vbuf.data != json->vbuf_internal) { 556 if (json->vbuf.data != json->vbuf_internal) {
563 cx_array_free(json->vbuf); 557 cx_array_free(json->vbuf);
564 } 558 }
565 cxJsonValueFree(json->parsed); 559 cxJsonValueFree(json->parsed);
566 json->parsed = NULL; 560 json->parsed = NULL;
567 token_destroy(&json->uncompleted); 561 json->uncompleted_tokentype = CX_JSON_NO_TOKEN;
562 cx_strfree(&json->uncompleted_content);
568 cx_strfree_a(json->allocator, &json->uncompleted_member_name); 563 cx_strfree_a(json->allocator, &json->uncompleted_member_name);
569 } 564 }
570 565
571 void cxJsonReset(CxJson *json) { 566 void cxJsonReset(CxJson *json) {
572 const CxAllocator *allocator = json->allocator; 567 const CxAllocator *allocator = json->allocator;
1081 CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) { 1076 CxJsonValue *cxJsonArrRemove(CxJsonValue *value, size_t index) {
1082 if (index >= value->array.size) { 1077 if (index >= value->array.size) {
1083 return NULL; 1078 return NULL;
1084 } 1079 }
1085 CxJsonValue *ret = value->array.data[index]; 1080 CxJsonValue *ret = value->array.data[index];
1086 // TODO: replace with a low level cx_array_remove() 1081 cx_array_remove(value->array, index);
1087 size_t count = value->array.size - index - 1;
1088 if (count > 0) {
1089 memmove(value->array.data + index, value->array.data + index + 1, count * sizeof(CxJsonValue*));
1090 }
1091 value->array.size--;
1092 return ret; 1082 return ret;
1093 } 1083 }
1094 1084
1095 char *cxJsonAsString(const CxJsonValue *value) { 1085 char *cxJsonAsString(const CxJsonValue *value) {
1096 return value->string.ptr; 1086 return value->string.ptr;
1229 } 1219 }
1230 } 1220 }
1231 1221
1232 // the name 1222 // the name
1233 actual += wfunc("\"", 1, 1, target); 1223 actual += wfunc("\"", 1, 1, target);
1234 cxstring key = cx_strn(member->key->data, member->key->len); 1224 cxstring key = cx_hash_key_as_string(member->key);
1235 cxmutstr name = escape_string(key, settings->escape_slash); 1225 cxmutstr name = escape_string(key, settings->escape_slash);
1236 actual += wfunc(name.ptr, 1, name.length, target); 1226 actual += wfunc(name.ptr, 1, name.length, target);
1237 actual += wfunc("\"", 1, 1, target); 1227 actual += wfunc("\"", 1, 1, target);
1238 const char *obj_name_sep = ": "; 1228 const char *obj_name_sep = ": ";
1239 if (settings->pretty) { 1229 if (settings->pretty) {
1435 static cxmutstr cx_json_to_string(CxJsonValue *value, const CxAllocator *allocator, CxJsonWriter *writer) { 1425 static cxmutstr cx_json_to_string(CxJsonValue *value, const CxAllocator *allocator, CxJsonWriter *writer) {
1436 if (allocator == NULL) allocator = cxDefaultAllocator; 1426 if (allocator == NULL) allocator = cxDefaultAllocator;
1437 CxBuffer buffer; 1427 CxBuffer buffer;
1438 if (cxBufferInit(&buffer, allocator, NULL, 128, 1428 if (cxBufferInit(&buffer, allocator, NULL, 128,
1439 CX_BUFFER_AUTO_EXTEND | CX_BUFFER_DO_NOT_FREE)) { 1429 CX_BUFFER_AUTO_EXTEND | CX_BUFFER_DO_NOT_FREE)) {
1440 return (cxmutstr){NULL, 0}; 1430 return CX_NULLSTR; // LCOV_EXCL_LINE
1441 } 1431 }
1442 if (cx_json_write_rec(&buffer, value, cxBufferWriteFunc, writer, 0) 1432 if (cx_json_write_rec(&buffer, value, cxBufferWriteFunc, writer, 0)
1443 || cxBufferTerminate(&buffer)) { 1433 || cxBufferTerminate(&buffer)) {
1444 // LCOV_EXCL_START 1434 // LCOV_EXCL_START
1445 buffer.flags &= ~CX_BUFFER_DO_NOT_FREE; 1435 buffer.flags &= ~CX_BUFFER_DO_NOT_FREE;
1446 cxBufferDestroy(&buffer); 1436 cxBufferDestroy(&buffer);
1447 return (cxmutstr){NULL, 0}; 1437 return CX_NULLSTR;
1448 // LCOV_EXCL_STOP 1438 // LCOV_EXCL_STOP
1449 } else { 1439 } else {
1450 cxmutstr str = cx_mutstrn(buffer.space, buffer.size); 1440 cxmutstr str = cx_bstr_m(&buffer);
1451 cxBufferDestroy(&buffer); 1441 cxBufferDestroy(&buffer);
1452 return str; 1442 return str;
1453 } 1443 }
1454 1444
1455 } 1445 }
1493 } 1483 }
1494 case CX_JSON_NUMBER: 1484 case CX_JSON_NUMBER:
1495 return cx_vcmp_double(json->number, cxJsonAsDouble(other)); 1485 return cx_vcmp_double(json->number, cxJsonAsDouble(other));
1496 case CX_JSON_LITERAL: 1486 case CX_JSON_LITERAL:
1497 return json->literal == other->literal ? 0 : -1; 1487 return json->literal == other->literal ? 0 : -1;
1498 default: 1488 default: // LCOV_EXCL_START
1499 // LCOV_EXCL_START
1500 // unreachable 1489 // unreachable
1501 assert(false); 1490 assert(false);
1502 return -1; 1491 return -1;
1503 // LCOV_EXCL_STOP 1492 // LCOV_EXCL_STOP
1504 } 1493 }
1507 CxJsonValue* cxJsonClone(const CxJsonValue* value, const CxAllocator* allocator) { 1496 CxJsonValue* cxJsonClone(const CxJsonValue* value, const CxAllocator* allocator) {
1508 return cx_json_clone_func(NULL, value, allocator, NULL); 1497 return cx_json_clone_func(NULL, value, allocator, NULL);
1509 } 1498 }
1510 1499
1511 CxJsonValue* cx_json_clone_func(CxJsonValue* target, const CxJsonValue* source, 1500 CxJsonValue* cx_json_clone_func(CxJsonValue* target, const CxJsonValue* source,
1512 const CxAllocator* allocator, cx_attr_unused void *data) { 1501 const CxAllocator* allocator, CX_UNUSED void *data) {
1513 if (source == NULL || source->type == CX_JSON_NOTHING) { 1502 if (source == NULL || source->type == CX_JSON_NOTHING) {
1514 return &cx_json_value_nothing; 1503 return &cx_json_value_nothing;
1515 } 1504 }
1516 if (allocator == NULL) allocator = cxDefaultAllocator; 1505 if (allocator == NULL) allocator = cxDefaultAllocator;
1517 1506
1519 CxJsonValue *ret = v; \ 1508 CxJsonValue *ret = v; \
1520 if (target == NULL) { \ 1509 if (target == NULL) { \
1521 return ret; \ 1510 return ret; \
1522 } else { \ 1511 } else { \
1523 *target = *ret; \ 1512 *target = *ret; \
1524 cxFree(allocator, ret); \ 1513 ret->type = CX_JSON_UNINITIALIZED; \
1514 cxJsonValueFree(ret); \
1525 return target; \ 1515 return target; \
1526 } \ 1516 } \
1527 } 1517 }
1528 1518
1529 switch (source->type) { 1519 switch (source->type) {
1543 CxJsonValue *arr = cxJsonCreateArr(allocator, elem_count); 1533 CxJsonValue *arr = cxJsonCreateArr(allocator, elem_count);
1544 if (arr == NULL) return NULL; // LCOV_EXCL_LINE 1534 if (arr == NULL) return NULL; // LCOV_EXCL_LINE
1545 arr->array.size = elem_count; 1535 arr->array.size = elem_count;
1546 for (size_t i = 0 ; i < elem_count ; i++) { 1536 for (size_t i = 0 ; i < elem_count ; i++) {
1547 CxJsonValue *e = cx_json_clone_func(NULL, source->array.data[i], allocator, NULL); 1537 CxJsonValue *e = cx_json_clone_func(NULL, source->array.data[i], allocator, NULL);
1548 if (e == NULL) { 1538 if (e == NULL) { // LCOV_EXCL_START
1549 // LCOV_EXCL_START
1550 cxJsonValueFree(arr); 1539 cxJsonValueFree(arr);
1551 return NULL; 1540 return NULL;
1552 // LCOV_EXCL_STOP 1541 // LCOV_EXCL_STOP
1553 } 1542 }
1554 arr->array.data[i] = e; 1543 arr->array.data[i] = e;
1561 return_value(cxJsonCreateInteger(allocator, source->integer)); 1550 return_value(cxJsonCreateInteger(allocator, source->integer));
1562 case CX_JSON_NUMBER: 1551 case CX_JSON_NUMBER:
1563 return_value(cxJsonCreateNumber(allocator, source->number)); 1552 return_value(cxJsonCreateNumber(allocator, source->number));
1564 case CX_JSON_LITERAL: 1553 case CX_JSON_LITERAL:
1565 return_value(cxJsonCreateLiteral(allocator, source->literal)); 1554 return_value(cxJsonCreateLiteral(allocator, source->literal));
1566 default: 1555 default: // LCOV_EXCL_START
1567 // LCOV_EXCL_START
1568 // unreachable 1556 // unreachable
1569 assert(false); 1557 assert(false);
1570 return NULL; 1558 return NULL;
1571 // LCOV_EXCL_STOP 1559 // LCOV_EXCL_STOP
1572 } 1560 }

mercurial