2 * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
3 * Copyright (c) 2011 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
5 * Jansson is free software; you can redistribute it and/or modify
6 * it under the terms of the MIT license. See LICENSE for details.
14 #include "jansson_private.h"
24 static void next_token(scanner_t *s)
26 const char *t = s->fmt;
29 /* skip space and ignored chars */
30 while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') {
47 static void set_error(scanner_t *s, const char *fmt, ...)
51 jsonp_error_vset(s->error, s->line, s->column, fmt, ap);
55 static json_t *pack(scanner_t *s, va_list *ap);
57 static json_t *pack_object(scanner_t *s, va_list *ap)
59 json_t *object = json_object();
62 while(s->token != '}') {
67 set_error(s, "Unexpected end of format string");
72 set_error(s, "Expected format 's', got '%c'\n", *s->fmt);
76 key = va_arg(*ap, const char *);
78 set_error(s, "NULL object key");
88 if(json_object_set_new(object, key, value)) {
89 set_error(s, "Unable to add key \"%s\"", key);
103 static json_t *pack_array(scanner_t *s, va_list *ap)
105 json_t *array = json_array();
108 while(s->token != ']') {
112 set_error(s, "Unexpected end of format string");
120 if(json_array_append_new(array, value)) {
121 set_error(s, "Unable to append to array");
134 static json_t *pack(scanner_t *s, va_list *ap)
138 return pack_object(s, ap);
141 return pack_array(s, ap);
143 case 's': /* string */
145 const char *str = va_arg(*ap, const char *);
148 set_error(s, "NULL string");
151 return json_string(str);
157 case 'b': /* boolean */
158 return va_arg(*ap, int) ? json_true() : json_false();
160 case 'i': /* integer */
161 return json_integer(va_arg(*ap, int));
163 case 'f': /* double-precision float */
164 return json_real(va_arg(*ap, double));
166 case 'O': /* a json_t object; increments refcount */
167 return json_incref(va_arg(*ap, json_t *));
169 case 'o': /* a json_t object; doesn't increment refcount */
170 return va_arg(*ap, json_t *);
172 default: /* Whoops! */
173 set_error(s, "Unrecognized format character '%c'", s->token);
178 static int json_vnunpack(json_t *root, json_error_t *error, ssize_t size, const char *fmt, va_list *ap)
181 int rv = 0; /* Return value */
182 int line = 1; /* Line number */
183 int column = 1; /* Column */
185 /* Position markers for arrays or objects */
191 /* Scanner variables */
192 const char *tok = fmt;
198 /* If we're successful, we need to know if the number of arguments
199 * provided matches the number of JSON objects. We can do this by
200 * counting the elements in every array or object we open up, and
201 * decrementing the count as we visit their children. */
204 /* Skip whitespace at the beginning of the string. */
205 while(size && *tok == ' ') {
212 jsonp_error_set(error, 1, 1, "Empty format string!");
216 /* tok must contain either a container type, or a length-1 string for a
218 if(*tok != '[' && *tok != '{')
220 /* Simple object. Permit trailing spaces, otherwise complain. */
221 if((ssize_t)strspn(tok+1, " ") < size-1)
223 jsonp_error_set(error, 1, 1,
224 "Expected a single object, got %i", size);
231 if(!json_is_string(root))
233 jsonp_error_set(error, line, column,
234 "Type mismatch! Object (%i) wasn't a string.",
238 s = va_arg(*ap, const char **);
240 jsonp_error_set(error, line, column, "Passed a NULL string pointer!");
243 *s = json_string_value(root);
247 if(!json_is_integer(root))
249 jsonp_error_set(error, line, column,
250 "Type mismatch! Object (%i) wasn't an integer.",
254 *va_arg(*ap, int*) = json_integer_value(root);
258 if(!json_is_boolean(root))
260 jsonp_error_set(error, line, column,
261 "Type mismatch! Object (%i) wasn't a boolean.",
265 *va_arg(*ap, int*) = json_is_true(root);
269 if(!json_is_number(root))
271 jsonp_error_set(error, line, column,
272 "Type mismatch! Object (%i) wasn't a real.",
276 *va_arg(*ap, double*) = json_number_value(root);
284 *va_arg(*ap, json_t**) = root;
288 /* Don't actually assign anything; we're just happy
289 * the null turned up as promised in the format
294 jsonp_error_set(error, line, column,
295 "Unknown format character '%c'", *tok);
300 /* Move past container opening token */
303 while(tok-fmt < size) {
310 case ' ': /* Whitespace */
313 case ',': /* Element spacer */
316 jsonp_error_set(error, line, column,
317 "Expected KEY, got COMMA!");
322 case ':': /* Key/value separator */
325 jsonp_error_set(error, line, column,
326 "Got key/value separator without "
327 "a key preceding it!");
331 if(!json_is_object(root))
333 jsonp_error_set(error, line, column,
334 "Got a key/value separator "
335 "(':') outside an object!");
341 case ']': /* Close array or object */
344 if(tok-fmt + (ssize_t)strspn(tok+1, " ") != size-1)
346 jsonp_error_set(error, line, column,
347 "Unexpected close-bracket '%c'", *tok);
351 if((*tok == ']' && !json_is_array(root)) ||
352 (*tok == '}' && !json_is_object(root)))
354 jsonp_error_set(error, line, column,
355 "Stray close-array '%c' character", *tok);
363 /* Find corresponding close bracket */
368 if(!*etok || etok-fmt >= size) {
369 jsonp_error_set(error, line, column,
370 "Couldn't find matching close bracket for '%c'",
377 else if(*tok == '[' && *etok == ']') {
380 } else if(*tok == '{' && *etok == '}') {
389 if(json_is_array(root)) {
390 rv = json_vnunpack(json_object_get(root, key),
391 error, etok-tok+1, tok, ap);
393 rv = json_vnunpack(json_array_get(root, array_index++),
394 error, etok-tok+1, tok, ap);
398 /* error should already be set */
399 error->column += column-1;
400 error->line += line-1;
410 /* Handle strings specially, since they're used for both keys
413 if(json_is_object(root) && !key)
416 key = va_arg(*ap, char *);
420 jsonp_error_set(error, line, column,
421 "Refusing to handle a NULL key");
431 /* Fetch the element from the JSON container */
432 if(json_is_object(root))
433 obj = json_object_get(root, key);
435 obj = json_array_get(root, array_index++);
438 jsonp_error_set(error, line, column,
439 "Array/object entry didn't exist!");
443 rv = json_vnunpack(obj, error, 1, tok, ap);
453 /* Whoops -- we didn't match the close bracket! */
454 jsonp_error_set(error, line, column, "Missing close array or object!");
458 json_t *json_pack(json_error_t *error, const char *fmt, ...)
464 jsonp_error_init(error, "");
467 jsonp_error_set(error, 1, 1, "Null or empty format string!");
479 value = pack(&s, &ap);
484 set_error(&s, "Garbage after format string");
491 int json_unpack(json_t *root, json_error_t *error, const char *fmt, ...)
496 jsonp_error_init(error, "");
499 jsonp_error_set(error, 1, 1, "Null or empty format string!");
504 rv = json_vnunpack(root, error, strlen(fmt), fmt, &ap);