src/cx/json.h

changeset 937
10123f4d5618
equal deleted inserted replaced
936:9b9385fcdfd5 937:10123f4d5618
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2024 Mike Becker, Olaf Wintermann All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28 /**
29 * \file json.h
30 * \brief Interface for parsing data from JSON files.
31 * \author Mike Becker
32 * \author Olaf Wintermann
33 * \copyright 2-Clause BSD License
34 */
35
36 #ifndef UCX_JSON_H
37 #define UCX_JSON_H
38
39 #include "common.h"
40 #include "string.h"
41
42 #ifdef __cplusplus
43 extern "C" {
44 #endif
45
46 enum cx_json_token_type {
47 CX_JSON_NO_TOKEN,
48 CX_JSON_TOKEN_ERROR,
49 CX_JSON_TOKEN_BEGIN_ARRAY,
50 CX_JSON_TOKEN_BEGIN_OBJECT,
51 CX_JSON_TOKEN_END_ARRAY,
52 CX_JSON_TOKEN_END_OBJECT,
53 CX_JSON_TOKEN_NAME_SEPARATOR,
54 CX_JSON_TOKEN_VALUE_SEPARATOR,
55 CX_JSON_TOKEN_STRING,
56 CX_JSON_TOKEN_INTEGER,
57 CX_JSON_TOKEN_NUMBER,
58 CX_JSON_TOKEN_LITERAL,
59 CX_JSON_TOKEN_SPACE
60 };
61
62 enum cx_json_value_type {
63 CX_JSON_NOTHING, // this allows us to always return non-NULL values
64 CX_JSON_OBJECT,
65 CX_JSON_ARRAY,
66 CX_JSON_STRING,
67 CX_JSON_INTEGER, // TODO: the spec does not know integer types
68 CX_JSON_NUMBER,
69 CX_JSON_LITERAL
70 };
71
72 enum cx_json_literal_type {
73 CX_JSON_NULL,
74 CX_JSON_TRUE,
75 CX_JSON_FALSE
76 };
77
78 enum cx_json_reader_type {
79 CX_JSON_READER_OBJECT_BEGIN,
80 CX_JSON_READER_OBJECT_END,
81 CX_JSON_READER_ARRAY_BEGIN,
82 CX_JSON_READER_ARRAY_END,
83 CX_JSON_READER_STRING,
84 CX_JSON_READER_INTEGER,
85 CX_JSON_READER_NUMBER,
86 CX_JSON_READER_LITERAL
87 };
88
89 typedef enum cx_json_token_type CxJsonTokenType;
90 typedef enum cx_json_value_type CxJsonValueType;
91 typedef enum cx_json_literal_type CxJsonLiteralType;
92 typedef enum cx_json_reader_type CxJsonReaderType;
93
94 typedef struct cx_json_s CxJson;
95 typedef struct cx_json_token_s CxJsonToken;
96
97 typedef struct cx_json_value_s CxJsonValue;
98
99 typedef struct cx_json_array_s CxJsonArray;
100 typedef struct cx_json_object_s CxJsonObject;
101 typedef struct cx_mutstr_s CxJsonString;
102 typedef struct cx_json_integer_s CxJsonInteger;
103 typedef struct cx_json_number_s CxJsonNumber;
104 typedef struct cx_json_literal_s CxJsonLiteral;
105
106 typedef struct cx_json_obj_value_s CxJsonObjValue;
107
108 struct cx_json_token_s {
109 CxJsonTokenType tokentype;
110 const char *content;
111 size_t length;
112 size_t alloc;
113 };
114
115 struct cx_json_s {
116 const char *buffer;
117 size_t size;
118 size_t pos;
119
120 CxJsonToken uncompleted;
121 int tokenizer_escape;
122
123 int *states;
124 int nstates;
125 int states_alloc;
126
127 CxJsonToken reader_token;
128 CxJsonReaderType reader_type;
129 int value_ready;
130 char *value_name;
131 size_t value_name_len;
132 char *value_str;
133 size_t value_str_len;
134 int64_t value_int;
135 double value_double;
136
137 CxJsonValue **readvalue_stack;
138 int readvalue_nelm;
139 int readvalue_alloc;
140 CxJsonValue *read_value;
141 int readvalue_initialized;
142
143 int reader_array_alloc;
144
145 int error;
146 };
147
148 struct cx_json_array_s {
149 CxJsonValue **array;
150 size_t alloc;
151 size_t size;
152 };
153
154 struct cx_json_object_s {
155 CxJsonObjValue *values;
156 size_t alloc;
157 size_t size;
158 };
159
160 struct cx_json_obj_value_s {
161 char *name;
162 CxJsonValue *value;
163 };
164
165 // TODO: remove single member structs
166
167 struct cx_json_integer_s {
168 int64_t value;
169 };
170
171 struct cx_json_number_s {
172 double value;
173 };
174
175 struct cx_json_literal_s {
176 CxJsonLiteralType literal;
177 };
178
179 struct cx_json_value_s {
180 CxJsonValueType type;
181 union {
182 CxJsonArray array;
183 CxJsonObject object;
184 CxJsonString string;
185 CxJsonInteger integer;
186 CxJsonNumber number;
187 CxJsonLiteral literal;
188 } value;
189 };
190
191 // TODO: add support for CxAllocator
192
193 __attribute__((__nonnull__))
194 void cxJsonInit(CxJson *json);
195
196 __attribute__((__nonnull__))
197 void cxJsonDestroy(CxJson *json);
198
199 __attribute__((__nonnull__))
200 void cxJsonFill(CxJson *json, const char *buf, size_t len);
201
202 // TODO: discuss if it is intentional that cxJsonNext() will usually parse an entire file in one go
203 __attribute__((__nonnull__))
204 int cxJsonNext(CxJson *json, CxJsonValue **value);
205
206 void cxJsonValueFree(CxJsonValue *value);
207
208 __attribute__((__nonnull__))
209 static inline bool cxJsonIsObject(CxJsonValue *value) {
210 return value->type == CX_JSON_OBJECT;
211 }
212
213 __attribute__((__nonnull__))
214 static inline bool cxJsonIsArray(CxJsonValue *value) {
215 return value->type == CX_JSON_ARRAY;
216 }
217
218 __attribute__((__nonnull__))
219 static inline bool cxJsonIsString(CxJsonValue *value) {
220 return value->type == CX_JSON_STRING;
221 }
222
223 __attribute__((__nonnull__))
224 static inline bool cxJsonIsNumber(CxJsonValue *value) {
225 // TODO: this is not good, because an integer is also a number
226 return value->type == CX_JSON_NUMBER;
227 }
228
229 __attribute__((__nonnull__))
230 static inline bool cxJsonIsInteger(CxJsonValue *value) {
231 return value->type == CX_JSON_INTEGER;
232 }
233
234 __attribute__((__nonnull__))
235 static inline bool cxJsonIsLiteral(CxJsonValue *value) {
236 return value->type == CX_JSON_LITERAL;
237 }
238
239 __attribute__((__nonnull__))
240 static inline bool cxJsonIsBool(CxJsonValue *value) {
241 return cxJsonIsLiteral(value) && value->value.literal.literal != CX_JSON_NULL;
242 }
243
244 __attribute__((__nonnull__))
245 static inline bool cxJsonIsTrue(CxJsonValue *value) {
246 return cxJsonIsLiteral(value) && value->value.literal.literal == CX_JSON_TRUE;
247 }
248
249 __attribute__((__nonnull__))
250 static inline bool cxJsonIsFalse(CxJsonValue *value) {
251 return cxJsonIsLiteral(value) && value->value.literal.literal == CX_JSON_FALSE;
252 }
253
254 __attribute__((__nonnull__))
255 static inline bool cxJsonIsNull(CxJsonValue *value) {
256 return cxJsonIsLiteral(value) && value->value.literal.literal == CX_JSON_NULL;
257 }
258
259 __attribute__((__nonnull__))
260 static inline cxmutstr cxJsonAsString(CxJsonValue *value) {
261 // TODO: do we need a separate method to return this directly as cxstring?
262 return value->value.string;
263 }
264
265 __attribute__((__nonnull__))
266 static inline double cxJsonAsDouble(CxJsonValue *value) {
267 return value->value.number.value;
268 }
269
270 __attribute__((__nonnull__))
271 static inline int64_t cxJsonAsInteger(CxJsonValue *value) {
272 return value->value.integer.value;
273 }
274
275 __attribute__((__nonnull__))
276 static inline bool cxJsonAsBool(CxJsonValue *value) {
277 return value->value.literal.literal == CX_JSON_TRUE;
278 }
279
280 __attribute__((__nonnull__))
281 static inline size_t cxJsonArrSize(CxJsonValue *value) {
282 return value->value.array.size;
283 }
284
285 __attribute__((__nonnull__, __returns_nonnull__))
286 CxJsonValue *cxJsonArrGet(CxJsonValue *value, size_t index);
287
288 // TODO: add cxJsonArrIter()
289
290 // TODO: implement cxJsonObjGet as a _Generic with support for cxstring
291 __attribute__((__nonnull__, __returns_nonnull__))
292 CxJsonValue *cxJsonObjGet(CxJsonValue *value, const char* name);
293
294 #ifdef __cplusplus
295 }
296 #endif
297
298 #endif /* UCX_JSON_H */
299

mercurial