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