jansson 2.0
[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, jsonp_hash_key, jsonp_key_equal, NULL, NULL)) {
237         set_error(s, "<internal>", "Out of memory");
238         return -1;
239     }
240
241     if(!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
252         if(strict != 0) {
253             set_error(s, "<format>", "Expected '}' after '%c', got '%c'",
254                       (strict == 1 ? '!' : '*'), s->token);
255             goto out;
256         }
257
258         if(!s->token) {
259             set_error(s, "<format>", "Unexpected end of format string");
260             goto out;
261         }
262
263         if(s->token == '!' || s->token == '*') {
264             strict = (s->token == '!' ? 1 : -1);
265             next_token(s);
266             continue;
267         }
268
269         if(s->token != 's') {
270             set_error(s, "<format>", "Expected format 's', got '%c'", s->token);
271             goto out;
272         }
273
274         key = va_arg(*ap, const char *);
275         if(!key) {
276             set_error(s, "<args>", "NULL object key");
277             goto out;
278         }
279
280         next_token(s);
281
282         value = json_object_get(root, key);
283         if(!value) {
284             set_error(s, "<validation>", "Object item not found: %s", key);
285             goto out;
286         }
287
288         if(unpack(s, value, ap))
289             goto out;
290
291         hashtable_set(&key_set, (void *)key, NULL);
292         next_token(s);
293     }
294
295     if(strict == 0 && (s->flags & JSON_STRICT))
296         strict = 1;
297
298     if(strict == 1 && key_set.size != json_object_size(root)) {
299         long diff = (long)json_object_size(root) - (long)key_set.size;
300         set_error(s, "<validation>", "%li object item(s) left unpacked", diff);
301         goto out;
302     }
303
304     ret = 0;
305
306 out:
307     hashtable_close(&key_set);
308     return ret;
309 }
310
311 static int unpack_array(scanner_t *s, json_t *root, va_list *ap)
312 {
313     size_t i = 0;
314     int strict = 0;
315
316     if(!json_is_array(root)) {
317         set_error(s, "<validation>", "Expected array, got %s", type_name(root));
318         return -1;
319     }
320     next_token(s);
321
322     while(s->token != ']') {
323         json_t *value;
324
325         if(strict != 0) {
326             set_error(s, "<format>", "Expected ']' after '%c', got '%c'",
327                       (strict == 1 ? '!' : '*'),
328                       s->token);
329             return -1;
330         }
331
332         if(!s->token) {
333             set_error(s, "<format>", "Unexpected end of format string");
334             return -1;
335         }
336
337         if(s->token == '!' || s->token == '*') {
338             strict = (s->token == '!' ? 1 : -1);
339             next_token(s);
340             continue;
341         }
342
343         if(!strchr(unpack_value_starters, s->token)) {
344             set_error(s, "<format>", "Unexpected format character '%c'",
345                       s->token);
346             return -1;
347         }
348
349         value = json_array_get(root, i);
350         if(!value) {
351             set_error(s, "<validation>", "Array index %lu out of range",
352                       (unsigned long)i);
353             return -1;
354         }
355
356         if(unpack(s, value, ap))
357             return -1;
358
359         next_token(s);
360         i++;
361     }
362
363     if(strict == 0 && (s->flags & JSON_STRICT))
364         strict = 1;
365
366     if(strict == 1 && i != json_array_size(root)) {
367         long diff = (long)json_array_size(root) - (long)i;
368         set_error(s, "<validation>", "%li array item(s) left unpacked", diff);
369         return -1;
370     }
371
372     return 0;
373 }
374
375 static int unpack(scanner_t *s, json_t *root, va_list *ap)
376 {
377     switch(s->token)
378     {
379         case '{':
380             return unpack_object(s, root, ap);
381
382         case '[':
383             return unpack_array(s, root, ap);
384
385         case 's':
386             if(!json_is_string(root)) {
387                 set_error(s, "<validation>", "Expected string, got %s",
388                           type_name(root));
389                 return -1;
390             }
391
392             if(!(s->flags & JSON_VALIDATE_ONLY)) {
393                 const char **str;
394
395                 str = va_arg(*ap, const char **);
396                 if(!str) {
397                     set_error(s, "<args>", "NULL string argument");
398                     return -1;
399                 }
400
401                 *str = json_string_value(root);
402             }
403             return 0;
404
405         case 'i':
406             if(!json_is_integer(root)) {
407                 set_error(s, "<validation>", "Expected integer, got %s",
408                           type_name(root));
409                 return -1;
410             }
411
412             if(!(s->flags & JSON_VALIDATE_ONLY))
413                 *va_arg(*ap, int*) = json_integer_value(root);
414
415             return 0;
416
417         case 'I':
418             if(!json_is_integer(root)) {
419                 set_error(s, "<validation>", "Expected integer, got %s",
420                           type_name(root));
421                 return -1;
422             }
423
424             if(!(s->flags & JSON_VALIDATE_ONLY))
425                 *va_arg(*ap, json_int_t*) = json_integer_value(root);
426
427             return 0;
428
429         case 'b':
430             if(!json_is_boolean(root)) {
431                 set_error(s, "<validation>", "Expected true or false, got %s",
432                           type_name(root));
433                 return -1;
434             }
435
436             if(!(s->flags & JSON_VALIDATE_ONLY))
437                 *va_arg(*ap, int*) = json_is_true(root);
438
439             return 0;
440
441         case 'f':
442             if(!json_is_real(root)) {
443                 set_error(s, "<validation>", "Expected real, got %s",
444                           type_name(root));
445                 return -1;
446             }
447
448             if(!(s->flags & JSON_VALIDATE_ONLY))
449                 *va_arg(*ap, double*) = json_real_value(root);
450
451             return 0;
452
453         case 'F':
454             if(!json_is_number(root)) {
455                 set_error(s, "<validation>", "Expected real or integer, got %s",
456                           type_name(root));
457                 return -1;
458             }
459
460             if(!(s->flags & JSON_VALIDATE_ONLY))
461                 *va_arg(*ap, double*) = json_number_value(root);
462
463             return 0;
464
465         case 'O':
466             if(!(s->flags & JSON_VALIDATE_ONLY))
467                 json_incref(root);
468             /* Fall through */
469
470         case 'o':
471             if(!(s->flags & JSON_VALIDATE_ONLY))
472                 *va_arg(*ap, json_t**) = root;
473
474             return 0;
475
476         case 'n':
477             /* Never assign, just validate */
478             if(!json_is_null(root)) {
479                 set_error(s, "<validation>", "Expected null, got %s",
480                           type_name(root));
481                 return -1;
482             }
483             return 0;
484
485         default:
486             set_error(s, "<format>", "Unexpected format character '%c'",
487                       s->token);
488             return -1;
489     }
490 }
491
492 json_t *json_vpack_ex(json_error_t *error, size_t flags,
493                       const char *fmt, va_list ap)
494 {
495     scanner_t s;
496     va_list ap_copy;
497     json_t *value;
498
499     if(!fmt || !*fmt) {
500         jsonp_error_init(error, "<format>");
501         jsonp_error_set(error, -1, -1, 0, "NULL or empty format string");
502         return NULL;
503     }
504     jsonp_error_init(error, NULL);
505
506     scanner_init(&s, error, flags, fmt);
507     next_token(&s);
508
509     va_copy(ap_copy, ap);
510     value = pack(&s, &ap_copy);
511     va_end(ap_copy);
512
513     if(!value)
514         return NULL;
515
516     next_token(&s);
517     if(s.token) {
518         json_decref(value);
519         set_error(&s, "<format>", "Garbage after format string");
520         return NULL;
521     }
522
523     return value;
524 }
525
526 json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...)
527 {
528     json_t *value;
529     va_list ap;
530
531     va_start(ap, fmt);
532     value = json_vpack_ex(error, flags, fmt, ap);
533     va_end(ap);
534
535     return value;
536 }
537
538 json_t *json_pack(const char *fmt, ...)
539 {
540     json_t *value;
541     va_list ap;
542
543     va_start(ap, fmt);
544     value = json_vpack_ex(NULL, 0, fmt, ap);
545     va_end(ap);
546
547     return value;
548 }
549
550 int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags,
551                     const char *fmt, va_list ap)
552 {
553     scanner_t s;
554     va_list ap_copy;
555
556     if(!root) {
557         jsonp_error_init(error, "<root>");
558         jsonp_error_set(error, -1, -1, 0, "NULL root value");
559         return -1;
560     }
561
562     if(!fmt || !*fmt) {
563         jsonp_error_init(error, "<format>");
564         jsonp_error_set(error, -1, -1, 0, "NULL or empty format string");
565         return -1;
566     }
567     jsonp_error_init(error, NULL);
568
569     scanner_init(&s, error, flags, fmt);
570     next_token(&s);
571
572     va_copy(ap_copy, ap);
573     if(unpack(&s, root, &ap_copy)) {
574         va_end(ap_copy);
575         return -1;
576     }
577     va_end(ap_copy);
578
579     next_token(&s);
580     if(s.token) {
581         set_error(&s, "<format>", "Garbage after format string");
582         return -1;
583     }
584
585     return 0;
586 }
587
588 int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...)
589 {
590     int ret;
591     va_list ap;
592
593     va_start(ap, fmt);
594     ret = json_vunpack_ex(root, error, flags, fmt, ap);
595     va_end(ap);
596
597     return ret;
598 }
599
600 int json_unpack(json_t *root, const char *fmt, ...)
601 {
602     int ret;
603     va_list ap;
604
605     va_start(ap, fmt);
606     ret = json_vunpack_ex(root, NULL, 0, fmt, ap);
607     va_end(ap);
608
609     return ret;
610 }