1 /* JSON Parser
2 * ZZJSON - Copyright (C) 2008-2009 by Ivo van Poorten
3 * License: GNU Lesser General Public License version 2.1
4 */
5
6 #include "zzjson.h"
7 #include <ctype.h>
8 #include <string.h>
9 #include <math.h>
10 #include <stdio.h>
11
12 #define GETC() config->getchar(config->ihandle)
13 #define UNGETC(c) config->ungetchar(c, config->ihandle)
14 #define SKIPWS() skipws(config)
15 #ifdef CONFIG_NO_ERROR_MESSAGES
16 #define ERROR(x...)
17 #else
18 #define ERROR(x...) config->error(config->ehandle, ##x)
19 #endif
20 #define MEMERROR() ERROR("out of memory")
21
22 #define ALLOW_EXTRA_COMMA (config->strictness & ZZJSON_ALLOW_EXTRA_COMMA)
23 #define ALLOW_ILLEGAL_ESCAPE (config->strictness & ZZJSON_ALLOW_ILLEGAL_ESCAPE)
24 #define ALLOW_CONTROL_CHARS (config->strictness & ZZJSON_ALLOW_CONTROL_CHARS)
25 #define ALLOW_GARBAGE_AT_END (config->strictness & ZZJSON_ALLOW_GARBAGE_AT_END)
26 #define ALLOW_COMMENTS (config->strictness & ZZJSON_ALLOW_COMMENTS)
27
28 static ZZJSON *parse_array(ZZJSON_CONFIG *config);
29 static ZZJSON *parse_object(ZZJSON_CONFIG *config);
30
skipws(ZZJSON_CONFIG * config)31 static void skipws(ZZJSON_CONFIG *config) {
32 int d, c = GETC();
33 morews:
34 while (isspace(c)) c = GETC();
35 if (!ALLOW_COMMENTS) goto endws;
36 if (c != '/') goto endws;
37 d = GETC();
38 if (d != '*') goto endws; /* pushing back c will generate a parse error */
39 c = GETC();
40 morecomments:
41 while (c != '*') {
42 if (c == EOF) goto endws;
43 c = GETC();
44 }
45 c = GETC();
46 if (c != '/') goto morecomments;
47 c = GETC();
48 if (isspace(c) || c == '/') goto morews;
49 endws:
50 UNGETC(c);
51 }
52
parse_string(ZZJSON_CONFIG * config)53 static char *parse_string(ZZJSON_CONFIG *config) {
54 unsigned int len = 16, pos = 0;
55 int c;
56 char *str = NULL;
57
58 SKIPWS();
59 c = GETC();
60 if (c != '"') {
61 ERROR("string: expected \" at the start");
62 return NULL;
63 }
64
65 str = config->malloc(len);
66 if (!str) {
67 MEMERROR();
68 return NULL;
69 }
70 c = GETC();
71 while (c > 0 && c != '"') {
72 if (!ALLOW_CONTROL_CHARS && c >= 0 && c <= 31) {
73 ERROR("string: control characters not allowed");
74 goto errout;
75 }
76 if (c == '\\') {
77 c = GETC();
78 switch (c) {
79 case 'b': c = '\b'; break;
80 case 'f': c = '\f'; break;
81 case 'n': c = '\n'; break;
82 case 'r': c = '\r'; break;
83 case 't': c = '\t'; break;
84 case 'u': {
85 UNGETC(c); /* ignore \uHHHH, copy verbatim */
86 c = '\\';
87 break;
88 }
89 case '\\': case '/': case '"':
90 break;
91 default:
92 if (!ALLOW_ILLEGAL_ESCAPE) {
93 ERROR("string: illegal escape character");
94 goto errout;
95 }
96 }
97 }
98 str[pos++] = c;
99 if (pos == len-1) {
100 void *tmp = str;
101 len *= 2;
102 str = config->realloc(str, len);
103 if (!str) {
104 MEMERROR();
105 str = tmp;
106 goto errout;
107 }
108 }
109 c = GETC();
110 }
111 if (c != '"') {
112 ERROR("string: expected \" at the end");
113 goto errout;
114 }
115 str[pos] = 0;
116 return str;
117
118 errout:
119 config->free(str);
120 return NULL;
121 }
122
parse_string2(ZZJSON_CONFIG * config)123 static ZZJSON *parse_string2(ZZJSON_CONFIG *config) {
124 ZZJSON *zzjson = NULL;
125 char *str;
126
127 str = parse_string(config);
128 if (str) {
129 zzjson = config->calloc(1, sizeof(ZZJSON));
130 if (!zzjson) {
131 MEMERROR();
132 config->free(str);
133 return NULL;
134 }
135 zzjson->type = ZZJSON_STRING;
136 zzjson->value.string.string = str;
137 }
138 return zzjson;
139 }
140
parse_number(ZZJSON_CONFIG * config)141 static ZZJSON *parse_number(ZZJSON_CONFIG *config) {
142 ZZJSON *zzjson;
143 unsigned long long ival = 0, expo = 0;
144 double dval = 0.0, frac = 0.0, fracshft = 10.0;
145 int c, dbl = 0, sign = 1, signexpo = 1;
146
147 SKIPWS();
148 c = GETC();
149 if (c == '-') {
150 sign = -1;
151 c = GETC();
152 }
153 if (c == '0') {
154 c = GETC();
155 goto skip;
156 }
157
158 if (!isdigit(c)) {
159 ERROR("number: digit expected");
160 return NULL;
161 }
162
163 while (isdigit(c)) {
164 ival *= 10;
165 ival += c - '0';
166 c = GETC();
167 }
168
169 skip:
170 if (c != '.') goto skipfrac;
171
172 dbl = 1;
173
174 c = GETC();
175 if (!isdigit(c)) {
176 ERROR("number: digit expected");
177 return NULL;
178 }
179
180 while (isdigit(c)) {
181 frac += (double)(c - '0') / fracshft;
182 fracshft *= 10.0;
183 c = GETC();
184 }
185
186 skipfrac:
187 if (c != 'e' && c != 'E') goto skipexpo;
188
189 dbl = 1;
190
191 c = GETC();
192 if (c == '+')
193 c = GETC();
194 else if (c == '-') {
195 signexpo = -1;
196 c = GETC();
197 }
198
199 if (!isdigit(c)) {
200 ERROR("number: digit expected");
201 return NULL;
202 }
203
204 while (isdigit(c)) {
205 expo *= 10;
206 expo += c - '0';
207 c = GETC();
208 }
209
210 skipexpo:
211 UNGETC(c);
212
213 if (dbl) {
214 dval = sign * (long long) ival;
215 dval += sign * frac;
216 dval *= pow(10.0, (double) signexpo * expo);
217 }
218
219 zzjson = config->calloc(1, sizeof(ZZJSON));
220 if (!zzjson) {
221 MEMERROR();
222 return NULL;
223 }
224 if (dbl) {
225 zzjson->type = ZZJSON_NUMBER_DOUBLE;
226 zzjson->value.number.val.dval = dval;
227 } else {
228 zzjson->type = sign < 0 ? ZZJSON_NUMBER_NEGINT : ZZJSON_NUMBER_POSINT;
229 zzjson->value.number.val.ival = ival;
230 }
231
232 return zzjson;
233 }
234
parse_literal(ZZJSON_CONFIG * config,char * s,ZZJSON_TYPE t)235 static ZZJSON *parse_literal(ZZJSON_CONFIG *config, char *s, ZZJSON_TYPE t) {
236 char b[strlen(s)+1];
237 unsigned int i;
238
239 for (i=0; i<strlen(s); i++) b[i] = GETC();
240 b[i] = 0;
241
242 if (!strcmp(b,s)) {
243 ZZJSON *zzjson;
244 zzjson = config->calloc(1, sizeof(ZZJSON));
245 if (!zzjson) {
246 MEMERROR();
247 return NULL;
248 }
249 zzjson->type = t;
250 return zzjson;
251 }
252 ERROR("literal: expected %s", s);
253 return NULL;
254 }
255
parse_true(ZZJSON_CONFIG * config)256 static ZZJSON *parse_true(ZZJSON_CONFIG *config) {
257 return parse_literal(config, (char *)"true", ZZJSON_TRUE);
258 }
259
parse_false(ZZJSON_CONFIG * config)260 static ZZJSON *parse_false(ZZJSON_CONFIG *config) {
261 return parse_literal(config, (char *)"false", ZZJSON_FALSE);
262 }
263
parse_null(ZZJSON_CONFIG * config)264 static ZZJSON *parse_null(ZZJSON_CONFIG *config) {
265 return parse_literal(config, (char *)"null", ZZJSON_NULL);
266 }
267
parse_value(ZZJSON_CONFIG * config)268 static ZZJSON *parse_value(ZZJSON_CONFIG *config) {
269 ZZJSON *retval = NULL;
270 int c;
271
272 SKIPWS();
273 c = GETC();
274 UNGETC(c);
275 switch (c) {
276 case '"': retval = parse_string2(config); break;
277 case '0': case '1': case '2': case '3': case '4': case '5':
278 case '6': case '7': case '8': case '9': case '-':
279 retval = parse_number(config); break;
280 case '{': retval = parse_object(config); break;
281 case '[': retval = parse_array(config); break;
282 case 't': retval = parse_true(config); break;
283 case 'f': retval = parse_false(config); break;
284 case 'n': retval = parse_null(config); break;
285 }
286
287 if (!retval) {
288 ERROR("value: invalid value");
289 return retval;
290 }
291
292 return retval;
293 }
294
parse_array(ZZJSON_CONFIG * config)295 static ZZJSON *parse_array(ZZJSON_CONFIG *config) {
296 ZZJSON *retval = NULL, **next = &retval;
297 int c;
298
299 SKIPWS();
300 c = GETC();
301 if (c != '[') {
302 ERROR("array: expected '['");
303 return NULL;
304 }
305
306 SKIPWS();
307 c = GETC();
308 while (c > 0 && c != ']') {
309 ZZJSON *zzjson = NULL, *val = NULL;
310
311 UNGETC(c);
312
313 SKIPWS();
314 val = parse_value(config);
315 if (!val) {
316 ERROR("array: value expected");
317 goto errout;
318 }
319
320 SKIPWS();
321 c = GETC();
322 if (c != ',' && c != ']') {
323 ERROR("array: expected ',' or ']'");
324 errout_with_val:
325 zzjson_free(config, val);
326 goto errout;
327 }
328 if (c == ',') {
329 SKIPWS();
330 c = GETC();
331 if (c == ']' && !ALLOW_EXTRA_COMMA) {
332 ERROR("array: expected value after ','");
333 goto errout_with_val;
334 }
335 }
336 UNGETC(c);
337
338 zzjson = config->calloc(1, sizeof(ZZJSON));
339 if (!zzjson) {
340 MEMERROR();
341 zzjson_free(config, val);
342 goto errout_with_val;
343 }
344 zzjson->type = ZZJSON_ARRAY;
345 zzjson->value.array.val = val;
346 *next = zzjson;
347 next = &zzjson->next;
348
349 c = GETC();
350 }
351
352 if (c != ']') {
353 ERROR("array: expected ']'");
354 goto errout;
355 }
356
357 if (!retval) { /* empty array, [ ] */
358 retval = config->calloc(1, sizeof(ZZJSON));
359 if (!retval) {
360 MEMERROR();
361 return NULL;
362 }
363 retval->type = ZZJSON_ARRAY;
364 }
365
366 return retval;
367
368 errout:
369 zzjson_free(config, retval);
370 return NULL;
371 }
372
parse_object(ZZJSON_CONFIG * config)373 static ZZJSON *parse_object(ZZJSON_CONFIG *config) {
374 ZZJSON *retval = NULL;
375 int c;
376 ZZJSON **next = &retval;
377
378 SKIPWS();
379 c = GETC();
380 if (c != '{') {
381 ERROR("object: expected '{'");
382 return NULL;
383 }
384
385 SKIPWS();
386 c = GETC();
387 while (c > 0 && c != '}') {
388 ZZJSON *zzjson = NULL, *val = NULL;
389 char *str;
390
391 UNGETC(c);
392
393 str = parse_string(config);
394 if (!str) {
395 ERROR("object: expected string");
396 errout_with_str:
397 config->free(str);
398 goto errout;
399 }
400
401 SKIPWS();
402 c = GETC();
403 if (c != ':') {
404 ERROR("object: expected ':'");
405 goto errout_with_str;
406 }
407
408 SKIPWS();
409 val = parse_value(config);
410 if (!val) {
411 ERROR("object: value expected");
412 goto errout_with_str;
413 }
414
415 SKIPWS();
416 c = GETC();
417 if (c != ',' && c != '}') {
418 ERROR("object: expected ',' or '}'");
419 errout_with_str_and_val:
420 zzjson_free(config, val);
421 goto errout_with_str;
422 }
423 if (c == ',') {
424 SKIPWS();
425 c = GETC();
426 if (c == '}' && !ALLOW_EXTRA_COMMA) {
427 ERROR("object: expected pair after ','");
428 goto errout_with_str_and_val;
429 }
430 }
431 UNGETC(c);
432
433 zzjson = config->calloc(1, sizeof(ZZJSON));
434 if (!zzjson) {
435 MEMERROR();
436 goto errout_with_str_and_val;
437 }
438 zzjson->type = ZZJSON_OBJECT;
439 zzjson->value.object.label = str;
440 zzjson->value.object.val = val;
441 *next = zzjson;
442 next = &zzjson->next;
443
444 c = GETC();
445 }
446
447 if (c != '}') {
448 ERROR("object: expected '}'");
449 goto errout;
450 }
451
452 if (!retval) { /* empty object, { } */
453 retval = config->calloc(1, sizeof(ZZJSON));
454 if (!retval) {
455 MEMERROR();
456 return NULL;
457 }
458 retval->type = ZZJSON_OBJECT;
459 }
460
461 return retval;
462
463 errout:
464 zzjson_free(config, retval);
465 return NULL;
466 }
467
zzjson_parse(ZZJSON_CONFIG * config)468 ZZJSON *zzjson_parse(ZZJSON_CONFIG *config) {
469 ZZJSON *retval;
470 int c;
471
472 SKIPWS();
473 c = GETC();
474 UNGETC(c);
475 if (c == '[') retval = parse_array(config);
476 else if (c == '{') retval = parse_object(config);
477 else { ERROR("expected '[' or '{'"); return NULL; }
478
479 if (!retval) return NULL;
480
481 SKIPWS();
482 c = GETC();
483 if (c >= 0 && !ALLOW_GARBAGE_AT_END) {
484 ERROR("parse: garbage at end of file");
485 zzjson_free(config, retval);
486 return NULL;
487 }
488
489 return retval;
490 }
491