1/*
2 * Copyright (c) 2009-2012 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
14typedef struct {
15 const char *start;
16 const char *fmt;
17 char token;
18 json_error_t *error;
19 size_t flags;
20 int line;
21 int column;
22} scanner_t;
23
24static const char * const type_names[] = {
25 "object",
26 "array",
27 "string",
28 "integer",
29 "real",
30 "true",
31 "false",
32 "null"
33};
34
35#define type_name(x) type_names[json_typeof(x)]
36
37static const char unpack_value_starters[] = "{[siIbfFOon";
38
39
40static void scanner_init(scanner_t *s, json_error_t *error,
41 size_t flags, const char *fmt)
42{
43 s->error = error;
44 s->flags = flags;
45 s->fmt = s->start = fmt;
46 s->line = 1;
47 s->column = 0;
48}
49
50static void next_token(scanner_t *s)
51{
52 const char *t = s->fmt;
53 s->column++;
54
55 /* skip space and ignored chars */
56 while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') {
57 if(*t == '\n') {
58 s->line++;
59 s->column = 1;
60 }
61 else
62 s->column++;
63
64 t++;
65 }
66
67 s->token = *t;
68
69 t++;
70 s->fmt = t;
71}
72
73static void set_error(scanner_t *s, const char *source, const char *fmt, ...)
74{
75 va_list ap;
76 size_t pos;
77 va_start(ap, fmt);
78
79 pos = (size_t)(s->fmt - s->start);
80 jsonp_error_vset(s->error, s->line, s->column, pos, fmt, ap);
81
82 jsonp_error_set_source(s->error, source);
83
84 va_end(ap);
85}
86
87static json_t *pack(scanner_t *s, va_list *ap);
88
89static json_t *pack_object(scanner_t *s, va_list *ap)
90{
91 json_t *object = json_object();
92 next_token(s);
93
94 while(s->token != '}') {
95 const char *key;
96 json_t *value;
97
98 if(!s->token) {
99 set_error(s, "<format>", "Unexpected end of format string");
100 goto error;
101 }
102
103 if(s->token != 's') {
104 set_error(s, "<format>", "Expected format 's', got '%c'", s->token);
105 goto error;
106 }
107
108 key = va_arg(*ap, const char *);
109 if(!key) {
110 set_error(s, "<args>", "NULL object key");
111 goto error;
112 }
113
114 if(!utf8_check_string(key, -1)) {
115 set_error(s, "<args>", "Invalid UTF-8 in object key");
116 goto error;
117 }
118
119 next_token(s);
120
121 value = pack(s, ap);
122 if(!value)
123 goto error;
124
125 if(json_object_set_new_nocheck(object, key, value)) {
126 set_error(s, "<internal>", "Unable to add key \"%s\"", key);
127 goto error;
128 }
129
130 next_token(s);
131 }
132
133 return object;
134
135error:
136 json_decref(object);
137 return NULL;
138}
139
140static json_t *pack_array(scanner_t *s, va_list *ap)
141{
142 json_t *array = json_array();
143 next_token(s);
144
145 while(s->token != ']') {
146 json_t *value;
147
148 if(!s->token) {
149 set_error(s, "<format>", "Unexpected end of format string");
150 goto error;
151 }
152
153 value = pack(s, ap);
154 if(!value)
155 goto error;
156
157 if(json_array_append_new(array, value)) {
158 set_error(s, "<internal>", "Unable to append to array");
159 goto error;
160 }
161
162 next_token(s);
163 }
164 return array;
165
166error:
167 json_decref(array);
168 return NULL;
169}
170
171static json_t *pack(scanner_t *s, va_list *ap)
172{
173 switch(s->token) {
174 case '{':
175 return pack_object(s, ap);
176
177 case '[':
178 return pack_array(s, ap);
179
180 case 's': /* string */
181 {
182 const char *str = va_arg(*ap, const char *);
183 if(!str) {
184 set_error(s, "<args>", "NULL string argument");
185 return NULL;
186 }
187 if(!utf8_check_string(str, -1)) {
188 set_error(s, "<args>", "Invalid UTF-8 string");
189 return NULL;
190 }
191 return json_string_nocheck(str);
192 }
193
194 case 'n': /* null */
195 return json_null();
196
197 case 'b': /* boolean */
198 return va_arg(*ap, int) ? json_true() : json_false();
199
200 case 'i': /* integer from int */
201 return json_integer(va_arg(*ap, int));
202
203 case 'I': /* integer from json_int_t */
204 return json_integer(va_arg(*ap, json_int_t));
205
206 case 'f': /* real */
207 return json_real(va_arg(*ap, double));
208
209 case 'O': /* a json_t object; increments refcount */
210 return json_incref(va_arg(*ap, json_t *));
211
212 case 'o': /* a json_t object; doesn't increment refcount */
213 return va_arg(*ap, json_t *);
214
215 default:
216 set_error(s, "<format>", "Unexpected format character '%c'",
217 s->token);
218 return NULL;
219 }
220}
221
222static int unpack(scanner_t *s, json_t *root, va_list *ap);
223
224static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
225{
226 int ret = -1;
227 int strict = 0;
228
229 /* Use a set (emulated by a hashtable) to check that all object
230 keys are accessed. Checking that the correct number of keys
231 were accessed is not enough, as the same key can be unpacked
232 multiple times.
233 */
234 hashtable_t key_set;
235
236 if(hashtable_init(&key_set)) {
237 set_error(s, "<internal>", "Out of memory");
238 return -1;
239 }
240
241 if(root && !json_is_object(root)) {
242 set_error(s, "<validation>", "Expected object, got %s",
243 type_name(root));
244 goto out;
245 }
246 next_token(s);
247
248 while(s->token != '}') {
249 const char *key;
250 json_t *value;
251 int opt = 0;
252
253 if(strict != 0) {
254 set_error(s, "<format>", "Expected '}' after '%c', got '%c'",
255 (strict == 1 ? '!' : '*'), s->token);
256 goto out;
257 }
258
259 if(!s->token) {
260 set_error(s, "<format>", "Unexpected end of format string");
261 goto out;
262 }
263
264 if(s->token == '!' || s->token == '*') {
265 strict = (s->token == '!' ? 1 : -1);
266 next_token(s);
267 continue;
268 }
269
270 if(s->token != 's') {
271 set_error(s, "<format>", "Expected format 's', got '%c'", s->token);
272 goto out;
273 }
274
275 key = va_arg(*ap, const char *);
276 if(!key) {
277 set_error(s, "<args>", "NULL object key");
278 goto out;
279 }
280
281 next_token(s);
282
283 if(s->token == '?') {
284 opt = 1;
285 next_token(s);
286 }
287
288 if(!root) {
289 /* skipping */
290 value = NULL;
291 }
292 else {
293 value = json_object_get(root, key);
294 if(!value && !opt) {
295 set_error(s, "<validation>", "Object item not found: %s", key);
296 goto out;
297 }
298 }
299
300 if(unpack(s, value, ap))
301 goto out;
302
303 hashtable_set(&key_set, key, 0, json_null());
304 next_token(s);
305 }
306
307 if(strict == 0 && (s->flags & JSON_STRICT))
308 strict = 1;
309
310 if(root && strict == 1 && key_set.size != json_object_size(root)) {
311 long diff = (long)json_object_size(root) - (long)key_set.size;
312 set_error(s, "<validation>", "%li object item(s) left unpacked", diff);
313 goto out;
314 }
315
316 ret = 0;
317
318out:
319 hashtable_close(&key_set);
320 return ret;
321}
322
323static int unpack_array(scanner_t *s, json_t *root, va_list *ap)
324{
325 size_t i = 0;
326 int strict = 0;
327
328 if(root && !json_is_array(root)) {
329 set_error(s, "<validation>", "Expected array, got %s", type_name(root));
330 return -1;
331 }
332 next_token(s);
333
334 while(s->token != ']') {
335 json_t *value;
336
337 if(strict != 0) {
338 set_error(s, "<format>", "Expected ']' after '%c', got '%c'",
339 (strict == 1 ? '!' : '*'),
340 s->token);
341 return -1;
342 }
343
344 if(!s->token) {
345 set_error(s, "<format>", "Unexpected end of format string");
346 return -1;
347 }
348
349 if(s->token == '!' || s->token == '*') {
350 strict = (s->token == '!' ? 1 : -1);
351 next_token(s);
352 continue;
353 }
354
355 if(!strchr(unpack_value_starters, s->token)) {
356 set_error(s, "<format>", "Unexpected format character '%c'",
357 s->token);
358 return -1;
359 }
360
361 if(!root) {
362 /* skipping */
363 value = NULL;
364 }
365 else {
366 value = json_array_get(root, i);
367 if(!value) {
368 set_error(s, "<validation>", "Array index %lu out of range",
369 (unsigned long)i);
370 return -1;
371 }
372 }
373
374 if(unpack(s, value, ap))
375 return -1;
376
377 next_token(s);
378 i++;
379 }
380
381 if(strict == 0 && (s->flags & JSON_STRICT))
382 strict = 1;
383
384 if(root && strict == 1 && i != json_array_size(root)) {
385 long diff = (long)json_array_size(root) - (long)i;
386 set_error(s, "<validation>", "%li array item(s) left unpacked", diff);
387 return -1;
388 }
389
390 return 0;
391}
392
393static int unpack(scanner_t *s, json_t *root, va_list *ap)
394{
395 switch(s->token)
396 {
397 case '{':
398 return unpack_object(s, root, ap);
399
400 case '[':
401 return unpack_array(s, root, ap);
402
403 case 's':
404 if(root && !json_is_string(root)) {
405 set_error(s, "<validation>", "Expected string, got %s",
406 type_name(root));
407 return -1;
408 }
409
410 if(!(s->flags & JSON_VALIDATE_ONLY)) {
411 const char **target;
412
413 target = va_arg(*ap, const char **);
414 if(!target) {
415 set_error(s, "<args>", "NULL string argument");
416 return -1;
417 }
418
419 if(root)
420 *target = json_string_value(root);
421 }
422 return 0;
423
424 case 'i':
425 if(root && !json_is_integer(root)) {
426 set_error(s, "<validation>", "Expected integer, got %s",
427 type_name(root));
428 return -1;
429 }
430
431 if(!(s->flags & JSON_VALIDATE_ONLY)) {
432 int *target = va_arg(*ap, int*);
433 if(root)
434 *target = (int)json_integer_value(root);
435 }
436
437 return 0;
438
439 case 'I':
440 if(root && !json_is_integer(root)) {
441 set_error(s, "<validation>", "Expected integer, got %s",
442 type_name(root));
443 return -1;
444 }
445
446 if(!(s->flags & JSON_VALIDATE_ONLY)) {
447 json_int_t *target = va_arg(*ap, json_int_t*);
448 if(root)
449 *target = json_integer_value(root);
450 }
451
452 return 0;
453
454 case 'b':
455 if(root && !json_is_boolean(root)) {
456 set_error(s, "<validation>", "Expected true or false, got %s",
457 type_name(root));
458 return -1;
459 }
460
461 if(!(s->flags & JSON_VALIDATE_ONLY)) {
462 int *target = va_arg(*ap, int*);
463 if(root)
464 *target = json_is_true(root);
465 }
466
467 return 0;
468
469 case 'f':
470 if(root && !json_is_real(root)) {
471 set_error(s, "<validation>", "Expected real, got %s",
472 type_name(root));
473 return -1;
474 }
475
476 if(!(s->flags & JSON_VALIDATE_ONLY)) {
477 double *target = va_arg(*ap, double*);
478 if(root)
479 *target = json_real_value(root);
480 }
481
482 return 0;
483
484 case 'F':
485 if(root && !json_is_number(root)) {
486 set_error(s, "<validation>", "Expected real or integer, got %s",
487 type_name(root));
488 return -1;
489 }
490
491 if(!(s->flags & JSON_VALIDATE_ONLY)) {
492 double *target = va_arg(*ap, double*);
493 if(root)
494 *target = json_number_value(root);
495 }
496
497 return 0;
498
499 case 'O':
500 if(root && !(s->flags & JSON_VALIDATE_ONLY))
501 json_incref(root);
502 /* Fall through */
503
504 case 'o':
505 if(!(s->flags & JSON_VALIDATE_ONLY)) {
506 json_t **target = va_arg(*ap, json_t**);
507 if(root)
508 *target = root;
509 }
510
511 return 0;
512
513 case 'n':
514 /* Never assign, just validate */
515 if(root && !json_is_null(root)) {
516 set_error(s, "<validation>", "Expected null, got %s",
517 type_name(root));
518 return -1;
519 }
520 return 0;
521
522 default:
523 set_error(s, "<format>", "Unexpected format character '%c'",
524 s->token);
525 return -1;
526 }
527}
528
529json_t *json_vpack_ex(json_error_t *error, size_t flags,
530 const char *fmt, va_list ap)
531{
532 scanner_t s;
533 va_list ap_copy;
534 json_t *value;
535
536 if(!fmt || !*fmt) {
537 jsonp_error_init(error, "<format>");
538 jsonp_error_set(error, -1, -1, 0, "NULL or empty format string");
539 return NULL;
540 }
541 jsonp_error_init(error, NULL);
542
543 scanner_init(&s, error, flags, fmt);
544 next_token(&s);
545
546 va_copy(ap_copy, ap);
547 value = pack(&s, &ap_copy);
548 va_end(ap_copy);
549
550 if(!value)
551 return NULL;
552
553 next_token(&s);
554 if(s.token) {
555 json_decref(value);
556 set_error(&s, "<format>", "Garbage after format string");
557 return NULL;
558 }
559
560 return value;
561}
562
563json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...)
564{
565 json_t *value;
566 va_list ap;
567
568 va_start(ap, fmt);
569 value = json_vpack_ex(error, flags, fmt, ap);
570 va_end(ap);
571
572 return value;
573}
574
575json_t *json_pack(const char *fmt, ...)
576{
577 json_t *value;
578 va_list ap;
579
580 va_start(ap, fmt);
581 value = json_vpack_ex(NULL, 0, fmt, ap);
582 va_end(ap);
583
584 return value;
585}
586
587int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags,
588 const char *fmt, va_list ap)
589{
590 scanner_t s;
591 va_list ap_copy;
592
593 if(!root) {
594 jsonp_error_init(error, "<root>");
595 jsonp_error_set(error, -1, -1, 0, "NULL root value");
596 return -1;
597 }
598
599 if(!fmt || !*fmt) {
600 jsonp_error_init(error, "<format>");
601 jsonp_error_set(error, -1, -1, 0, "NULL or empty format string");
602 return -1;
603 }
604 jsonp_error_init(error, NULL);
605
606 scanner_init(&s, error, flags, fmt);
607 next_token(&s);
608
609 va_copy(ap_copy, ap);
610 if(unpack(&s, root, &ap_copy)) {
611 va_end(ap_copy);
612 return -1;
613 }
614 va_end(ap_copy);
615
616 next_token(&s);
617 if(s.token) {
618 set_error(&s, "<format>", "Garbage after format string");
619 return -1;
620 }
621
622 return 0;
623}
624
625int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...)
626{
627 int ret;
628 va_list ap;
629
630 va_start(ap, fmt);
631 ret = json_vunpack_ex(root, error, flags, fmt, ap);
632 va_end(ap);
633
634 return ret;
635}
636
637int json_unpack(json_t *root, const char *fmt, ...)
638{
639 int ret;
640 va_list ap;
641
642 va_start(ap, fmt);
643 ret = json_vunpack_ex(root, NULL, 0, fmt, ap);
644 va_end(ap);
645
646 return ret;
647}
648