-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjson-parser.h
More file actions
307 lines (257 loc) · 11.8 KB
/
json-parser.h
File metadata and controls
307 lines (257 loc) · 11.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
/*
* CentiJSON
* <http://github.com/mity/centijson>
*
* Copyright (c) 2018 Martin Mitas
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef JSON_H
#define JSON_H
#include <stdlib.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* JSON data types.
*
* Note that we distinguish beginning/end of the arrays and objects for
* the purposes of the processing.
*/
typedef enum JSON_TYPE {
JSON_NULL,
JSON_FALSE,
JSON_TRUE,
JSON_NUMBER,
JSON_STRING,
JSON_KEY, /* String in the specific role of an object key. */
JSON_ARRAY_BEG,
JSON_ARRAY_END,
JSON_OBJECT_BEG,
JSON_OBJECT_END
} JSON_TYPE;
/* Error codes.
*/
#define JSON_ERR_SUCCESS 0
#define JSON_ERR_INTERNAL (-1) /* This should never happen. If you see it, report bug ;-) */
#define JSON_ERR_OUTOFMEMORY (-2)
#define JSON_ERR_SYNTAX (-4) /* Generic syntax error. (More specific error codes are preferred.) */
#define JSON_ERR_BADCLOSER (-5) /* Mismatch in brackets (e.g. "{ ]" or "[ }") */
#define JSON_ERR_BADROOTTYPE (-6) /* Root type not allowed by CONFIG::flags. */
#define JSON_ERR_EXPECTEDVALUE (-7) /* Something unexpected where value has to be. */
#define JSON_ERR_EXPECTEDKEY (-8) /* Something unexpected where key has to be. */
#define JSON_ERR_EXPECTEDVALUEORCLOSER (-9) /* Something unexpected where value or array/object closer has to be. */
#define JSON_ERR_EXPECTEDKEYORCLOSER (-10) /* Something unexpected where key or array/object closer has to be. */
#define JSON_ERR_EXPECTEDCOLON (-11) /* Something unexpected where colon has to be. */
#define JSON_ERR_EXPECTEDCOMMAORCLOSER (-12) /* Something unexpected where comma or array/object has to be. */
#define JSON_ERR_EXPECTEDEOF (-13) /* Something unexpected where end-of-file has to be. */
#define JSON_ERR_MAXTOTALLEN (-14) /* Reached JSON_CONFIG::max_total_len */
#define JSON_ERR_MAXTOTALVALUES (-15) /* Reached JSON_CONFIG::max_total_values */
#define JSON_ERR_MAXNESTINGLEVEL (-16) /* Reached JSON_CONFIG::max_nesting_level */
#define JSON_ERR_MAXNUMBERLEN (-17) /* Reached JSON_CONFIG::max_number_len */
#define JSON_ERR_MAXSTRINGLEN (-18) /* Reached JSON_CONFIG::max_string_len */
#define JSON_ERR_MAXKEYLEN (-19) /* Reached JSON_CONFIG::max_key_len */
#define JSON_ERR_UNCLOSEDSTRING (-20) /* Unclosed string */
#define JSON_ERR_UNESCAPEDCONTROL (-21) /* Unescaped control character (in a string) */
#define JSON_ERR_INVALIDESCAPE (-22) /* Invalid/unknown escape sequence (in a string) */
#define JSON_ERR_INVALIDUTF8 (-23) /* Invalid UTF-8 (in a string) */
/* Bits for JSON_CONFIG::flags.
*/
#define JSON_NONULLASROOT 0x0001 /* Disallow null to be root value */
#define JSON_NOBOOLASROOT 0x0002 /* Disallow false or true to be root value */
#define JSON_NONUMBERASROOT 0x0004 /* Disallow number to be root value */
#define JSON_NOSTRINGASROOT 0x0008 /* Disallow string to be root value */
#define JSON_NOARRAYASROOT 0x0010 /* Disallow array to be root value */
#define JSON_NOOBJECTASROOT 0x0020 /* Disallow object to be root value */
#define JSON_NOSCALARROOT (JSON_NONULLASROOT | JSON_NOBOOLASROOT | \
JSON_NONUMBERASROOT | JSON_NOSTRINGASROOT)
#define JSON_NOVECTORROOT (JSON_NOARRAYASROOT | JSON_NOOBJECTASROOT)
#define JSON_IGNOREILLUTF8KEY 0x0100 /* Ignore ill-formed UTF-8 (for keys). */
#define JSON_FIXILLUTF8KEY 0x0200 /* Replace ill-formed UTF-8 char with replacement char (for keys). */
#define JSON_IGNOREILLUTF8VALUE 0x0400 /* Ignore ill-formed UTF-8 (for string values). */
#define JSON_FIXILLUTF8VALUE 0x0800 /* Replace ill-formed UTF-8 char with replacement char (for string values). */
/* Parser options, passed into json_init().
*
* If NULL is passed to json_init(), default values are used.
*/
typedef struct JSON_CONFIG {
size_t max_total_len; /* zero means no limit; default: 10 MB */
size_t max_total_values; /* zero means no limit; default: 0 */
size_t max_number_len; /* zero means no limit; default: 512 */
size_t max_string_len; /* zero means no limit; default: 65536 */
size_t max_key_len; /* zero means no limit; default: 512 */
unsigned max_nesting_level; /* zero means no limit; default: 512 */
unsigned flags; /* default: 0 */
} JSON_CONFIG;
/* Helper structure describing position in the input.
*
* It is used to specify where in the input a parsing error occurred for
* better diagnostics.
*/
typedef struct JSON_INPUT_POS {
size_t offset;
unsigned line_number;
unsigned column_number;
} JSON_INPUT_POS;
/* Callbacks the application has to implement, to process the parsed data.
*/
typedef struct JSON_CALLBACKS {
/* Data processing callback. For now (and maybe forever) the only callback.
*
* Note that `data` and `data_size` are set only for JSON_KEY, JSON_STRING
* and JSON_NUMBER. (For the other types the callback always gets NULL and
* 0).
*
* Inside an object, the application is guaranteed to get keys and their
* corresponding values in the alternating fashion (i.e. in the order
* as they are in the JSON input.).
*
* Application can abort the parsing operation by returning a non-zero.
* Note the non-zero return value of the callback is propagated to
* json_feed() and json_fini().
*/
int (*process)(JSON_TYPE /*type*/, const char* /*data*/,
size_t /*data_size*/, void* /*user_data*/);
} JSON_CALLBACKS;
/* Internal parser state. Use pointer to this structure as an opaque handle.
*/
typedef struct JSON_PARSER {
JSON_CALLBACKS callbacks;
JSON_CONFIG config;
void* user_data;
JSON_INPUT_POS pos;
JSON_INPUT_POS value_pos;
JSON_INPUT_POS err_pos;
int errcode;
size_t value_counter;
char* nesting_stack;
size_t nesting_level;
size_t nesting_stack_size;
unsigned automaton;
unsigned state;
unsigned substate;
uint32_t codepoint[2];
char* buf;
size_t buf_used;
size_t buf_alloced;
size_t last_cl_offset; /* Offset of most recently seen '\r' */
} JSON_PARSER;
/* Fill `config` with options used by default.
*/
void json_default_config(JSON_CONFIG* config);
/* Initialize the parser, associate it with the given callbacks and
* configuration. Returns zero on success, non-zero on an error.
*
* If `config` is NULL, default values are used.
*/
int json_init(JSON_PARSER* parser,
const JSON_CALLBACKS* callbacks,
const JSON_CONFIG* config,
void* user_data);
/* Feed the parser with more input.
*
* Returns zero on success.
*
* If an error occurs it returns non-zero and any attempt to call json_feed()
* again shall just fail with the same error code. Note the application should
* still call json_fini() to release all resources allocated by the parser.
*/
int json_feed(JSON_PARSER* parser, const char* input, size_t size);
/* Finish parsing of the document (note it can still call some callbacks); and
* release any resources held by the parser.
*
* Returns zero on success, or non-zero on failure.
*
* If `p_pos` is not NULL, it is filled with info about reached position in the
* input. It can help in diagnostics if the parsing failed.
*
* Note that if the preceding call to json_feed() failed, the error status also
* propagates into json_fini().
*
* Also note this function may still fail even when all preceding calls to
* json_feed() succeeded. This typically happens when the parser was fed with
* an incomplete JSON document.
*/
int json_fini(JSON_PARSER* parser, JSON_INPUT_POS* p_pos);
/* Simple wrapper function for json_init() + json_feed() + json_fini(), usable
* when the provided input contains complete JSON document.
*/
int json_parse(const char* input, size_t size,
const JSON_CALLBACKS* callbacks, const JSON_CONFIG* config,
void* user_data, JSON_INPUT_POS* p_pos);
/* Converts error code to human readable error message
*/
const char* json_error_str(int err_code);
/*****************
*** Utilities ***
*****************/
/* When implementing the callback processing the parsed data, these utilities
* below may come handy.
*/
/* Analyze the string holding a JSON number, and analyze whether it can
* fit into integer types.
*
* (Note it says "no" in cases the number string contains any fraction or
* exponent part.)
*/
void json_analyze_number(const char* num, size_t num_size,
int* p_is_int32_compatible,
int* p_is_uint32_compatible,
int* p_is_int64_compatible,
int* p_is_uint64_compatible);
/* Convert the string holding JSON number to the given C type.
*
* Note the conversion to any of the integer types is undefined unless
* json_analyze_number() says it's fine.
*
* Also note that json_number_to_double() can fail with JSON_ERR_OUTOFMEMORY.
* Hence its prototype differs.
*/
int32_t json_number_to_int32(const char* num, size_t num_size);
uint32_t json_number_to_uint32(const char* num, size_t num_size);
int64_t json_number_to_int64(const char* num, size_t num_size);
uint64_t json_number_to_uint64(const char* num, size_t num_size);
int json_number_to_double(const char* num, size_t num_size, double* p_result);
typedef int (*JSON_DUMP_CALLBACK)(const char* /*str*/, size_t /*size*/, void* /*user_data*/);
/* Helpers for writing numbers and strings in JSON-compatible format.
*
* Note that json_dump_string() assumes the string is a well-formed UTF-8
* string which needs no additional Unicode validation. The function "only"
* handles proper escaping of control characters.
*
* The provided writer callback must write all the data provided to it and
* return zero to indicate success, or non-zero to indicate an error and abort
* the operation.
*
* All these return zero on success, JSON_ERR_OUTOFMEMORY, or an error code
* propagated from the writer callback.
*
* (Given that all the other JSON stuff is trivial to output, the application
* is supposed to implement that manually.)
*/
int json_dump_int32(int32_t i32, JSON_DUMP_CALLBACK write_func, void* user_data);
int json_dump_uint32(uint32_t u32, JSON_DUMP_CALLBACK write_func, void* user_data);
int json_dump_int64(int64_t i64, JSON_DUMP_CALLBACK write_func, void* user_data);
int json_dump_uint64(uint64_t u64, JSON_DUMP_CALLBACK write_func, void* user_data);
int json_dump_double(double dbl, JSON_DUMP_CALLBACK write_func, void* user_data);
int json_dump_string(const char* str, size_t size, JSON_DUMP_CALLBACK write_func, void* user_data);
#ifdef __cplusplus
} /* extern "C" { */
#endif
#endif /* JSON_H */