src/json.c

changeset 1121
7fd2672199d7
parent 1119
ff4d7e76f85a
child 1122
49ab92de9a13
equal deleted inserted replaced
1120:608bdcc8f9ad 1121:7fd2672199d7
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29 #include "cx/json.h" 29 #include "cx/json.h"
30 #include "cx/compare.h"
31 30
32 #include <string.h> 31 #include <string.h>
33 #include <ctype.h> 32 #include <ctype.h>
34 #include <assert.h> 33 #include <assert.h>
35 #include <stdio.h> 34 #include <stdio.h>
36 #include <errno.h>
37 #include <inttypes.h> 35 #include <inttypes.h>
38 36
39 /* 37 /*
40 * RFC 8259 38 * RFC 8259
41 * https://tools.ietf.org/html/rfc8259 39 * https://tools.ietf.org/html/rfc8259
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 }

mercurial