4 * Copyright Metaparadigm Pte. Ltd. 2004.
5 * Michael Clark <michael@metaparadigm.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public (LGPL)
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details: http://www.gnu.org/
24 #include "json_tokener.h"
29 #include "arraylist.h"
30 #include "json_object.h"
31 #include "ossupport.h"
32 #include "json_object_private.h"
36 static struct json_object* json_tokener_do_parse(struct json_tokener *this);
38 struct json_object* json_tokener_parse(char * s)
40 struct json_tokener tok;
41 struct json_object* obj;
45 tok.pb = printbuf_new();
46 obj = json_tokener_do_parse(&tok);
47 printbuf_free(tok.pb);
51 static struct json_object* json_tokener_do_parse(struct json_tokener *this)
53 enum json_tokener_state state, saved_state;
54 enum json_tokener_error err = json_tokener_success;
55 struct json_object *current = NULL, *obj;
56 char *obj_field_name = NULL;
58 int deemed_double, start_offset;
60 state = json_tokener_state_eatws;
61 saved_state = json_tokener_state_start;
65 c = this->source[this->pos];
68 case json_tokener_state_eatws:
72 state = json_tokener_state_comment_start;
73 start_offset = this->pos++;
79 case json_tokener_state_start:
82 state = json_tokener_state_eatws;
83 saved_state = json_tokener_state_object;
84 current = json_object_new_object();
88 state = json_tokener_state_eatws;
89 saved_state = json_tokener_state_array;
90 current = json_object_new_array();
95 state = json_tokener_state_null;
96 start_offset = this->pos++;
101 printbuf_reset(this->pb);
102 state = json_tokener_state_string;
103 start_offset = ++this->pos;
109 state = json_tokener_state_boolean;
110 start_offset = this->pos++;
115 state = json_tokener_state_number;
116 start_offset = this->pos++;
119 err = json_tokener_error_parse_unexpected;
124 case json_tokener_state_finish:
127 case json_tokener_state_null:
128 if(strncasecmp("null", this->source + start_offset,
129 this->pos - start_offset))
130 return error_ptr(-json_tokener_error_parse_null);
131 if(this->pos - start_offset == 4) {
133 saved_state = json_tokener_state_finish;
134 state = json_tokener_state_eatws;
140 case json_tokener_state_comment_start:
142 state = json_tokener_state_comment;
143 } else if(c == '/') {
144 state = json_tokener_state_comment_eol;
146 err = json_tokener_error_parse_comment;
152 case json_tokener_state_comment:
153 if(c == '*') state = json_tokener_state_comment_end;
157 case json_tokener_state_comment_eol:
160 char *tmp = strndup(this->source + start_offset,
161 this->pos - start_offset);
162 mc_debug("json_tokener_comment: %s\n", tmp);
165 state = json_tokener_state_eatws;
170 case json_tokener_state_comment_end:
173 char *tmp = strndup(this->source + start_offset,
174 this->pos - start_offset + 1);
175 mc_debug("json_tokener_comment: %s\n", tmp);
178 state = json_tokener_state_eatws;
180 state = json_tokener_state_comment;
185 case json_tokener_state_string:
186 if(c == quote_char) {
187 printbuf_memappend(this->pb, this->source + start_offset,
188 this->pos - start_offset);
189 current = json_object_new_string(this->pb->buf);
190 saved_state = json_tokener_state_finish;
191 state = json_tokener_state_eatws;
192 } else if(c == '\\') {
193 saved_state = json_tokener_state_string;
194 state = json_tokener_state_string_escape;
199 case json_tokener_state_string_escape:
204 printbuf_memappend(this->pb, this->source + start_offset,
205 this->pos - start_offset - 1);
206 start_offset = this->pos++;
213 printbuf_memappend(this->pb, this->source + start_offset,
214 this->pos - start_offset - 1);
215 if(c == 'b') printbuf_memappend(this->pb, "\b", 1);
216 else if(c == 'n') printbuf_memappend(this->pb, "\n", 1);
217 else if(c == 'r') printbuf_memappend(this->pb, "\r", 1);
218 else if(c == 't') printbuf_memappend(this->pb, "\t", 1);
219 start_offset = ++this->pos;
223 printbuf_memappend(this->pb, this->source + start_offset,
224 this->pos - start_offset - 1);
225 start_offset = ++this->pos;
226 state = json_tokener_state_escape_unicode;
229 err = json_tokener_error_parse_string;
234 case json_tokener_state_escape_unicode:
236 if(strchr(json_hex_chars, c)) {
239 if(this->pos - start_offset == 4) {
240 unsigned char utf_out[3];
241 unsigned int ucs_char =
242 (hexdigit(*(this->source + start_offset)) << 12) +
243 (hexdigit(*(this->source + start_offset + 1)) << 8) +
244 (hexdigit(*(this->source + start_offset + 2)) << 4) +
245 hexdigit(*(this->source + start_offset + 3));
247 if (ucs_char < 0x80) {
248 utf_out[0] = ucs_char;
249 printbuf_memappend(this->pb, utf_out, 1);
250 } else if (ucs_char < 0x800) {
251 utf_out[0] = 0xc0 | (ucs_char >> 6);
252 utf_out[1] = 0x80 | (ucs_char & 0x3f);
253 printbuf_memappend(this->pb, utf_out, 2);
255 utf_out[0] = 0xe0 | (ucs_char >> 12);
256 utf_out[1] = 0x80 | ((ucs_char >> 6) & 0x3f);
257 utf_out[2] = 0x80 | (ucs_char & 0x3f);
258 printbuf_memappend(this->pb, utf_out, 3);
260 start_offset = this->pos;
264 err = json_tokener_error_parse_string;
269 case json_tokener_state_boolean:
270 if(strncasecmp("true", this->source + start_offset,
271 this->pos - start_offset) == 0) {
272 if(this->pos - start_offset == 4) {
273 current = json_object_new_boolean(1);
274 saved_state = json_tokener_state_finish;
275 state = json_tokener_state_eatws;
279 } else if(strncasecmp("false", this->source + start_offset,
280 this->pos - start_offset) == 0) {
281 if(this->pos - start_offset == 5) {
282 current = json_object_new_boolean(0);
283 saved_state = json_tokener_state_finish;
284 state = json_tokener_state_eatws;
289 err = json_tokener_error_parse_boolean;
294 case json_tokener_state_number:
295 if(!c || !strchr(json_number_chars, c)) {
298 char *tmp = strndup(this->source + start_offset,
299 this->pos - start_offset);
300 if(!deemed_double && sscanf(tmp, "%d", &numi) == 1) {
301 current = json_object_new_int(numi);
302 } else if(deemed_double && sscanf(tmp, "%lf", &numd) == 1) {
303 current = json_object_new_double(numd);
306 err = json_tokener_error_parse_number;
310 saved_state = json_tokener_state_finish;
311 state = json_tokener_state_eatws;
313 if(c == '.' || c == 'e') deemed_double = 1;
318 case json_tokener_state_array:
321 saved_state = json_tokener_state_finish;
322 state = json_tokener_state_eatws;
324 obj = json_tokener_do_parse(this);
326 err = (enum json_tokener_error)obj;
329 json_object_array_add(current, obj);
330 saved_state = json_tokener_state_array_sep;
331 state = json_tokener_state_eatws;
335 case json_tokener_state_array_sep:
338 saved_state = json_tokener_state_finish;
339 state = json_tokener_state_eatws;
340 } else if(c == ',') {
342 saved_state = json_tokener_state_array;
343 state = json_tokener_state_eatws;
345 json_object_put(current);
346 return error_ptr(-json_tokener_error_parse_array);
350 case json_tokener_state_object:
351 state = json_tokener_state_object_field_start;
352 start_offset = this->pos;
355 case json_tokener_state_object_field_start:
358 saved_state = json_tokener_state_finish;
359 state = json_tokener_state_eatws;
360 } else if (c == '"' || c == '\'') {
362 printbuf_reset(this->pb);
363 state = json_tokener_state_object_field;
364 start_offset = ++this->pos;
368 case json_tokener_state_object_field:
369 if(c == quote_char) {
370 printbuf_memappend(this->pb, this->source + start_offset,
371 this->pos - start_offset);
372 obj_field_name = strdup(this->pb->buf);
373 saved_state = json_tokener_state_object_field_end;
374 state = json_tokener_state_eatws;
375 } else if(c == '\\') {
376 saved_state = json_tokener_state_object_field;
377 state = json_tokener_state_string_escape;
382 case json_tokener_state_object_field_end:
385 saved_state = json_tokener_state_object_value;
386 state = json_tokener_state_eatws;
388 return error_ptr(-json_tokener_error_parse_object);
392 case json_tokener_state_object_value:
393 obj = json_tokener_do_parse(this);
395 err = (enum json_tokener_error)obj;
398 json_object_object_add(current, obj_field_name, obj);
399 free(obj_field_name);
400 obj_field_name = NULL;
401 saved_state = json_tokener_state_object_sep;
402 state = json_tokener_state_eatws;
405 case json_tokener_state_object_sep:
408 saved_state = json_tokener_state_finish;
409 state = json_tokener_state_eatws;
410 } else if(c == ',') {
412 saved_state = json_tokener_state_object;
413 state = json_tokener_state_eatws;
415 err = json_tokener_error_parse_object;
423 if(state != json_tokener_state_finish &&
424 saved_state != json_tokener_state_finish)
425 err = json_tokener_error_parse_eof;
428 free(obj_field_name);
429 if(err == json_tokener_success) return current;
430 mc_debug("json_tokener_do_parse: error=%d state=%d char=%c\n",
432 json_object_put(current);
433 return error_ptr(-err);