1 : /*
2 : * $Id: json_tokener.c,v 1.20 2006/07/25 03:24:50 mclark Exp $
3 : *
4 : * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
5 : * Michael Clark <michael@metaparadigm.com>
6 : *
7 : * This library is free software; you can redistribute it and/or modify
8 : * it under the terms of the MIT license. See COPYING for details.
9 : *
10 : */
11 :
12 : #include "config.h"
13 :
14 : #include <stdio.h>
15 : #include <stdlib.h>
16 : #include <ctype.h>
17 : #include <string.h>
18 :
19 : #include "bits.h"
20 : #include "debug.h"
21 : #include "printbuf.h"
22 : #include "arraylist.h"
23 : #include "json_object.h"
24 : #include "json_tokener.h"
25 :
26 : #include <cpl_port.h> /* MIN and MAX macros */
27 :
28 : #if !HAVE_STRNCASECMP && defined(_MSC_VER)
29 : /* MSC has the version as _strnicmp */
30 : # define strncasecmp _strnicmp
31 : #endif /* HAVE_STRNCASECMP */
32 :
33 :
34 : static const char* json_null_str = "null";
35 : static const char* json_true_str = "true";
36 : static const char* json_false_str = "false";
37 :
38 : const char* json_tokener_errors[] = {
39 : "success",
40 : "continue",
41 : "nesting to deep",
42 : "unexpected end of data",
43 : "unexpected character",
44 : "null expected",
45 : "boolean expected",
46 : "number expected",
47 : "array value separator ',' expected",
48 : "quoted object property name expected",
49 : "object property name separator ':' expected",
50 : "object value separator ',' expected",
51 : "invalid string sequence",
52 : "expected comment",
53 : };
54 :
55 :
56 14 : struct json_tokener* json_tokener_new()
57 : {
58 14 : struct json_tokener *tok = calloc(1, sizeof(struct json_tokener));
59 14 : tok->pb = printbuf_new();
60 14 : json_tokener_reset(tok);
61 14 : return tok;
62 : }
63 :
64 14 : void json_tokener_free(struct json_tokener *tok)
65 : {
66 14 : json_tokener_reset(tok);
67 14 : if(tok) printbuf_free(tok->pb);
68 14 : free(tok);
69 14 : }
70 :
71 630 : static void json_tokener_reset_level(struct json_tokener *tok, int depth)
72 : {
73 630 : tok->stack[depth].state = json_tokener_state_eatws;
74 630 : tok->stack[depth].saved_state = json_tokener_state_start;
75 630 : json_object_put(tok->stack[depth].current);
76 630 : tok->stack[depth].current = NULL;
77 630 : free(tok->stack[depth].obj_field_name);
78 630 : tok->stack[depth].obj_field_name = NULL;
79 630 : }
80 :
81 28 : void json_tokener_reset(struct json_tokener *tok)
82 : {
83 : int i;
84 56 : for(i = tok->depth; i >= 0; i--)
85 28 : json_tokener_reset_level(tok, i);
86 28 : tok->depth = 0;
87 28 : tok->err = json_tokener_success;
88 28 : }
89 :
90 0 : struct json_object* json_tokener_parse(const char *str)
91 : {
92 : struct json_tokener* tok;
93 : struct json_object* obj;
94 :
95 0 : tok = json_tokener_new();
96 0 : obj = json_tokener_parse_ex(tok, str, -1);
97 0 : if(tok->err != json_tokener_success)
98 0 : obj = error_ptr(-tok->err);
99 0 : json_tokener_free(tok);
100 0 : return obj;
101 : }
102 :
103 :
104 : #if !HAVE_STRNDUP
105 : /* CAW: compliant version of strndup() */
106 : char* strndup(const char* str, size_t n)
107 : {
108 0 : if(str) {
109 0 : size_t len = strlen(str);
110 0 : size_t nn = MIN(len,n);
111 0 : char* s = (char*)malloc(sizeof(char) * (nn + 1));
112 :
113 0 : if(s) {
114 0 : memcpy(s, str, nn);
115 0 : s[nn] = '\0';
116 : }
117 :
118 0 : return s;
119 : }
120 :
121 0 : return NULL;
122 : }
123 : #endif
124 :
125 :
126 : #define state tok->stack[tok->depth].state
127 : #define saved_state tok->stack[tok->depth].saved_state
128 : #define current tok->stack[tok->depth].current
129 : #define obj_field_name tok->stack[tok->depth].obj_field_name
130 :
131 14 : struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
132 : const char *str, int len)
133 : {
134 14 : struct json_object *obj = NULL;
135 : char c;
136 :
137 14 : tok->char_offset = 0;
138 14 : tok->err = json_tokener_success;
139 :
140 : do {
141 3629 : if(tok->char_offset == len) {
142 0 : if(tok->depth == 0 && state == json_tokener_state_eatws &&
143 0 : saved_state == json_tokener_state_finish)
144 0 : tok->err = json_tokener_success;
145 : else
146 0 : tok->err = json_tokener_continue;
147 0 : goto out;
148 : }
149 :
150 3629 : c = *str;
151 : redo_char:
152 6204 : switch(state) {
153 :
154 : case json_tokener_state_eatws:
155 2387 : if(isspace((unsigned char)c)) {
156 : /* okay */
157 1404 : } else if(c == '/') {
158 0 : printbuf_reset(tok->pb);
159 0 : printbuf_memappend(tok->pb, &c, 1);
160 0 : state = json_tokener_state_comment_start;
161 : } else {
162 1404 : state = saved_state;
163 1404 : goto redo_char;
164 : }
165 983 : break;
166 :
167 : case json_tokener_state_start:
168 315 : switch(c) {
169 : case '{':
170 40 : state = json_tokener_state_eatws;
171 40 : saved_state = json_tokener_state_object_field_start;
172 40 : current = json_object_new_object();
173 40 : break;
174 : case '[':
175 101 : state = json_tokener_state_eatws;
176 101 : saved_state = json_tokener_state_array;
177 101 : current = json_object_new_array();
178 101 : break;
179 : case 'N':
180 : case 'n':
181 0 : state = json_tokener_state_null;
182 0 : printbuf_reset(tok->pb);
183 0 : tok->st_pos = 0;
184 0 : goto redo_char;
185 : case '"':
186 : case '\'':
187 40 : state = json_tokener_state_string;
188 40 : printbuf_reset(tok->pb);
189 40 : tok->quote_char = c;
190 40 : break;
191 : case 'T':
192 : case 't':
193 : case 'F':
194 : case 'f':
195 0 : state = json_tokener_state_boolean;
196 0 : printbuf_reset(tok->pb);
197 0 : tok->st_pos = 0;
198 0 : goto redo_char;
199 : #if defined(__GNUC__)
200 : case '0' ... '9':
201 : #else
202 : case '0':
203 : case '1':
204 : case '2':
205 : case '3':
206 : case '4':
207 : case '5':
208 : case '6':
209 : case '7':
210 : case '8':
211 : case '9':
212 : #endif
213 : case '-':
214 134 : state = json_tokener_state_number;
215 134 : printbuf_reset(tok->pb);
216 134 : tok->is_double = 0;
217 134 : goto redo_char;
218 : default:
219 0 : tok->err = json_tokener_error_parse_unexpected;
220 0 : goto out;
221 : }
222 181 : break;
223 :
224 : case json_tokener_state_finish:
225 315 : if(tok->depth == 0) goto out;
226 301 : obj = json_object_get(current);
227 301 : json_tokener_reset_level(tok, tok->depth);
228 301 : tok->depth--;
229 301 : goto redo_char;
230 :
231 : case json_tokener_state_null:
232 0 : printbuf_memappend(tok->pb, &c, 1);
233 0 : if(strncasecmp(json_null_str, tok->pb->buf,
234 0 : MIN(tok->st_pos+1, (int)strlen(json_null_str))) == 0) {
235 0 : if(tok->st_pos == (int)strlen(json_null_str)) {
236 0 : current = NULL;
237 0 : saved_state = json_tokener_state_finish;
238 0 : state = json_tokener_state_eatws;
239 0 : goto redo_char;
240 : }
241 : } else {
242 0 : tok->err = json_tokener_error_parse_null;
243 0 : goto out;
244 : }
245 0 : tok->st_pos++;
246 0 : break;
247 :
248 : case json_tokener_state_comment_start:
249 0 : if(c == '*') {
250 0 : state = json_tokener_state_comment;
251 0 : } else if(c == '/') {
252 0 : state = json_tokener_state_comment_eol;
253 : } else {
254 0 : tok->err = json_tokener_error_parse_comment;
255 0 : goto out;
256 : }
257 0 : printbuf_memappend(tok->pb, &c, 1);
258 0 : break;
259 :
260 : case json_tokener_state_comment:
261 0 : if(c == '*') state = json_tokener_state_comment_end;
262 0 : printbuf_memappend(tok->pb, &c, 1);
263 0 : break;
264 :
265 : case json_tokener_state_comment_eol:
266 0 : if(c == '\n') {
267 0 : mc_debug("json_tokener_comment: %s\n", tok->pb->buf);
268 0 : state = json_tokener_state_eatws;
269 : } else {
270 0 : printbuf_memappend(tok->pb, &c, 1);
271 : }
272 0 : break;
273 :
274 : case json_tokener_state_comment_end:
275 0 : printbuf_memappend(tok->pb, &c, 1);
276 0 : if(c == '/') {
277 0 : mc_debug("json_tokener_comment: %s\n", tok->pb->buf);
278 0 : state = json_tokener_state_eatws;
279 : } else {
280 0 : state = json_tokener_state_comment;
281 : }
282 0 : break;
283 :
284 : case json_tokener_state_string:
285 486 : if(c == tok->quote_char) {
286 40 : current = json_object_new_string(tok->pb->buf);
287 40 : saved_state = json_tokener_state_finish;
288 40 : state = json_tokener_state_eatws;
289 446 : } else if(c == '\\') {
290 0 : saved_state = json_tokener_state_string;
291 0 : state = json_tokener_state_string_escape;
292 : } else {
293 446 : printbuf_memappend(tok->pb, &c, 1);
294 : }
295 486 : break;
296 :
297 : case json_tokener_state_string_escape:
298 0 : switch(c) {
299 : case '"':
300 : case '\\':
301 : case '/':
302 0 : printbuf_memappend(tok->pb, &c, 1);
303 0 : state = saved_state;
304 0 : break;
305 : case 'b':
306 : case 'n':
307 : case 'r':
308 : case 't':
309 0 : if(c == 'b') printbuf_memappend(tok->pb, "\b", 1);
310 0 : else if(c == 'n') printbuf_memappend(tok->pb, "\n", 1);
311 0 : else if(c == 'r') printbuf_memappend(tok->pb, "\r", 1);
312 0 : else if(c == 't') printbuf_memappend(tok->pb, "\t", 1);
313 0 : state = saved_state;
314 0 : break;
315 : case 'u':
316 0 : tok->ucs_char = 0;
317 0 : tok->st_pos = 0;
318 0 : state = json_tokener_state_escape_unicode;
319 0 : break;
320 : default:
321 0 : tok->err = json_tokener_error_parse_string;
322 0 : goto out;
323 : }
324 0 : break;
325 :
326 : case json_tokener_state_escape_unicode:
327 0 : if(strchr(json_hex_chars, c)) {
328 0 : tok->ucs_char += ((unsigned int)hexdigit(c) << ((3-tok->st_pos++)*4));
329 0 : if(tok->st_pos == 4) {
330 : unsigned char utf_out[3];
331 0 : if (tok->ucs_char < 0x80) {
332 0 : utf_out[0] = (unsigned char)tok->ucs_char;
333 0 : printbuf_memappend(tok->pb, (char*)utf_out, 1);
334 0 : } else if (tok->ucs_char < 0x800) {
335 0 : utf_out[0] = (unsigned char)(0xc0 | (tok->ucs_char >> 6));
336 0 : utf_out[1] = (unsigned char)(0x80 | (tok->ucs_char & 0x3f));
337 0 : printbuf_memappend(tok->pb, (char*)utf_out, 2);
338 : } else {
339 0 : utf_out[0] = (unsigned char)(0xe0 | (tok->ucs_char >> 12));
340 0 : utf_out[1] = (unsigned char)(0x80 | ((tok->ucs_char >> 6) & 0x3f));
341 0 : utf_out[2] = (unsigned char)(0x80 | (tok->ucs_char & 0x3f));
342 0 : printbuf_memappend(tok->pb, (char*)utf_out, 3);
343 : }
344 0 : state = saved_state;
345 : }
346 : } else {
347 0 : tok->err = json_tokener_error_parse_string;
348 0 : goto out;
349 : }
350 0 : break;
351 :
352 : case json_tokener_state_boolean:
353 0 : printbuf_memappend(tok->pb, &c, 1);
354 0 : if(strncasecmp(json_true_str, tok->pb->buf,
355 0 : MIN(tok->st_pos+1, (int)strlen(json_true_str))) == 0) {
356 0 : if(tok->st_pos == (int)strlen(json_true_str)) {
357 0 : current = json_object_new_boolean(1);
358 0 : saved_state = json_tokener_state_finish;
359 0 : state = json_tokener_state_eatws;
360 0 : goto redo_char;
361 : }
362 0 : } else if(strncasecmp(json_false_str, tok->pb->buf,
363 0 : MIN(tok->st_pos+1, (int)strlen(json_false_str))) == 0) {
364 0 : if(tok->st_pos == (int)strlen(json_false_str)) {
365 0 : current = json_object_new_boolean(0);
366 0 : saved_state = json_tokener_state_finish;
367 0 : state = json_tokener_state_eatws;
368 0 : goto redo_char;
369 : }
370 : } else {
371 0 : tok->err = json_tokener_error_parse_boolean;
372 0 : goto out;
373 : }
374 0 : tok->st_pos++;
375 0 : break;
376 :
377 : case json_tokener_state_number:
378 984 : if(c && strchr(json_number_chars, c)) {
379 850 : printbuf_memappend(tok->pb, &c, 1);
380 850 : if(c == '.' || c == 'e' || c == 'E')
381 134 : tok->is_double = 1;
382 : } else {
383 : int numi;
384 : double numd;
385 134 : if(!tok->is_double && sscanf(tok->pb->buf, "%d", &numi) == 1) {
386 0 : current = json_object_new_int(numi);
387 268 : } else if(tok->is_double && sscanf(tok->pb->buf, "%lf", &numd) == 1) {
388 134 : current = json_object_new_double(numd);
389 : } else {
390 0 : tok->err = json_tokener_error_parse_number;
391 0 : goto out;
392 : }
393 134 : saved_state = json_tokener_state_finish;
394 134 : state = json_tokener_state_eatws;
395 134 : goto redo_char;
396 : }
397 850 : break;
398 :
399 : case json_tokener_state_array:
400 215 : if(c == ']') {
401 0 : saved_state = json_tokener_state_finish;
402 0 : state = json_tokener_state_eatws;
403 : } else {
404 215 : if(tok->depth >= JSON_TOKENER_MAX_DEPTH-1) {
405 0 : tok->err = json_tokener_error_depth;
406 0 : goto out;
407 : }
408 215 : state = json_tokener_state_array_add;
409 215 : tok->depth++;
410 215 : json_tokener_reset_level(tok, tok->depth);
411 215 : goto redo_char;
412 : }
413 0 : break;
414 :
415 : case json_tokener_state_array_add:
416 215 : json_object_array_add(current, obj);
417 215 : saved_state = json_tokener_state_array_sep;
418 215 : state = json_tokener_state_eatws;
419 215 : goto redo_char;
420 :
421 : case json_tokener_state_array_sep:
422 215 : if(c == ']') {
423 101 : saved_state = json_tokener_state_finish;
424 101 : state = json_tokener_state_eatws;
425 114 : } else if(c == ',') {
426 114 : saved_state = json_tokener_state_array;
427 114 : state = json_tokener_state_eatws;
428 : } else {
429 0 : tok->err = json_tokener_error_parse_array;
430 0 : goto out;
431 : }
432 215 : break;
433 :
434 : case json_tokener_state_object_field_start:
435 86 : if(c == '}') {
436 0 : saved_state = json_tokener_state_finish;
437 0 : state = json_tokener_state_eatws;
438 172 : } else if (c == '"' || c == '\'') {
439 86 : tok->quote_char = c;
440 86 : printbuf_reset(tok->pb);
441 86 : state = json_tokener_state_object_field;
442 : } else {
443 0 : tok->err = json_tokener_error_parse_object_key_name;
444 0 : goto out;
445 : }
446 86 : break;
447 :
448 : case json_tokener_state_object_field:
449 642 : if(c == tok->quote_char) {
450 86 : obj_field_name = strdup(tok->pb->buf);
451 86 : saved_state = json_tokener_state_object_field_end;
452 86 : state = json_tokener_state_eatws;
453 556 : } else if(c == '\\') {
454 0 : saved_state = json_tokener_state_object_field;
455 0 : state = json_tokener_state_string_escape;
456 : } else {
457 556 : printbuf_memappend(tok->pb, &c, 1);
458 : }
459 642 : break;
460 :
461 : case json_tokener_state_object_field_end:
462 86 : if(c == ':') {
463 86 : saved_state = json_tokener_state_object_value;
464 86 : state = json_tokener_state_eatws;
465 : } else {
466 0 : tok->err = json_tokener_error_parse_object_key_sep;
467 0 : goto out;
468 : }
469 86 : break;
470 :
471 : case json_tokener_state_object_value:
472 86 : if(tok->depth >= JSON_TOKENER_MAX_DEPTH-1) {
473 0 : tok->err = json_tokener_error_depth;
474 0 : goto out;
475 : }
476 86 : state = json_tokener_state_object_value_add;
477 86 : tok->depth++;
478 86 : json_tokener_reset_level(tok, tok->depth);
479 86 : goto redo_char;
480 :
481 : case json_tokener_state_object_value_add:
482 86 : json_object_object_add(current, obj_field_name, obj);
483 86 : free(obj_field_name);
484 86 : obj_field_name = NULL;
485 86 : saved_state = json_tokener_state_object_sep;
486 86 : state = json_tokener_state_eatws;
487 86 : goto redo_char;
488 :
489 : case json_tokener_state_object_sep:
490 86 : if(c == '}') {
491 40 : saved_state = json_tokener_state_finish;
492 40 : state = json_tokener_state_eatws;
493 46 : } else if(c == ',') {
494 46 : saved_state = json_tokener_state_object_field_start;
495 46 : state = json_tokener_state_eatws;
496 : } else {
497 0 : tok->err = json_tokener_error_parse_object_value_sep;
498 0 : goto out;
499 : }
500 : break;
501 :
502 : }
503 3615 : str++;
504 3615 : tok->char_offset++;
505 3615 : } while(c);
506 :
507 0 : if(state != json_tokener_state_finish &&
508 0 : saved_state != json_tokener_state_finish)
509 0 : tok->err = json_tokener_error_parse_eof;
510 :
511 : out:
512 14 : if(tok->err == json_tokener_success) return json_object_get(current);
513 0 : mc_debug("json_tokener_parse_ex: error %s at offset %d\n",
514 0 : json_tokener_errors[tok->err], tok->char_offset);
515 0 : return NULL;
516 : }
|