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