ucx/json.c

branch
dav-2
changeset 894
e86049631677
parent 891
4d58cbcc9efa
equal deleted inserted replaced
893:38800d479cd4 894:e86049631677
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;
1224 } 1219 }
1225 } 1220 }
1226 1221
1227 // the name 1222 // the name
1228 actual += wfunc("\"", 1, 1, target); 1223 actual += wfunc("\"", 1, 1, target);
1229 cxstring key = cx_strn(member->key->data, member->key->len); 1224 cxstring key = cx_hash_key_as_string(member->key);
1230 cxmutstr name = escape_string(key, settings->escape_slash); 1225 cxmutstr name = escape_string(key, settings->escape_slash);
1231 actual += wfunc(name.ptr, 1, name.length, target); 1226 actual += wfunc(name.ptr, 1, name.length, target);
1232 actual += wfunc("\"", 1, 1, target); 1227 actual += wfunc("\"", 1, 1, target);
1233 const char *obj_name_sep = ": "; 1228 const char *obj_name_sep = ": ";
1234 if (settings->pretty) { 1229 if (settings->pretty) {
1430 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) {
1431 if (allocator == NULL) allocator = cxDefaultAllocator; 1426 if (allocator == NULL) allocator = cxDefaultAllocator;
1432 CxBuffer buffer; 1427 CxBuffer buffer;
1433 if (cxBufferInit(&buffer, allocator, NULL, 128, 1428 if (cxBufferInit(&buffer, allocator, NULL, 128,
1434 CX_BUFFER_AUTO_EXTEND | CX_BUFFER_DO_NOT_FREE)) { 1429 CX_BUFFER_AUTO_EXTEND | CX_BUFFER_DO_NOT_FREE)) {
1435 return (cxmutstr){NULL, 0}; 1430 return CX_NULLSTR; // LCOV_EXCL_LINE
1436 } 1431 }
1437 if (cx_json_write_rec(&buffer, value, cxBufferWriteFunc, writer, 0) 1432 if (cx_json_write_rec(&buffer, value, cxBufferWriteFunc, writer, 0)
1438 || cxBufferTerminate(&buffer)) { 1433 || cxBufferTerminate(&buffer)) {
1439 // LCOV_EXCL_START 1434 // LCOV_EXCL_START
1440 buffer.flags &= ~CX_BUFFER_DO_NOT_FREE; 1435 buffer.flags &= ~CX_BUFFER_DO_NOT_FREE;
1441 cxBufferDestroy(&buffer); 1436 cxBufferDestroy(&buffer);
1442 return (cxmutstr){NULL, 0}; 1437 return CX_NULLSTR;
1443 // LCOV_EXCL_STOP 1438 // LCOV_EXCL_STOP
1444 } else { 1439 } else {
1445 cxmutstr str = cx_mutstrn(buffer.space, buffer.size); 1440 cxmutstr str = cx_bstr_m(&buffer);
1446 cxBufferDestroy(&buffer); 1441 cxBufferDestroy(&buffer);
1447 return str; 1442 return str;
1448 } 1443 }
1449 1444
1450 } 1445 }
1488 } 1483 }
1489 case CX_JSON_NUMBER: 1484 case CX_JSON_NUMBER:
1490 return cx_vcmp_double(json->number, cxJsonAsDouble(other)); 1485 return cx_vcmp_double(json->number, cxJsonAsDouble(other));
1491 case CX_JSON_LITERAL: 1486 case CX_JSON_LITERAL:
1492 return json->literal == other->literal ? 0 : -1; 1487 return json->literal == other->literal ? 0 : -1;
1493 default: 1488 default: // LCOV_EXCL_START
1494 // LCOV_EXCL_START
1495 // unreachable 1489 // unreachable
1496 assert(false); 1490 assert(false);
1497 return -1; 1491 return -1;
1498 // LCOV_EXCL_STOP 1492 // LCOV_EXCL_STOP
1499 } 1493 }
1502 CxJsonValue* cxJsonClone(const CxJsonValue* value, const CxAllocator* allocator) { 1496 CxJsonValue* cxJsonClone(const CxJsonValue* value, const CxAllocator* allocator) {
1503 return cx_json_clone_func(NULL, value, allocator, NULL); 1497 return cx_json_clone_func(NULL, value, allocator, NULL);
1504 } 1498 }
1505 1499
1506 CxJsonValue* cx_json_clone_func(CxJsonValue* target, const CxJsonValue* source, 1500 CxJsonValue* cx_json_clone_func(CxJsonValue* target, const CxJsonValue* source,
1507 const CxAllocator* allocator, cx_attr_unused void *data) { 1501 const CxAllocator* allocator, CX_UNUSED void *data) {
1508 if (source == NULL || source->type == CX_JSON_NOTHING) { 1502 if (source == NULL || source->type == CX_JSON_NOTHING) {
1509 return &cx_json_value_nothing; 1503 return &cx_json_value_nothing;
1510 } 1504 }
1511 if (allocator == NULL) allocator = cxDefaultAllocator; 1505 if (allocator == NULL) allocator = cxDefaultAllocator;
1512 1506
1514 CxJsonValue *ret = v; \ 1508 CxJsonValue *ret = v; \
1515 if (target == NULL) { \ 1509 if (target == NULL) { \
1516 return ret; \ 1510 return ret; \
1517 } else { \ 1511 } else { \
1518 *target = *ret; \ 1512 *target = *ret; \
1519 cxFree(allocator, ret); \ 1513 ret->type = CX_JSON_UNINITIALIZED; \
1514 cxJsonValueFree(ret); \
1520 return target; \ 1515 return target; \
1521 } \ 1516 } \
1522 } 1517 }
1523 1518
1524 switch (source->type) { 1519 switch (source->type) {
1538 CxJsonValue *arr = cxJsonCreateArr(allocator, elem_count); 1533 CxJsonValue *arr = cxJsonCreateArr(allocator, elem_count);
1539 if (arr == NULL) return NULL; // LCOV_EXCL_LINE 1534 if (arr == NULL) return NULL; // LCOV_EXCL_LINE
1540 arr->array.size = elem_count; 1535 arr->array.size = elem_count;
1541 for (size_t i = 0 ; i < elem_count ; i++) { 1536 for (size_t i = 0 ; i < elem_count ; i++) {
1542 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);
1543 if (e == NULL) { 1538 if (e == NULL) { // LCOV_EXCL_START
1544 // LCOV_EXCL_START
1545 cxJsonValueFree(arr); 1539 cxJsonValueFree(arr);
1546 return NULL; 1540 return NULL;
1547 // LCOV_EXCL_STOP 1541 // LCOV_EXCL_STOP
1548 } 1542 }
1549 arr->array.data[i] = e; 1543 arr->array.data[i] = e;
1556 return_value(cxJsonCreateInteger(allocator, source->integer)); 1550 return_value(cxJsonCreateInteger(allocator, source->integer));
1557 case CX_JSON_NUMBER: 1551 case CX_JSON_NUMBER:
1558 return_value(cxJsonCreateNumber(allocator, source->number)); 1552 return_value(cxJsonCreateNumber(allocator, source->number));
1559 case CX_JSON_LITERAL: 1553 case CX_JSON_LITERAL:
1560 return_value(cxJsonCreateLiteral(allocator, source->literal)); 1554 return_value(cxJsonCreateLiteral(allocator, source->literal));
1561 default: 1555 default: // LCOV_EXCL_START
1562 // LCOV_EXCL_START
1563 // unreachable 1556 // unreachable
1564 assert(false); 1557 assert(false);
1565 return NULL; 1558 return NULL;
1566 // LCOV_EXCL_STOP 1559 // LCOV_EXCL_STOP
1567 } 1560 }

mercurial