| 427 } |
425 } |
| 428 cxBufferDestroy(&buf); |
426 cxBufferDestroy(&buf); |
| 429 return str; |
427 return str; |
| 430 } |
428 } |
| 431 |
429 |
| 432 static CxJsonValue* create_json_value(CxJson *json, CxJsonValueType type) { |
430 static CxJsonValue* json_create_value(CxJson *json, CxJsonValueType type) { |
| 433 CxJsonValue *v = cxCalloc(json->allocator, 1, sizeof(CxJsonValue)); |
431 CxJsonValue *v = cxCalloc(json->allocator, 1, sizeof(CxJsonValue)); |
| 434 if (v == NULL) return NULL; // LCOV_EXCL_LINE |
432 if (v == NULL) return NULL; // LCOV_EXCL_LINE |
| 435 |
433 |
| 436 // initialize the value |
434 // initialize the value |
| 437 v->type = type; |
435 v->type = type; |
| 593 if (state < 3) { |
591 if (state < 3) { |
| 594 // push expected end state to the stack |
592 // push expected end state to the stack |
| 595 json_add_state(json, 10 + state); |
593 json_add_state(json, 10 + state); |
| 596 switch (token.tokentype) { |
594 switch (token.tokentype) { |
| 597 case CX_JSON_TOKEN_BEGIN_ARRAY: { |
595 case CX_JSON_TOKEN_BEGIN_ARRAY: { |
| 598 if (create_json_value(json, CX_JSON_ARRAY) == NULL) { |
596 if (json_create_value(json, CX_JSON_ARRAY) == NULL) { |
| 599 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
597 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
| 600 } |
598 } |
| 601 json_add_state(json, JP_STATE_VALUE_BEGIN_AR); |
599 json_add_state(json, JP_STATE_VALUE_BEGIN_AR); |
| 602 return_rec(CX_JSON_NO_ERROR); |
600 return_rec(CX_JSON_NO_ERROR); |
| 603 } |
601 } |
| 604 case CX_JSON_TOKEN_BEGIN_OBJECT: { |
602 case CX_JSON_TOKEN_BEGIN_OBJECT: { |
| 605 if (create_json_value(json, CX_JSON_OBJECT) == NULL) { |
603 if (json_create_value(json, CX_JSON_OBJECT) == NULL) { |
| 606 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
604 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
| 607 } |
605 } |
| 608 json_add_state(json, JP_STATE_OBJ_NAME_OR_CLOSE); |
606 json_add_state(json, JP_STATE_OBJ_NAME_OR_CLOSE); |
| 609 return_rec(CX_JSON_NO_ERROR); |
607 return_rec(CX_JSON_NO_ERROR); |
| 610 } |
608 } |
| 611 case CX_JSON_TOKEN_STRING: { |
609 case CX_JSON_TOKEN_STRING: { |
| 612 if ((vbuf = create_json_value(json, CX_JSON_STRING)) == NULL) { |
610 if ((vbuf = json_create_value(json, CX_JSON_STRING)) == NULL) { |
| 613 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
611 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
| 614 } |
612 } |
| 615 cxmutstr str = unescape_string(json->allocator, token.content); |
613 cxmutstr str = unescape_string(json->allocator, token.content); |
| 616 if (str.ptr == NULL) { |
614 if (str.ptr == NULL) { |
| 617 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
615 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
| 620 return_rec(CX_JSON_NO_ERROR); |
618 return_rec(CX_JSON_NO_ERROR); |
| 621 } |
619 } |
| 622 case CX_JSON_TOKEN_INTEGER: |
620 case CX_JSON_TOKEN_INTEGER: |
| 623 case CX_JSON_TOKEN_NUMBER: { |
621 case CX_JSON_TOKEN_NUMBER: { |
| 624 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER; |
622 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER; |
| 625 if (NULL == (vbuf = create_json_value(json, type))) { |
623 if (NULL == (vbuf = json_create_value(json, type))) { |
| 626 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
624 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
| 627 } |
625 } |
| 628 if (type == CX_JSON_INTEGER) { |
626 if (type == CX_JSON_INTEGER) { |
| 629 if (cx_strtoi64(token.content, &vbuf->value.integer, 10)) { |
627 if (cx_strtoi64(token.content, &vbuf->value.integer, 10)) { |
| 630 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); |
628 return_rec(CX_JSON_FORMAT_ERROR_NUMBER); |
| 635 } |
633 } |
| 636 } |
634 } |
| 637 return_rec(CX_JSON_NO_ERROR); |
635 return_rec(CX_JSON_NO_ERROR); |
| 638 } |
636 } |
| 639 case CX_JSON_TOKEN_LITERAL: { |
637 case CX_JSON_TOKEN_LITERAL: { |
| 640 if ((vbuf = create_json_value(json, CX_JSON_LITERAL)) == NULL) { |
638 if ((vbuf = json_create_value(json, CX_JSON_LITERAL)) == NULL) { |
| 641 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
639 return_rec(CX_JSON_VALUE_ALLOC_FAILED); // LCOV_EXCL_LINE |
| 642 } |
640 } |
| 643 if (0 == cx_strcmp(cx_strcast(token.content), cx_str("true"))) { |
641 if (0 == cx_strcmp(cx_strcast(token.content), cx_str("true"))) { |
| 644 vbuf->value.literal = CX_JSON_TRUE; |
642 vbuf->value.literal = CX_JSON_TRUE; |
| 645 } else if (0 == cx_strcmp(cx_strcast(token.content), cx_str("false"))) { |
643 } else if (0 == cx_strcmp(cx_strcast(token.content), cx_str("false"))) { |
| 866 return v; |
864 return v; |
| 867 } |
865 } |
| 868 |
866 |
| 869 // LCOV_EXCL_START |
867 // LCOV_EXCL_START |
| 870 // never called as long as malloc() does not return NULL |
868 // never called as long as malloc() does not return NULL |
| 871 static void cx_json_arr_free_temp(CxJsonValue** values, size_t count) { |
869 static void json_arr_free_temp(CxJsonValue** values, size_t count) { |
| 872 for (size_t i = 0; i < count; i++) { |
870 for (size_t i = 0; i < count; i++) { |
| 873 if (values[i] == NULL) break; |
871 if (values[i] == NULL) break; |
| 874 cxJsonValueFree(values[i]); |
872 cxJsonValueFree(values[i]); |
| 875 } |
873 } |
| 876 free(values); |
874 free(values); |
| 880 int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count) { |
878 int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count) { |
| 881 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*)); |
879 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*)); |
| 882 if (values == NULL) return -1; |
880 if (values == NULL) return -1; |
| 883 for (size_t i = 0; i < count; i++) { |
881 for (size_t i = 0; i < count; i++) { |
| 884 values[i] = cxJsonCreateNumber(arr->allocator, num[i]); |
882 values[i] = cxJsonCreateNumber(arr->allocator, num[i]); |
| 885 if (values[i] == NULL) { cx_json_arr_free_temp(values, count); return -1; } |
883 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; } |
| 886 } |
884 } |
| 887 int ret = cxJsonArrAddValues(arr, values, count); |
885 int ret = cxJsonArrAddValues(arr, values, count); |
| 888 free(values); |
886 free(values); |
| 889 return ret; |
887 return ret; |
| 890 } |
888 } |
| 892 int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count) { |
890 int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count) { |
| 893 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*)); |
891 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*)); |
| 894 if (values == NULL) return -1; |
892 if (values == NULL) return -1; |
| 895 for (size_t i = 0; i < count; i++) { |
893 for (size_t i = 0; i < count; i++) { |
| 896 values[i] = cxJsonCreateInteger(arr->allocator, num[i]); |
894 values[i] = cxJsonCreateInteger(arr->allocator, num[i]); |
| 897 if (values[i] == NULL) { cx_json_arr_free_temp(values, count); return -1; } |
895 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; } |
| 898 } |
896 } |
| 899 int ret = cxJsonArrAddValues(arr, values, count); |
897 int ret = cxJsonArrAddValues(arr, values, count); |
| 900 free(values); |
898 free(values); |
| 901 return ret; |
899 return ret; |
| 902 } |
900 } |
| 904 int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count) { |
902 int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count) { |
| 905 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*)); |
903 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*)); |
| 906 if (values == NULL) return -1; |
904 if (values == NULL) return -1; |
| 907 for (size_t i = 0; i < count; i++) { |
905 for (size_t i = 0; i < count; i++) { |
| 908 values[i] = cxJsonCreateString(arr->allocator, str[i]); |
906 values[i] = cxJsonCreateString(arr->allocator, str[i]); |
| 909 if (values[i] == NULL) { cx_json_arr_free_temp(values, count); return -1; } |
907 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; } |
| 910 } |
908 } |
| 911 int ret = cxJsonArrAddValues(arr, values, count); |
909 int ret = cxJsonArrAddValues(arr, values, count); |
| 912 free(values); |
910 free(values); |
| 913 return ret; |
911 return ret; |
| 914 } |
912 } |
| 916 int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count) { |
914 int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count) { |
| 917 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*)); |
915 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*)); |
| 918 if (values == NULL) return -1; |
916 if (values == NULL) return -1; |
| 919 for (size_t i = 0; i < count; i++) { |
917 for (size_t i = 0; i < count; i++) { |
| 920 values[i] = cxJsonCreateCxString(arr->allocator, str[i]); |
918 values[i] = cxJsonCreateCxString(arr->allocator, str[i]); |
| 921 if (values[i] == NULL) { cx_json_arr_free_temp(values, count); return -1; } |
919 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; } |
| 922 } |
920 } |
| 923 int ret = cxJsonArrAddValues(arr, values, count); |
921 int ret = cxJsonArrAddValues(arr, values, count); |
| 924 free(values); |
922 free(values); |
| 925 return ret; |
923 return ret; |
| 926 } |
924 } |
| 928 int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t count) { |
926 int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t count) { |
| 929 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*)); |
927 CxJsonValue** values = calloc(count, sizeof(CxJsonValue*)); |
| 930 if (values == NULL) return -1; |
928 if (values == NULL) return -1; |
| 931 for (size_t i = 0; i < count; i++) { |
929 for (size_t i = 0; i < count; i++) { |
| 932 values[i] = cxJsonCreateLiteral(arr->allocator, lit[i]); |
930 values[i] = cxJsonCreateLiteral(arr->allocator, lit[i]); |
| 933 if (values[i] == NULL) { cx_json_arr_free_temp(values, count); return -1; } |
931 if (values[i] == NULL) { json_arr_free_temp(values, count); return -1; } |
| 934 } |
932 } |
| 935 int ret = cxJsonArrAddValues(arr, values, count); |
933 int ret = cxJsonArrAddValues(arr, values, count); |
| 936 free(values); |
934 free(values); |
| 937 return ret; |
935 return ret; |
| 938 } |
936 } |
| 1037 } else { |
1035 } else { |
| 1038 return member->value; |
1036 return member->value; |
| 1039 } |
1037 } |
| 1040 } |
1038 } |
| 1041 |
1039 |
| 1042 static const CxJsonWriter cx_json_writer_default = { |
|
| 1043 false, |
|
| 1044 true, |
|
| 1045 6, |
|
| 1046 false, |
|
| 1047 4 |
|
| 1048 }; |
|
| 1049 |
|
| 1050 CxJsonWriter cxJsonWriterCompact(void) { |
1040 CxJsonWriter cxJsonWriterCompact(void) { |
| 1051 return cx_json_writer_default; |
1041 return (CxJsonWriter) { |
| |
1042 false, |
| |
1043 true, |
| |
1044 6, |
| |
1045 false, |
| |
1046 4 |
| |
1047 }; |
| 1052 } |
1048 } |
| 1053 |
1049 |
| 1054 CxJsonWriter cxJsonWriterPretty(bool use_spaces) { |
1050 CxJsonWriter cxJsonWriterPretty(bool use_spaces) { |
| 1055 return (CxJsonWriter) { |
1051 return (CxJsonWriter) { |
| 1056 true, |
1052 true, |
| 1322 void *target, |
1318 void *target, |
| 1323 const CxJsonValue *value, |
1319 const CxJsonValue *value, |
| 1324 cx_write_func wfunc, |
1320 cx_write_func wfunc, |
| 1325 const CxJsonWriter *settings |
1321 const CxJsonWriter *settings |
| 1326 ) { |
1322 ) { |
| 1327 if (settings == NULL) { |
|
| 1328 settings = &cx_json_writer_default; |
|
| 1329 } |
|
| 1330 assert(target != NULL); |
1323 assert(target != NULL); |
| 1331 assert(value != NULL); |
1324 assert(value != NULL); |
| 1332 assert(wfunc != NULL); |
1325 assert(wfunc != NULL); |
| 1333 |
1326 |
| |
1327 CxJsonWriter writer_default = cxJsonWriterCompact(); |
| |
1328 if (settings == NULL) { |
| |
1329 settings = &writer_default; |
| |
1330 } |
| 1334 return cx_json_write_rec(target, value, wfunc, settings, 0); |
1331 return cx_json_write_rec(target, value, wfunc, settings, 0); |
| 1335 } |
1332 } |