Use 'f' for real and 'F' for number (real or integer) in unpack
[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 */
170             return json_integer(va_arg(*ap, int));
171
172         case 'f': /* real */
173             return json_real(va_arg(*ap, double));
174
175         case 'O': /* a json_t object; increments refcount */
176             return json_incref(va_arg(*ap, json_t *));
177
178         case 'o': /* a json_t object; doesn't increment refcount */
179             return va_arg(*ap, json_t *);
180
181         default:
182             set_error(s, "Unrecognized format character '%c'", s->token);
183             return NULL;
184     }
185 }
186
187 static int unpack(scanner_t *s, json_t *root, va_list *ap);
188
189 static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
190 {
191     int ret = -1;
192     int wildcard = 0;
193
194     /* Use a set (emulated by a hashtable) to check that all object
195        keys are accessed. Checking that the correct number of keys
196        were accessed is not enough, as the same key can be unpacked
197        multiple times.
198     */
199     hashtable_t *key_set;
200
201     if(!(s->flags & JSON_UNPACK_ONLY)) {
202         key_set = hashtable_create(jsonp_hash_key, jsonp_key_equal, NULL, NULL);
203         if(!key_set) {
204             set_error(s, "Out of memory");
205             return -1;
206         }
207     }
208
209     if(!json_is_object(root)) {
210         set_error(s, "Expected object, got %s", type_name(root));
211         goto error;
212     }
213     next_token(s);
214
215     while(s->token != '}') {
216         const char *key;
217         json_t *value;
218
219         if(wildcard) {
220             set_error(s, "Expected '}' after '*', got '%c'", s->token);
221             goto error;
222         }
223
224         if(!s->token) {
225             set_error(s, "Unexpected end of format string");
226             goto error;
227         }
228
229         if(s->token == '*') {
230             wildcard = 1;
231             next_token(s);
232             continue;
233         }
234
235         if(s->token != 's') {
236             set_error(s, "Expected format 's', got '%c'\n", *s->fmt);
237             goto error;
238         }
239
240         key = va_arg(*ap, const char *);
241         if(!key) {
242             set_error(s, "NULL object key");
243             goto error;
244         }
245
246         next_token(s);
247
248         value = json_object_get(root, key);
249         if(unpack(s, value, ap))
250             goto error;
251
252         if(!(s->flags & JSON_UNPACK_ONLY))
253             hashtable_set(key_set, (void *)key, NULL);
254
255         next_token(s);
256     }
257
258     if(s->flags & JSON_UNPACK_ONLY)
259         wildcard = 1;
260
261     if(!wildcard && key_set->size != json_object_size(root)) {
262         long diff = (long)json_object_size(root) - (long)key_set->size;
263         set_error(s, "%li object items left unpacked", diff);
264         goto error;
265     }
266
267     ret = 0;
268
269 error:
270     if(!(s->flags & JSON_UNPACK_ONLY))
271         hashtable_destroy(key_set);
272
273     return ret;
274 }
275
276 static int unpack_array(scanner_t *s, json_t *root, va_list *ap)
277 {
278     size_t i = 0;
279     int wildcard = 0;
280
281     if(!json_is_array(root)) {
282         set_error(s, "Expected array, got %s", type_name(root));
283         return -1;
284     }
285     next_token(s);
286
287     while(s->token != ']') {
288         json_t *value;
289
290         if(wildcard) {
291             set_error(s, "Expected ']' after '*', got '%c'", s->token);
292             return -1;
293         }
294
295         if(!s->token) {
296             set_error(s, "Unexpected end of format string");
297             return -1;
298         }
299
300         if(s->token == '*') {
301             wildcard = 1;
302             next_token(s);
303             continue;
304         }
305
306         value = json_array_get(root, i);
307         if(!value) {
308             set_error(s, "Array index %lu out of range", (unsigned long)i);
309             return -1;
310         }
311
312         if(unpack(s, value, ap))
313             return -1;
314
315         next_token(s);
316         i++;
317     }
318
319     if(s->flags & JSON_UNPACK_ONLY)
320         wildcard = 1;
321
322     if(!wildcard && i != json_array_size(root)) {
323         long diff = (long)json_array_size(root) - (long)i;
324         set_error(s, "%li array items left upacked", diff);
325         return -1;
326     }
327
328     return 0;
329 }
330
331 static int unpack(scanner_t *s, json_t *root, va_list *ap)
332 {
333     switch(s->token)
334     {
335         case '{':
336             return unpack_object(s, root, ap);
337
338         case '[':
339             return unpack_array(s, root, ap);
340
341         case 's':
342             if(!json_is_string(root)) {
343                 set_error(s, "Expected string, got %s", type_name(root));
344                 return -1;
345             }
346
347             if(!(s->flags & JSON_VALIDATE_ONLY)) {
348                 const char **str;
349
350                 str = va_arg(*ap, const char **);
351                 if(!str) {
352                     set_error(s, "NULL string");
353                     return -1;
354                 }
355
356                 *str = json_string_value(root);
357             }
358             return 0;
359
360         case 'i':
361             if(!json_is_integer(root)) {
362                 set_error(s, "Expected integer, got %s", type_name(root));
363                 return -1;
364             }
365
366             if(!(s->flags & JSON_VALIDATE_ONLY))
367                 *va_arg(*ap, int*) = json_integer_value(root);
368
369             return 0;
370
371         case 'b':
372             if(!json_is_boolean(root)) {
373                 set_error(s, "Expected true or false, got %s", type_name(root));
374                 return -1;
375             }
376
377             if(!(s->flags & JSON_VALIDATE_ONLY))
378                 *va_arg(*ap, int*) = json_is_true(root);
379
380             return 0;
381
382         case 'f':
383             if(!json_is_real(root)) {
384                 set_error(s, "Expected real, got %s", type_name(root));
385                 return -1;
386             }
387
388             if(!(s->flags & JSON_VALIDATE_ONLY))
389                 *va_arg(*ap, double*) = json_real_value(root);
390
391             return 0;
392
393         case 'F':
394             if(!json_is_number(root)) {
395                 set_error(s, "Expected real or integer, got %s",
396                           type_name(root));
397                 return -1;
398             }
399
400             if(!(s->flags & JSON_VALIDATE_ONLY))
401                 *va_arg(*ap, double*) = json_number_value(root);
402
403             return 0;
404
405         case 'O':
406             if(!(s->flags & JSON_VALIDATE_ONLY))
407                 json_incref(root);
408             /* Fall through */
409
410         case 'o':
411             if(!(s->flags & JSON_VALIDATE_ONLY))
412                 *va_arg(*ap, json_t**) = root;
413
414             return 0;
415
416         case 'n':
417             /* Never assign, just validate */
418             if(!json_is_null(root)) {
419                 set_error(s, "Expected null, got %s", type_name(root));
420                 return -1;
421             }
422             return 0;
423
424         default:
425             set_error(s, "Unknown format character '%c'", s->token);
426             return -1;
427     }
428 }
429
430 json_t *json_vpack_ex(json_error_t *error, size_t flags,
431                       const char *fmt, va_list ap)
432 {
433     scanner_t s;
434     json_t *value;
435
436     jsonp_error_init(error, "");
437
438     if(!fmt || !*fmt) {
439         jsonp_error_set(error, 1, 1, "Null or empty format string");
440         return NULL;
441     }
442
443     s.error = error;
444     s.flags = flags;
445     s.fmt = fmt;
446     s.line = 1;
447     s.column = 0;
448
449     next_token(&s);
450     value = pack(&s, &ap);
451
452     next_token(&s);
453     if(s.token) {
454         json_decref(value);
455         set_error(&s, "Garbage after format string");
456         return NULL;
457     }
458
459     return value;
460 }
461
462 json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...)
463 {
464     json_t *value;
465     va_list ap;
466
467     va_start(ap, fmt);
468     value = json_vpack_ex(error, flags, fmt, ap);
469     va_end(ap);
470
471     return value;
472 }
473
474 json_t *json_pack(const char *fmt, ...)
475 {
476     json_t *value;
477     va_list ap;
478
479     va_start(ap, fmt);
480     value = json_vpack_ex(NULL, 0, fmt, ap);
481     va_end(ap);
482
483     return value;
484 }
485
486 int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags,
487                     const char *fmt, va_list ap)
488 {
489     scanner_t s;
490
491     jsonp_error_init(error, "");
492
493     if(!fmt || !*fmt) {
494         jsonp_error_set(error, 1, 1, "Null or empty format string");
495         return -1;
496     }
497
498     s.error = error;
499     s.flags = flags;
500     s.fmt = fmt;
501     s.line = 1;
502     s.column = 0;
503
504     next_token(&s);
505
506     if(unpack(&s, root, &ap))
507         return -1;
508
509     next_token(&s);
510     if(s.token) {
511         set_error(&s, "Garbage after format string");
512         return -1;
513     }
514
515     return 0;
516 }
517
518 int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...)
519 {
520     int ret;
521     va_list ap;
522
523     va_start(ap, fmt);
524     ret = json_vunpack_ex(root, error, flags, fmt, ap);
525     va_end(ap);
526
527     return ret;
528 }
529
530 int json_unpack(json_t *root, const char *fmt, ...)
531 {
532     int ret;
533     va_list ap;
534
535     va_start(ap, fmt);
536     ret = json_vunpack_ex(root, NULL, 0, fmt, ap);
537     va_end(ap);
538
539     return ret;
540 }