src/json.c

changeset 1065
6eb7b54975ee
parent 1060
0a7c1bb2372d
child 1067
7799addf475f
equal deleted inserted replaced
1064:f3b04cd60776 1065:6eb7b54975ee
97 cxmutstr str = cx_mutstrn(json->buffer.space + start, end - start); 97 cxmutstr str = cx_mutstrn(json->buffer.space + start, end - start);
98 bool allocated = false; 98 bool allocated = false;
99 if (json->uncompleted.tokentype != CX_JSON_NO_TOKEN) { 99 if (json->uncompleted.tokentype != CX_JSON_NO_TOKEN) {
100 allocated = true; 100 allocated = true;
101 str = cx_strcat_m(json->uncompleted.content, 1, str); 101 str = cx_strcat_m(json->uncompleted.content, 1, str);
102 if (str.ptr == NULL) { 102 if (str.ptr == NULL) { // LCOV_EXCL_START
103 return (CxJsonToken){CX_JSON_NO_TOKEN, false, {NULL, 0}}; 103 return (CxJsonToken){CX_JSON_NO_TOKEN, false, {NULL, 0}};
104 } 104 } // LCOV_EXCL_STOP
105 } 105 }
106 json->uncompleted = (CxJsonToken){0}; 106 json->uncompleted = (CxJsonToken){0};
107 CxJsonTokenType ttype; 107 CxJsonTokenType ttype;
108 if (isstring) { 108 if (isstring) {
109 ttype = CX_JSON_TOKEN_STRING; 109 ttype = CX_JSON_TOKEN_STRING;
193 } else { 193 } else {
194 // finish token 194 // finish token
195 if (ctype != CX_JSON_NO_TOKEN) { 195 if (ctype != CX_JSON_NO_TOKEN) {
196 *result = token_create(json, false, token_start, i); 196 *result = token_create(json, false, token_start, i);
197 if (result->tokentype == CX_JSON_NO_TOKEN) { 197 if (result->tokentype == CX_JSON_NO_TOKEN) {
198 return CX_JSON_BUFFER_ALLOC_FAILED; 198 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE
199 } 199 }
200 if (result->tokentype == CX_JSON_TOKEN_ERROR) { 200 if (result->tokentype == CX_JSON_TOKEN_ERROR) {
201 return CX_JSON_FORMAT_ERROR_NUMBER; 201 return CX_JSON_FORMAT_ERROR_NUMBER;
202 } 202 }
203 json->buffer.pos = i; 203 json->buffer.pos = i;
210 json->tokenizer_escape = false; 210 json->tokenizer_escape = false;
211 } else { 211 } else {
212 if (c == '"') { 212 if (c == '"') {
213 *result = token_create(json, true, token_start, i + 1); 213 *result = token_create(json, true, token_start, i + 1);
214 if (result->tokentype == CX_JSON_NO_TOKEN) { 214 if (result->tokentype == CX_JSON_NO_TOKEN) {
215 return CX_JSON_BUFFER_ALLOC_FAILED; 215 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE
216 } 216 }
217 json->buffer.pos = i + 1; 217 json->buffer.pos = i + 1;
218 return CX_JSON_NO_ERROR; 218 return CX_JSON_NO_ERROR;
219 } else if (c == '\\') { 219 } else if (c == '\\') {
220 json->tokenizer_escape = true; 220 json->tokenizer_escape = true;
232 CxJsonToken uncompleted = { 232 CxJsonToken uncompleted = {
233 ttype, true, 233 ttype, true,
234 cx_strdup(cx_strn(json->buffer.space + token_start, uncompleted_len)) 234 cx_strdup(cx_strn(json->buffer.space + token_start, uncompleted_len))
235 }; 235 };
236 if (uncompleted.content.ptr == NULL) { 236 if (uncompleted.content.ptr == NULL) {
237 return CX_JSON_BUFFER_ALLOC_FAILED; 237 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE
238 } 238 }
239 json->uncompleted = uncompleted; 239 json->uncompleted = uncompleted;
240 } else { 240 } else {
241 // previously we also had an uncompleted token 241 // previously we also had an uncompleted token
242 // combine the uncompleted token with the current token 242 // combine the uncompleted token with the current token
243 assert(json->uncompleted.allocated); 243 assert(json->uncompleted.allocated);
244 cxmutstr str = cx_strcat_m(json->uncompleted.content, 1, 244 cxmutstr str = cx_strcat_m(json->uncompleted.content, 1,
245 cx_strn(json->buffer.space + token_start, uncompleted_len)); 245 cx_strn(json->buffer.space + token_start, uncompleted_len));
246 if (str.ptr == NULL) { 246 if (str.ptr == NULL) {
247 return CX_JSON_BUFFER_ALLOC_FAILED; 247 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE
248 } 248 }
249 json->uncompleted.content = str; 249 json->uncompleted.content = str;
250 } 250 }
251 // advance the buffer position - we saved the stuff in the uncompleted token 251 // advance the buffer position - we saved the stuff in the uncompleted token
252 json->buffer.pos += uncompleted_len; 252 json->buffer.pos += uncompleted_len;
259 // TODO: support more escape sequences 259 // TODO: support more escape sequences
260 // we know that the unescaped string will be shorter by at least 2 chars 260 // we know that the unescaped string will be shorter by at least 2 chars
261 cxmutstr result; 261 cxmutstr result;
262 result.length = 0; 262 result.length = 0;
263 result.ptr = cxMalloc(a, str.length - 1); 263 result.ptr = cxMalloc(a, str.length - 1);
264 if (result.ptr == NULL) { 264 if (result.ptr == NULL) return result; // LCOV_EXCL_LINE
265 return result;
266 }
267 265
268 bool u = false; 266 bool u = false;
269 for (size_t i = 1; i < str.length - 1; i++) { 267 for (size_t i = 1; i < str.length - 1; i++) {
270 char c = str.ptr[i]; 268 char c = str.ptr[i];
271 if (u) { 269 if (u) {
289 return result; 287 return result;
290 } 288 }
291 289
292 static CxJsonValue* create_json_value(CxJson *json, CxJsonValueType type) { 290 static CxJsonValue* create_json_value(CxJson *json, CxJsonValueType type) {
293 CxJsonValue *v = cxMalloc(json->allocator, sizeof(CxJsonValue)); 291 CxJsonValue *v = cxMalloc(json->allocator, sizeof(CxJsonValue));
294 if (v == NULL) { 292 if (v == NULL) return NULL; // LCOV_EXCL_LINE
295 return NULL;
296 }
297 293
298 // initialize the value 294 // initialize the value
299 if (type == CX_JSON_ARRAY) { 295 if (type == CX_JSON_ARRAY) {
300 cx_array_initialize_a(json->allocator, v->value.array.array, 16); 296 cx_array_initialize_a(json->allocator, v->value.array.array, 16);
301 if (v->value.array.array == NULL) { 297 if (v->value.array.array == NULL) { // LCOV_EXCL_START
302 cxFree(json->allocator, v); 298 cxFree(json->allocator, v);
303 return NULL; 299 return NULL;
304 } 300 } // LCOV_EXCL_STOP
305 } else if (type == CX_JSON_OBJECT) { 301 } else if (type == CX_JSON_OBJECT) {
306 cx_array_initialize_a(json->allocator, v->value.object.values, 16); 302 cx_array_initialize_a(json->allocator, v->value.object.values, 16);
307 if (v->value.object.values == NULL) { 303 if (v->value.object.values == NULL) { // LCOV_EXCL_START
308 cxFree(json->allocator, v); 304 cxFree(json->allocator, v);
309 return NULL; 305 return NULL;
310 } 306 } // LCOV_EXCL_STOP
311 } else { 307 } else {
312 memset(v, 0, sizeof(CxJsonValue)); 308 memset(v, 0, sizeof(CxJsonValue));
313 } 309 }
314 v->type = type; 310 v->type = type;
315 v->allocator = json->allocator; 311 v->allocator = json->allocator;
323 } else if (parent->type == CX_JSON_OBJECT) { 319 } else if (parent->type == CX_JSON_OBJECT) {
324 assert(parent->value.object.values_size > 0); 320 assert(parent->value.object.values_size > 0);
325 assert(parent->value.object.values[parent->value.object.values_size - 1].value == NULL); 321 assert(parent->value.object.values[parent->value.object.values_size - 1].value == NULL);
326 parent->value.object.values[parent->value.object.values_size - 1].value = v; 322 parent->value.object.values[parent->value.object.values_size - 1].value = v;
327 } else { 323 } else {
328 assert(false); 324 assert(false); // LCOV_EXCL_LINE
329 } 325 }
330 } 326 }
331 327
332 // add the new value to the stack, if it is an array or object 328 // add the new value to the stack, if it is an array or object
333 if (type == CX_JSON_ARRAY || type == CX_JSON_OBJECT) { 329 if (type == CX_JSON_ARRAY || type == CX_JSON_OBJECT) {
334 CxArrayReallocator vbuf_realloc = cx_array_reallocator(NULL, json->vbuf_internal); 330 CxArrayReallocator vbuf_realloc = cx_array_reallocator(NULL, json->vbuf_internal);
335 if (cx_array_simple_add_a(&vbuf_realloc, json->vbuf, v)) { 331 if (cx_array_simple_add_a(&vbuf_realloc, json->vbuf, v)) {
332 // LCOV_EXCL_START
336 cxFree(json->allocator, v); 333 cxFree(json->allocator, v);
337 return NULL; 334 return NULL;
338 } 335 } // LCOV_EXCL_STOP
339 } 336 }
340 337
341 // if currently no value is parsed, this is now the value of interest 338 // if currently no value is parsed, this is now the value of interest
342 if (json->parsed == NULL) { 339 if (json->parsed == NULL) {
343 json->parsed = v; 340 json->parsed = v;
426 int state = json->states[--json->states_size]; 423 int state = json->states[--json->states_size];
427 424
428 // guarantee that at least two more states fit on the stack 425 // guarantee that at least two more states fit on the stack
429 CxArrayReallocator state_realloc = cx_array_reallocator(NULL, json->states_internal); 426 CxArrayReallocator state_realloc = cx_array_reallocator(NULL, json->states_internal);
430 if (cx_array_simple_reserve_a(&state_realloc, json->states, 2)) { 427 if (cx_array_simple_reserve_a(&state_realloc, json->states, 2)) {
431 return CX_JSON_BUFFER_ALLOC_FAILED; 428 return CX_JSON_BUFFER_ALLOC_FAILED; // LCOV_EXCL_LINE
432 } 429 }
433 430
434 431
435 // 0 JP_STATE_VALUE_BEGIN value begin 432 // 0 JP_STATE_VALUE_BEGIN value begin
436 // 10 JP_STATE_VALUE_END expect value end 433 // 10 JP_STATE_VALUE_END expect value end
446 // push expected end state to the stack 443 // push expected end state to the stack
447 json_add_state(json, 10 + state); 444 json_add_state(json, 10 + state);
448 switch (token.tokentype) { 445 switch (token.tokentype) {
449 case CX_JSON_TOKEN_BEGIN_ARRAY: { 446 case CX_JSON_TOKEN_BEGIN_ARRAY: {
450 if (create_json_value(json, CX_JSON_ARRAY) == NULL) { 447 if (create_json_value(json, CX_JSON_ARRAY) == NULL) {
451 return_rec(CX_JSON_VALUE_ALLOC_FAILED); 448 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
452 } 449 }
453 json_add_state(json, JP_STATE_VALUE_BEGIN_AR); 450 json_add_state(json, JP_STATE_VALUE_BEGIN_AR);
454 return_rec(CX_JSON_NO_ERROR); 451 return_rec(CX_JSON_NO_ERROR);
455 } 452 }
456 case CX_JSON_TOKEN_BEGIN_OBJECT: { 453 case CX_JSON_TOKEN_BEGIN_OBJECT: {
457 if (create_json_value(json, CX_JSON_OBJECT) == NULL) { 454 if (create_json_value(json, CX_JSON_OBJECT) == NULL) {
458 return_rec(CX_JSON_VALUE_ALLOC_FAILED); 455 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
459 } 456 }
460 json_add_state(json, JP_STATE_OBJ_NAME_OR_CLOSE); 457 json_add_state(json, JP_STATE_OBJ_NAME_OR_CLOSE);
461 return_rec(CX_JSON_NO_ERROR); 458 return_rec(CX_JSON_NO_ERROR);
462 } 459 }
463 case CX_JSON_TOKEN_STRING: { 460 case CX_JSON_TOKEN_STRING: {
464 if ((vbuf = create_json_value(json, CX_JSON_STRING)) == NULL) { 461 if ((vbuf = create_json_value(json, CX_JSON_STRING)) == NULL) {
465 return_rec(CX_JSON_VALUE_ALLOC_FAILED); 462 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
466 } 463 }
467 cxmutstr str = unescape_string(json->allocator, token.content); 464 cxmutstr str = unescape_string(json->allocator, token.content);
468 if (str.ptr == NULL) { 465 if (str.ptr == NULL) {
469 return_rec(CX_JSON_VALUE_ALLOC_FAILED); 466 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
470 } 467 }
471 vbuf->value.string = str; 468 vbuf->value.string = str;
472 return_rec(CX_JSON_NO_ERROR); 469 return_rec(CX_JSON_NO_ERROR);
473 } 470 }
474 case CX_JSON_TOKEN_INTEGER: 471 case CX_JSON_TOKEN_INTEGER:
475 case CX_JSON_TOKEN_NUMBER: { 472 case CX_JSON_TOKEN_NUMBER: {
476 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER; 473 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER;
477 if (NULL == (vbuf = create_json_value(json, type))) { 474 if (NULL == (vbuf = create_json_value(json, type))) {
478 return_rec(CX_JSON_VALUE_ALLOC_FAILED); 475 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
479 } 476 }
480 if (type == CX_JSON_INTEGER) { 477 if (type == CX_JSON_INTEGER) {
481 if (cx_strtoi64(token.content, &vbuf->value.integer, 10)) { 478 if (cx_strtoi64(token.content, &vbuf->value.integer, 10)) {
482 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); 479 return_rec(CX_JSON_FORMAT_ERROR_NUMBER);
483 } 480 }
488 } 485 }
489 return_rec(CX_JSON_NO_ERROR); 486 return_rec(CX_JSON_NO_ERROR);
490 } 487 }
491 case CX_JSON_TOKEN_LITERAL: { 488 case CX_JSON_TOKEN_LITERAL: {
492 if ((vbuf = create_json_value(json, CX_JSON_LITERAL)) == NULL) { 489 if ((vbuf = create_json_value(json, CX_JSON_LITERAL)) == NULL) {
493 return_rec(CX_JSON_VALUE_ALLOC_FAILED); 490 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
494 } 491 }
495 if (0 == cx_strcmp(cx_strcast(token.content), cx_str("true"))) { 492 if (0 == cx_strcmp(cx_strcast(token.content), cx_str("true"))) {
496 vbuf->value.literal = CX_JSON_TRUE; 493 vbuf->value.literal = CX_JSON_TRUE;
497 } else if (0 == cx_strcmp(cx_strcast(token.content), cx_str("false"))) { 494 } else if (0 == cx_strcmp(cx_strcast(token.content), cx_str("false"))) {
498 vbuf->value.literal = CX_JSON_FALSE; 495 vbuf->value.literal = CX_JSON_FALSE;
529 } 526 }
530 527
531 // add new entry 528 // add new entry
532 cxmutstr name = unescape_string(json->allocator, token.content); 529 cxmutstr name = unescape_string(json->allocator, token.content);
533 if (name.ptr == NULL) { 530 if (name.ptr == NULL) {
534 return_rec(CX_JSON_VALUE_ALLOC_FAILED); 531 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
535 } 532 }
536 CxJsonObjValue kv = {name, NULL}; 533 CxJsonObjValue kv = {name, NULL};
537 assert(json->vbuf_size > 0); 534 assert(json->vbuf_size > 0);
538 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1]; 535 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1];
539 assert(parent != NULL); 536 assert(parent != NULL);
540 assert(parent->type == CX_JSON_OBJECT); 537 assert(parent->type == CX_JSON_OBJECT);
541 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL); 538 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL);
542 if (cx_array_simple_add_a(&value_realloc, parent->value.object.values, kv)) { 539 if (cx_array_simple_add_a(&value_realloc, parent->value.object.values, kv)) {
543 return_rec(CX_JSON_VALUE_ALLOC_FAILED); 540 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE
544 } 541 }
545 542
546 // next state 543 // next state
547 json_add_state(json, JP_STATE_OBJ_COLON); 544 json_add_state(json, JP_STATE_OBJ_COLON);
548 return_rec(CX_JSON_NO_ERROR); 545 return_rec(CX_JSON_NO_ERROR);
704 v->type = CX_JSON_LITERAL; 701 v->type = CX_JSON_LITERAL;
705 v->value.literal = lit; 702 v->value.literal = lit;
706 return v; 703 return v;
707 } 704 }
708 705
706 // LCOV_EXCL_START
707 // never called as long as malloc() does not return NULL
709 static void cx_json_arr_free_temp(CxJsonValue** values, size_t count) { 708 static void cx_json_arr_free_temp(CxJsonValue** values, size_t count) {
710 for (size_t i = 0; i < count; i++) { 709 for (size_t i = 0; i < count; i++) {
711 if (values[i] == NULL) break; 710 if (values[i] == NULL) break;
712 cxJsonValueFree(values[i]); 711 cxJsonValueFree(values[i]);
713 } 712 }
714 free(values); 713 free(values);
715 } 714 }
715 // LCOV_EXCL_STOP
716 716
717 int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count) { 717 int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count) {
718 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*)); 718 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*));
719 if (values == NULL) return -1; 719 if (values == NULL) return -1;
720 for (size_t i = 0; i < count; i++) { 720 for (size_t i = 0; i < count; i++) {

mercurial