| 264 |
264 |
| 265 CxJsonToken ret = {CX_JSON_NO_TOKEN, NULL, 0, 0}; |
265 CxJsonToken ret = {CX_JSON_NO_TOKEN, NULL, 0, 0}; |
| 266 return ret; |
266 return ret; |
| 267 } |
267 } |
| 268 |
268 |
| 269 static cxmutstr unescape_string(const char *str, size_t len) { |
269 static cxmutstr unescape_string(const CxAllocator *a, const char *str, size_t len) { |
| 270 // TODO: support more escape sequences |
270 // TODO: support more escape sequences |
| 271 // we know that the unescaped string will be shorter by at least 2 chars |
271 // we know that the unescaped string will be shorter by at least 2 chars |
| 272 cxmutstr result; |
272 cxmutstr result; |
| 273 result.length = 0; |
273 result.length = 0; |
| 274 result.ptr = malloc(len - 1); |
274 result.ptr = cxMalloc(a, len - 1); |
| 275 if (result.ptr == NULL) { |
275 if (result.ptr == NULL) { |
| 276 // TODO: check if this actually leads to correct error handling |
276 // TODO: check if this actually leads to correct error handling |
| 277 return result; |
277 return result; |
| 278 } |
278 } |
| 279 |
279 |
| 435 end_elm(p, CX_JSON_READER_ARRAY_END); |
435 end_elm(p, CX_JSON_READER_ARRAY_END); |
| 436 break; |
436 break; |
| 437 } |
437 } |
| 438 case CX_JSON_TOKEN_STRING: { |
438 case CX_JSON_TOKEN_STRING: { |
| 439 p->reader_type = CX_JSON_READER_STRING; |
439 p->reader_type = CX_JSON_READER_STRING; |
| 440 cxmutstr str = unescape_string(token.content, token.length); |
440 cxmutstr str = unescape_string(p->allocator, token.content, token.length); |
| 441 if (str.ptr) { |
441 if (str.ptr) { |
| 442 p->value_str = str.ptr; |
442 p->value_str = str.ptr; |
| 443 p->value_str_len = str.length; |
443 p->value_str_len = str.length; |
| 444 } else { |
444 } else { |
| 445 ret = -1; |
445 ret = -1; |
| 485 } else { |
485 } else { |
| 486 // expect string |
486 // expect string |
| 487 if (token.tokentype != CX_JSON_TOKEN_STRING) return -1; |
487 if (token.tokentype != CX_JSON_TOKEN_STRING) return -1; |
| 488 |
488 |
| 489 if (p->value_name) free(p->value_name); |
489 if (p->value_name) free(p->value_name); |
| 490 cxmutstr valname = unescape_string(token.content, token.length); |
490 cxmutstr valname = unescape_string(p->allocator, token.content, token.length); |
| 491 p->value_name = valname.ptr; |
491 p->value_name = valname.ptr; |
| 492 p->value_name_len = valname.length; |
492 p->value_name_len = valname.length; |
| 493 |
493 |
| 494 // next state |
494 // next state |
| 495 p->states[p->nstates] = JP_STATE_OBJ_COLON; |
495 p->states[p->nstates] = JP_STATE_OBJ_COLON; |
| 547 |
547 |
| 548 static int add_to_parent(CxJson *p, CxJsonValue *parent, CxJsonValue *v) { |
548 static int add_to_parent(CxJson *p, CxJsonValue *parent, CxJsonValue *v) { |
| 549 if (!parent) { |
549 if (!parent) { |
| 550 return -1; // shouldn't happen but who knows |
550 return -1; // shouldn't happen but who knows |
| 551 } |
551 } |
| 552 |
552 |
| |
553 CxArrayReallocator reallocator = cx_array_reallocator(p->allocator, NULL); |
| 553 if (parent->type == CX_JSON_OBJECT) { |
554 if (parent->type == CX_JSON_OBJECT) { |
| 554 if (!p->value_name || p->value_name_len == 0) { |
555 if (!p->value_name || p->value_name_len == 0) { |
| 555 return -1; |
556 return -1; |
| 556 } |
557 } |
| 557 char *valuename = p->value_name; |
558 char *valuename = p->value_name; |
| 559 |
560 |
| 560 CxJsonObjValue newvalue; |
561 CxJsonObjValue newvalue; |
| 561 newvalue.name = valuename; |
562 newvalue.name = valuename; |
| 562 newvalue.value = v; |
563 newvalue.value = v; |
| 563 |
564 |
| 564 return cx_array_simple_add(parent->value.object.values, newvalue); |
565 return cx_array_add( |
| |
566 &parent->value.object.values, |
| |
567 &parent->value.object.values_size, |
| |
568 &parent->value.object.values_capacity, |
| |
569 sizeof(CxJsonObjValue), |
| |
570 &newvalue, |
| |
571 &reallocator); |
| 565 } else if (parent->type == CX_JSON_ARRAY) { |
572 } else if (parent->type == CX_JSON_ARRAY) { |
| 566 return cx_array_simple_add(parent->value.array.array, v); |
573 return cx_array_add( |
| |
574 &parent->value.array.array, |
| |
575 &parent->value.array.array_size, |
| |
576 &parent->value.array.array_capacity, |
| |
577 sizeof(CxJsonValue*), |
| |
578 &v, |
| |
579 &reallocator); |
| 567 } else { |
580 } else { |
| 568 return -1; // should also never happen |
581 return -1; // should also never happen |
| 569 } |
582 } |
| 570 } |
583 } |
| 571 |
584 |
| 579 } |
592 } |
| 580 p->readvalue_stack[p->readvalue_nelm++] = v; |
593 p->readvalue_stack[p->readvalue_nelm++] = v; |
| 581 return 0; |
594 return 0; |
| 582 } |
595 } |
| 583 |
596 |
| 584 void cxJsonInit(CxJson *json) { |
597 void cxJsonInit(const CxAllocator *allocator, CxJson *json) { |
| |
598 if (allocator == NULL) { |
| |
599 allocator = cxDefaultAllocator; |
| |
600 } |
| |
601 |
| 585 memset(json, 0, sizeof(CxJson)); |
602 memset(json, 0, sizeof(CxJson)); |
| |
603 json->allocator = allocator; |
| 586 json->states = json->states_internal; |
604 json->states = json->states_internal; |
| 587 json->states_alloc = cx_nmemb(json->states_internal); |
605 json->states_alloc = cx_nmemb(json->states_internal); |
| 588 // TODO: find better way to configure the initial allocation size for arrays and objects |
606 // TODO: find better way to configure the initial allocation size for arrays and objects |
| 589 json->reader_array_alloc = 8; |
607 json->reader_array_alloc = 8; |
| 590 } |
608 } |
| 616 } |
634 } |
| 617 |
635 |
| 618 while (p->readvalue_nelm > 0 || !p->read_value) { |
636 while (p->readvalue_nelm > 0 || !p->read_value) { |
| 619 if (p->value_ready) { |
637 if (p->value_ready) { |
| 620 // value available without another read |
638 // value available without another read |
| 621 CxJsonValue *v = calloc(1, sizeof(CxJsonValue)); |
639 CxJsonValue *v = cxCalloc(p->allocator, 1, sizeof(CxJsonValue)); |
| 622 if (!v) return -1; |
640 if (!v) return -1; |
| |
641 v->allocator = p->allocator; |
| 623 |
642 |
| 624 if (p->readvalue_nelm > 0) { |
643 if (p->readvalue_nelm > 0) { |
| 625 if (add_to_parent(p, p->readvalue_stack[p->readvalue_nelm - 1], v)) { |
644 if (add_to_parent(p, p->readvalue_stack[p->readvalue_nelm - 1], v)) { |
| 626 free(v); |
645 free(v); |
| 627 return -1; |
646 return -1; |
| 702 } |
721 } |
| 703 |
722 |
| 704 void cxJsonValueFree(CxJsonValue *value) { |
723 void cxJsonValueFree(CxJsonValue *value) { |
| 705 if (value == NULL || value == &cx_json_value_nothing) return; |
724 if (value == NULL || value == &cx_json_value_nothing) return; |
| 706 |
725 |
| 707 // TODO: discuss if we should keep freeing the stuff recursively |
|
| 708 switch (value->type) { |
726 switch (value->type) { |
| 709 case CX_JSON_OBJECT: { |
727 case CX_JSON_OBJECT: { |
| 710 CxJsonObject obj = value->value.object; |
728 CxJsonObject obj = value->value.object; |
| 711 for (size_t i = 0; i < obj.values_size; i++) { |
729 for (size_t i = 0; i < obj.values_size; i++) { |
| 712 cxJsonValueFree(obj.values[i].value); |
730 cxJsonValueFree(obj.values[i].value); |
| 713 free(obj.values[i].name); |
731 cxFree(value->allocator, obj.values[i].name); |
| 714 } |
732 } |
| 715 free(obj.values); |
733 cxFree(value->allocator, obj.values); |
| 716 break; |
734 break; |
| 717 } |
735 } |
| 718 case CX_JSON_ARRAY: { |
736 case CX_JSON_ARRAY: { |
| 719 CxJsonArray array = value->value.array; |
737 CxJsonArray array = value->value.array; |
| 720 for (size_t i = 0; i < array.array_size; i++) { |
738 for (size_t i = 0; i < array.array_size; i++) { |
| 721 cxJsonValueFree(array.array[i]); |
739 cxJsonValueFree(array.array[i]); |
| 722 } |
740 } |
| 723 free(array.array); |
741 cxFree(value->allocator, array.array); |
| 724 break; |
742 break; |
| 725 } |
743 } |
| 726 case CX_JSON_STRING: { |
744 case CX_JSON_STRING: { |
| 727 free(value->value.string.ptr); |
745 cxFree(value->allocator, value->value.string.ptr); |
| 728 break; |
746 break; |
| 729 } |
747 } |
| 730 default: { |
748 default: { |
| 731 break; |
749 break; |
| 732 } |
750 } |
| 733 } |
751 } |
| 734 free(value); |
752 cxFree(value->allocator, value); |
| 735 } |
753 } |
| 736 |
754 |
| 737 CxJsonValue *cxJsonArrGet(CxJsonValue *value, size_t index) { |
755 CxJsonValue *cxJsonArrGet(CxJsonValue *value, size_t index) { |
| 738 if (index >= value->value.array.array_size) { |
756 if (index >= value->value.array.array_size) { |
| 739 return &cx_json_value_nothing; |
757 return &cx_json_value_nothing; |