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; |