src/json.c

Sun, 22 Dec 2024 22:10:04 +0100

author
Mike Becker <universe@uap-core.de>
date
Sun, 22 Dec 2024 22:10:04 +0100
changeset 1047
40aad3f0bc9e
parent 1040
1ecf4dbbc60c
permissions
-rw-r--r--

don't trust that size_t always has word width

it should be the case on all platforms supported by UCX, but it's not strictly defined in POSIX that it must be the case

937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
1 /*
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
3 *
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
4 * Copyright 2024 Mike Becker, Olaf Wintermann All rights reserved.
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
5 *
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
6 * Redistribution and use in source and binary forms, with or without
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
7 * modification, are permitted provided that the following conditions are met:
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
8 *
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
9 * 1. Redistributions of source code must retain the above copyright
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
10 * notice, this list of conditions and the following disclaimer.
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
11 *
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
12 * 2. Redistributions in binary form must reproduce the above copyright
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
13 * notice, this list of conditions and the following disclaimer in the
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
14 * documentation and/or other materials provided with the distribution.
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
15 *
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
26 * POSSIBILITY OF SUCH DAMAGE.
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
27 */
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
28
1040
1ecf4dbbc60c add some more overflow treatment and make sure to set errno properly
Mike Becker <universe@uap-core.de>
parents: 1037
diff changeset
29 #include "cx/json.h"
1ecf4dbbc60c add some more overflow treatment and make sure to set errno properly
Mike Becker <universe@uap-core.de>
parents: 1037
diff changeset
30
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
31 #include <string.h>
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
32 #include <ctype.h>
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
33 #include <assert.h>
1007
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
34 #include <stdio.h>
1014
56eb7da4f3e1 fix number parser not detecting integers out of range
Mike Becker <universe@uap-core.de>
parents: 1012
diff changeset
35 #include <errno.h>
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
36
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
37 /*
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
38 * RFC 8259
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
39 * https://tools.ietf.org/html/rfc8259
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
40 */
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
41
944
c26299cc9897 make both gcc and clang happy with how cx_json_value_nothing is initialized
Mike Becker <universe@uap-core.de>
parents: 943
diff changeset
42 static CxJsonValue cx_json_value_nothing = {.type = CX_JSON_NOTHING};
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
43
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
44 static void token_destroy(CxJsonToken *token) {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
45 if (token->allocated) {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
46 cx_strfree(&token->content);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
47 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
48 }
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
49
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
50 static int num_isexp(const char *content, size_t length, size_t pos) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
51 if (pos >= length) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
52 return 0;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
53 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
54
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
55 int ok = 0;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
56 for (size_t i = pos; i < length; i++) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
57 char c = content[i];
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
58 if (isdigit(c)) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
59 ok = 1;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
60 } else if (i == pos) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
61 if (!(c == '+' || c == '-')) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
62 return 0;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
63 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
64 } else {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
65 return 0;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
66 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
67 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
68
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
69 return ok;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
70 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
71
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
72 static CxJsonTokenType token_numbertype(const char *content, size_t length) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
73 if (length == 0) return CX_JSON_TOKEN_ERROR;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
74
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
75 if (content[0] != '-' && !isdigit(content[0])) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
76 return CX_JSON_TOKEN_ERROR;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
77 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
78
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
79 CxJsonTokenType type = CX_JSON_TOKEN_INTEGER;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
80 for (size_t i = 1; i < length; i++) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
81 if (content[i] == '.') {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
82 if (type == CX_JSON_TOKEN_NUMBER) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
83 return CX_JSON_TOKEN_ERROR; // more than one decimal separator
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
84 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
85 type = CX_JSON_TOKEN_NUMBER;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
86 } else if (content[i] == 'e' || content[i] == 'E') {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
87 return num_isexp(content, length, i + 1) ? CX_JSON_TOKEN_NUMBER : CX_JSON_TOKEN_ERROR;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
88 } else if (!isdigit(content[i])) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
89 return CX_JSON_TOKEN_ERROR; // char is not a digit, decimal separator or exponent sep
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
90 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
91 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
92
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
93 return type;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
94 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
95
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
96 static CxJsonToken token_create(CxJson *json, bool isstring, size_t start, size_t end) {
1007
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
97 cxmutstr str = cx_mutstrn(json->buffer.space + start, end - start);
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
98 bool allocated = false;
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
99 if (json->uncompleted.tokentype != CX_JSON_NO_TOKEN) {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
100 allocated = true;
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
101 str = cx_strcat_m(json->uncompleted.content, 1, str);
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
102 if (str.ptr == NULL) {
1020
e78e65405c56 fix wrong "variant" of zero/NULL/false
Mike Becker <universe@uap-core.de>
parents: 1014
diff changeset
103 return (CxJsonToken){CX_JSON_NO_TOKEN, false, {NULL, 0}};
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
104 }
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
105 }
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
106 json->uncompleted = (CxJsonToken){0};
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
107 CxJsonTokenType ttype;
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
108 if (isstring) {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
109 ttype = CX_JSON_TOKEN_STRING;
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
110 } else {
1009
7650e722437e minor cleanup
Mike Becker <universe@uap-core.de>
parents: 1008
diff changeset
111 cxstring s = cx_strcast(str);
7650e722437e minor cleanup
Mike Becker <universe@uap-core.de>
parents: 1008
diff changeset
112 if (!cx_strcmp(s, CX_STR("true")) || !cx_strcmp(s, CX_STR("false"))
7650e722437e minor cleanup
Mike Becker <universe@uap-core.de>
parents: 1008
diff changeset
113 || !cx_strcmp(s, CX_STR("null"))) {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
114 ttype = CX_JSON_TOKEN_LITERAL;
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
115 } else {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
116 ttype = token_numbertype(str.ptr, str.length);
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
117 }
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
118 }
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
119 if (ttype == CX_JSON_TOKEN_ERROR) {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
120 if (allocated) {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
121 cx_strfree(&str);
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
122 }
1020
e78e65405c56 fix wrong "variant" of zero/NULL/false
Mike Becker <universe@uap-core.de>
parents: 1014
diff changeset
123 return (CxJsonToken){CX_JSON_TOKEN_ERROR, false, {NULL, 0}};
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
124 }
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
125 return (CxJsonToken){ttype, allocated, str};
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
126 }
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
127
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
128 static CxJsonTokenType char2ttype(char c) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
129 switch (c) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
130 case '[': {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
131 return CX_JSON_TOKEN_BEGIN_ARRAY;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
132 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
133 case '{': {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
134 return CX_JSON_TOKEN_BEGIN_OBJECT;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
135 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
136 case ']': {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
137 return CX_JSON_TOKEN_END_ARRAY;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
138 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
139 case '}': {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
140 return CX_JSON_TOKEN_END_OBJECT;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
141 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
142 case ':': {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
143 return CX_JSON_TOKEN_NAME_SEPARATOR;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
144 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
145 case ',': {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
146 return CX_JSON_TOKEN_VALUE_SEPARATOR;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
147 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
148 case '"': {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
149 return CX_JSON_TOKEN_STRING;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
150 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
151 default: {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
152 if (isspace(c)) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
153 return CX_JSON_TOKEN_SPACE;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
154 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
155 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
156 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
157 return CX_JSON_NO_TOKEN;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
158 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
159
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
160 static enum cx_json_status token_parse_next(CxJson *json, CxJsonToken *result) {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
161 // check if there is data in the buffer
1007
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
162 if (cxBufferEof(&json->buffer)) {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
163 return json->uncompleted.tokentype == CX_JSON_NO_TOKEN ?
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
164 CX_JSON_NO_DATA : CX_JSON_INCOMPLETE_DATA;
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
165 }
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
166
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
167 // current token type and start index
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
168 CxJsonTokenType ttype = json->uncompleted.tokentype;
1007
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
169 size_t token_start = json->buffer.pos;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
170
1007
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
171 for (size_t i = json->buffer.pos; i < json->buffer.size; i++) {
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
172 char c = json->buffer.space[i];
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
173 if (ttype != CX_JSON_TOKEN_STRING) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
174 // currently non-string token
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
175 CxJsonTokenType ctype = char2ttype(c); // start of new token?
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
176 if (ttype == CX_JSON_NO_TOKEN) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
177 if (ctype == CX_JSON_TOKEN_SPACE) {
1008
3b69f025f083 json: enable multiple subsequent fills - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1007
diff changeset
178 json->buffer.pos++;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
179 continue;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
180 } else if (ctype == CX_JSON_TOKEN_STRING) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
181 // begin string
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
182 ttype = CX_JSON_TOKEN_STRING;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
183 token_start = i;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
184 } else if (ctype != CX_JSON_NO_TOKEN) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
185 // single-char token
1007
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
186 json->buffer.pos = i + 1;
1020
e78e65405c56 fix wrong "variant" of zero/NULL/false
Mike Becker <universe@uap-core.de>
parents: 1014
diff changeset
187 *result = (CxJsonToken){ctype, false, {NULL, 0}};
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
188 return CX_JSON_NO_ERROR;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
189 } else {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
190 ttype = CX_JSON_TOKEN_LITERAL; // number or literal
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
191 token_start = i;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
192 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
193 } else {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
194 // finish token
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
195 if (ctype != CX_JSON_NO_TOKEN) {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
196 *result = token_create(json, false, token_start, i);
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
197 if (result->tokentype == CX_JSON_NO_TOKEN) {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
198 return CX_JSON_BUFFER_ALLOC_FAILED;
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
199 }
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
200 if (result->tokentype == CX_JSON_TOKEN_ERROR) {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
201 return CX_JSON_FORMAT_ERROR_NUMBER;
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
202 }
1007
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
203 json->buffer.pos = i;
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
204 return CX_JSON_NO_ERROR;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
205 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
206 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
207 } else {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
208 // currently inside a string
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
209 if (json->tokenizer_escape) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
210 json->tokenizer_escape = false;
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
211 } else {
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
212 if (c == '"') {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
213 *result = token_create(json, true, token_start, i + 1);
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
214 if (result->tokentype == CX_JSON_NO_TOKEN) {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
215 return CX_JSON_BUFFER_ALLOC_FAILED;
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
216 }
1007
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
217 json->buffer.pos = i + 1;
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
218 return CX_JSON_NO_ERROR;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
219 } else if (c == '\\') {
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
220 json->tokenizer_escape = true;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
221 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
222 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
223 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
224 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
225
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
226 if (ttype != CX_JSON_NO_TOKEN) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
227 // uncompleted token
1008
3b69f025f083 json: enable multiple subsequent fills - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1007
diff changeset
228 size_t uncompleted_len = json->buffer.size - token_start;
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
229 if (json->uncompleted.tokentype == CX_JSON_NO_TOKEN) {
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
230 // current token is uncompleted
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
231 // save current token content
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
232 CxJsonToken uncompleted = {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
233 ttype, true,
1008
3b69f025f083 json: enable multiple subsequent fills - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1007
diff changeset
234 cx_strdup(cx_strn(json->buffer.space + token_start, uncompleted_len))
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
235 };
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
236 if (uncompleted.content.ptr == NULL) {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
237 return CX_JSON_BUFFER_ALLOC_FAILED;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
238 }
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
239 json->uncompleted = uncompleted;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
240 } else {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
241 // previously we also had an uncompleted token
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
242 // combine the uncompleted token with the current token
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
243 assert(json->uncompleted.allocated);
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
244 cxmutstr str = cx_strcat_m(json->uncompleted.content, 1,
1008
3b69f025f083 json: enable multiple subsequent fills - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1007
diff changeset
245 cx_strn(json->buffer.space + token_start, uncompleted_len));
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
246 if (str.ptr == NULL) {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
247 return CX_JSON_BUFFER_ALLOC_FAILED;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
248 }
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
249 json->uncompleted.content = str;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
250 }
1008
3b69f025f083 json: enable multiple subsequent fills - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1007
diff changeset
251 // advance the buffer position - we saved the stuff in the uncompleted token
3b69f025f083 json: enable multiple subsequent fills - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1007
diff changeset
252 json->buffer.pos += uncompleted_len;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
253 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
254
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
255 return CX_JSON_INCOMPLETE_DATA;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
256 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
257
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
258 static cxmutstr unescape_string(const CxAllocator *a, cxmutstr str) {
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
259 // TODO: support more escape sequences
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
260 // we know that the unescaped string will be shorter by at least 2 chars
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
261 cxmutstr result;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
262 result.length = 0;
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
263 result.ptr = cxMalloc(a, str.length - 1);
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
264 if (result.ptr == NULL) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
265 return result;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
266 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
267
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
268 bool u = false;
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
269 for (size_t i = 1; i < str.length - 1; i++) {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
270 char c = str.ptr[i];
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
271 if (u) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
272 u = false;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
273 if (c == 'n') {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
274 c = '\n';
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
275 } else if (c == 't') {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
276 c = '\t';
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
277 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
278 result.ptr[result.length++] = c;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
279 } else {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
280 if (c == '\\') {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
281 u = true;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
282 } else {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
283 result.ptr[result.length++] = c;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
284 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
285 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
286 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
287 result.ptr[result.length] = 0;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
288
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
289 return result;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
290 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
291
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
292 static int parse_number(cxmutstr str, void *value, bool asint) {
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
293 char *endptr = NULL;
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
294 if (str.length > 30) {
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
295 return 1;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
296 }
1007
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
297 // the buffer guarantees that we are working on a copied string
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
298 char c = str.ptr[str.length];
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
299 str.ptr[str.length] = 0;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
300
969
72e5432f6b42 simplify parsing of numbers
Mike Becker <universe@uap-core.de>
parents: 967
diff changeset
301 if (asint) {
1014
56eb7da4f3e1 fix number parser not detecting integers out of range
Mike Becker <universe@uap-core.de>
parents: 1012
diff changeset
302 errno = 0;
1007
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
303 long long v = strtoll(str.ptr, &endptr, 10);
1014
56eb7da4f3e1 fix number parser not detecting integers out of range
Mike Becker <universe@uap-core.de>
parents: 1012
diff changeset
304 if (errno == ERANGE) {
56eb7da4f3e1 fix number parser not detecting integers out of range
Mike Becker <universe@uap-core.de>
parents: 1012
diff changeset
305 return 1;
56eb7da4f3e1 fix number parser not detecting integers out of range
Mike Becker <universe@uap-core.de>
parents: 1012
diff changeset
306 }
969
72e5432f6b42 simplify parsing of numbers
Mike Becker <universe@uap-core.de>
parents: 967
diff changeset
307 *((int64_t*)value) = (int64_t) v;
72e5432f6b42 simplify parsing of numbers
Mike Becker <universe@uap-core.de>
parents: 967
diff changeset
308 } else {
72e5432f6b42 simplify parsing of numbers
Mike Becker <universe@uap-core.de>
parents: 967
diff changeset
309 // TODO: proper JSON spec number parser
1014
56eb7da4f3e1 fix number parser not detecting integers out of range
Mike Becker <universe@uap-core.de>
parents: 1012
diff changeset
310 // TODO: also return an error when loss of precision is high
1007
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
311 double v = strtod(str.ptr, &endptr);
969
72e5432f6b42 simplify parsing of numbers
Mike Becker <universe@uap-core.de>
parents: 967
diff changeset
312 *((double*)value) = v;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
313 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
314
1007
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
315 // recover from the hack
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
316 str.ptr[str.length] = c;
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
317
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
318 return endptr != &str.ptr[str.length];
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
319 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
320
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
321 static CxJsonValue* create_json_value(CxJson *json, CxJsonValueType type) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
322 CxJsonValue *v = cxMalloc(json->allocator, sizeof(CxJsonValue));
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
323 if (v == NULL) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
324 return NULL;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
325 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
326
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
327 // initialize the value
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
328 if (type == CX_JSON_ARRAY) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
329 cx_array_initialize_a(json->allocator, v->value.array.array, 16);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
330 if (v->value.array.array == NULL) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
331 cxFree(json->allocator, v);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
332 return NULL;
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
333 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
334 } else if (type == CX_JSON_OBJECT) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
335 cx_array_initialize_a(json->allocator, v->value.object.values, 16);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
336 if (v->value.object.values == NULL) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
337 cxFree(json->allocator, v);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
338 return NULL;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
339 }
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
340 } else {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
341 memset(v, 0, sizeof(CxJsonValue));
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
342 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
343 v->type = type;
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
344 v->allocator = json->allocator;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
345
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
346 // add the new value to a possible parent
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
347 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
348 if (json->vbuf_size > 0) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
349 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1];
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
350 if (parent->type == CX_JSON_ARRAY) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
351 cx_array_simple_add_a(&value_realloc, parent->value.array.array, v);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
352 } else if (parent->type == CX_JSON_OBJECT) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
353 assert(parent->value.object.values_size > 0);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
354 assert(parent->value.object.values[parent->value.object.values_size - 1].value == NULL);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
355 parent->value.object.values[parent->value.object.values_size - 1].value = v;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
356 } else {
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
357 assert(false);
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
358 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
359 }
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
360
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
361 // add the new value to the stack, if it is an array or object
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
362 if (type == CX_JSON_ARRAY || type == CX_JSON_OBJECT) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
363 CxArrayReallocator vbuf_realloc = cx_array_reallocator(NULL, json->vbuf_internal);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
364 if (cx_array_simple_add_a(&vbuf_realloc, json->vbuf, v)) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
365 cxFree(json->allocator, v);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
366 return NULL;
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
367 }
940
bbf41b9c2658 fix memory leak in json reader when handling incomplete tokens
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 938
diff changeset
368 }
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
369
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
370 // if currently no value is parsed, this is now the value of interest
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
371 if (json->parsed == NULL) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
372 json->parsed = v;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
373 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
374
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
375 return v;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
376 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
377
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
378 #define JP_STATE_VALUE_BEGIN 0
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
379 #define JP_STATE_VALUE_END 10
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
380 #define JP_STATE_VALUE_BEGIN_OBJ 1
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
381 #define JP_STATE_OBJ_SEP_OR_CLOSE 11
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
382 #define JP_STATE_VALUE_BEGIN_AR 2
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
383 #define JP_STATE_ARRAY_SEP_OR_CLOSE 12
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
384 #define JP_STATE_OBJ_NAME_OR_CLOSE 5
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
385 #define JP_STATE_OBJ_NAME 6
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
386 #define JP_STATE_OBJ_COLON 7
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
387
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
388 void cxJsonInit(CxJson *json, const CxAllocator *allocator) {
996
333155f234c4 add support for allocators to the json parser
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 976
diff changeset
389 if (allocator == NULL) {
333155f234c4 add support for allocators to the json parser
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 976
diff changeset
390 allocator = cxDefaultAllocator;
333155f234c4 add support for allocators to the json parser
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 976
diff changeset
391 }
333155f234c4 add support for allocators to the json parser
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 976
diff changeset
392
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
393 memset(json, 0, sizeof(CxJson));
996
333155f234c4 add support for allocators to the json parser
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 976
diff changeset
394 json->allocator = allocator;
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
395
946
b428424c0214 avoid state buffer allocation for JSON with reasonable nesting depth
Mike Becker <universe@uap-core.de>
parents: 944
diff changeset
396 json->states = json->states_internal;
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
397 json->states_capacity = cx_nmemb(json->states_internal);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
398 json->states[0] = JP_STATE_VALUE_BEGIN;
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
399 json->states_size = 1;
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
400
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
401 json->vbuf = json->vbuf_internal;
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
402 json->vbuf_capacity = cx_nmemb(json->vbuf_internal);
1007
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
403
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
404 cxBufferInit(&json->buffer, NULL, 256, NULL, CX_BUFFER_AUTO_EXTEND);
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
405 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
406
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
407 void cxJsonDestroy(CxJson *json) {
1007
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
408 cxBufferDestroy(&json->buffer);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
409 if (json->states != json->states_internal) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
410 free(json->states);
946
b428424c0214 avoid state buffer allocation for JSON with reasonable nesting depth
Mike Becker <universe@uap-core.de>
parents: 944
diff changeset
411 }
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
412 if (json->vbuf != json->vbuf_internal) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
413 free(json->vbuf);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
414 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
415 cxJsonValueFree(json->parsed);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
416 json->parsed = NULL;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
417 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
418
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
419 int cxJsonFilln(CxJson *json, const char *buf, size_t size) {
1007
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
420 // we use the UCX buffer to write the data
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
421 // but reset the position immediately to enable parsing
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
422 size_t old_pos = json->buffer.pos;
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
423 cxBufferSeek(&json->buffer, 0, SEEK_END);
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
424 size_t written = cxBufferWrite(buf, 1, size, &json->buffer);
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
425 if (0 == cxBufferTerminate(&json->buffer)) {
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
426 written++;
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
427 }
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
428 json->buffer.pos = old_pos;
81b2986d2b04 fix that cxBufferSeek() cannot move pos past the end - fixes #523
Mike Becker <universe@uap-core.de>
parents: 1002
diff changeset
429 return written != size + 1;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
430 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
431
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
432 static void json_add_state(CxJson *json, int state) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
433 // we have guaranteed the necessary space with cx_array_simple_reserve()
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
434 // therefore, we can safely add the state in the simplest way possible
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
435 json->states[json->states_size++] = state;
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
436 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
437
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
438 #define return_rec(code) \
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
439 token_destroy(&token); \
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
440 return code
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
441
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
442 static enum cx_json_status json_parse(CxJson *json) {
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
443 // Reserve a pointer for a possibly read value
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
444 CxJsonValue *vbuf = NULL;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
445
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
446 // grab the next token
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
447 CxJsonToken token;
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
448 {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
449 enum cx_json_status ret = token_parse_next(json, &token);
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
450 if (ret != CX_JSON_NO_ERROR) {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
451 return ret;
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
452 }
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
453 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
454
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
455 // pop the current state
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
456 assert(json->states_size > 0);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
457 int state = json->states[--json->states_size];
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
458
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
459 // guarantee that at least two more states fit on the stack
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
460 CxArrayReallocator state_realloc = cx_array_reallocator(NULL, json->states_internal);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
461 if (cx_array_simple_reserve_a(&state_realloc, json->states, 2)) {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
462 return CX_JSON_BUFFER_ALLOC_FAILED;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
463 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
464
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
465
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
466 // 0 JP_STATE_VALUE_BEGIN value begin
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
467 // 10 JP_STATE_VALUE_END expect value end
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
468 // 1 JP_STATE_VALUE_BEGIN_OBJ value begin (inside object)
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
469 // 11 JP_STATE_OBJ_SEP_OR_CLOSE object, expect separator, objclose
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
470 // 2 JP_STATE_VALUE_BEGIN_AR value begin (inside array)
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
471 // 12 JP_STATE_ARRAY_SEP_OR_CLOSE array, expect separator or arrayclose
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
472 // 5 JP_STATE_OBJ_NAME_OR_CLOSE object, expect name or objclose
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
473 // 6 JP_STATE_OBJ_NAME object, expect name
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
474 // 7 JP_STATE_OBJ_COLON object, expect ':'
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
475
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
476 if (state < 3) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
477 // push expected end state to the stack
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
478 json_add_state(json, 10 + state);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
479 switch (token.tokentype) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
480 case CX_JSON_TOKEN_BEGIN_ARRAY: {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
481 if (create_json_value(json, CX_JSON_ARRAY) == NULL) {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
482 return_rec(CX_JSON_VALUE_ALLOC_FAILED);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
483 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
484 json_add_state(json, JP_STATE_VALUE_BEGIN_AR);
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
485 return_rec(CX_JSON_NO_ERROR);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
486 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
487 case CX_JSON_TOKEN_BEGIN_OBJECT: {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
488 if (create_json_value(json, CX_JSON_OBJECT) == NULL) {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
489 return_rec(CX_JSON_VALUE_ALLOC_FAILED);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
490 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
491 json_add_state(json, JP_STATE_OBJ_NAME_OR_CLOSE);
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
492 return_rec(CX_JSON_NO_ERROR);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
493 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
494 case CX_JSON_TOKEN_STRING: {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
495 if ((vbuf = create_json_value(json, CX_JSON_STRING)) == NULL) {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
496 return_rec(CX_JSON_VALUE_ALLOC_FAILED);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
497 }
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
498 cxmutstr str = unescape_string(json->allocator, token.content);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
499 if (str.ptr == NULL) {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
500 return_rec(CX_JSON_VALUE_ALLOC_FAILED);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
501 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
502 vbuf->value.string = str;
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
503 return_rec(CX_JSON_NO_ERROR);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
504 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
505 case CX_JSON_TOKEN_INTEGER:
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
506 case CX_JSON_TOKEN_NUMBER: {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
507 int type = token.tokentype == CX_JSON_TOKEN_INTEGER ? CX_JSON_INTEGER : CX_JSON_NUMBER;
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
508 if (NULL == (vbuf = create_json_value(json, type))) {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
509 return_rec(CX_JSON_VALUE_ALLOC_FAILED);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
510 }
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
511 if (parse_number(token.content, &vbuf->value,type == CX_JSON_INTEGER)) {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
512 return_rec(CX_JSON_FORMAT_ERROR_NUMBER);
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
513 }
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
514 return_rec(CX_JSON_NO_ERROR);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
515 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
516 case CX_JSON_TOKEN_LITERAL: {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
517 if ((vbuf = create_json_value(json, CX_JSON_LITERAL)) == NULL) {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
518 return_rec(CX_JSON_VALUE_ALLOC_FAILED);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
519 }
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
520 if (0 == cx_strcmp(cx_strcast(token.content), cx_str("true"))) {
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
521 vbuf->value.literal = CX_JSON_TRUE;
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
522 } else if (0 == cx_strcmp(cx_strcast(token.content), cx_str("false"))) {
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
523 vbuf->value.literal = CX_JSON_FALSE;
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
524 } else {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
525 vbuf->value.literal = CX_JSON_NULL;
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
526 }
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
527 return_rec(CX_JSON_NO_ERROR);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
528 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
529 default: {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
530 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
531 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
532 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
533 } else if (state == JP_STATE_ARRAY_SEP_OR_CLOSE) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
534 // expect ',' or ']'
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
535 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
536 json_add_state(json, JP_STATE_VALUE_BEGIN_AR);
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
537 return_rec(CX_JSON_NO_ERROR);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
538 } else if (token.tokentype == CX_JSON_TOKEN_END_ARRAY) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
539 // discard the array from the value buffer
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
540 json->vbuf_size--;
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
541 return_rec(CX_JSON_NO_ERROR);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
542 } else {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
543 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
544 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
545 } else if (state == JP_STATE_OBJ_NAME_OR_CLOSE || state == JP_STATE_OBJ_NAME) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
546 if (state == JP_STATE_OBJ_NAME_OR_CLOSE && token.tokentype == CX_JSON_TOKEN_END_OBJECT) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
547 // discard the obj from the value buffer
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
548 json->vbuf_size--;
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
549 return_rec(CX_JSON_NO_ERROR);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
550 } else {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
551 // expect string
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
552 if (token.tokentype != CX_JSON_TOKEN_STRING) {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
553 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
554 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
555
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
556 // add new entry
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
557 cxmutstr name = unescape_string(json->allocator, token.content);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
558 if (name.ptr == NULL) {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
559 return_rec(CX_JSON_VALUE_ALLOC_FAILED);
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
560 }
1037
83620ba72cc1 generify cxJsonObjGet() - fixes #525
Mike Becker <universe@uap-core.de>
parents: 1033
diff changeset
561 CxJsonObjValue kv = {name, NULL};
83620ba72cc1 generify cxJsonObjGet() - fixes #525
Mike Becker <universe@uap-core.de>
parents: 1033
diff changeset
562 assert(json->vbuf_size > 0);
83620ba72cc1 generify cxJsonObjGet() - fixes #525
Mike Becker <universe@uap-core.de>
parents: 1033
diff changeset
563 CxJsonValue *parent = json->vbuf[json->vbuf_size - 1];
83620ba72cc1 generify cxJsonObjGet() - fixes #525
Mike Becker <universe@uap-core.de>
parents: 1033
diff changeset
564 assert(parent != NULL);
83620ba72cc1 generify cxJsonObjGet() - fixes #525
Mike Becker <universe@uap-core.de>
parents: 1033
diff changeset
565 assert(parent->type == CX_JSON_OBJECT);
83620ba72cc1 generify cxJsonObjGet() - fixes #525
Mike Becker <universe@uap-core.de>
parents: 1033
diff changeset
566 CxArrayReallocator value_realloc = cx_array_reallocator(json->allocator, NULL);
83620ba72cc1 generify cxJsonObjGet() - fixes #525
Mike Becker <universe@uap-core.de>
parents: 1033
diff changeset
567 if (cx_array_simple_add_a(&value_realloc, parent->value.object.values, kv)) {
83620ba72cc1 generify cxJsonObjGet() - fixes #525
Mike Becker <universe@uap-core.de>
parents: 1033
diff changeset
568 return_rec(CX_JSON_VALUE_ALLOC_FAILED);
83620ba72cc1 generify cxJsonObjGet() - fixes #525
Mike Becker <universe@uap-core.de>
parents: 1033
diff changeset
569 }
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
570
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
571 // next state
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
572 json_add_state(json, JP_STATE_OBJ_COLON);
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
573 return_rec(CX_JSON_NO_ERROR);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
574 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
575 } else if (state == JP_STATE_OBJ_COLON) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
576 // expect ':'
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
577 if (token.tokentype != CX_JSON_TOKEN_NAME_SEPARATOR) {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
578 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
579 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
580 // next state
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
581 json_add_state(json, JP_STATE_VALUE_BEGIN_OBJ);
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
582 return_rec(CX_JSON_NO_ERROR);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
583 } else if (state == JP_STATE_OBJ_SEP_OR_CLOSE) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
584 // expect ',' or '}'
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
585 if (token.tokentype == CX_JSON_TOKEN_VALUE_SEPARATOR) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
586 json_add_state(json, JP_STATE_OBJ_NAME);
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
587 return_rec(CX_JSON_NO_ERROR);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
588 } else if (token.tokentype == CX_JSON_TOKEN_END_OBJECT) {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
589 // discard the obj from the value buffer
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
590 json->vbuf_size--;
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
591 return_rec(CX_JSON_NO_ERROR);
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
592 } else {
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
593 return_rec(CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN);
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
594 }
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
595 } else {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
596 // should be unreachable
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
597 assert(false);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
598 return_rec(-1);
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
599 }
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
600 }
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
601
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
602 CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value) {
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
603 // initialize output value
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
604 *value = &cx_json_value_nothing;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
605
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
606 // parse data
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
607 CxJsonStatus result;
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
608 do {
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
609 result = json_parse(json);
1008
3b69f025f083 json: enable multiple subsequent fills - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1007
diff changeset
610 cxBufferShiftLeft(&json->buffer, json->buffer.pos);
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
611 if (result == CX_JSON_NO_ERROR && json->states_size == 1) {
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
612 // final state reached
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
613 assert(json->states[0] == JP_STATE_VALUE_END);
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
614 assert(json->vbuf_size == 0);
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
615
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
616 // write output value
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
617 *value = json->parsed;
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
618 json->parsed = NULL;
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
619
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
620 // re-initialize state machine
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
621 json->states[0] = JP_STATE_VALUE_BEGIN;
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
622
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
623 return CX_JSON_NO_ERROR;
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
624 }
1002
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
625 } while (result == CX_JSON_NO_ERROR);
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
626
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
627 // the parser might think there is no data
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
628 // but when we did not reach the final state,
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
629 // we know that there must be more to come
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
630 if (result == CX_JSON_NO_DATA && json->states_size > 1) {
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
631 return CX_JSON_INCOMPLETE_DATA;
1483c47063a8 add status codes to json parser - relates to #431
Mike Becker <universe@uap-core.de>
parents: 1000
diff changeset
632 }
1000
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
633
1aecddf7e209 simplify how the json parser works
Mike Becker <universe@uap-core.de>
parents: 996
diff changeset
634 return result;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
635 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
636
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
637 void cxJsonValueFree(CxJsonValue *value) {
1012
21884374edbb add documentation - resolves #431
Mike Becker <universe@uap-core.de>
parents: 1009
diff changeset
638 if (value == NULL || value->type == CX_JSON_NOTHING) return;
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
639 switch (value->type) {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
640 case CX_JSON_OBJECT: {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
641 CxJsonObject obj = value->value.object;
967
a58f602ed2fe simplify parsing of array and object elements
Mike Becker <universe@uap-core.de>
parents: 965
diff changeset
642 for (size_t i = 0; i < obj.values_size; i++) {
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
643 cxJsonValueFree(obj.values[i].value);
1037
83620ba72cc1 generify cxJsonObjGet() - fixes #525
Mike Becker <universe@uap-core.de>
parents: 1033
diff changeset
644 cx_strfree_a(value->allocator, &obj.values[i].name);
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
645 }
996
333155f234c4 add support for allocators to the json parser
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 976
diff changeset
646 cxFree(value->allocator, obj.values);
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
647 break;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
648 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
649 case CX_JSON_ARRAY: {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
650 CxJsonArray array = value->value.array;
967
a58f602ed2fe simplify parsing of array and object elements
Mike Becker <universe@uap-core.de>
parents: 965
diff changeset
651 for (size_t i = 0; i < array.array_size; i++) {
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
652 cxJsonValueFree(array.array[i]);
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
653 }
996
333155f234c4 add support for allocators to the json parser
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 976
diff changeset
654 cxFree(value->allocator, array.array);
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
655 break;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
656 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
657 case CX_JSON_STRING: {
996
333155f234c4 add support for allocators to the json parser
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 976
diff changeset
658 cxFree(value->allocator, value->value.string.ptr);
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
659 break;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
660 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
661 default: {
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
662 break;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
663 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
664 }
996
333155f234c4 add support for allocators to the json parser
Olaf Wintermann <olaf.wintermann@gmail.com>
parents: 976
diff changeset
665 cxFree(value->allocator, value);
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
666 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
667
1009
7650e722437e minor cleanup
Mike Becker <universe@uap-core.de>
parents: 1008
diff changeset
668 CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index) {
967
a58f602ed2fe simplify parsing of array and object elements
Mike Becker <universe@uap-core.de>
parents: 965
diff changeset
669 if (index >= value->value.array.array_size) {
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
670 return &cx_json_value_nothing;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
671 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
672 return value->value.array.array[index];
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
673 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
674
1033
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
675 static void *cx_json_iter_current(const void *it) {
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
676 const CxIterator *iter = it;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
677 return *(CxJsonValue**)iter->elem_handle;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
678 }
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
679
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
680 static bool cx_json_iter_valid(const void *it) {
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
681 const CxIterator *iter = it;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
682 return iter->index < iter->elem_count;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
683 }
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
684
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
685 static void cx_json_iter_next(void *it) {
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
686 CxIterator *iter = it;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
687 iter->index++;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
688 iter->elem_handle = (char *) iter->elem_handle + sizeof(void *);
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
689 }
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
690
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
691 CxIterator cxJsonArrIter(const CxJsonValue *value) {
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
692 CxIterator iter;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
693
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
694 iter.index = 0;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
695 iter.elem_count = value->value.array.array_size;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
696 iter.src_handle.m = value->value.array.array;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
697 iter.elem_handle = iter.src_handle.m;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
698 iter.elem_size = sizeof(CxJsonValue*);
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
699 iter.base.valid = cx_json_iter_valid;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
700 iter.base.current = cx_json_iter_current;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
701 iter.base.next = cx_json_iter_next;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
702 iter.base.remove = false;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
703 iter.base.mutating = false;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
704
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
705 return iter;
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
706 }
e3009345984b add cxJsonArrIter() - fixes #524
Mike Becker <universe@uap-core.de>
parents: 1020
diff changeset
707
1037
83620ba72cc1 generify cxJsonObjGet() - fixes #525
Mike Becker <universe@uap-core.de>
parents: 1033
diff changeset
708 CxJsonValue *cx_json_obj_get_cxstr(const CxJsonValue *value, cxstring name) {
1009
7650e722437e minor cleanup
Mike Becker <universe@uap-core.de>
parents: 1008
diff changeset
709 const CxJsonObject *obj = &(value->value.object);
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
710 // TODO: think about sorting the object so that we can use binary search here
967
a58f602ed2fe simplify parsing of array and object elements
Mike Becker <universe@uap-core.de>
parents: 965
diff changeset
711 for (size_t i = 0; i < obj->values_size; i++) {
1037
83620ba72cc1 generify cxJsonObjGet() - fixes #525
Mike Becker <universe@uap-core.de>
parents: 1033
diff changeset
712 if (0 == cx_strcmp(name, cx_strcast(obj->values[i].name))) {
937
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
713 return obj->values[i].value;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
714 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
715 }
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
716 return &cx_json_value_nothing;
10123f4d5618 add first draft of json implementation - relates to #431
Mike Becker <universe@uap-core.de>
parents:
diff changeset
717 }

mercurial