Add support for optional object keys for json_unpack() and friends
[jansson.git] / src / pack_unpack.c
1 /*
2  * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org>
3  * Copyright (c) 2011 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     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
24 static const char *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
37 static const char *unpack_value_starters = "{[siIbfFOon";
38
39
40 static 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
50 static 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
73 static 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
87 static json_t *pack(scanner_t *s, va_list *ap);
88
89 static 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
135 error:
136     json_decref(object);
137     return NULL;
138 }
139
140 static 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
166 error:
167     json_decref(array);
168     return NULL;
169 }
170
171 static 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
222 static int unpack(scanner_t *s, json_t *root, va_list *ap);
223
224 static 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
318 out:
319     hashtable_close(&key_set);
320     return ret;
321 }
322
323 static 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
393 static 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 = 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
529 json_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
563 json_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
575 json_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
587 int 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
625 int 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
637 int 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 }