0
|
1 /* |
|
2 * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org> |
|
3 * Copyright (c) 2011-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca> |
|
4 * |
|
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. |
|
7 */ |
|
8 |
|
9 #include <string.h> |
|
10 #include "jansson.h" |
|
11 #include "jansson_private.h" |
|
12 #include "utf.h" |
|
13 |
|
14 typedef struct { |
|
15 int line; |
|
16 int column; |
|
17 size_t pos; |
|
18 char token; |
|
19 } token_t; |
|
20 |
|
21 typedef struct { |
|
22 const char *start; |
|
23 const char *fmt; |
|
24 token_t prev_token; |
|
25 token_t token; |
|
26 token_t next_token; |
|
27 json_error_t *error; |
|
28 size_t flags; |
|
29 int line; |
|
30 int column; |
|
31 size_t pos; |
|
32 } scanner_t; |
|
33 |
|
34 #define token(scanner) ((scanner)->token.token) |
|
35 |
|
36 static const char * const type_names[] = { |
|
37 "object", |
|
38 "array", |
|
39 "string", |
|
40 "integer", |
|
41 "real", |
|
42 "true", |
|
43 "false", |
|
44 "null" |
|
45 }; |
|
46 |
|
47 #define type_name(x) type_names[json_typeof(x)] |
|
48 |
|
49 static const char unpack_value_starters[] = "{[siIbfFOon"; |
|
50 |
|
51 |
|
52 static void scanner_init(scanner_t *s, json_error_t *error, |
|
53 size_t flags, const char *fmt) |
|
54 { |
|
55 s->error = error; |
|
56 s->flags = flags; |
|
57 s->fmt = s->start = fmt; |
|
58 memset(&s->prev_token, 0, sizeof(token_t)); |
|
59 memset(&s->token, 0, sizeof(token_t)); |
|
60 memset(&s->next_token, 0, sizeof(token_t)); |
|
61 s->line = 1; |
|
62 s->column = 0; |
|
63 s->pos = 0; |
|
64 } |
|
65 |
|
66 static void next_token(scanner_t *s) |
|
67 { |
|
68 const char *t; |
|
69 s->prev_token = s->token; |
|
70 |
|
71 if(s->next_token.line) { |
|
72 s->token = s->next_token; |
|
73 s->next_token.line = 0; |
|
74 return; |
|
75 } |
|
76 |
|
77 t = s->fmt; |
|
78 s->column++; |
|
79 s->pos++; |
|
80 |
|
81 /* skip space and ignored chars */ |
|
82 while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') { |
|
83 if(*t == '\n') { |
|
84 s->line++; |
|
85 s->column = 1; |
|
86 } |
|
87 else |
|
88 s->column++; |
|
89 |
|
90 s->pos++; |
|
91 t++; |
|
92 } |
|
93 |
|
94 s->token.token = *t; |
|
95 s->token.line = s->line; |
|
96 s->token.column = s->column; |
|
97 s->token.pos = s->pos; |
|
98 |
|
99 t++; |
|
100 s->fmt = t; |
|
101 } |
|
102 |
|
103 static void prev_token(scanner_t *s) |
|
104 { |
|
105 s->next_token = s->token; |
|
106 s->token = s->prev_token; |
|
107 } |
|
108 |
|
109 static void set_error(scanner_t *s, const char *source, const char *fmt, ...) |
|
110 { |
|
111 va_list ap; |
|
112 va_start(ap, fmt); |
|
113 |
|
114 jsonp_error_vset(s->error, s->token.line, s->token.column, s->token.pos, |
|
115 fmt, ap); |
|
116 |
|
117 jsonp_error_set_source(s->error, source); |
|
118 |
|
119 va_end(ap); |
|
120 } |
|
121 |
|
122 static json_t *pack(scanner_t *s, va_list *ap); |
|
123 |
|
124 |
|
125 /* ours will be set to 1 if jsonp_free() must be called for the result |
|
126 afterwards */ |
|
127 static char *read_string(scanner_t *s, va_list *ap, |
|
128 const char *purpose, size_t *out_len, int *ours) |
|
129 { |
|
130 char t; |
|
131 strbuffer_t strbuff; |
|
132 const char *str; |
|
133 size_t length; |
|
134 |
|
135 next_token(s); |
|
136 t = token(s); |
|
137 prev_token(s); |
|
138 |
|
139 if(t != '#' && t != '%' && t != '+') { |
|
140 /* Optimize the simple case */ |
|
141 str = va_arg(*ap, const char *); |
|
142 |
|
143 if(!str) { |
|
144 set_error(s, "<args>", "NULL string argument"); |
|
145 return NULL; |
|
146 } |
|
147 |
|
148 length = strlen(str); |
|
149 |
|
150 if(!utf8_check_string(str, length)) { |
|
151 set_error(s, "<args>", "Invalid UTF-8 %s", purpose); |
|
152 return NULL; |
|
153 } |
|
154 |
|
155 *out_len = length; |
|
156 *ours = 0; |
|
157 return (char *)str; |
|
158 } |
|
159 |
|
160 strbuffer_init(&strbuff); |
|
161 |
|
162 while(1) { |
|
163 str = va_arg(*ap, const char *); |
|
164 if(!str) { |
|
165 set_error(s, "<args>", "NULL string argument"); |
|
166 strbuffer_close(&strbuff); |
|
167 return NULL; |
|
168 } |
|
169 |
|
170 next_token(s); |
|
171 |
|
172 if(token(s) == '#') { |
|
173 length = va_arg(*ap, int); |
|
174 } |
|
175 else if(token(s) == '%') { |
|
176 length = va_arg(*ap, size_t); |
|
177 } |
|
178 else { |
|
179 prev_token(s); |
|
180 length = strlen(str); |
|
181 } |
|
182 |
|
183 if(strbuffer_append_bytes(&strbuff, str, length) == -1) { |
|
184 set_error(s, "<internal>", "Out of memory"); |
|
185 strbuffer_close(&strbuff); |
|
186 return NULL; |
|
187 } |
|
188 |
|
189 next_token(s); |
|
190 if(token(s) != '+') { |
|
191 prev_token(s); |
|
192 break; |
|
193 } |
|
194 } |
|
195 |
|
196 if(!utf8_check_string(strbuff.value, strbuff.length)) { |
|
197 set_error(s, "<args>", "Invalid UTF-8 %s", purpose); |
|
198 strbuffer_close(&strbuff); |
|
199 return NULL; |
|
200 } |
|
201 |
|
202 *out_len = strbuff.length; |
|
203 *ours = 1; |
|
204 return strbuffer_steal_value(&strbuff); |
|
205 } |
|
206 |
|
207 static json_t *pack_object(scanner_t *s, va_list *ap) |
|
208 { |
|
209 json_t *object = json_object(); |
|
210 next_token(s); |
|
211 |
|
212 while(token(s) != '}') { |
|
213 char *key; |
|
214 size_t len; |
|
215 int ours; |
|
216 json_t *value; |
|
217 |
|
218 if(!token(s)) { |
|
219 set_error(s, "<format>", "Unexpected end of format string"); |
|
220 goto error; |
|
221 } |
|
222 |
|
223 if(token(s) != 's') { |
|
224 set_error(s, "<format>", "Expected format 's', got '%c'", token(s)); |
|
225 goto error; |
|
226 } |
|
227 |
|
228 key = read_string(s, ap, "object key", &len, &ours); |
|
229 if(!key) |
|
230 goto error; |
|
231 |
|
232 next_token(s); |
|
233 |
|
234 value = pack(s, ap); |
|
235 if(!value) { |
|
236 if(ours) |
|
237 jsonp_free(key); |
|
238 |
|
239 goto error; |
|
240 } |
|
241 |
|
242 if(json_object_set_new_nocheck(object, key, value)) { |
|
243 if(ours) |
|
244 jsonp_free(key); |
|
245 |
|
246 set_error(s, "<internal>", "Unable to add key \"%s\"", key); |
|
247 goto error; |
|
248 } |
|
249 |
|
250 if(ours) |
|
251 jsonp_free(key); |
|
252 |
|
253 next_token(s); |
|
254 } |
|
255 |
|
256 return object; |
|
257 |
|
258 error: |
|
259 json_decref(object); |
|
260 return NULL; |
|
261 } |
|
262 |
|
263 static json_t *pack_array(scanner_t *s, va_list *ap) |
|
264 { |
|
265 json_t *array = json_array(); |
|
266 next_token(s); |
|
267 |
|
268 while(token(s) != ']') { |
|
269 json_t *value; |
|
270 |
|
271 if(!token(s)) { |
|
272 set_error(s, "<format>", "Unexpected end of format string"); |
|
273 goto error; |
|
274 } |
|
275 |
|
276 value = pack(s, ap); |
|
277 if(!value) |
|
278 goto error; |
|
279 |
|
280 if(json_array_append_new(array, value)) { |
|
281 set_error(s, "<internal>", "Unable to append to array"); |
|
282 goto error; |
|
283 } |
|
284 |
|
285 next_token(s); |
|
286 } |
|
287 return array; |
|
288 |
|
289 error: |
|
290 json_decref(array); |
|
291 return NULL; |
|
292 } |
|
293 |
|
294 static json_t *pack(scanner_t *s, va_list *ap) |
|
295 { |
|
296 switch(token(s)) { |
|
297 case '{': |
|
298 return pack_object(s, ap); |
|
299 |
|
300 case '[': |
|
301 return pack_array(s, ap); |
|
302 |
|
303 case 's': /* string */ |
|
304 { |
|
305 char *str; |
|
306 size_t len; |
|
307 int ours; |
|
308 |
|
309 str = read_string(s, ap, "string", &len, &ours); |
|
310 if(!str) |
|
311 return NULL; |
|
312 |
|
313 if (ours) |
|
314 return jsonp_stringn_nocheck_own(str, len); |
|
315 else |
|
316 return json_stringn_nocheck(str, len); |
|
317 } |
|
318 |
|
319 case 'n': /* null */ |
|
320 return json_null(); |
|
321 |
|
322 case 'b': /* boolean */ |
|
323 return va_arg(*ap, int) ? json_true() : json_false(); |
|
324 |
|
325 case 'i': /* integer from int */ |
|
326 return json_integer(va_arg(*ap, int)); |
|
327 |
|
328 case 'I': /* integer from json_int_t */ |
|
329 return json_integer(va_arg(*ap, json_int_t)); |
|
330 |
|
331 case 'f': /* real */ |
|
332 return json_real(va_arg(*ap, double)); |
|
333 |
|
334 case 'O': /* a json_t object; increments refcount */ |
|
335 return json_incref(va_arg(*ap, json_t *)); |
|
336 |
|
337 case 'o': /* a json_t object; doesn't increment refcount */ |
|
338 return va_arg(*ap, json_t *); |
|
339 |
|
340 default: |
|
341 set_error(s, "<format>", "Unexpected format character '%c'", |
|
342 token(s)); |
|
343 return NULL; |
|
344 } |
|
345 } |
|
346 |
|
347 static int unpack(scanner_t *s, json_t *root, va_list *ap); |
|
348 |
|
349 static int unpack_object(scanner_t *s, json_t *root, va_list *ap) |
|
350 { |
|
351 int ret = -1; |
|
352 int strict = 0; |
|
353 int gotopt = 0; |
|
354 |
|
355 /* Use a set (emulated by a hashtable) to check that all object |
|
356 keys are accessed. Checking that the correct number of keys |
|
357 were accessed is not enough, as the same key can be unpacked |
|
358 multiple times. |
|
359 */ |
|
360 hashtable_t key_set; |
|
361 |
|
362 if(hashtable_init(&key_set)) { |
|
363 set_error(s, "<internal>", "Out of memory"); |
|
364 return -1; |
|
365 } |
|
366 |
|
367 if(root && !json_is_object(root)) { |
|
368 set_error(s, "<validation>", "Expected object, got %s", |
|
369 type_name(root)); |
|
370 goto out; |
|
371 } |
|
372 next_token(s); |
|
373 |
|
374 while(token(s) != '}') { |
|
375 const char *key; |
|
376 json_t *value; |
|
377 int opt = 0; |
|
378 |
|
379 if(strict != 0) { |
|
380 set_error(s, "<format>", "Expected '}' after '%c', got '%c'", |
|
381 (strict == 1 ? '!' : '*'), token(s)); |
|
382 goto out; |
|
383 } |
|
384 |
|
385 if(!token(s)) { |
|
386 set_error(s, "<format>", "Unexpected end of format string"); |
|
387 goto out; |
|
388 } |
|
389 |
|
390 if(token(s) == '!' || token(s) == '*') { |
|
391 strict = (token(s) == '!' ? 1 : -1); |
|
392 next_token(s); |
|
393 continue; |
|
394 } |
|
395 |
|
396 if(token(s) != 's') { |
|
397 set_error(s, "<format>", "Expected format 's', got '%c'", token(s)); |
|
398 goto out; |
|
399 } |
|
400 |
|
401 key = va_arg(*ap, const char *); |
|
402 if(!key) { |
|
403 set_error(s, "<args>", "NULL object key"); |
|
404 goto out; |
|
405 } |
|
406 |
|
407 next_token(s); |
|
408 |
|
409 if(token(s) == '?') { |
|
410 opt = gotopt = 1; |
|
411 next_token(s); |
|
412 } |
|
413 |
|
414 if(!root) { |
|
415 /* skipping */ |
|
416 value = NULL; |
|
417 } |
|
418 else { |
|
419 value = json_object_get(root, key); |
|
420 if(!value && !opt) { |
|
421 set_error(s, "<validation>", "Object item not found: %s", key); |
|
422 goto out; |
|
423 } |
|
424 } |
|
425 |
|
426 if(unpack(s, value, ap)) |
|
427 goto out; |
|
428 |
|
429 hashtable_set(&key_set, key, 0, json_null()); |
|
430 next_token(s); |
|
431 } |
|
432 |
|
433 if(strict == 0 && (s->flags & JSON_STRICT)) |
|
434 strict = 1; |
|
435 |
|
436 if(root && strict == 1) { |
|
437 /* We need to check that all non optional items have been parsed */ |
|
438 const char *key; |
|
439 json_t *value; |
|
440 long unpacked = 0; |
|
441 if (gotopt) { |
|
442 /* We have optional keys, we need to iter on each key */ |
|
443 json_object_foreach(root, key, value) { |
|
444 if(!hashtable_get(&key_set, key)) { |
|
445 unpacked++; |
|
446 } |
|
447 } |
|
448 } else { |
|
449 /* No optional keys, we can just compare the number of items */ |
|
450 unpacked = (long)json_object_size(root) - (long)key_set.size; |
|
451 } |
|
452 if (unpacked) { |
|
453 set_error(s, "<validation>", "%li object item(s) left unpacked", unpacked); |
|
454 goto out; |
|
455 } |
|
456 } |
|
457 |
|
458 ret = 0; |
|
459 |
|
460 out: |
|
461 hashtable_close(&key_set); |
|
462 return ret; |
|
463 } |
|
464 |
|
465 static int unpack_array(scanner_t *s, json_t *root, va_list *ap) |
|
466 { |
|
467 size_t i = 0; |
|
468 int strict = 0; |
|
469 |
|
470 if(root && !json_is_array(root)) { |
|
471 set_error(s, "<validation>", "Expected array, got %s", type_name(root)); |
|
472 return -1; |
|
473 } |
|
474 next_token(s); |
|
475 |
|
476 while(token(s) != ']') { |
|
477 json_t *value; |
|
478 |
|
479 if(strict != 0) { |
|
480 set_error(s, "<format>", "Expected ']' after '%c', got '%c'", |
|
481 (strict == 1 ? '!' : '*'), |
|
482 token(s)); |
|
483 return -1; |
|
484 } |
|
485 |
|
486 if(!token(s)) { |
|
487 set_error(s, "<format>", "Unexpected end of format string"); |
|
488 return -1; |
|
489 } |
|
490 |
|
491 if(token(s) == '!' || token(s) == '*') { |
|
492 strict = (token(s) == '!' ? 1 : -1); |
|
493 next_token(s); |
|
494 continue; |
|
495 } |
|
496 |
|
497 if(!strchr(unpack_value_starters, token(s))) { |
|
498 set_error(s, "<format>", "Unexpected format character '%c'", |
|
499 token(s)); |
|
500 return -1; |
|
501 } |
|
502 |
|
503 if(!root) { |
|
504 /* skipping */ |
|
505 value = NULL; |
|
506 } |
|
507 else { |
|
508 value = json_array_get(root, i); |
|
509 if(!value) { |
|
510 set_error(s, "<validation>", "Array index %lu out of range", |
|
511 (unsigned long)i); |
|
512 return -1; |
|
513 } |
|
514 } |
|
515 |
|
516 if(unpack(s, value, ap)) |
|
517 return -1; |
|
518 |
|
519 next_token(s); |
|
520 i++; |
|
521 } |
|
522 |
|
523 if(strict == 0 && (s->flags & JSON_STRICT)) |
|
524 strict = 1; |
|
525 |
|
526 if(root && strict == 1 && i != json_array_size(root)) { |
|
527 long diff = (long)json_array_size(root) - (long)i; |
|
528 set_error(s, "<validation>", "%li array item(s) left unpacked", diff); |
|
529 return -1; |
|
530 } |
|
531 |
|
532 return 0; |
|
533 } |
|
534 |
|
535 static int unpack(scanner_t *s, json_t *root, va_list *ap) |
|
536 { |
|
537 switch(token(s)) |
|
538 { |
|
539 case '{': |
|
540 return unpack_object(s, root, ap); |
|
541 |
|
542 case '[': |
|
543 return unpack_array(s, root, ap); |
|
544 |
|
545 case 's': |
|
546 if(root && !json_is_string(root)) { |
|
547 set_error(s, "<validation>", "Expected string, got %s", |
|
548 type_name(root)); |
|
549 return -1; |
|
550 } |
|
551 |
|
552 if(!(s->flags & JSON_VALIDATE_ONLY)) { |
|
553 const char **str_target; |
|
554 size_t *len_target = NULL; |
|
555 |
|
556 str_target = va_arg(*ap, const char **); |
|
557 if(!str_target) { |
|
558 set_error(s, "<args>", "NULL string argument"); |
|
559 return -1; |
|
560 } |
|
561 |
|
562 next_token(s); |
|
563 |
|
564 if(token(s) == '%') { |
|
565 len_target = va_arg(*ap, size_t *); |
|
566 if(!len_target) { |
|
567 set_error(s, "<args>", "NULL string length argument"); |
|
568 return -1; |
|
569 } |
|
570 } |
|
571 else |
|
572 prev_token(s); |
|
573 |
|
574 if(root) { |
|
575 *str_target = json_string_value(root); |
|
576 if(len_target) |
|
577 *len_target = json_string_length(root); |
|
578 } |
|
579 } |
|
580 return 0; |
|
581 |
|
582 case 'i': |
|
583 if(root && !json_is_integer(root)) { |
|
584 set_error(s, "<validation>", "Expected integer, got %s", |
|
585 type_name(root)); |
|
586 return -1; |
|
587 } |
|
588 |
|
589 if(!(s->flags & JSON_VALIDATE_ONLY)) { |
|
590 int *target = va_arg(*ap, int*); |
|
591 if(root) |
|
592 *target = (int)json_integer_value(root); |
|
593 } |
|
594 |
|
595 return 0; |
|
596 |
|
597 case 'I': |
|
598 if(root && !json_is_integer(root)) { |
|
599 set_error(s, "<validation>", "Expected integer, got %s", |
|
600 type_name(root)); |
|
601 return -1; |
|
602 } |
|
603 |
|
604 if(!(s->flags & JSON_VALIDATE_ONLY)) { |
|
605 json_int_t *target = va_arg(*ap, json_int_t*); |
|
606 if(root) |
|
607 *target = json_integer_value(root); |
|
608 } |
|
609 |
|
610 return 0; |
|
611 |
|
612 case 'b': |
|
613 if(root && !json_is_boolean(root)) { |
|
614 set_error(s, "<validation>", "Expected true or false, got %s", |
|
615 type_name(root)); |
|
616 return -1; |
|
617 } |
|
618 |
|
619 if(!(s->flags & JSON_VALIDATE_ONLY)) { |
|
620 int *target = va_arg(*ap, int*); |
|
621 if(root) |
|
622 *target = json_is_true(root); |
|
623 } |
|
624 |
|
625 return 0; |
|
626 |
|
627 case 'f': |
|
628 if(root && !json_is_real(root)) { |
|
629 set_error(s, "<validation>", "Expected real, got %s", |
|
630 type_name(root)); |
|
631 return -1; |
|
632 } |
|
633 |
|
634 if(!(s->flags & JSON_VALIDATE_ONLY)) { |
|
635 double *target = va_arg(*ap, double*); |
|
636 if(root) |
|
637 *target = json_real_value(root); |
|
638 } |
|
639 |
|
640 return 0; |
|
641 |
|
642 case 'F': |
|
643 if(root && !json_is_number(root)) { |
|
644 set_error(s, "<validation>", "Expected real or integer, got %s", |
|
645 type_name(root)); |
|
646 return -1; |
|
647 } |
|
648 |
|
649 if(!(s->flags & JSON_VALIDATE_ONLY)) { |
|
650 double *target = va_arg(*ap, double*); |
|
651 if(root) |
|
652 *target = json_number_value(root); |
|
653 } |
|
654 |
|
655 return 0; |
|
656 |
|
657 case 'O': |
|
658 if(root && !(s->flags & JSON_VALIDATE_ONLY)) |
|
659 json_incref(root); |
|
660 /* Fall through */ |
|
661 |
|
662 case 'o': |
|
663 if(!(s->flags & JSON_VALIDATE_ONLY)) { |
|
664 json_t **target = va_arg(*ap, json_t**); |
|
665 if(root) |
|
666 *target = root; |
|
667 } |
|
668 |
|
669 return 0; |
|
670 |
|
671 case 'n': |
|
672 /* Never assign, just validate */ |
|
673 if(root && !json_is_null(root)) { |
|
674 set_error(s, "<validation>", "Expected null, got %s", |
|
675 type_name(root)); |
|
676 return -1; |
|
677 } |
|
678 return 0; |
|
679 |
|
680 default: |
|
681 set_error(s, "<format>", "Unexpected format character '%c'", |
|
682 token(s)); |
|
683 return -1; |
|
684 } |
|
685 } |
|
686 |
|
687 json_t *json_vpack_ex(json_error_t *error, size_t flags, |
|
688 const char *fmt, va_list ap) |
|
689 { |
|
690 scanner_t s; |
|
691 va_list ap_copy; |
|
692 json_t *value; |
|
693 |
|
694 if(!fmt || !*fmt) { |
|
695 jsonp_error_init(error, "<format>"); |
|
696 jsonp_error_set(error, -1, -1, 0, "NULL or empty format string"); |
|
697 return NULL; |
|
698 } |
|
699 jsonp_error_init(error, NULL); |
|
700 |
|
701 scanner_init(&s, error, flags, fmt); |
|
702 next_token(&s); |
|
703 |
|
704 va_copy(ap_copy, ap); |
|
705 value = pack(&s, &ap_copy); |
|
706 va_end(ap_copy); |
|
707 |
|
708 if(!value) |
|
709 return NULL; |
|
710 |
|
711 next_token(&s); |
|
712 if(token(&s)) { |
|
713 json_decref(value); |
|
714 set_error(&s, "<format>", "Garbage after format string"); |
|
715 return NULL; |
|
716 } |
|
717 |
|
718 return value; |
|
719 } |
|
720 |
|
721 json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) |
|
722 { |
|
723 json_t *value; |
|
724 va_list ap; |
|
725 |
|
726 va_start(ap, fmt); |
|
727 value = json_vpack_ex(error, flags, fmt, ap); |
|
728 va_end(ap); |
|
729 |
|
730 return value; |
|
731 } |
|
732 |
|
733 json_t *json_pack(const char *fmt, ...) |
|
734 { |
|
735 json_t *value; |
|
736 va_list ap; |
|
737 |
|
738 va_start(ap, fmt); |
|
739 value = json_vpack_ex(NULL, 0, fmt, ap); |
|
740 va_end(ap); |
|
741 |
|
742 return value; |
|
743 } |
|
744 |
|
745 int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, |
|
746 const char *fmt, va_list ap) |
|
747 { |
|
748 scanner_t s; |
|
749 va_list ap_copy; |
|
750 |
|
751 if(!root) { |
|
752 jsonp_error_init(error, "<root>"); |
|
753 jsonp_error_set(error, -1, -1, 0, "NULL root value"); |
|
754 return -1; |
|
755 } |
|
756 |
|
757 if(!fmt || !*fmt) { |
|
758 jsonp_error_init(error, "<format>"); |
|
759 jsonp_error_set(error, -1, -1, 0, "NULL or empty format string"); |
|
760 return -1; |
|
761 } |
|
762 jsonp_error_init(error, NULL); |
|
763 |
|
764 scanner_init(&s, error, flags, fmt); |
|
765 next_token(&s); |
|
766 |
|
767 va_copy(ap_copy, ap); |
|
768 if(unpack(&s, root, &ap_copy)) { |
|
769 va_end(ap_copy); |
|
770 return -1; |
|
771 } |
|
772 va_end(ap_copy); |
|
773 |
|
774 next_token(&s); |
|
775 if(token(&s)) { |
|
776 set_error(&s, "<format>", "Garbage after format string"); |
|
777 return -1; |
|
778 } |
|
779 |
|
780 return 0; |
|
781 } |
|
782 |
|
783 int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...) |
|
784 { |
|
785 int ret; |
|
786 va_list ap; |
|
787 |
|
788 va_start(ap, fmt); |
|
789 ret = json_vunpack_ex(root, error, flags, fmt, ap); |
|
790 va_end(ap); |
|
791 |
|
792 return ret; |
|
793 } |
|
794 |
|
795 int json_unpack(json_t *root, const char *fmt, ...) |
|
796 { |
|
797 int ret; |
|
798 va_list ap; |
|
799 |
|
800 va_start(ap, fmt); |
|
801 ret = json_vunpack_ex(root, NULL, 0, fmt, ap); |
|
802 va_end(ap); |
|
803 |
|
804 return ret; |
|
805 } |