Line | Count | Source |
1 | | #include <stdio.h> |
2 | | #include <stdlib.h> |
3 | | #include <string.h> |
4 | | #include <limits.h> |
5 | | #include <assert.h> |
6 | | #include "jv.h" |
7 | | #include "jv_dtoa.h" |
8 | | #include "jv_unicode.h" |
9 | | #include "jv_alloc.h" |
10 | | #include "jv_dtoa.h" |
11 | | |
12 | | typedef const char* presult; |
13 | | |
14 | | #ifndef MAX_PARSING_DEPTH |
15 | 50.7k | #define MAX_PARSING_DEPTH (10000) |
16 | | #endif |
17 | | |
18 | 29.3M | #define TRY(x) do {presult msg__ = (x); if (msg__) return msg__; } while(0) |
19 | | #ifdef __GNUC__ |
20 | | #define pfunc __attribute__((warn_unused_result)) presult |
21 | | #else |
22 | | #define pfunc presult |
23 | | #endif |
24 | | |
25 | | enum last_seen { |
26 | | JV_LAST_NONE = 0, |
27 | | JV_LAST_OPEN_ARRAY = '[', |
28 | | JV_LAST_OPEN_OBJECT = '{', |
29 | | JV_LAST_COLON = ':', |
30 | | JV_LAST_COMMA = ',', |
31 | | JV_LAST_VALUE = 'V', |
32 | | }; |
33 | | |
34 | | struct jv_parser { |
35 | | const char* curr_buf; |
36 | | int curr_buf_length; |
37 | | int curr_buf_pos; |
38 | | int curr_buf_is_partial; |
39 | | int eof; |
40 | | unsigned bom_strip_position; |
41 | | |
42 | | int flags; |
43 | | |
44 | | jv* stack; // parser |
45 | | int stackpos; // parser |
46 | | int stacklen; // both (optimization; it's really pathlen for streaming) |
47 | | jv path; // streamer |
48 | | enum last_seen last_seen; // streamer |
49 | | jv output; // streamer |
50 | | jv next; // both |
51 | | |
52 | | char* tokenbuf; |
53 | | int tokenpos; |
54 | | int tokenlen; |
55 | | |
56 | | int line, column; |
57 | | |
58 | | struct dtoa_context dtoa; |
59 | | |
60 | | enum { |
61 | | JV_PARSER_NORMAL, |
62 | | JV_PARSER_STRING, |
63 | | JV_PARSER_STRING_ESCAPE, |
64 | | JV_PARSER_WAITING_FOR_RS // parse error, waiting for RS |
65 | | } st; |
66 | | unsigned int last_ch_was_ws:1; |
67 | | }; |
68 | | |
69 | | |
70 | 496k | static void parser_init(struct jv_parser* p, int flags) { |
71 | 496k | p->flags = flags; |
72 | 496k | if ((p->flags & JV_PARSE_STREAMING)) { |
73 | 0 | p->path = jv_array(); |
74 | 496k | } else { |
75 | 496k | p->path = jv_invalid(); |
76 | 496k | p->flags &= ~(JV_PARSE_STREAM_ERRORS); |
77 | 496k | } |
78 | 496k | p->stack = 0; |
79 | 496k | p->stacklen = p->stackpos = 0; |
80 | 496k | p->last_seen = JV_LAST_NONE; |
81 | 496k | p->output = jv_invalid(); |
82 | 496k | p->next = jv_invalid(); |
83 | 496k | p->tokenlen = 256; |
84 | 496k | p->tokenbuf = jv_mem_alloc(p->tokenlen); |
85 | 496k | p->tokenpos = 0; |
86 | 496k | if ((p->flags & JV_PARSE_SEQ)) |
87 | 0 | p->st = JV_PARSER_WAITING_FOR_RS; |
88 | 496k | else |
89 | 496k | p->st = JV_PARSER_NORMAL; |
90 | 496k | p->eof = 0; |
91 | 496k | p->curr_buf = 0; |
92 | 496k | p->curr_buf_length = p->curr_buf_pos = p->curr_buf_is_partial = 0; |
93 | 496k | p->bom_strip_position = 0; |
94 | 496k | p->last_ch_was_ws = 0; |
95 | 496k | p->line = 1; |
96 | 496k | p->column = 0; |
97 | 496k | jvp_dtoa_context_init(&p->dtoa); |
98 | 496k | } |
99 | | |
100 | 525k | static void parser_reset(struct jv_parser* p) { |
101 | 525k | if ((p->flags & JV_PARSE_STREAMING)) { |
102 | 0 | jv_free(p->path); |
103 | 0 | p->path = jv_array(); |
104 | 0 | p->stacklen = 0; |
105 | 0 | } |
106 | 525k | p->last_seen = JV_LAST_NONE; |
107 | 525k | jv_free(p->output); |
108 | 525k | p->output = jv_invalid(); |
109 | 525k | jv_free(p->next); |
110 | 525k | p->next = jv_invalid(); |
111 | 568k | for (int i=0; i<p->stackpos; i++) |
112 | 42.9k | jv_free(p->stack[i]); |
113 | 525k | p->stackpos = 0; |
114 | 525k | p->tokenpos = 0; |
115 | 525k | p->st = JV_PARSER_NORMAL; |
116 | 525k | } |
117 | | |
118 | 496k | static void parser_free(struct jv_parser* p) { |
119 | 496k | parser_reset(p); |
120 | 496k | jv_free(p->path); |
121 | 496k | jv_free(p->output); |
122 | 496k | jv_mem_free(p->stack); |
123 | 496k | jv_mem_free(p->tokenbuf); |
124 | 496k | jvp_dtoa_context_free(&p->dtoa); |
125 | 496k | } |
126 | | |
127 | 501k | static pfunc value(struct jv_parser* p, jv val) { |
128 | 501k | if ((p->flags & JV_PARSE_STREAMING)) { |
129 | 0 | if (jv_is_valid(p->next) || p->last_seen == JV_LAST_VALUE) { |
130 | 0 | jv_free(val); |
131 | 0 | return "Expected separator between values"; |
132 | 0 | } |
133 | 0 | if (p->stacklen > 0) |
134 | 0 | p->last_seen = JV_LAST_VALUE; |
135 | 0 | else |
136 | 0 | p->last_seen = JV_LAST_NONE; |
137 | 501k | } else { |
138 | 501k | if (jv_is_valid(p->next)) { |
139 | 2.32k | jv_free(val); |
140 | 2.32k | return "Expected separator between values"; |
141 | 2.32k | } |
142 | 501k | } |
143 | 499k | jv_free(p->next); |
144 | 499k | p->next = val; |
145 | 499k | return 0; |
146 | 501k | } |
147 | | |
148 | 50.3k | static void push(struct jv_parser* p, jv v) { |
149 | 50.3k | assert(p->stackpos <= p->stacklen); |
150 | 50.3k | if (p->stackpos == p->stacklen) { |
151 | 22.9k | p->stacklen = p->stacklen * 2 + 10; |
152 | 22.9k | p->stack = jv_mem_realloc(p->stack, p->stacklen * sizeof(jv)); |
153 | 22.9k | } |
154 | 50.3k | assert(p->stackpos < p->stacklen); |
155 | 50.3k | p->stack[p->stackpos++] = v; |
156 | 50.3k | } |
157 | | |
158 | 80.9k | static pfunc parse_token(struct jv_parser* p, char ch) { |
159 | 80.9k | switch (ch) { |
160 | 35.1k | case '[': |
161 | 35.1k | if (p->stackpos >= MAX_PARSING_DEPTH) return "Exceeds depth limit for parsing"; |
162 | 35.1k | if (jv_is_valid(p->next)) return "Expected separator between values"; |
163 | 34.9k | push(p, jv_array()); |
164 | 34.9k | break; |
165 | | |
166 | 15.5k | case '{': |
167 | 15.5k | if (p->stackpos >= MAX_PARSING_DEPTH) return "Exceeds depth limit for parsing"; |
168 | 15.5k | if (jv_is_valid(p->next)) return "Expected separator between values"; |
169 | 14.2k | push(p, jv_object()); |
170 | 14.2k | break; |
171 | | |
172 | 3.17k | case ':': |
173 | 3.17k | if (!jv_is_valid(p->next)) |
174 | 342 | return "Expected string key before ':'"; |
175 | 2.83k | if (p->stackpos == 0 || jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_OBJECT) |
176 | 1.54k | return "':' not as part of an object"; |
177 | 1.28k | if (jv_get_kind(p->next) != JV_KIND_STRING) |
178 | 112 | return "Object keys must be strings"; |
179 | 1.17k | push(p, p->next); |
180 | 1.17k | p->next = jv_invalid(); |
181 | 1.17k | break; |
182 | | |
183 | 13.7k | case ',': |
184 | 13.7k | if (!jv_is_valid(p->next)) |
185 | 320 | return "Expected value before ','"; |
186 | 13.4k | if (p->stackpos == 0) |
187 | 0 | return "',' not as part of an object or array"; |
188 | 13.4k | if (jv_get_kind(p->stack[p->stackpos-1]) == JV_KIND_ARRAY) { |
189 | 12.8k | p->stack[p->stackpos-1] = jv_array_append(p->stack[p->stackpos-1], p->next); |
190 | 12.8k | p->next = jv_invalid(); |
191 | 12.8k | } else if (jv_get_kind(p->stack[p->stackpos-1]) == JV_KIND_STRING) { |
192 | 476 | assert(p->stackpos > 1 && jv_get_kind(p->stack[p->stackpos-2]) == JV_KIND_OBJECT); |
193 | 476 | p->stack[p->stackpos-2] = jv_object_set(p->stack[p->stackpos-2], |
194 | 476 | p->stack[p->stackpos-1], p->next); |
195 | 476 | p->stackpos--; |
196 | 476 | p->next = jv_invalid(); |
197 | 476 | } else { |
198 | | // this case hits on input like {"a", "b"} |
199 | 70 | return "Objects must consist of key:value pairs"; |
200 | 70 | } |
201 | 13.3k | break; |
202 | | |
203 | 13.3k | case ']': |
204 | 12.5k | if (p->stackpos == 0 || jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_ARRAY) |
205 | 5.87k | return "Unmatched ']'"; |
206 | 6.71k | if (jv_is_valid(p->next)) { |
207 | 6.22k | p->stack[p->stackpos-1] = jv_array_append(p->stack[p->stackpos-1], p->next); |
208 | 6.22k | p->next = jv_invalid(); |
209 | 6.22k | } else { |
210 | 488 | if (jv_array_length(jv_copy(p->stack[p->stackpos-1])) != 0) { |
211 | | // this case hits on input like [1,2,3,] |
212 | 229 | return "Expected another array element"; |
213 | 229 | } |
214 | 488 | } |
215 | 6.48k | jv_free(p->next); |
216 | 6.48k | p->next = p->stack[--p->stackpos]; |
217 | 6.48k | break; |
218 | | |
219 | 793 | case '}': |
220 | 793 | if (p->stackpos == 0) |
221 | 106 | return "Unmatched '}'"; |
222 | 687 | if (jv_is_valid(p->next)) { |
223 | 349 | if (jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_STRING) |
224 | 271 | return "Objects must consist of key:value pairs"; |
225 | 349 | assert(p->stackpos > 1 && jv_get_kind(p->stack[p->stackpos-2]) == JV_KIND_OBJECT); |
226 | 78 | p->stack[p->stackpos-2] = jv_object_set(p->stack[p->stackpos-2], |
227 | 78 | p->stack[p->stackpos-1], p->next); |
228 | 78 | p->stackpos--; |
229 | 78 | p->next = jv_invalid(); |
230 | 338 | } else { |
231 | 338 | if (jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_OBJECT) |
232 | 73 | return "Unmatched '}'"; |
233 | 265 | if (jv_object_length(jv_copy(p->stack[p->stackpos-1])) != 0) |
234 | 0 | return "Expected another key-value pair"; |
235 | 265 | } |
236 | 343 | jv_free(p->next); |
237 | 343 | p->next = p->stack[--p->stackpos]; |
238 | 343 | break; |
239 | 80.9k | } |
240 | 70.4k | return 0; |
241 | 80.9k | } |
242 | | |
243 | 0 | static pfunc stream_token(struct jv_parser* p, char ch) { |
244 | 0 | jv_kind k; |
245 | 0 | jv last; |
246 | |
|
247 | 0 | switch (ch) { |
248 | 0 | case '[': |
249 | 0 | if (jv_is_valid(p->next)) |
250 | 0 | return "Expected a separator between values"; |
251 | 0 | if (p->last_seen == JV_LAST_OPEN_OBJECT) |
252 | | // Looks like {["foo"]} |
253 | 0 | return "Expected string key after '{', not '['"; |
254 | 0 | if (p->last_seen == JV_LAST_COMMA) { |
255 | 0 | last = jv_array_get(jv_copy(p->path), p->stacklen - 1); |
256 | 0 | k = jv_get_kind(last); |
257 | 0 | jv_free(last); |
258 | 0 | if (k != JV_KIND_NUMBER) |
259 | | // Looks like {"x":"y",["foo"]} |
260 | 0 | return "Expected string key after ',' in object, not '['"; |
261 | 0 | } |
262 | 0 | p->path = jv_array_append(p->path, jv_number(0)); // push |
263 | 0 | p->last_seen = JV_LAST_OPEN_ARRAY; |
264 | 0 | p->stacklen++; |
265 | 0 | break; |
266 | | |
267 | 0 | case '{': |
268 | 0 | if (p->last_seen == JV_LAST_VALUE) |
269 | 0 | return "Expected a separator between values"; |
270 | 0 | if (p->last_seen == JV_LAST_OPEN_OBJECT) |
271 | | // Looks like {{"foo":"bar"}} |
272 | 0 | return "Expected string key after '{', not '{'"; |
273 | 0 | if (p->last_seen == JV_LAST_COMMA) { |
274 | 0 | last = jv_array_get(jv_copy(p->path), p->stacklen - 1); |
275 | 0 | k = jv_get_kind(last); |
276 | 0 | jv_free(last); |
277 | 0 | if (k != JV_KIND_NUMBER) |
278 | | // Looks like {"x":"y",{"foo":"bar"}} |
279 | 0 | return "Expected string key after ',' in object, not '{'"; |
280 | 0 | } |
281 | | // Push object key: null, since we don't know it yet |
282 | 0 | p->path = jv_array_append(p->path, jv_null()); // push |
283 | 0 | p->last_seen = JV_LAST_OPEN_OBJECT; |
284 | 0 | p->stacklen++; |
285 | 0 | break; |
286 | | |
287 | 0 | case ':': |
288 | 0 | last = jv_invalid(); |
289 | 0 | if (p->stacklen == 0 || jv_get_kind(last = jv_array_get(jv_copy(p->path), p->stacklen - 1)) == JV_KIND_NUMBER) { |
290 | 0 | jv_free(last); |
291 | 0 | return "':' not as part of an object"; |
292 | 0 | } |
293 | 0 | jv_free(last); |
294 | 0 | if (!jv_is_valid(p->next) || p->last_seen == JV_LAST_NONE) |
295 | 0 | return "Expected string key before ':'"; |
296 | 0 | if (jv_get_kind(p->next) != JV_KIND_STRING) |
297 | 0 | return "Object keys must be strings"; |
298 | 0 | if (p->last_seen != JV_LAST_VALUE) |
299 | 0 | return "':' should follow a key"; |
300 | 0 | p->last_seen = JV_LAST_COLON; |
301 | 0 | p->path = jv_array_set(p->path, p->stacklen - 1, p->next); |
302 | 0 | p->next = jv_invalid(); |
303 | 0 | break; |
304 | | |
305 | 0 | case ',': |
306 | 0 | if (p->last_seen != JV_LAST_VALUE) |
307 | 0 | return "Expected value before ','"; |
308 | 0 | if (p->stacklen == 0) |
309 | 0 | return "',' not as part of an object or array"; |
310 | 0 | last = jv_array_get(jv_copy(p->path), p->stacklen - 1); |
311 | 0 | k = jv_get_kind(last); |
312 | 0 | if (k == JV_KIND_NUMBER) { |
313 | 0 | int idx = jv_number_value(last); |
314 | |
|
315 | 0 | if (jv_is_valid(p->next)) { |
316 | 0 | p->output = JV_ARRAY(jv_copy(p->path), p->next); |
317 | 0 | p->next = jv_invalid(); |
318 | 0 | } |
319 | 0 | p->path = jv_array_set(p->path, p->stacklen - 1, jv_number(idx + 1)); |
320 | 0 | p->last_seen = JV_LAST_COMMA; |
321 | 0 | } else if (k == JV_KIND_STRING) { |
322 | 0 | if (jv_is_valid(p->next)) { |
323 | 0 | p->output = JV_ARRAY(jv_copy(p->path), p->next); |
324 | 0 | p->next = jv_invalid(); |
325 | 0 | } |
326 | 0 | p->path = jv_array_set(p->path, p->stacklen - 1, jv_null()); // ready for another key:value pair |
327 | 0 | p->last_seen = JV_LAST_COMMA; |
328 | 0 | } else { |
329 | 0 | assert(k == JV_KIND_NULL); |
330 | | // this case hits on input like {,} |
331 | | // make sure to handle input like {"a", "b"} and {"a":, ...} |
332 | 0 | jv_free(last); |
333 | 0 | return "Objects must consist of key:value pairs"; |
334 | 0 | } |
335 | 0 | jv_free(last); |
336 | 0 | break; |
337 | | |
338 | 0 | case ']': |
339 | 0 | if (p->stacklen == 0) |
340 | 0 | return "Unmatched ']' at the top-level"; |
341 | 0 | if (p->last_seen == JV_LAST_COMMA) |
342 | 0 | return "Expected another array element"; |
343 | 0 | if (p->last_seen == JV_LAST_OPEN_ARRAY) |
344 | 0 | assert(!jv_is_valid(p->next)); |
345 | |
|
346 | 0 | last = jv_array_get(jv_copy(p->path), p->stacklen - 1); |
347 | 0 | k = jv_get_kind(last); |
348 | 0 | jv_free(last); |
349 | |
|
350 | 0 | if (k != JV_KIND_NUMBER) |
351 | 0 | return "Unmatched ']' in the middle of an object"; |
352 | 0 | if (jv_is_valid(p->next)) { |
353 | 0 | p->output = JV_ARRAY(jv_copy(p->path), p->next, jv_true()); |
354 | 0 | p->next = jv_invalid(); |
355 | 0 | } else if (p->last_seen != JV_LAST_OPEN_ARRAY) { |
356 | 0 | p->output = JV_ARRAY(jv_copy(p->path)); |
357 | 0 | } |
358 | |
|
359 | 0 | p->path = jv_array_slice(p->path, 0, --(p->stacklen)); // pop |
360 | | //assert(!jv_is_valid(p->next)); |
361 | 0 | jv_free(p->next); |
362 | 0 | p->next = jv_invalid(); |
363 | |
|
364 | 0 | if (p->last_seen == JV_LAST_OPEN_ARRAY) |
365 | 0 | p->output = JV_ARRAY(jv_copy(p->path), jv_array()); // Empty arrays are leaves |
366 | |
|
367 | 0 | if (p->stacklen == 0) |
368 | 0 | p->last_seen = JV_LAST_NONE; |
369 | 0 | else |
370 | 0 | p->last_seen = JV_LAST_VALUE; |
371 | 0 | break; |
372 | | |
373 | 0 | case '}': |
374 | 0 | if (p->stacklen == 0) |
375 | 0 | return "Unmatched '}' at the top-level"; |
376 | 0 | if (p->last_seen == JV_LAST_COMMA) |
377 | 0 | return "Expected another key:value pair"; |
378 | 0 | if (p->last_seen == JV_LAST_OPEN_OBJECT) |
379 | 0 | assert(!jv_is_valid(p->next)); |
380 | |
|
381 | 0 | last = jv_array_get(jv_copy(p->path), p->stacklen - 1); |
382 | 0 | k = jv_get_kind(last); |
383 | 0 | jv_free(last); |
384 | 0 | if (k == JV_KIND_NUMBER) |
385 | 0 | return "Unmatched '}' in the middle of an array"; |
386 | | |
387 | 0 | if (jv_is_valid(p->next)) { |
388 | 0 | if (k != JV_KIND_STRING) |
389 | 0 | return "Objects must consist of key:value pairs"; |
390 | 0 | p->output = JV_ARRAY(jv_copy(p->path), p->next, jv_true()); |
391 | 0 | p->next = jv_invalid(); |
392 | 0 | } else { |
393 | | // Perhaps {"a":[]} |
394 | 0 | if (p->last_seen == JV_LAST_COLON) |
395 | | // Looks like {"a":} |
396 | 0 | return "Missing value in key:value pair"; |
397 | 0 | if (p->last_seen == JV_LAST_COMMA) |
398 | | // Looks like {"a":0,} |
399 | 0 | return "Expected another key-value pair"; |
400 | 0 | if (p->last_seen == JV_LAST_OPEN_ARRAY) |
401 | 0 | return "Unmatched '}' in the middle of an array"; |
402 | 0 | if (p->last_seen != JV_LAST_VALUE && p->last_seen != JV_LAST_OPEN_OBJECT) |
403 | 0 | return "Unmatched '}'"; |
404 | 0 | if (p->last_seen != JV_LAST_OPEN_OBJECT) |
405 | 0 | p->output = JV_ARRAY(jv_copy(p->path)); |
406 | 0 | } |
407 | 0 | p->path = jv_array_slice(p->path, 0, --(p->stacklen)); // pop |
408 | 0 | jv_free(p->next); |
409 | 0 | p->next = jv_invalid(); |
410 | |
|
411 | 0 | if (p->last_seen == JV_LAST_OPEN_OBJECT) |
412 | 0 | p->output = JV_ARRAY(jv_copy(p->path), jv_object()); // Empty arrays are leaves |
413 | |
|
414 | 0 | if (p->stacklen == 0) |
415 | 0 | p->last_seen = JV_LAST_NONE; |
416 | 0 | else |
417 | 0 | p->last_seen = JV_LAST_VALUE; |
418 | 0 | break; |
419 | 0 | } |
420 | 0 | return 0; |
421 | 0 | } |
422 | | |
423 | 28.6M | static pfunc tokenadd(struct jv_parser* p, char c) { |
424 | 28.6M | assert(p->tokenpos <= p->tokenlen); |
425 | 28.6M | if (p->tokenpos >= (p->tokenlen - 1)) { |
426 | 7.50k | if (p->tokenlen > INT_MAX / 2) |
427 | 0 | return "Token too long"; |
428 | 7.50k | p->tokenlen *= 2; |
429 | 7.50k | p->tokenbuf = jv_mem_realloc(p->tokenbuf, p->tokenlen); |
430 | 7.50k | } |
431 | 28.6M | assert(p->tokenpos < p->tokenlen); |
432 | 28.6M | p->tokenbuf[p->tokenpos++] = c; |
433 | 28.6M | return 0; |
434 | 28.6M | } |
435 | | |
436 | 4.89k | static int unhex4(char* hex) { |
437 | 4.89k | int r = 0; |
438 | 23.1k | for (int i=0; i<4; i++) { |
439 | 19.0k | char c = *hex++; |
440 | 19.0k | int n; |
441 | 19.0k | if ('0' <= c && c <= '9') n = c - '0'; |
442 | 10.5k | else if ('a' <= c && c <= 'f') n = c - 'a' + 10; |
443 | 5.62k | else if ('A' <= c && c <= 'F') n = c - 'A' + 10; |
444 | 742 | else return -1; |
445 | 18.2k | r <<= 4; |
446 | 18.2k | r |= n; |
447 | 18.2k | } |
448 | 4.15k | return r; |
449 | 4.89k | } |
450 | | |
451 | 9.12k | static pfunc found_string(struct jv_parser* p) { |
452 | 9.12k | char* in = p->tokenbuf; |
453 | 9.12k | char* out = p->tokenbuf; |
454 | 9.12k | char* end = p->tokenbuf + p->tokenpos; |
455 | | |
456 | 18.1M | while (in < end) { |
457 | 18.1M | char c = *in++; |
458 | 18.1M | if (c == '\\') { |
459 | 52.2k | if (in >= end) |
460 | 0 | return "Expected escape character at end of string"; |
461 | 52.2k | c = *in++; |
462 | 52.2k | switch (c) { |
463 | 45.2k | case '\\': |
464 | 45.3k | case '"': |
465 | 45.6k | case '/': *out++ = c; break; |
466 | 80 | case 'b': *out++ = '\b'; break; |
467 | 216 | case 'f': *out++ = '\f'; break; |
468 | 261 | case 't': *out++ = '\t'; break; |
469 | 690 | case 'n': *out++ = '\n'; break; |
470 | 235 | case 'r': *out++ = '\r'; break; |
471 | | |
472 | 4.34k | case 'u': |
473 | | /* ahh, the complicated case */ |
474 | 4.34k | if (in + 4 > end) |
475 | 619 | return "Invalid \\uXXXX escape"; |
476 | 3.72k | int hexvalue = unhex4(in); |
477 | 3.72k | if (hexvalue < 0) |
478 | 532 | return "Invalid characters in \\uXXXX escape"; |
479 | 3.19k | unsigned long codepoint = (unsigned long)hexvalue; |
480 | 3.19k | in += 4; |
481 | 3.19k | if (0xD800 <= codepoint && codepoint <= 0xDBFF) { |
482 | | /* who thought UTF-16 surrogate pairs were a good idea? */ |
483 | 1.68k | if (in + 6 > end || in[0] != '\\' || in[1] != 'u') |
484 | 513 | return "Invalid \\uXXXX\\uXXXX surrogate pair escape"; |
485 | 1.16k | unsigned long surrogate = unhex4(in+2); |
486 | 1.16k | if (!(0xDC00 <= surrogate && surrogate <= 0xDFFF)) |
487 | 467 | return "Invalid \\uXXXX\\uXXXX surrogate pair escape"; |
488 | 701 | in += 6; |
489 | 701 | codepoint = 0x10000 + (((codepoint - 0xD800) << 10) |
490 | 701 | |(surrogate - 0xDC00)); |
491 | 701 | } |
492 | 2.21k | if (codepoint > 0x10FFFF) |
493 | 0 | codepoint = 0xFFFD; // U+FFFD REPLACEMENT CHARACTER |
494 | 2.21k | out += jvp_utf8_encode(codepoint, out); |
495 | 2.21k | break; |
496 | | |
497 | 718 | default: |
498 | 718 | return "Invalid escape"; |
499 | 52.2k | } |
500 | 18.0M | } else { |
501 | 18.0M | if (!(c & ~0x1F)) |
502 | 3 | return "Invalid string: control characters from U+0000 through U+001F must be escaped"; |
503 | 18.0M | *out++ = c; |
504 | 18.0M | } |
505 | 18.1M | } |
506 | 6.26k | TRY(value(p, jv_string_sized(p->tokenbuf, out - p->tokenbuf))); |
507 | 6.26k | p->tokenpos = 0; |
508 | 6.26k | return 0; |
509 | 6.26k | } |
510 | | |
511 | 579k | static pfunc check_literal(struct jv_parser* p) { |
512 | 579k | if (p->tokenpos == 0) return 0; |
513 | | |
514 | 508k | const char* pattern = 0; |
515 | 508k | int plen; |
516 | 508k | jv v; |
517 | 508k | switch (p->tokenbuf[0]) { |
518 | 249 | case 't': pattern = "true"; plen = 4; v = jv_true(); break; |
519 | 245 | case 'f': pattern = "false"; plen = 5; v = jv_false(); break; |
520 | 244 | case '\'': |
521 | 244 | return "Invalid string literal; expected \", but got '"; |
522 | 5.45k | case 'n': |
523 | | // if it starts with 'n', it could be a literal "nan" |
524 | 5.45k | if (p->tokenpos > 1 && p->tokenbuf[1] == 'u') { |
525 | 201 | pattern = "null"; plen = 4; v = jv_null(); |
526 | 201 | } |
527 | 508k | } |
528 | 507k | if (pattern) { |
529 | 695 | if (p->tokenpos != plen) return "Invalid literal"; |
530 | 892 | for (int i=0; i<plen; i++) |
531 | 814 | if (p->tokenbuf[i] != pattern[i]) |
532 | 212 | return "Invalid literal"; |
533 | 78 | TRY(value(p, v)); |
534 | 507k | } else { |
535 | | // FIXME: better parser |
536 | 507k | p->tokenbuf[p->tokenpos] = 0; |
537 | 507k | #ifdef USE_DECNUM |
538 | 507k | jv number = jv_number_with_literal(p->tokenbuf); |
539 | 507k | if (jv_get_kind(number) == JV_KIND_INVALID) { |
540 | 11.8k | return "Invalid numeric literal"; |
541 | 11.8k | } |
542 | 495k | TRY(value(p, number)); |
543 | | #else |
544 | | char *end = 0; |
545 | | double d = jvp_strtod(&p->dtoa, p->tokenbuf, &end); |
546 | | if (end == 0 || *end != 0) { |
547 | | return "Invalid numeric literal"; |
548 | | } |
549 | | TRY(value(p, jv_number(d))); |
550 | | #endif |
551 | 495k | } |
552 | 492k | p->tokenpos = 0; |
553 | 492k | return 0; |
554 | 507k | } |
555 | | |
556 | | typedef enum { |
557 | | LITERAL, |
558 | | WHITESPACE, |
559 | | STRUCTURE, |
560 | | QUOTE, |
561 | | INVALID |
562 | | } chclass; |
563 | | |
564 | 9.98M | static chclass classify(char c) { |
565 | 9.98M | switch (c) { |
566 | 13.6k | case ' ': |
567 | 13.6k | case '\t': |
568 | 13.6k | case '\r': |
569 | 13.8k | case '\n': |
570 | 13.8k | return WHITESPACE; |
571 | 9.35k | case '"': |
572 | 9.35k | return QUOTE; |
573 | 35.6k | case '[': |
574 | 55.7k | case ',': |
575 | 68.9k | case ']': |
576 | 84.7k | case '{': |
577 | 88.6k | case ':': |
578 | 89.4k | case '}': |
579 | 89.4k | return STRUCTURE; |
580 | 9.86M | default: |
581 | 9.86M | return LITERAL; |
582 | 9.98M | } |
583 | 9.98M | } |
584 | | |
585 | | |
586 | | static const presult OK = "output produced"; |
587 | | |
588 | 10.0M | static int parse_check_done(struct jv_parser* p, jv* out) { |
589 | 10.0M | if (p->stackpos == 0 && jv_is_valid(p->next)) { |
590 | 13.4k | *out = p->next; |
591 | 13.4k | p->next = jv_invalid(); |
592 | 13.4k | return 1; |
593 | 10.0M | } else { |
594 | 10.0M | return 0; |
595 | 10.0M | } |
596 | 10.0M | } |
597 | | |
598 | 0 | static int stream_check_done(struct jv_parser* p, jv* out) { |
599 | 0 | if (p->stacklen == 0 && jv_is_valid(p->next)) { |
600 | 0 | *out = JV_ARRAY(jv_copy(p->path),p->next); |
601 | 0 | p->next = jv_invalid(); |
602 | 0 | return 1; |
603 | 0 | } else if (jv_is_valid(p->output)) { |
604 | 0 | if (jv_array_length(jv_copy(p->output)) > 2) { |
605 | | // At end of an array or object, necessitating one more output by |
606 | | // which to indicate this |
607 | 0 | *out = jv_array_slice(jv_copy(p->output), 0, 2); |
608 | 0 | p->output = jv_array_slice(p->output, 0, 1); // arrange one more output |
609 | 0 | } else { |
610 | | // No further processing needed |
611 | 0 | *out = p->output; |
612 | 0 | p->output = jv_invalid(); |
613 | 0 | } |
614 | 0 | return 1; |
615 | 0 | } else { |
616 | 0 | return 0; |
617 | 0 | } |
618 | 0 | } |
619 | | |
620 | 0 | static int seq_check_truncation(struct jv_parser* p) { |
621 | 0 | return (!p->last_ch_was_ws && (p->stackpos > 0 || p->tokenpos > 0 || jv_get_kind(p->next) == JV_KIND_NUMBER)); |
622 | 0 | } |
623 | | |
624 | 0 | static int stream_seq_check_truncation(struct jv_parser* p) { |
625 | 0 | jv_kind k = jv_get_kind(p->next); |
626 | 0 | return (p->stacklen > 0 || k == JV_KIND_NUMBER || k == JV_KIND_TRUE || k == JV_KIND_FALSE || k == JV_KIND_NULL); |
627 | 0 | } |
628 | | |
629 | 0 | static int parse_is_top_num(struct jv_parser* p) { |
630 | 0 | return (p->stackpos == 0 && jv_get_kind(p->next) == JV_KIND_NUMBER); |
631 | 0 | } |
632 | | |
633 | 0 | static int stream_is_top_num(struct jv_parser* p) { |
634 | 0 | return (p->stacklen == 0 && jv_get_kind(p->next) == JV_KIND_NUMBER); |
635 | 0 | } |
636 | | |
637 | | #define check_done(p, o) \ |
638 | 10.0M | (((p)->flags & JV_PARSE_STREAMING) ? stream_check_done((p), (o)) : parse_check_done((p), (o))) |
639 | | |
640 | | #define token(p, ch) \ |
641 | | (((p)->flags & JV_PARSE_STREAMING) ? stream_token((p), (ch)) : parse_token((p), (ch))) |
642 | | |
643 | | #define check_truncation(p) \ |
644 | 0 | (((p)->flags & JV_PARSE_STREAMING) ? stream_seq_check_truncation((p)) : seq_check_truncation((p))) |
645 | | |
646 | | #define is_top_num(p) \ |
647 | 0 | (((p)->flags & JV_PARSE_STREAMING) ? stream_is_top_num((p)) : parse_is_top_num((p))) |
648 | | |
649 | 28.7M | static pfunc scan(struct jv_parser* p, char ch, jv* out) { |
650 | 28.7M | p->column++; |
651 | 28.7M | if (ch == '\n') { |
652 | 207 | p->line++; |
653 | 207 | p->column = 0; |
654 | 207 | } |
655 | 28.7M | if ((p->flags & JV_PARSE_SEQ) |
656 | 0 | && ch == '\036' /* ASCII RS; see draft-ietf-json-sequence-07 */) { |
657 | 0 | if (check_truncation(p)) { |
658 | 0 | if (check_literal(p) == 0 && is_top_num(p)) |
659 | 0 | return "Potentially truncated top-level numeric value"; |
660 | 0 | return "Truncated value"; |
661 | 0 | } |
662 | 0 | TRY(check_literal(p)); |
663 | 0 | if (p->st == JV_PARSER_NORMAL && check_done(p, out)) |
664 | 0 | return OK; |
665 | | // shouldn't happen? |
666 | 0 | assert(!jv_is_valid(*out)); |
667 | 0 | parser_reset(p); |
668 | 0 | jv_free(*out); |
669 | 0 | *out = jv_invalid(); |
670 | 0 | return OK; |
671 | 0 | } |
672 | 28.7M | presult answer = 0; |
673 | 28.7M | p->last_ch_was_ws = 0; |
674 | 28.7M | if (p->st == JV_PARSER_NORMAL) { |
675 | 9.98M | chclass cls = classify(ch); |
676 | 9.98M | if (cls == WHITESPACE) |
677 | 13.8k | p->last_ch_was_ws = 1; |
678 | 9.98M | if (cls != LITERAL) { |
679 | 112k | TRY(check_literal(p)); |
680 | 97.9k | if (check_done(p, out)) answer = OK; |
681 | 97.9k | } |
682 | 9.96M | switch (cls) { |
683 | 9.86M | case LITERAL: |
684 | 9.86M | TRY(tokenadd(p, ch)); |
685 | 9.86M | break; |
686 | 9.86M | case WHITESPACE: |
687 | 7.62k | break; |
688 | 9.35k | case QUOTE: |
689 | 9.35k | p->st = JV_PARSER_STRING; |
690 | 9.35k | break; |
691 | 80.9k | case STRUCTURE: |
692 | 80.9k | TRY(token(p, ch)); |
693 | 70.4k | break; |
694 | 70.4k | case INVALID: |
695 | 0 | return "Invalid character"; |
696 | 9.96M | } |
697 | 9.95M | if (check_done(p, out)) answer = OK; |
698 | 18.8M | } else { |
699 | 18.8M | if (ch == '"' && p->st == JV_PARSER_STRING) { |
700 | 9.12k | TRY(found_string(p)); |
701 | 6.26k | p->st = JV_PARSER_NORMAL; |
702 | 6.26k | if (check_done(p, out)) answer = OK; |
703 | 18.8M | } else { |
704 | 18.8M | TRY(tokenadd(p, ch)); |
705 | 18.8M | if (ch == '\\' && p->st == JV_PARSER_STRING) { |
706 | 56.9k | p->st = JV_PARSER_STRING_ESCAPE; |
707 | 18.7M | } else { |
708 | 18.7M | p->st = JV_PARSER_STRING; |
709 | 18.7M | } |
710 | 18.8M | } |
711 | 18.8M | } |
712 | 28.7M | return answer; |
713 | 28.7M | } |
714 | | |
715 | 0 | struct jv_parser* jv_parser_new(int flags) { |
716 | 0 | struct jv_parser* p = jv_mem_alloc(sizeof(struct jv_parser)); |
717 | 0 | parser_init(p, flags); |
718 | 0 | p->flags = flags; |
719 | 0 | return p; |
720 | 0 | } |
721 | | |
722 | 0 | void jv_parser_free(struct jv_parser* p) { |
723 | 0 | parser_free(p); |
724 | 0 | jv_mem_free(p); |
725 | 0 | } |
726 | | |
727 | | static const unsigned char UTF8_BOM[] = {0xEF,0xBB,0xBF}; |
728 | | |
729 | 0 | int jv_parser_remaining(struct jv_parser* p) { |
730 | 0 | if (p->curr_buf == 0) |
731 | 0 | return 0; |
732 | 0 | return (p->curr_buf_length - p->curr_buf_pos); |
733 | 0 | } |
734 | | |
735 | 496k | void jv_parser_set_buf(struct jv_parser* p, const char* buf, int length, int is_partial) { |
736 | 496k | assert((p->curr_buf == 0 || p->curr_buf_pos == p->curr_buf_length) |
737 | 496k | && "previous buffer not exhausted"); |
738 | 994k | while (length > 0 && p->bom_strip_position < sizeof(UTF8_BOM)) { |
739 | 497k | if ((unsigned char)*buf == UTF8_BOM[p->bom_strip_position]) { |
740 | | // matched a BOM character |
741 | 1.25k | buf++; |
742 | 1.25k | length--; |
743 | 1.25k | p->bom_strip_position++; |
744 | 496k | } else { |
745 | 496k | if (p->bom_strip_position == 0) { |
746 | | // no BOM in this document |
747 | 495k | p->bom_strip_position = sizeof(UTF8_BOM); |
748 | 495k | } else { |
749 | | // malformed BOM (prefix present, rest missing) |
750 | 1.25k | p->bom_strip_position = 0xff; |
751 | 1.25k | } |
752 | 496k | } |
753 | 497k | } |
754 | 496k | p->curr_buf = buf; |
755 | 496k | p->curr_buf_length = length; |
756 | 496k | p->curr_buf_pos = 0; |
757 | 496k | p->curr_buf_is_partial = is_partial; |
758 | 496k | } |
759 | | |
760 | | static jv make_error(struct jv_parser*, const char *, ...) JV_PRINTF_LIKE(2, 3); |
761 | | |
762 | 28.7k | static jv make_error(struct jv_parser* p, const char *fmt, ...) { |
763 | 28.7k | va_list ap; |
764 | 28.7k | va_start(ap, fmt); |
765 | 28.7k | jv e = jv_string_vfmt(fmt, ap); |
766 | 28.7k | va_end(ap); |
767 | 28.7k | if ((p->flags & JV_PARSE_STREAM_ERRORS)) |
768 | 0 | return JV_ARRAY(e, jv_copy(p->path)); |
769 | 28.7k | return jv_invalid_with_msg(e); |
770 | 28.7k | } |
771 | | |
772 | 970k | jv jv_parser_next(struct jv_parser* p) { |
773 | 970k | if (p->eof) |
774 | 460k | return jv_invalid(); |
775 | 509k | if (!p->curr_buf) |
776 | 0 | return jv_invalid(); // Need a buffer |
777 | 509k | if (p->bom_strip_position == 0xff) { |
778 | 1.25k | if (!(p->flags & JV_PARSE_SEQ)) |
779 | 1.25k | return jv_invalid_with_msg(jv_string("Malformed BOM")); |
780 | 0 | p->st =JV_PARSER_WAITING_FOR_RS; |
781 | 0 | parser_reset(p); |
782 | 0 | } |
783 | 508k | jv value = jv_invalid(); |
784 | 508k | if ((p->flags & JV_PARSE_STREAMING) && stream_check_done(p, &value)) |
785 | 0 | return value; |
786 | 508k | char ch; |
787 | 508k | presult msg = 0; |
788 | 29.3M | while (!msg && p->curr_buf_pos < p->curr_buf_length) { |
789 | 28.7M | ch = p->curr_buf[p->curr_buf_pos++]; |
790 | 28.7M | if (p->st == JV_PARSER_WAITING_FOR_RS) { |
791 | 0 | if (ch == '\n') { |
792 | 0 | p->line++; |
793 | 0 | p->column = 0; |
794 | 0 | } else { |
795 | 0 | p->column++; |
796 | 0 | } |
797 | 0 | if (ch == '\036') |
798 | 0 | p->st = JV_PARSER_NORMAL; |
799 | 0 | continue; // need to resync, wait for RS |
800 | 0 | } |
801 | 28.7M | msg = scan(p, ch, &value); |
802 | 28.7M | } |
803 | 508k | if (msg == OK) { |
804 | 13.3k | return value; |
805 | 495k | } else if (msg) { |
806 | 28.1k | jv_free(value); |
807 | 28.1k | if (ch != '\036' && (p->flags & JV_PARSE_SEQ)) { |
808 | | // Skip to the next RS |
809 | 0 | p->st = JV_PARSER_WAITING_FOR_RS; |
810 | 0 | value = make_error(p, "%s at line %d, column %d (need RS to resync)", msg, p->line, p->column); |
811 | 0 | parser_reset(p); |
812 | 0 | return value; |
813 | 0 | } |
814 | 28.1k | value = make_error(p, "%s at line %d, column %d", msg, p->line, p->column); |
815 | 28.1k | parser_reset(p); |
816 | 28.1k | if (!(p->flags & JV_PARSE_SEQ)) { |
817 | | // We're not parsing a JSON text sequence; throw this buffer away. |
818 | | // XXX We should fail permanently here. |
819 | 28.1k | p->curr_buf = 0; |
820 | 28.1k | p->curr_buf_pos = 0; |
821 | 28.1k | } // Else ch must be RS; don't clear buf so we can start parsing again after this ch |
822 | 28.1k | return value; |
823 | 467k | } else if (p->curr_buf_is_partial) { |
824 | 0 | assert(p->curr_buf_pos == p->curr_buf_length); |
825 | | // need another buffer |
826 | 0 | return jv_invalid(); |
827 | 467k | } else { |
828 | | // at EOF |
829 | 467k | p->eof = 1; |
830 | 467k | assert(p->curr_buf_pos == p->curr_buf_length); |
831 | 467k | jv_free(value); |
832 | 467k | if (p->st == JV_PARSER_WAITING_FOR_RS) |
833 | 0 | return make_error(p, "Unfinished abandoned text at EOF at line %d, column %d", p->line, p->column); |
834 | 467k | if (p->st != JV_PARSER_NORMAL) { |
835 | 236 | value = make_error(p, "Unfinished string at EOF at line %d, column %d", p->line, p->column); |
836 | 236 | parser_reset(p); |
837 | 236 | p->st = JV_PARSER_WAITING_FOR_RS; |
838 | 236 | return value; |
839 | 236 | } |
840 | 466k | if ((msg = check_literal(p))) { |
841 | 275 | value = make_error(p, "%s at EOF at line %d, column %d", msg, p->line, p->column); |
842 | 275 | parser_reset(p); |
843 | 275 | p->st = JV_PARSER_WAITING_FOR_RS; |
844 | 275 | return value; |
845 | 275 | } |
846 | 466k | if (((p->flags & JV_PARSE_STREAMING) && p->stacklen != 0) || |
847 | 466k | (!(p->flags & JV_PARSE_STREAMING) && p->stackpos != 0)) { |
848 | 157 | value = make_error(p, "Unfinished JSON term at EOF at line %d, column %d", p->line, p->column); |
849 | 157 | parser_reset(p); |
850 | 157 | p->st = JV_PARSER_WAITING_FOR_RS; |
851 | 157 | return value; |
852 | 157 | } |
853 | | // p->next is either invalid (nothing here, but no syntax error) |
854 | | // or valid (this is the value). either way it's the thing to return |
855 | 466k | if ((p->flags & JV_PARSE_STREAMING) && jv_is_valid(p->next)) { |
856 | 0 | value = JV_ARRAY(jv_copy(p->path), p->next); // except in streaming mode we've got to make it [path,value] |
857 | 466k | } else { |
858 | 466k | value = p->next; |
859 | 466k | } |
860 | 466k | p->next = jv_invalid(); |
861 | 466k | if ((p->flags & JV_PARSE_SEQ) && !p->last_ch_was_ws && jv_get_kind(value) == JV_KIND_NUMBER) { |
862 | 0 | jv_free(value); |
863 | 0 | return make_error(p, "Potentially truncated top-level numeric value at EOF at line %d, column %d", p->line, p->column); |
864 | 0 | } |
865 | 466k | return value; |
866 | 466k | } |
867 | 508k | } |
868 | | |
869 | 496k | jv jv_parse_sized_custom_flags(const char* string, int length, int flags) { |
870 | 496k | struct jv_parser parser; |
871 | 496k | parser_init(&parser, flags); |
872 | 496k | jv_parser_set_buf(&parser, string, length, 0); |
873 | 496k | jv value = jv_parser_next(&parser); |
874 | 496k | if (jv_is_valid(value)) { |
875 | 474k | jv next = jv_parser_next(&parser); |
876 | 474k | if (jv_is_valid(next)) { |
877 | | // multiple JSON values, we only wanted one |
878 | 225 | jv_free(value); |
879 | 225 | jv_free(next); |
880 | 225 | value = jv_invalid_with_msg(jv_string("Unexpected extra JSON values")); |
881 | 473k | } else if (jv_invalid_has_msg(jv_copy(next))) { |
882 | | // parser error after the first JSON value |
883 | 7.57k | jv_free(value); |
884 | 7.57k | value = next; |
885 | 466k | } else { |
886 | | // a single valid JSON value |
887 | 466k | jv_free(next); |
888 | 466k | } |
889 | 474k | } else if (jv_invalid_has_msg(jv_copy(value))) { |
890 | | // parse error, we'll return it |
891 | 22.4k | } else { |
892 | | // no value at all |
893 | 255 | jv_free(value); |
894 | 255 | value = jv_invalid_with_msg(jv_string("Expected JSON value")); |
895 | 255 | } |
896 | 496k | parser_free(&parser); |
897 | | |
898 | 496k | if (!jv_is_valid(value) && jv_invalid_has_msg(jv_copy(value))) { |
899 | 30.5k | jv msg = jv_invalid_get_msg(value); |
900 | 30.5k | value = jv_invalid_with_msg(jv_string_fmt("%s (while parsing '%.*s')", |
901 | 30.5k | jv_string_value(msg), |
902 | 30.5k | length, |
903 | 30.5k | string)); |
904 | 30.5k | jv_free(msg); |
905 | 30.5k | } |
906 | 496k | return value; |
907 | 496k | } |
908 | | |
909 | 496k | jv jv_parse_sized(const char* string, int length) { |
910 | 496k | return jv_parse_sized_custom_flags(string, length, 0); |
911 | 496k | } |
912 | | |
913 | 7.30k | jv jv_parse(const char* string) { |
914 | 7.30k | return jv_parse_sized(string, strlen(string)); |
915 | 7.30k | } |
916 | | |
917 | 0 | jv jv_parse_custom_flags(const char* string, int flags) { |
918 | 0 | return jv_parse_sized_custom_flags(string, strlen(string), flags); |
919 | 0 | } |