blob: beaa956c669a9cdb04b8d0f5cfcc33c7e115df91 [file] [log] [blame]
Michael Clarkf0d08882007-03-13 08:26:18 +00001/*
Michael Clarka850f8e2007-03-13 08:26:26 +00002 * $Id: json_tokener.c,v 1.20 2006/07/25 03:24:50 mclark Exp $
Michael Clarkf0d08882007-03-13 08:26:18 +00003 *
Michael Clarkf6a6e482007-03-13 08:26:23 +00004 * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
Michael Clarkf0d08882007-03-13 08:26:18 +00005 * Michael Clark <michael@metaparadigm.com>
6 *
Michael Clarkf6a6e482007-03-13 08:26:23 +00007 * 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.
Michael Clarkf0d08882007-03-13 08:26:18 +00009 *
10 */
11
Michael Clark4504df72007-03-13 08:26:20 +000012#include "config.h"
13
Michael Clarkf0d08882007-03-13 08:26:18 +000014#include <stdio.h>
15#include <stdlib.h>
Michael Clarkc8f4a6e2007-12-07 02:44:24 +000016#include <stddef.h>
Michael Clarkf0d08882007-03-13 08:26:18 +000017#include <ctype.h>
18#include <string.h>
19
20#include "bits.h"
21#include "debug.h"
22#include "printbuf.h"
23#include "arraylist.h"
24#include "json_object.h"
25#include "json_tokener.h"
26
Michael Clarka850f8e2007-03-13 08:26:26 +000027
Michael Clark837240f2007-03-13 08:26:25 +000028#if !HAVE_STRNCASECMP && defined(_MSC_VER)
29 /* MSC has the version as _strnicmp */
30# define strncasecmp _strnicmp
31#elif !HAVE_STRNCASECMP
32# error You do not have strncasecmp on your system.
33#endif /* HAVE_STRNCASECMP */
34
35
Michael Clarka850f8e2007-03-13 08:26:26 +000036static const char* json_null_str = "null";
37static const char* json_true_str = "true";
38static const char* json_false_str = "false";
Michael Clarkf0d08882007-03-13 08:26:18 +000039
Michael Clarka850f8e2007-03-13 08:26:26 +000040const char* json_tokener_errors[] = {
41 "success",
42 "continue",
43 "nesting to deep",
44 "unexpected end of data",
45 "unexpected character",
46 "null expected",
47 "boolean expected",
48 "number expected",
49 "array value separator ',' expected",
50 "quoted object property name expected",
51 "object property name separator ':' expected",
52 "object value separator ',' expected",
53 "invalid string sequence",
54 "expected comment",
55};
56
57
Michael Clarke8de0782009-02-25 01:45:00 +000058struct json_tokener* json_tokener_new(void)
Michael Clarkf0d08882007-03-13 08:26:18 +000059{
Michael Clarkaaec1ef2009-02-25 02:31:32 +000060 struct json_tokener *tok;
61
62 tok = (struct json_tokener*)calloc(1, sizeof(struct json_tokener));
Michael Clarka850f8e2007-03-13 08:26:26 +000063 tok->pb = printbuf_new();
64 json_tokener_reset(tok);
65 return tok;
66}
67
68void json_tokener_free(struct json_tokener *tok)
69{
70 json_tokener_reset(tok);
71 if(tok) printbuf_free(tok->pb);
72 free(tok);
73}
74
75static void json_tokener_reset_level(struct json_tokener *tok, int depth)
76{
77 tok->stack[depth].state = json_tokener_state_eatws;
78 tok->stack[depth].saved_state = json_tokener_state_start;
79 json_object_put(tok->stack[depth].current);
80 tok->stack[depth].current = NULL;
81 free(tok->stack[depth].obj_field_name);
82 tok->stack[depth].obj_field_name = NULL;
83}
84
85void json_tokener_reset(struct json_tokener *tok)
86{
87 int i;
Michael Clark22dee7c2009-02-25 01:51:40 +000088 if (!tok)
89 return;
90
Michael Clarka850f8e2007-03-13 08:26:26 +000091 for(i = tok->depth; i >= 0; i--)
92 json_tokener_reset_level(tok, i);
93 tok->depth = 0;
94 tok->err = json_tokener_success;
95}
96
97struct json_object* json_tokener_parse(char *str)
98{
99 struct json_tokener* tok;
Michael Clarkf0d08882007-03-13 08:26:18 +0000100 struct json_object* obj;
101
Michael Clarka850f8e2007-03-13 08:26:26 +0000102 tok = json_tokener_new();
103 obj = json_tokener_parse_ex(tok, str, -1);
104 if(tok->err != json_tokener_success)
Michael Clarkaaec1ef2009-02-25 02:31:32 +0000105 obj = (struct json_object*)error_ptr(-tok->err);
Michael Clarka850f8e2007-03-13 08:26:26 +0000106 json_tokener_free(tok);
Michael Clarkf0d08882007-03-13 08:26:18 +0000107 return obj;
108}
109
Michael Clarka850f8e2007-03-13 08:26:26 +0000110
Michael Clark4504df72007-03-13 08:26:20 +0000111#if !HAVE_STRNDUP
112/* CAW: compliant version of strndup() */
113char* strndup(const char* str, size_t n)
114{
Michael Clarka850f8e2007-03-13 08:26:26 +0000115 if(str) {
116 size_t len = strlen(str);
117 size_t nn = min(len,n);
118 char* s = (char*)malloc(sizeof(char) * (nn + 1));
Michael Clark4504df72007-03-13 08:26:20 +0000119
Michael Clarka850f8e2007-03-13 08:26:26 +0000120 if(s) {
121 memcpy(s, str, nn);
122 s[nn] = '\0';
123 }
Michael Clark4504df72007-03-13 08:26:20 +0000124
Michael Clarka850f8e2007-03-13 08:26:26 +0000125 return s;
126 }
Michael Clark4504df72007-03-13 08:26:20 +0000127
Michael Clarka850f8e2007-03-13 08:26:26 +0000128 return NULL;
Michael Clark4504df72007-03-13 08:26:20 +0000129}
130#endif
131
Michael Clarka850f8e2007-03-13 08:26:26 +0000132
133#define state tok->stack[tok->depth].state
134#define saved_state tok->stack[tok->depth].saved_state
135#define current tok->stack[tok->depth].current
136#define obj_field_name tok->stack[tok->depth].obj_field_name
137
138struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
139 char *str, int len)
Michael Clarkf0d08882007-03-13 08:26:18 +0000140{
Michael Clarka850f8e2007-03-13 08:26:26 +0000141 struct json_object *obj = NULL;
Michael Clark4504df72007-03-13 08:26:20 +0000142 char c;
Michael Clarkf0d08882007-03-13 08:26:18 +0000143
Michael Clarka850f8e2007-03-13 08:26:26 +0000144 tok->char_offset = 0;
145 tok->err = json_tokener_success;
Michael Clarkf0d08882007-03-13 08:26:18 +0000146
Michael Clarkf0d08882007-03-13 08:26:18 +0000147 do {
Michael Clarka850f8e2007-03-13 08:26:26 +0000148 if(tok->char_offset == len) {
149 if(tok->depth == 0 && state == json_tokener_state_eatws &&
150 saved_state == json_tokener_state_finish)
151 tok->err = json_tokener_success;
152 else
153 tok->err = json_tokener_continue;
154 goto out;
155 }
156
157 c = *str;
158 redo_char:
Michael Clarkf0d08882007-03-13 08:26:18 +0000159 switch(state) {
160
161 case json_tokener_state_eatws:
162 if(isspace(c)) {
Michael Clarka850f8e2007-03-13 08:26:26 +0000163 /* okay */
Michael Clarkf0d08882007-03-13 08:26:18 +0000164 } else if(c == '/') {
Michael Clarka850f8e2007-03-13 08:26:26 +0000165 printbuf_reset(tok->pb);
166 printbuf_memappend(tok->pb, &c, 1);
Michael Clarkf0d08882007-03-13 08:26:18 +0000167 state = json_tokener_state_comment_start;
Michael Clarkf0d08882007-03-13 08:26:18 +0000168 } else {
169 state = saved_state;
Michael Clarka850f8e2007-03-13 08:26:26 +0000170 goto redo_char;
Michael Clarkf0d08882007-03-13 08:26:18 +0000171 }
172 break;
173
174 case json_tokener_state_start:
175 switch(c) {
176 case '{':
177 state = json_tokener_state_eatws;
Michael Clarka850f8e2007-03-13 08:26:26 +0000178 saved_state = json_tokener_state_object_field_start;
Michael Clarkf0d08882007-03-13 08:26:18 +0000179 current = json_object_new_object();
Michael Clarkf0d08882007-03-13 08:26:18 +0000180 break;
181 case '[':
182 state = json_tokener_state_eatws;
183 saved_state = json_tokener_state_array;
184 current = json_object_new_array();
Michael Clarkf0d08882007-03-13 08:26:18 +0000185 break;
186 case 'N':
187 case 'n':
188 state = json_tokener_state_null;
Michael Clarka850f8e2007-03-13 08:26:26 +0000189 printbuf_reset(tok->pb);
190 tok->st_pos = 0;
191 goto redo_char;
Michael Clarkf0d08882007-03-13 08:26:18 +0000192 case '"':
193 case '\'':
Michael Clarkf0d08882007-03-13 08:26:18 +0000194 state = json_tokener_state_string;
Michael Clarka850f8e2007-03-13 08:26:26 +0000195 printbuf_reset(tok->pb);
196 tok->quote_char = c;
Michael Clarkf0d08882007-03-13 08:26:18 +0000197 break;
198 case 'T':
199 case 't':
200 case 'F':
201 case 'f':
202 state = json_tokener_state_boolean;
Michael Clarka850f8e2007-03-13 08:26:26 +0000203 printbuf_reset(tok->pb);
204 tok->st_pos = 0;
205 goto redo_char;
Michael Clark4504df72007-03-13 08:26:20 +0000206#if defined(__GNUC__)
207 case '0' ... '9':
208#else
209 case '0':
210 case '1':
211 case '2':
212 case '3':
213 case '4':
214 case '5':
215 case '6':
216 case '7':
217 case '8':
218 case '9':
219#endif
Michael Clarkf0d08882007-03-13 08:26:18 +0000220 case '-':
Michael Clarkf0d08882007-03-13 08:26:18 +0000221 state = json_tokener_state_number;
Michael Clarka850f8e2007-03-13 08:26:26 +0000222 printbuf_reset(tok->pb);
223 tok->is_double = 0;
224 goto redo_char;
Michael Clarkf0d08882007-03-13 08:26:18 +0000225 default:
Michael Clarka850f8e2007-03-13 08:26:26 +0000226 tok->err = json_tokener_error_parse_unexpected;
Michael Clarkf0d08882007-03-13 08:26:18 +0000227 goto out;
228 }
229 break;
230
231 case json_tokener_state_finish:
Michael Clarka850f8e2007-03-13 08:26:26 +0000232 if(tok->depth == 0) goto out;
233 obj = json_object_get(current);
234 json_tokener_reset_level(tok, tok->depth);
235 tok->depth--;
236 goto redo_char;
Michael Clarkf0d08882007-03-13 08:26:18 +0000237
238 case json_tokener_state_null:
Michael Clarka850f8e2007-03-13 08:26:26 +0000239 printbuf_memappend(tok->pb, &c, 1);
240 if(strncasecmp(json_null_str, tok->pb->buf,
241 min(tok->st_pos+1, strlen(json_null_str))) == 0) {
242 if(tok->st_pos == strlen(json_null_str)) {
243 current = NULL;
244 saved_state = json_tokener_state_finish;
245 state = json_tokener_state_eatws;
246 goto redo_char;
247 }
Michael Clarkf0d08882007-03-13 08:26:18 +0000248 } else {
Michael Clarka850f8e2007-03-13 08:26:26 +0000249 tok->err = json_tokener_error_parse_null;
250 goto out;
Michael Clarkf0d08882007-03-13 08:26:18 +0000251 }
Michael Clarka850f8e2007-03-13 08:26:26 +0000252 tok->st_pos++;
Michael Clarkf0d08882007-03-13 08:26:18 +0000253 break;
254
255 case json_tokener_state_comment_start:
256 if(c == '*') {
257 state = json_tokener_state_comment;
258 } else if(c == '/') {
259 state = json_tokener_state_comment_eol;
260 } else {
Michael Clarka850f8e2007-03-13 08:26:26 +0000261 tok->err = json_tokener_error_parse_comment;
Michael Clarkf0d08882007-03-13 08:26:18 +0000262 goto out;
263 }
Michael Clarka850f8e2007-03-13 08:26:26 +0000264 printbuf_memappend(tok->pb, &c, 1);
Michael Clarkf0d08882007-03-13 08:26:18 +0000265 break;
266
267 case json_tokener_state_comment:
268 if(c == '*') state = json_tokener_state_comment_end;
Michael Clarka850f8e2007-03-13 08:26:26 +0000269 printbuf_memappend(tok->pb, &c, 1);
Michael Clarkf0d08882007-03-13 08:26:18 +0000270 break;
271
272 case json_tokener_state_comment_eol:
273 if(c == '\n') {
Michael Clarkdfaf6702007-10-25 02:26:00 +0000274 MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf);
Michael Clarkf0d08882007-03-13 08:26:18 +0000275 state = json_tokener_state_eatws;
Michael Clarka850f8e2007-03-13 08:26:26 +0000276 } else {
277 printbuf_memappend(tok->pb, &c, 1);
Michael Clarkf0d08882007-03-13 08:26:18 +0000278 }
Michael Clarkf0d08882007-03-13 08:26:18 +0000279 break;
280
281 case json_tokener_state_comment_end:
Michael Clarka850f8e2007-03-13 08:26:26 +0000282 printbuf_memappend(tok->pb, &c, 1);
Michael Clarkf0d08882007-03-13 08:26:18 +0000283 if(c == '/') {
Michael Clarkdfaf6702007-10-25 02:26:00 +0000284 MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf);
Michael Clarkf0d08882007-03-13 08:26:18 +0000285 state = json_tokener_state_eatws;
286 } else {
287 state = json_tokener_state_comment;
288 }
Michael Clarkf0d08882007-03-13 08:26:18 +0000289 break;
290
291 case json_tokener_state_string:
Michael Clarka850f8e2007-03-13 08:26:26 +0000292 if(c == tok->quote_char) {
293 current = json_object_new_string(tok->pb->buf);
Michael Clarkf0d08882007-03-13 08:26:18 +0000294 saved_state = json_tokener_state_finish;
295 state = json_tokener_state_eatws;
296 } else if(c == '\\') {
297 saved_state = json_tokener_state_string;
298 state = json_tokener_state_string_escape;
Michael Clarka850f8e2007-03-13 08:26:26 +0000299 } else {
300 printbuf_memappend(tok->pb, &c, 1);
Michael Clarkf0d08882007-03-13 08:26:18 +0000301 }
Michael Clarkf0d08882007-03-13 08:26:18 +0000302 break;
303
304 case json_tokener_state_string_escape:
305 switch(c) {
306 case '"':
307 case '\\':
Michael Clarka850f8e2007-03-13 08:26:26 +0000308 case '/':
309 printbuf_memappend(tok->pb, &c, 1);
Michael Clarkf0d08882007-03-13 08:26:18 +0000310 state = saved_state;
311 break;
312 case 'b':
313 case 'n':
314 case 'r':
315 case 't':
Michael Clarka850f8e2007-03-13 08:26:26 +0000316 if(c == 'b') printbuf_memappend(tok->pb, "\b", 1);
317 else if(c == 'n') printbuf_memappend(tok->pb, "\n", 1);
318 else if(c == 'r') printbuf_memappend(tok->pb, "\r", 1);
319 else if(c == 't') printbuf_memappend(tok->pb, "\t", 1);
Michael Clarkf0d08882007-03-13 08:26:18 +0000320 state = saved_state;
321 break;
322 case 'u':
Michael Clarka850f8e2007-03-13 08:26:26 +0000323 tok->ucs_char = 0;
324 tok->st_pos = 0;
Michael Clarkf0d08882007-03-13 08:26:18 +0000325 state = json_tokener_state_escape_unicode;
326 break;
327 default:
Michael Clarka850f8e2007-03-13 08:26:26 +0000328 tok->err = json_tokener_error_parse_string;
Michael Clarkf0d08882007-03-13 08:26:18 +0000329 goto out;
330 }
331 break;
332
333 case json_tokener_state_escape_unicode:
334 if(strchr(json_hex_chars, c)) {
Michael Clarka850f8e2007-03-13 08:26:26 +0000335 tok->ucs_char += ((unsigned int)hexdigit(c) << ((3-tok->st_pos++)*4));
336 if(tok->st_pos == 4) {
Michael Clarkf0d08882007-03-13 08:26:18 +0000337 unsigned char utf_out[3];
Michael Clarka850f8e2007-03-13 08:26:26 +0000338 if (tok->ucs_char < 0x80) {
339 utf_out[0] = tok->ucs_char;
340 printbuf_memappend(tok->pb, (char*)utf_out, 1);
341 } else if (tok->ucs_char < 0x800) {
342 utf_out[0] = 0xc0 | (tok->ucs_char >> 6);
343 utf_out[1] = 0x80 | (tok->ucs_char & 0x3f);
344 printbuf_memappend(tok->pb, (char*)utf_out, 2);
Michael Clarkf0d08882007-03-13 08:26:18 +0000345 } else {
Michael Clarka850f8e2007-03-13 08:26:26 +0000346 utf_out[0] = 0xe0 | (tok->ucs_char >> 12);
347 utf_out[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f);
348 utf_out[2] = 0x80 | (tok->ucs_char & 0x3f);
349 printbuf_memappend(tok->pb, (char*)utf_out, 3);
Michael Clarkf0d08882007-03-13 08:26:18 +0000350 }
Michael Clarkf0d08882007-03-13 08:26:18 +0000351 state = saved_state;
352 }
353 } else {
Michael Clarka850f8e2007-03-13 08:26:26 +0000354 tok->err = json_tokener_error_parse_string;
Michael Clarkf0d08882007-03-13 08:26:18 +0000355 goto out;
356 }
357 break;
358
359 case json_tokener_state_boolean:
Michael Clarka850f8e2007-03-13 08:26:26 +0000360 printbuf_memappend(tok->pb, &c, 1);
361 if(strncasecmp(json_true_str, tok->pb->buf,
362 min(tok->st_pos+1, strlen(json_true_str))) == 0) {
363 if(tok->st_pos == strlen(json_true_str)) {
Michael Clarkf0d08882007-03-13 08:26:18 +0000364 current = json_object_new_boolean(1);
365 saved_state = json_tokener_state_finish;
366 state = json_tokener_state_eatws;
Michael Clarka850f8e2007-03-13 08:26:26 +0000367 goto redo_char;
Michael Clarkf0d08882007-03-13 08:26:18 +0000368 }
Michael Clarka850f8e2007-03-13 08:26:26 +0000369 } else if(strncasecmp(json_false_str, tok->pb->buf,
370 min(tok->st_pos+1, strlen(json_false_str))) == 0) {
371 if(tok->st_pos == strlen(json_false_str)) {
Michael Clarkf0d08882007-03-13 08:26:18 +0000372 current = json_object_new_boolean(0);
373 saved_state = json_tokener_state_finish;
374 state = json_tokener_state_eatws;
Michael Clarka850f8e2007-03-13 08:26:26 +0000375 goto redo_char;
Michael Clarkf0d08882007-03-13 08:26:18 +0000376 }
377 } else {
Michael Clarka850f8e2007-03-13 08:26:26 +0000378 tok->err = json_tokener_error_parse_boolean;
Michael Clarkf0d08882007-03-13 08:26:18 +0000379 goto out;
380 }
Michael Clarka850f8e2007-03-13 08:26:26 +0000381 tok->st_pos++;
Michael Clarkf0d08882007-03-13 08:26:18 +0000382 break;
383
384 case json_tokener_state_number:
Michael Clarka850f8e2007-03-13 08:26:26 +0000385 if(c && strchr(json_number_chars, c)) {
386 printbuf_memappend(tok->pb, &c, 1);
Michael Clarkc8f4a6e2007-12-07 02:44:24 +0000387 if(c == '.' || c == 'e' || c == 'E') tok->is_double = 1;
Michael Clarka850f8e2007-03-13 08:26:26 +0000388 } else {
Michael Clarkf0d08882007-03-13 08:26:18 +0000389 int numi;
390 double numd;
Michael Clarka850f8e2007-03-13 08:26:26 +0000391 if(!tok->is_double && sscanf(tok->pb->buf, "%d", &numi) == 1) {
Michael Clarkf0d08882007-03-13 08:26:18 +0000392 current = json_object_new_int(numi);
Michael Clarka850f8e2007-03-13 08:26:26 +0000393 } else if(tok->is_double && sscanf(tok->pb->buf, "%lf", &numd) == 1) {
Michael Clarkf0d08882007-03-13 08:26:18 +0000394 current = json_object_new_double(numd);
395 } else {
Michael Clarka850f8e2007-03-13 08:26:26 +0000396 tok->err = json_tokener_error_parse_number;
Michael Clarkf0d08882007-03-13 08:26:18 +0000397 goto out;
398 }
Michael Clarkf0d08882007-03-13 08:26:18 +0000399 saved_state = json_tokener_state_finish;
400 state = json_tokener_state_eatws;
Michael Clarka850f8e2007-03-13 08:26:26 +0000401 goto redo_char;
Michael Clarkf0d08882007-03-13 08:26:18 +0000402 }
403 break;
404
405 case json_tokener_state_array:
406 if(c == ']') {
Michael Clarkf0d08882007-03-13 08:26:18 +0000407 saved_state = json_tokener_state_finish;
408 state = json_tokener_state_eatws;
409 } else {
Michael Clarka850f8e2007-03-13 08:26:26 +0000410 if(tok->depth >= JSON_TOKENER_MAX_DEPTH-1) {
411 tok->err = json_tokener_error_depth;
Michael Clarkf0d08882007-03-13 08:26:18 +0000412 goto out;
413 }
Michael Clarka850f8e2007-03-13 08:26:26 +0000414 state = json_tokener_state_array_add;
415 tok->depth++;
416 json_tokener_reset_level(tok, tok->depth);
417 goto redo_char;
Michael Clarkf0d08882007-03-13 08:26:18 +0000418 }
419 break;
420
Michael Clarka850f8e2007-03-13 08:26:26 +0000421 case json_tokener_state_array_add:
422 json_object_array_add(current, obj);
423 saved_state = json_tokener_state_array_sep;
424 state = json_tokener_state_eatws;
425 goto redo_char;
426
Michael Clarkf0d08882007-03-13 08:26:18 +0000427 case json_tokener_state_array_sep:
428 if(c == ']') {
Michael Clarkf0d08882007-03-13 08:26:18 +0000429 saved_state = json_tokener_state_finish;
430 state = json_tokener_state_eatws;
431 } else if(c == ',') {
Michael Clarkf0d08882007-03-13 08:26:18 +0000432 saved_state = json_tokener_state_array;
433 state = json_tokener_state_eatws;
434 } else {
Michael Clarka850f8e2007-03-13 08:26:26 +0000435 tok->err = json_tokener_error_parse_array;
436 goto out;
Michael Clarkf0d08882007-03-13 08:26:18 +0000437 }
438 break;
439
Michael Clarkf0d08882007-03-13 08:26:18 +0000440 case json_tokener_state_object_field_start:
441 if(c == '}') {
Michael Clarkf0d08882007-03-13 08:26:18 +0000442 saved_state = json_tokener_state_finish;
443 state = json_tokener_state_eatws;
444 } else if (c == '"' || c == '\'') {
Michael Clarka850f8e2007-03-13 08:26:26 +0000445 tok->quote_char = c;
446 printbuf_reset(tok->pb);
Michael Clarkf0d08882007-03-13 08:26:18 +0000447 state = json_tokener_state_object_field;
Michael Clark0370baa2007-03-13 08:26:22 +0000448 } else {
Michael Clarka850f8e2007-03-13 08:26:26 +0000449 tok->err = json_tokener_error_parse_object_key_name;
Michael Clark0370baa2007-03-13 08:26:22 +0000450 goto out;
Michael Clarkf0d08882007-03-13 08:26:18 +0000451 }
452 break;
453
454 case json_tokener_state_object_field:
Michael Clarka850f8e2007-03-13 08:26:26 +0000455 if(c == tok->quote_char) {
456 obj_field_name = strdup(tok->pb->buf);
Michael Clarkf0d08882007-03-13 08:26:18 +0000457 saved_state = json_tokener_state_object_field_end;
458 state = json_tokener_state_eatws;
459 } else if(c == '\\') {
460 saved_state = json_tokener_state_object_field;
461 state = json_tokener_state_string_escape;
Michael Clarka850f8e2007-03-13 08:26:26 +0000462 } else {
463 printbuf_memappend(tok->pb, &c, 1);
Michael Clarkf0d08882007-03-13 08:26:18 +0000464 }
Michael Clarkf0d08882007-03-13 08:26:18 +0000465 break;
466
467 case json_tokener_state_object_field_end:
468 if(c == ':') {
Michael Clarkf0d08882007-03-13 08:26:18 +0000469 saved_state = json_tokener_state_object_value;
470 state = json_tokener_state_eatws;
471 } else {
Michael Clarka850f8e2007-03-13 08:26:26 +0000472 tok->err = json_tokener_error_parse_object_key_sep;
473 goto out;
Michael Clarkf0d08882007-03-13 08:26:18 +0000474 }
475 break;
476
477 case json_tokener_state_object_value:
Michael Clarka850f8e2007-03-13 08:26:26 +0000478 if(tok->depth >= JSON_TOKENER_MAX_DEPTH-1) {
479 tok->err = json_tokener_error_depth;
Michael Clarkf0d08882007-03-13 08:26:18 +0000480 goto out;
481 }
Michael Clarka850f8e2007-03-13 08:26:26 +0000482 state = json_tokener_state_object_value_add;
483 tok->depth++;
484 json_tokener_reset_level(tok, tok->depth);
485 goto redo_char;
486
487 case json_tokener_state_object_value_add:
Michael Clarkf0d08882007-03-13 08:26:18 +0000488 json_object_object_add(current, obj_field_name, obj);
489 free(obj_field_name);
490 obj_field_name = NULL;
491 saved_state = json_tokener_state_object_sep;
492 state = json_tokener_state_eatws;
Michael Clarka850f8e2007-03-13 08:26:26 +0000493 goto redo_char;
Michael Clarkf0d08882007-03-13 08:26:18 +0000494
495 case json_tokener_state_object_sep:
496 if(c == '}') {
Michael Clarkf0d08882007-03-13 08:26:18 +0000497 saved_state = json_tokener_state_finish;
498 state = json_tokener_state_eatws;
499 } else if(c == ',') {
Michael Clarka850f8e2007-03-13 08:26:26 +0000500 saved_state = json_tokener_state_object_field_start;
Michael Clarkf0d08882007-03-13 08:26:18 +0000501 state = json_tokener_state_eatws;
502 } else {
Michael Clarka850f8e2007-03-13 08:26:26 +0000503 tok->err = json_tokener_error_parse_object_value_sep;
Michael Clarkf0d08882007-03-13 08:26:18 +0000504 goto out;
505 }
506 break;
507
508 }
Michael Clarka850f8e2007-03-13 08:26:26 +0000509 str++;
510 tok->char_offset++;
Michael Clarkf0d08882007-03-13 08:26:18 +0000511 } while(c);
512
513 if(state != json_tokener_state_finish &&
514 saved_state != json_tokener_state_finish)
Michael Clarka850f8e2007-03-13 08:26:26 +0000515 tok->err = json_tokener_error_parse_eof;
Michael Clarkf0d08882007-03-13 08:26:18 +0000516
517 out:
Michael Clarka850f8e2007-03-13 08:26:26 +0000518 if(tok->err == json_tokener_success) return json_object_get(current);
Michael Clarkdfaf6702007-10-25 02:26:00 +0000519 MC_DEBUG("json_tokener_parse_ex: error %s at offset %d\n",
Michael Clarka850f8e2007-03-13 08:26:26 +0000520 json_tokener_errors[tok->err], tok->char_offset);
521 return NULL;
Michael Clarkf0d08882007-03-13 08:26:18 +0000522}