wrap-json: Update for y/Y
[src/app-framework-main.git] / src / wrap-json.c
1 /*
2  Copyright (C) 2016, 2017, 2018 "IoT.bzh"
3
4  author: José Bollo <jose.bollo@iot.bzh>
5
6  Licensed under the Apache License, Version 2.0 (the "License");
7  you may not use this file except in compliance with the License.
8  You may obtain a copy of the License at
9
10      http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  See the License for the specific language governing permissions and
16  limitations under the License.
17 */
18
19 #include <string.h>
20
21 #include "wrap-json.h"
22
23 #define STACKCOUNT  32
24 #define STRCOUNT    8
25
26 enum {
27         wrap_json_error_none,
28         wrap_json_error_null_object,
29         wrap_json_error_truncated,
30         wrap_json_error_internal_error,
31         wrap_json_error_out_of_memory,
32         wrap_json_error_invalid_character,
33         wrap_json_error_too_long,
34         wrap_json_error_too_deep,
35         wrap_json_error_null_spec,
36         wrap_json_error_null_key,
37         wrap_json_error_null_string,
38         wrap_json_error_out_of_range,
39         wrap_json_error_incomplete,
40         wrap_json_error_missfit_type,
41         wrap_json_error_key_not_found,
42         wrap_json_error_bad_base64,
43         _wrap_json_error_count_
44 };
45
46 static const char ignore_all[] = " \t\n\r,:";
47 static const char pack_accept_arr[] = "][{snbiIfoOyY";
48 static const char pack_accept_key[] = "s}";
49 #define pack_accept_any (&pack_accept_arr[1])
50
51 static const char unpack_accept_arr[] = "*!][{snbiIfFoOyY";
52 static const char unpack_accept_key[] = "*!s}";
53 #define unpack_accept_any (&unpack_accept_arr[3])
54
55 static const char *pack_errors[_wrap_json_error_count_] =
56 {
57         [wrap_json_error_none] = "unknown error",
58         [wrap_json_error_null_object] = "null object",
59         [wrap_json_error_truncated] = "truncated",
60         [wrap_json_error_internal_error] = "internal error",
61         [wrap_json_error_out_of_memory] = "out of memory",
62         [wrap_json_error_invalid_character] = "invalid character",
63         [wrap_json_error_too_long] = "too long",
64         [wrap_json_error_too_deep] = "too deep",
65         [wrap_json_error_null_spec] = "spec is NULL",
66         [wrap_json_error_null_key] = "key is NULL",
67         [wrap_json_error_null_string] = "string is NULL",
68         [wrap_json_error_out_of_range] = "array too small",
69         [wrap_json_error_incomplete] = "incomplete container",
70         [wrap_json_error_missfit_type] = "missfit of type",
71         [wrap_json_error_key_not_found] = "key not found",
72         [wrap_json_error_bad_base64] = "bad base64 encoding"
73 };
74
75 int wrap_json_get_error_position(int rc)
76 {
77         if (rc < 0)
78                 rc = -rc;
79         return (rc >> 4) + 1;
80 }
81
82 int wrap_json_get_error_code(int rc)
83 {
84         if (rc < 0)
85                 rc = -rc;
86         return rc & 15;
87 }
88
89 const char *wrap_json_get_error_string(int rc)
90 {
91         rc = wrap_json_get_error_code(rc);
92         if (rc >= (int)(sizeof pack_errors / sizeof *pack_errors))
93                 rc = 0;
94         return pack_errors[rc];
95 }
96
97 static int encode_base64(
98                 const uint8_t *data,
99                 size_t datalen,
100                 char **encoded,
101                 size_t *encodedlen,
102                 int width,
103                 int pad,
104                 int url)
105 {
106         uint16_t u16 = 0;
107         uint8_t u8 = 0;
108         size_t in, out, rlen, n3, r3, iout, nout;
109         int iw;
110         char *result, c;
111
112         /* compute unformatted output length */
113         n3 = datalen / 3;
114         r3 = datalen % 3;
115         nout = 4 * n3 + r3 + !!r3;
116
117         /* deduce formatted output length */
118         rlen = nout;
119         if (pad)
120                 rlen += ((~rlen) + 1) & 3;
121         if (width)
122                 rlen += rlen / width;
123
124         /* allocate the output */
125         result = malloc(rlen + 1);
126         if (result == NULL)
127                 return wrap_json_error_out_of_memory;
128
129         /* compute the formatted output */
130         iw = width;
131         for (in = out = iout = 0 ; iout < nout ; iout++) {
132                 /* get in 'u8' the 6 bits value to add */
133                 switch (iout & 3) {
134                 case 0:
135                         u16 = (uint16_t)data[in++];
136                         u8 = (uint8_t)(u16 >> 2);
137                         break;
138                 case 1:
139                         u16 = (uint16_t)(u16 << 8);
140                         if (in < datalen)
141                                 u16 = (uint16_t)(u16 | data[in++]);
142                         u8 = (uint8_t)(u16 >> 4);
143                         break;
144                 case 2:
145                         u16 = (uint16_t)(u16 << 8);
146                         if (in < datalen)
147                                 u16 = (uint16_t)(u16 | data[in++]);
148                         u8 = (uint8_t)(u16 >> 6);
149                         break;
150                 case 3:
151                         u8 = (uint8_t)u16;
152                         break;
153                 }
154                 u8 &= 63;
155
156                 /* encode 'u8' to the char 'c' */
157                 if (u8 < 52) {
158                         if (u8 < 26)
159                                 c = (char)('A' + u8);
160                         else
161                                 c = (char)('a' + u8 - 26);
162                 } else {
163                         if (u8 < 62)
164                                 c = (char)('0' + u8 - 52);
165                         else if (u8 == 62)
166                                 c = url ? '-' : '+';
167                         else
168                                 c = url ? '_' : '/';
169                 }
170
171                 /* put to output with format */
172                 result[out++] = c;
173                 if (iw && !--iw) {
174                         result[out++] = '\n';
175                         iw = width;
176                 }
177         }
178
179         /* pad the output */
180         while (out < rlen) {
181                 result[out++] = '=';
182                 if (iw && !--iw) {
183                         result[out++] = '\n';
184                         iw = width;
185                 }
186         }
187
188         /* terminate */
189         result[out] = 0;
190         *encoded = result;
191         *encodedlen = rlen;
192         return 0;
193 }
194
195 static int decode_base64(
196                 const char *data,
197                 size_t datalen,
198                 uint8_t **decoded,
199                 size_t *decodedlen,
200                 int url)
201 {
202         uint16_t u16;
203         uint8_t u8, *result;
204         size_t in, out, iin;
205         char c;
206
207         /* allocate enougth output */
208         result = malloc(datalen);
209         if (result == NULL)
210                 return wrap_json_error_out_of_memory;
211
212         /* decode the input */
213         for (iin = in = out = 0 ; in < datalen ; in++) {
214                 c = data[in];
215                 if (c != '\n' && c != '\r' && c != '=') {
216                         if ('A' <= c && c <= 'Z')
217                                 u8 = (uint8_t)(c - 'A');
218                         else if ('a' <= c && c <= 'z')
219                                 u8 = (uint8_t)(c - 'a' + 26);
220                         else if ('0' <= c && c <= '9')
221                                 u8 = (uint8_t)(c - '0' + 52);
222                         else if (c == '+' || c == '-')
223                                 u8 = (uint8_t)62;
224                         else if (c == '/' || c == '_')
225                                 u8 = (uint8_t)63;
226                         else {
227                                 free(result);
228                                 return wrap_json_error_bad_base64;
229                         }
230                         if (!iin) {
231                                 u16 = (uint16_t)u8;
232                                 iin = 6;
233                         } else {
234                                 u16 = (uint16_t)((u16 << 6) | u8);
235                                 iin -= 2;
236                                 u8 = (uint8_t)(u16 >> iin);
237                                 result[out++] = u8;
238                         }
239                 }
240         }
241
242         /* terminate */
243         *decoded = realloc(result, out);
244         if (out && *decoded == NULL) {
245                 free(result);
246                 return wrap_json_error_out_of_memory;
247         }
248         *decodedlen = out;
249         return 0;
250 }
251
252 static inline const char *skip(const char *d)
253 {
254         while (*d && strchr(ignore_all, *d))
255                 d++;
256         return d;
257 }
258
259 int wrap_json_vpack(struct json_object **result, const char *desc, va_list args)
260 {
261         /* TODO: the case of structs with key being single char should be optimized */
262         int nstr, notnull, nullable, rc;
263         size_t sz, dsz, ssz;
264         char *s;
265         char c;
266         const char *d;
267         char buffer[256];
268         struct { const uint8_t *in; size_t insz; char *out; size_t outsz; } bytes;
269         struct { const char *str; size_t sz; } strs[STRCOUNT];
270         struct { struct json_object *cont, *key; const char *acc; char type; } stack[STACKCOUNT], *top;
271         struct json_object *obj;
272
273         ssz = sizeof buffer;
274         s = buffer;
275         top = stack;
276         top->key = NULL;
277         top->cont = NULL;
278         top->acc = pack_accept_any;
279         top->type = 0;
280         d = desc;
281         if (!d)
282                 goto null_spec;
283         d = skip(d);
284         for(;;) {
285                 c = *d;
286                 if (!c)
287                         goto truncated;
288                 if (!strchr(top->acc, c))
289                         goto invalid_character;
290                 d = skip(++d);
291                 switch(c) {
292                 case 's':
293                         nullable = 0;
294                         notnull = 0;
295                         nstr = 0;
296                         sz = 0;
297                         for (;;) {
298                                 strs[nstr].str = va_arg(args, const char*);
299                                 if (strs[nstr].str)
300                                         notnull = 1;
301                                 if (*d == '?') {
302                                         d = skip(++d);
303                                         nullable = 1;
304                                 }
305                                 switch(*d) {
306                                 case '%': strs[nstr].sz = va_arg(args, size_t); d = skip(++d); break;
307                                 case '#': strs[nstr].sz = (size_t)va_arg(args, int); d = skip(++d); break;
308                                 default: strs[nstr].sz = strs[nstr].str ? strlen(strs[nstr].str) : 0; break;
309                                 }
310                                 sz += strs[nstr++].sz;
311                                 if (*d == '?') {
312                                         d = skip(++d);
313                                         nullable = 1;
314                                 }
315                                 if (*d != '+')
316                                         break;
317                                 if (nstr >= STRCOUNT)
318                                         goto too_long;
319                                 d = skip(++d);
320                         }
321                         if (*d == '*')
322                                 nullable = 1;
323                         if (notnull) {
324                                 if (sz > ssz) {
325                                         ssz += ssz;
326                                         if (ssz < sz)
327                                                 ssz = sz;
328                                         s = alloca(sz);
329                                 }
330                                 dsz = sz;
331                                 while (nstr) {
332                                         nstr--;
333                                         dsz -= strs[nstr].sz;
334                                         memcpy(&s[dsz], strs[nstr].str, strs[nstr].sz);
335                                 }
336                                 obj = json_object_new_string_len(s, (int)sz);
337                                 if (!obj)
338                                         goto out_of_memory;
339                         } else if (nullable)
340                                 obj = NULL;
341                         else
342                                 goto null_string;
343                         break;
344                 case 'n':
345                         obj = NULL;
346                         break;
347                 case 'b':
348                         obj = json_object_new_boolean(va_arg(args, int));
349                         if (!obj)
350                                 goto out_of_memory;
351                         break;
352                 case 'i':
353                         obj = json_object_new_int(va_arg(args, int));
354                         if (!obj)
355                                 goto out_of_memory;
356                         break;
357                 case 'I':
358                         obj = json_object_new_int64(va_arg(args, int64_t));
359                         if (!obj)
360                                 goto out_of_memory;
361                         break;
362                 case 'f':
363                         obj = json_object_new_double(va_arg(args, double));
364                         if (!obj)
365                                 goto out_of_memory;
366                         break;
367                 case 'o':
368                 case 'O':
369                         obj = va_arg(args, struct json_object*);
370                         if (*d == '?')
371                                 d = skip(++d);
372                         else if (*d != '*' && !obj)
373                                 goto null_object;
374                         if (c == 'O')
375                                 json_object_get(obj);
376                         break;
377                 case 'y':
378                 case 'Y':
379                         bytes.in = va_arg(args, const uint8_t*);
380                         bytes.insz = va_arg(args, size_t);
381                         if (bytes.in == NULL || bytes.insz == 0)
382                                 obj = NULL;
383                         else {
384                                 rc = encode_base64(bytes.in, bytes.insz,
385                                         &bytes.out, &bytes.outsz, 0, 0, c == 'y');
386                                 if (rc)
387                                         goto error;
388                                 obj = json_object_new_string_len(bytes.out, (int)bytes.outsz);
389                                 free(bytes.out);
390                                 if (!obj)
391                                         goto out_of_memory;
392                         }
393                         if (*d == '?')
394                                 d = skip(++d);
395                         else if (*d != '*' && !obj) {
396                                 obj = json_object_new_string_len(d, 0);
397                                 if (!obj)
398                                         goto out_of_memory;
399                         }
400                         break;
401                 case '[':
402                 case '{':
403                         if (++top >= &stack[STACKCOUNT])
404                                 goto too_deep;
405                         top->key = NULL;
406                         if (c == '[') {
407                                 top->type = ']';
408                                 top->acc = pack_accept_arr;
409                                 top->cont = json_object_new_array();
410                         } else {
411                                 top->type = '}';
412                                 top->acc = pack_accept_key;
413                                 top->cont = json_object_new_object();
414                         }
415                         if (!top->cont)
416                                 goto out_of_memory;
417                         continue;
418                 case '}':
419                 case ']':
420                         if (c != top->type || top <= stack)
421                                 goto internal_error;
422                         obj = (top--)->cont;
423                         if (*d == '*' && !(c == '}' ? json_object_object_length(obj) : json_object_array_length(obj))) {
424                                 json_object_put(obj);
425                                 obj = NULL;
426                         }
427                         break;
428                 default:
429                         goto internal_error;
430                 }
431                 switch (top->type) {
432                 case 0:
433                         if (top != stack)
434                                 goto internal_error;
435                         if (*d)
436                                 goto invalid_character;
437                         *result = obj;
438                         return 0;
439                 case ']':
440                         if (obj || *d != '*')
441                                 json_object_array_add(top->cont, obj);
442                         if (*d == '*')
443                                 d = skip(++d);
444                         break;
445                 case '}':
446                         if (!obj)
447                                 goto null_key;
448                         top->key = obj;
449                         top->acc = pack_accept_any;
450                         top->type = ':';
451                         break;
452                 case ':':
453                         if (obj || *d != '*')
454                                 json_object_object_add(top->cont, json_object_get_string(top->key), obj);
455                         if (*d == '*')
456                                 d = skip(++d);
457                         json_object_put(top->key);
458                         top->key = NULL;
459                         top->acc = pack_accept_key;
460                         top->type = '}';
461                         break;
462                 default:
463                         goto internal_error;
464                 }
465         }
466
467 null_object:
468         rc = wrap_json_error_null_object;
469         goto error;
470 truncated:
471         rc = wrap_json_error_truncated;
472         goto error;
473 internal_error:
474         rc = wrap_json_error_internal_error;
475         goto error;
476 out_of_memory:
477         rc = wrap_json_error_out_of_memory;
478         goto error;
479 invalid_character:
480         rc = wrap_json_error_invalid_character;
481         goto error;
482 too_long:
483         rc = wrap_json_error_too_long;
484         goto error;
485 too_deep:
486         rc = wrap_json_error_too_deep;
487         goto error;
488 null_spec:
489         rc = wrap_json_error_null_spec;
490         goto error;
491 null_key:
492         rc = wrap_json_error_null_key;
493         goto error;
494 null_string:
495         rc = wrap_json_error_null_string;
496         goto error;
497 error:
498         do {
499                 json_object_put(top->key);
500                 json_object_put(top->cont);
501         } while (--top >= stack);
502         *result = NULL;
503         rc = rc | (int)((d - desc) << 4);
504         return -rc;
505 }
506
507 int wrap_json_pack(struct json_object **result, const char *desc, ...)
508 {
509         int rc;
510         va_list args;
511
512         va_start(args, desc);
513         rc = wrap_json_vpack(result, desc, args);
514         va_end(args);
515         return rc;
516 }
517
518 static int vunpack(struct json_object *object, const char *desc, va_list args, int store)
519 {
520         int rc = 0, optionnal, ignore;
521         char c, xacc[2] = { 0, 0 };
522         const char *acc;
523         const char *d, *fit = NULL;
524         const char *key = NULL;
525         const char **ps = NULL;
526         double *pf = NULL;
527         int *pi = NULL;
528         int64_t *pI = NULL;
529         size_t *pz = NULL;
530         uint8_t **py = NULL;
531         struct { struct json_object *parent; const char *acc; size_t index; size_t count; char type; } stack[STACKCOUNT], *top;
532         struct json_object *obj;
533         struct json_object **po;
534
535         xacc[0] = 0;
536         ignore = 0;
537         top = NULL;
538         acc = unpack_accept_any;
539         d = desc;
540         if (!d)
541                 goto null_spec;
542         d = skip(d);
543         obj = object;
544         for(;;) {
545                 fit = d;
546                 c = *d;
547                 if (!c)
548                         goto truncated;
549                 if (!strchr(acc, c))
550                         goto invalid_character;
551                 d = skip(++d);
552                 switch(c) {
553                 case 's':
554                         if (xacc[0] == '}') {
555                                 /* expects a key */
556                                 key = va_arg(args, const char *);
557                                 if (!key)
558                                         goto null_key;
559                                 if (*d != '?')
560                                         optionnal = 0;
561                                 else {
562                                         optionnal = 1;
563                                         d = skip(++d);
564                                 }
565                                 if (ignore)
566                                         ignore++;
567                                 else {
568                                         if (json_object_object_get_ex(top->parent, key, &obj)) {
569                                                 /* found */
570                                                 top->index++;
571                                         } else {
572                                                 /* not found */
573                                                 if (!optionnal)
574                                                         goto key_not_found;
575                                                 ignore = 1;
576                                                 obj = NULL;
577                                         }
578                                 }
579                                 xacc[0] = ':';
580                                 acc = unpack_accept_any;
581                                 continue;
582                         }
583                         /* get a string */
584                         if (store)
585                                 ps = va_arg(args, const char **);
586                         if (!ignore) {
587                                 if (!json_object_is_type(obj, json_type_string))
588                                         goto missfit;
589                                 if (store && ps)
590                                         *ps = json_object_get_string(obj);
591                         }
592                         if (*d == '%') {
593                                 d = skip(++d);
594                                 if (store) {
595                                         pz = va_arg(args, size_t *);
596                                         if (!ignore && pz)
597                                                 *pz = (size_t)json_object_get_string_len(obj);
598                                 }
599                         }
600                         break;
601                 case 'n':
602                         if (!ignore && !json_object_is_type(obj, json_type_null))
603                                 goto missfit;
604                         break;
605                 case 'b':
606                         if (store)
607                                 pi = va_arg(args, int *);
608
609                         if (!ignore) {
610                                 if (!json_object_is_type(obj, json_type_boolean))
611                                         goto missfit;
612                                 if (store && pi)
613                                         *pi = json_object_get_boolean(obj);
614                         }
615                         break;
616                 case 'i':
617                         if (store)
618                                 pi = va_arg(args, int *);
619
620                         if (!ignore) {
621                                 if (!json_object_is_type(obj, json_type_int))
622                                         goto missfit;
623                                 if (store && pi)
624                                         *pi = json_object_get_int(obj);
625                         }
626                         break;
627                 case 'I':
628                         if (store)
629                                 pI = va_arg(args, int64_t *);
630
631                         if (!ignore) {
632                                 if (!json_object_is_type(obj, json_type_int))
633                                         goto missfit;
634                                 if (store && pI)
635                                         *pI = json_object_get_int64(obj);
636                         }
637                         break;
638                 case 'f':
639                 case 'F':
640                         if (store)
641                                 pf = va_arg(args, double *);
642
643                         if (!ignore) {
644                                 if (!(json_object_is_type(obj, json_type_double) || (c == 'F' && json_object_is_type(obj, json_type_int))))
645                                         goto missfit;
646                                 if (store && pf)
647                                         *pf = json_object_get_double(obj);
648                         }
649                         break;
650                 case 'o':
651                 case 'O':
652                         if (store) {
653                                 po = va_arg(args, struct json_object **);
654                                 if (!ignore && po) {
655                                         if (c == 'O')
656                                                 obj = json_object_get(obj);
657                                         *po = obj;
658                                 }
659                         }
660                         break;
661                 case 'y':
662                 case 'Y':
663                         if (store) {
664                                 py = va_arg(args, uint8_t **);
665                                 pz = va_arg(args, size_t *);
666                         }
667                         if (!ignore) {
668                                 if (obj == NULL) {
669                                         if (store && py && pz) {
670                                                 *py = NULL;
671                                                 *pz = 0;
672                                         }
673                                 } else {
674                                         if (!json_object_is_type(obj, json_type_string))
675                                                 goto missfit;
676                                         if (store && py && pz) {
677                                                 rc = decode_base64(
678                                                         json_object_get_string(obj),
679                                                         (size_t)json_object_get_string_len(obj),
680                                                         py, pz, c == 'y');
681                                                 if (rc)
682                                                         goto error;
683                                         }
684                                 }
685                         }
686                         break;
687
688                 case '[':
689                 case '{':
690                         if (!top)
691                                 top = stack;
692                         else if (++top  >= &stack[STACKCOUNT])
693                                 goto too_deep;
694
695                         top->acc = acc;
696                         top->type = xacc[0];
697                         top->index = 0;
698                         top->parent = obj;
699                         if (ignore)
700                                 ignore++;
701                         if (c == '[') {
702                                 if (!ignore) {
703                                         if (!json_object_is_type(obj, json_type_array))
704                                                 goto missfit;
705                                         top->count = json_object_array_length(obj);
706                                 }
707                                 xacc[0] = ']';
708                                 acc = unpack_accept_arr;
709                         } else {
710                                 if (!ignore) {
711                                         if (!json_object_is_type(obj, json_type_object))
712                                                 goto missfit;
713                                         top->count = json_object_object_length(obj);
714                                 }
715                                 xacc[0] = '}';
716                                 acc = unpack_accept_key;
717                                 continue;
718                         }
719                         break;
720                 case '}':
721                 case ']':
722                         if (!top || c != xacc[0])
723                                 goto internal_error;
724                         acc = top->acc;
725                         xacc[0] = top->type;
726                         top = top == stack ? NULL : top - 1;
727                         if (ignore)
728                                 ignore--;
729                         break;
730                 case '!':
731                         if (*d != xacc[0])
732                                 goto invalid_character;
733                         if (!ignore && top->index != top->count)
734                                 goto incomplete;
735                         /*@fallthrough@*/
736                 case '*':
737                         acc = xacc;
738                         continue;
739                 default:
740                         goto internal_error;
741                 }
742                 switch (xacc[0]) {
743                 case 0:
744                         if (top)
745                                 goto internal_error;
746                         if (*d)
747                                 goto invalid_character;
748                         return 0;
749                 case ']':
750                         if (!ignore) {
751                                 key = strchr(unpack_accept_arr, *d);
752                                 if (key && key >= unpack_accept_any) {
753                                         if (top->index >= top->count)
754                                                 goto out_of_range;
755                                         obj = json_object_array_get_idx(top->parent, top->index++);
756                                 }
757                         }
758                         break;
759                 case ':':
760                         acc = unpack_accept_key;
761                         xacc[0] = '}';
762                         if (ignore)
763                                 ignore--;
764                         break;
765                 default:
766                         goto internal_error;
767                 }
768         }
769 truncated:
770         rc = wrap_json_error_truncated;
771         goto error;
772 internal_error:
773         rc = wrap_json_error_internal_error;
774         goto error;
775 invalid_character:
776         rc = wrap_json_error_invalid_character;
777         goto error;
778 too_deep:
779         rc = wrap_json_error_too_deep;
780         goto error;
781 null_spec:
782         rc = wrap_json_error_null_spec;
783         goto error;
784 null_key:
785         rc = wrap_json_error_null_key;
786         goto error;
787 out_of_range:
788         rc = wrap_json_error_out_of_range;
789         goto error;
790 incomplete:
791         rc = wrap_json_error_incomplete;
792         goto error;
793 missfit:
794         rc = wrap_json_error_missfit_type;
795         goto errorfit;
796 key_not_found:
797         rc = wrap_json_error_key_not_found;
798         goto error;
799 errorfit:
800         d = fit;
801 error:
802         rc = rc | (int)((d - desc) << 4);
803         return -rc;
804 }
805
806 int wrap_json_vcheck(struct json_object *object, const char *desc, va_list args)
807 {
808         return vunpack(object, desc, args, 0);
809 }
810
811 int wrap_json_check(struct json_object *object, const char *desc, ...)
812 {
813         int rc;
814         va_list args;
815
816         va_start(args, desc);
817         rc = vunpack(object, desc, args, 0);
818         va_end(args);
819         return rc;
820 }
821
822 int wrap_json_vmatch(struct json_object *object, const char *desc, va_list args)
823 {
824         return !vunpack(object, desc, args, 0);
825 }
826
827 int wrap_json_match(struct json_object *object, const char *desc, ...)
828 {
829         int rc;
830         va_list args;
831
832         va_start(args, desc);
833         rc = vunpack(object, desc, args, 0);
834         va_end(args);
835         return !rc;
836 }
837
838 int wrap_json_vunpack(struct json_object *object, const char *desc, va_list args)
839 {
840         return vunpack(object, desc, args, 1);
841 }
842
843 int wrap_json_unpack(struct json_object *object, const char *desc, ...)
844 {
845         int rc;
846         va_list args;
847
848         va_start(args, desc);
849         rc = vunpack(object, desc, args, 1);
850         va_end(args);
851         return rc;
852 }
853
854 static void object_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
855 {
856         struct json_object_iterator it = json_object_iter_begin(object);
857         struct json_object_iterator end = json_object_iter_end(object);
858         while (!json_object_iter_equal(&it, &end)) {
859                 callback(closure, json_object_iter_peek_value(&it), json_object_iter_peek_name(&it));
860                 json_object_iter_next(&it);
861         }
862 }
863
864 static void array_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
865 {
866         size_t n = json_object_array_length(object);
867         size_t i = 0;
868         while(i < n)
869                 callback(closure, json_object_array_get_idx(object, i++));
870 }
871
872 void wrap_json_optarray_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
873 {
874         if (json_object_is_type(object, json_type_array))
875                 array_for_all(object, callback, closure);
876         else
877                 callback(closure, object);
878 }
879
880 void wrap_json_array_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
881 {
882         if (json_object_is_type(object, json_type_array))
883                 array_for_all(object, callback, closure);
884 }
885
886 void wrap_json_object_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
887 {
888         if (json_object_is_type(object, json_type_object))
889                 object_for_all(object, callback, closure);
890 }
891
892 void wrap_json_optobject_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
893 {
894         if (json_object_is_type(object, json_type_object))
895                 object_for_all(object, callback, closure);
896         else
897                 callback(closure, object, NULL);
898 }
899
900 void wrap_json_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
901 {
902         if (!object)
903                 /* do nothing */;
904         else if (json_object_is_type(object, json_type_object))
905                 object_for_all(object, callback, closure);
906         else if (!json_object_is_type(object, json_type_array))
907                 callback(closure, object, NULL);
908         else {
909                 size_t n = json_object_array_length(object);
910                 size_t i = 0;
911                 while(i < n)
912                         callback(closure, json_object_array_get_idx(object, i++), NULL);
913         }
914 }
915
916 #if defined(WRAP_JSON_TEST)
917 #include <stdio.h>
918
919 void p(const char *desc, ...)
920 {
921         int rc;
922         va_list args;
923         struct json_object *result;
924
925         va_start(args, desc);
926         rc = wrap_json_vpack(&result, desc, args);
927         va_end(args);
928         if (!rc)
929                 printf("  SUCCESS %s\n\n", json_object_to_json_string(result));
930         else
931                 printf("  ERROR[char %d err %d] %s\n\n", wrap_json_get_error_position(rc), wrap_json_get_error_code(rc), wrap_json_get_error_string(rc));
932         json_object_put(result);
933 }
934
935 const char *xs[10];
936 int *xi[10];
937 int64_t *xI[10];
938 double *xf[10];
939 struct json_object *xo[10];
940 size_t xz[10];
941 uint8_t *xy[10];
942
943 void u(const char *value, const char *desc, ...)
944 {
945         unsigned m, k;
946         int rc;
947         va_list args;
948         struct json_object *obj, *o;
949
950         memset(xs, 0, sizeof xs);
951         memset(xi, 0, sizeof xi);
952         memset(xI, 0, sizeof xI);
953         memset(xf, 0, sizeof xf);
954         memset(xo, 0, sizeof xo);
955         memset(xy, 0, sizeof xy);
956         memset(xz, 0, sizeof xz);
957         obj = json_tokener_parse(value);
958         va_start(args, desc);
959         rc = wrap_json_vunpack(obj, desc, args);
960         va_end(args);
961         if (rc)
962                 printf("  ERROR[char %d err %d] %s\n\n", wrap_json_get_error_position(rc), wrap_json_get_error_code(rc), wrap_json_get_error_string(rc));
963         else {
964                 value = NULL;
965                 printf("  SUCCESS");
966                 va_start(args, desc);
967                 k = m = 0;
968                 while(*desc) {
969                         switch(*desc) {
970                         case '{': m = (m << 1) | 1; k = 1; break;
971                         case '}': m = m >> 1; k = m&1; break;
972                         case '[': m = m << 1; k = 0; break;
973                         case ']': m = m >> 1; k = m&1; break;
974                         case 's': printf(" s:%s", k ? va_arg(args, const char*) : *(va_arg(args, const char**)?:&value)); k ^= m&1; break;
975                         case '%': printf(" %%:%zu", *va_arg(args, size_t*)); k = m&1; break;
976                         case 'n': printf(" n"); k = m&1; break;
977                         case 'b': printf(" b:%d", *va_arg(args, int*)); k = m&1; break;
978                         case 'i': printf(" i:%d", *va_arg(args, int*)); k = m&1; break;
979                         case 'I': printf(" I:%lld", *va_arg(args, int64_t*)); k = m&1; break;
980                         case 'f': printf(" f:%f", *va_arg(args, double*)); k = m&1; break;
981                         case 'F': printf(" F:%f", *va_arg(args, double*)); k = m&1; break;
982                         case 'o': printf(" o:%s", json_object_to_json_string(*va_arg(args, struct json_object**))); k = m&1; break;
983                         case 'O': o = *va_arg(args, struct json_object**); printf(" O:%s", json_object_to_json_string(o)); json_object_put(o); k = m&1; break;
984                         case 'y':
985                         case 'Y': {
986                                 uint8_t *p = *va_arg(args, uint8_t**);
987                                 size_t s = *va_arg(args, size_t*);
988                                 printf(" y/%d:%.*s", (int)s, (int)s, (char*)p);
989                                 k ^= m&1;
990                                 break;
991                                 }
992                         default: break;
993                         }
994                         desc++;
995                 }
996                 va_end(args);
997                 printf("\n\n");
998         }
999         json_object_put(obj);
1000 }
1001
1002 #define P(...) do{ printf("pack(%s)\n",#__VA_ARGS__); p(__VA_ARGS__); } while(0)
1003 #define U(...) do{ printf("unpack(%s)\n",#__VA_ARGS__); u(__VA_ARGS__); } while(0)
1004
1005 int main()
1006 {
1007         char buffer[4] = {'t', 'e', 's', 't'};
1008
1009         P("n");
1010         P("b", 1);
1011         P("b", 0);
1012         P("i", 1);
1013         P("I", (uint64_t)0x123456789abcdef);
1014         P("f", 3.14);
1015         P("s", "test");
1016         P("s?", "test");
1017         P("s?", NULL);
1018         P("s#", "test asdf", 4);
1019         P("s%", "test asdf", (size_t)4);
1020         P("s#", buffer, 4);
1021         P("s%", buffer, (size_t)4);
1022         P("s++", "te", "st", "ing");
1023         P("s#+#+", "test", 1, "test", 2, "test");
1024         P("s%+%+", "test", (size_t)1, "test", (size_t)2, "test");
1025         P("{}", 1.0);
1026         P("[]", 1.0);
1027         P("o", json_object_new_int(1));
1028         P("o?", json_object_new_int(1));
1029         P("o?", NULL);
1030         P("O", json_object_new_int(1));
1031         P("O?", json_object_new_int(1));
1032         P("O?", NULL);
1033         P("{s:[]}", "foo");
1034         P("{s+#+: []}", "foo", "barbar", 3, "baz");
1035         P("{s:s,s:o,s:O}", "a", NULL, "b", NULL, "c", NULL);
1036         P("{s:**}", "a", NULL);
1037         P("{s:s*,s:o*,s:O*}", "a", NULL, "b", NULL, "c", NULL);
1038         P("[i,i,i]", 0, 1, 2);
1039         P("[s,o,O]", NULL, NULL, NULL);
1040         P("[**]", NULL);
1041         P("[s*,o*,O*]", NULL, NULL, NULL);
1042         P(" s ", "test");
1043         P("[ ]");
1044         P("[ i , i,  i ] ", 1, 2, 3);
1045         P("{\n\n1");
1046         P("[}");
1047         P("{]");
1048         P("[");
1049         P("{");
1050         P("[i]a", 42);
1051         P("ia", 42);
1052         P("s", NULL);
1053         P("+", NULL);
1054         P(NULL);
1055         P("{s:i}", NULL, 1);
1056         P("{ {}: s }", "foo");
1057         P("{ s: {},  s:[ii{} }", "foo", "bar", 12, 13);
1058         P("[[[[[   [[[[[  [[[[ }]]]] ]]]] ]]]]]");
1059         P("y", "???????hello>>>>>>>", (size_t)19);
1060         P("Y", "???????hello>>>>>>>", (size_t)19);
1061         P("{sy?}", "foo", "hi", (size_t)2);
1062         P("{sy?}", "foo", NULL, 0);
1063         P("{sy*}", "foo", "hi", (size_t)2);
1064         P("{sy*}", "foo", NULL, 0);
1065
1066         U("true", "b", &xi[0]);
1067         U("false", "b", &xi[0]);
1068         U("null", "n");
1069         U("42", "i", &xi[0]);
1070         U("123456789", "I", &xI[0]);
1071         U("3.14", "f", &xf[0]);
1072         U("12345", "F", &xf[0]);
1073         U("3.14", "F", &xf[0]);
1074         U("\"foo\"", "s", &xs[0]);
1075         U("\"foo\"", "s%", &xs[0], &xz[0]);
1076         U("{}", "{}");
1077         U("[]", "[]");
1078         U("{}", "o", &xo[0]);
1079         U("{}", "O", &xo[0]);
1080         U("{\"foo\":42}", "{si}", "foo", &xi[0]);
1081         U("[1,2,3]", "[i,i,i]", &xi[0], &xi[1], &xi[2]);
1082         U("{\"a\":1,\"b\":2,\"c\":3}", "{s:i, s:i, s:i}", "a", &xi[0], "b", &xi[1], "c", &xi[2]);
1083         U("42", "z");
1084         U("null", "[i]");
1085         U("[]", "[}");
1086         U("{}", "{]");
1087         U("[]", "[");
1088         U("{}", "{");
1089         U("[42]", "[i]a", &xi[0]);
1090         U("42", "ia", &xi[0]);
1091         U("[]", NULL);
1092         U("\"foo\"", "s", NULL);
1093         U("42", "s", NULL);
1094         U("42", "n");
1095         U("42", "b", NULL);
1096         U("42", "f", NULL);
1097         U("42", "[i]", NULL);
1098         U("42", "{si}", "foo", NULL);
1099         U("\"foo\"", "n");
1100         U("\"foo\"", "b", NULL);
1101         U("\"foo\"", "i", NULL);
1102         U("\"foo\"", "I", NULL);
1103         U("\"foo\"", "f", NULL);
1104         U("\"foo\"", "F", NULL);
1105         U("true", "s", NULL);
1106         U("true", "n");
1107         U("true", "i", NULL);
1108         U("true", "I", NULL);
1109         U("true", "f", NULL);
1110         U("true", "F", NULL);
1111         U("[42]", "[ii]", &xi[0], &xi[1]);
1112         U("{\"foo\":42}", "{si}", NULL, &xi[0]);
1113         U("{\"foo\":42}", "{si}", "baz", &xi[0]);
1114         U("[1,2,3]", "[iii!]", &xi[0], &xi[1], &xi[2]);
1115         U("[1,2,3]", "[ii!]", &xi[0], &xi[1]);
1116         U("[1,2,3]", "[ii]", &xi[0], &xi[1]);
1117         U("[1,2,3]", "[ii*]", &xi[0], &xi[1]);
1118         U("{\"foo\":42,\"baz\":45}", "{sisi}", "baz", &xi[0], "foo", &xi[1]);
1119         U("{\"foo\":42,\"baz\":45}", "{sisi*}", "baz", &xi[0], "foo", &xi[1]);
1120         U("{\"foo\":42,\"baz\":45}", "{sisi!}", "baz", &xi[0], "foo", &xi[1]);
1121         U("{\"foo\":42,\"baz\":45}", "{si}", "baz", &xi[0], "foo", &xi[1]);
1122         U("{\"foo\":42,\"baz\":45}", "{si*}", "baz", &xi[0], "foo", &xi[1]);
1123         U("{\"foo\":42,\"baz\":45}", "{si!}", "baz", &xi[0], "foo", &xi[1]);
1124         U("[1,{\"foo\":2,\"bar\":null},[3,4]]", "[i{sisn}[ii]]", &xi[0], "foo", &xi[1], "bar", &xi[2], &xi[3]);
1125         U("[1,2,3]", "[ii!i]", &xi[0], &xi[1], &xi[2]);
1126         U("[1,2,3]", "[ii*i]", &xi[0], &xi[1], &xi[2]);
1127         U("{\"foo\":1,\"bar\":2}", "{si!si}", "foo", &xi[1], "bar", &xi[2]);
1128         U("{\"foo\":1,\"bar\":2}", "{si*si}", "foo", &xi[1], "bar", &xi[2]);
1129         U("{\"foo\":{\"baz\":null,\"bar\":null}}", "{s{sn!}}", "foo", "bar");
1130         U("[[1,2,3]]", "[[ii!]]", &xi[0], &xi[1]);
1131         U("{}", "{s?i}", "foo", &xi[0]);
1132         U("{\"foo\":1}", "{s?i}", "foo", &xi[0]);
1133         U("{}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
1134         U("{\"foo\":[1,2]}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
1135         U("{\"bar\":{\"baz\":{\"quux\":15}}}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
1136         U("{\"foo\":{\"bar\":4}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
1137         U("{\"foo\":{}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
1138         U("{}", "{s?{s?i}}", "foo", "bar", &xi[0]);
1139         U("{\"foo\":42,\"baz\":45}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
1140         U("{\"foo\":42}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
1141
1142         U("\"Pz8_Pz8_P2hlbGxvPj4-Pj4-Pg\"", "y", &xy[0], &xz[0]);
1143         U("\"\"", "y", &xy[0], &xz[0]);
1144         U("null", "y", &xy[0], &xz[0]);
1145         U("{\"foo\":\"Pz8_Pz8_P2hlbGxvPj4-Pj4-Pg\"}", "{s?y}", "foo", &xy[0], &xz[0]);
1146         U("{\"foo\":\"\"}", "{s?y}", "foo", &xy[0], &xz[0]);
1147         U("{}", "{s?y}", "foo", &xy[0], &xz[0]);
1148         return 0;
1149 }
1150
1151 #endif
1152
1153 #if 0
1154
1155
1156     /* Unpack the same item twice */
1157     j = json_pack("{s:s, s:i, s:b}", "foo", "bar", "baz", 42, "quux", 1);
1158     if(!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s))
1159         fail("json_unpack object with strict validation failed");
1160     {
1161         const char *possible_errors[] = {
1162             "2 object item(s) left unpacked: baz, quux",
1163             "2 object item(s) left unpacked: quux, baz"
1164         };
1165         check_errors(possible_errors, 2, "<validation>", 1, 10, 10);
1166     }
1167     json_decref(j);
1168
1169 #endif