wrap-json: Sync with app-afb-helpers-submodule
[src/app-framework-binder.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 >= 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 (*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                         rc = encode_base64(bytes.in, bytes.insz,
382                                 &bytes.out, &bytes.outsz, 0, 0, c == 'y');
383                         if (rc)
384                                 goto error;
385                         obj = json_object_new_string_len(bytes.out, (int)bytes.outsz);
386                         free(bytes.out);
387                         if (!obj)
388                                 goto out_of_memory;
389                         break;
390                 case '[':
391                 case '{':
392                         if (++top >= &stack[STACKCOUNT])
393                                 goto too_deep;
394                         top->key = NULL;
395                         if (c == '[') {
396                                 top->type = ']';
397                                 top->acc = pack_accept_arr;
398                                 top->cont = json_object_new_array();
399                         } else {
400                                 top->type = '}';
401                                 top->acc = pack_accept_key;
402                                 top->cont = json_object_new_object();
403                         }
404                         if (!top->cont)
405                                 goto out_of_memory;
406                         continue;
407                 case '}':
408                 case ']':
409                         if (c != top->type || top <= stack)
410                                 goto internal_error;
411                         obj = (top--)->cont;
412                         if (*d == '*' && !(c == '}' ? json_object_object_length(obj) : json_object_array_length(obj))) {
413                                 json_object_put(obj);
414                                 obj = NULL;
415                         }
416                         break;
417                 default:
418                         goto internal_error;
419                 }
420                 switch (top->type) {
421                 case 0:
422                         if (top != stack)
423                                 goto internal_error;
424                         if (*d)
425                                 goto invalid_character;
426                         *result = obj;
427                         return 0;
428                 case ']':
429                         if (obj || *d != '*')
430                                 json_object_array_add(top->cont, obj);
431                         if (*d == '*')
432                                 d = skip(++d);
433                         break;
434                 case '}':
435                         if (!obj)
436                                 goto null_key;
437                         top->key = obj;
438                         top->acc = pack_accept_any;
439                         top->type = ':';
440                         break;
441                 case ':':
442                         if (obj || *d != '*')
443                                 json_object_object_add(top->cont, json_object_get_string(top->key), obj);
444                         if (*d == '*')
445                                 d = skip(++d);
446                         json_object_put(top->key);
447                         top->key = NULL;
448                         top->acc = pack_accept_key;
449                         top->type = '}';
450                         break;
451                 default:
452                         goto internal_error;
453                 }
454         }
455
456 null_object:
457         rc = wrap_json_error_null_object;
458         goto error;
459 truncated:
460         rc = wrap_json_error_truncated;
461         goto error;
462 internal_error:
463         rc = wrap_json_error_internal_error;
464         goto error;
465 out_of_memory:
466         rc = wrap_json_error_out_of_memory;
467         goto error;
468 invalid_character:
469         rc = wrap_json_error_invalid_character;
470         goto error;
471 too_long:
472         rc = wrap_json_error_too_long;
473         goto error;
474 too_deep:
475         rc = wrap_json_error_too_deep;
476         goto error;
477 null_spec:
478         rc = wrap_json_error_null_spec;
479         goto error;
480 null_key:
481         rc = wrap_json_error_null_key;
482         goto error;
483 null_string:
484         rc = wrap_json_error_null_string;
485         goto error;
486 error:
487         do {
488                 json_object_put(top->key);
489                 json_object_put(top->cont);
490         } while (--top >= stack);
491         *result = NULL;
492         rc = rc | (int)((d - desc) << 4);
493         return -rc;
494 }
495
496 int wrap_json_pack(struct json_object **result, const char *desc, ...)
497 {
498         int rc;
499         va_list args;
500
501         va_start(args, desc);
502         rc = wrap_json_vpack(result, desc, args);
503         va_end(args);
504         return rc;
505 }
506
507 static int vunpack(struct json_object *object, const char *desc, va_list args, int store)
508 {
509         int rc = 0, optionnal, ignore;
510         char c, xacc[2] = { 0, 0 };
511         const char *acc;
512         const char *d, *fit = NULL;
513         const char *key = NULL;
514         const char **ps = NULL;
515         double *pf = NULL;
516         int *pi = NULL;
517         int64_t *pI = NULL;
518         size_t *pz = NULL;
519         uint8_t **py = NULL;
520         struct { struct json_object *parent; const char *acc; int index; size_t count; char type; } stack[STACKCOUNT], *top;
521         struct json_object *obj;
522         struct json_object **po;
523
524         xacc[0] = 0;
525         ignore = 0;
526         top = NULL;
527         acc = unpack_accept_any;
528         d = desc;
529         if (!d)
530                 goto null_spec;
531         d = skip(d);
532         obj = object;
533         for(;;) {
534                 fit = d;
535                 c = *d;
536                 if (!c)
537                         goto truncated;
538                 if (!strchr(acc, c))
539                         goto invalid_character;
540                 d = skip(++d);
541                 switch(c) {
542                 case 's':
543                         if (xacc[0] == '}') {
544                                 /* expects a key */
545                                 key = va_arg(args, const char *);
546                                 if (!key)
547                                         goto null_key;
548                                 if (*d != '?')
549                                         optionnal = 0;
550                                 else {
551                                         optionnal = 1;
552                                         d = skip(++d);
553                                 }
554                                 if (ignore)
555                                         ignore++;
556                                 else {
557                                         if (json_object_object_get_ex(top->parent, key, &obj)) {
558                                                 /* found */
559                                                 top->index++;
560                                         } else {
561                                                 /* not found */
562                                                 if (!optionnal)
563                                                         goto key_not_found;
564                                                 ignore = 1;
565                                                 obj = NULL;
566                                         }
567                                 }
568                                 xacc[0] = ':';
569                                 acc = unpack_accept_any;
570                                 continue;
571                         }
572                         /* get a string */
573                         if (store)
574                                 ps = va_arg(args, const char **);
575                         if (!ignore) {
576                                 if (!json_object_is_type(obj, json_type_string))
577                                         goto missfit;
578                                 if (store && ps)
579                                         *ps = json_object_get_string(obj);
580                         }
581                         if (*d == '%') {
582                                 d = skip(++d);
583                                 if (store) {
584                                         pz = va_arg(args, size_t *);
585                                         if (!ignore && pz)
586                                                 *pz = (size_t)json_object_get_string_len(obj);
587                                 }
588                         }
589                         break;
590                 case 'n':
591                         if (!ignore && !json_object_is_type(obj, json_type_null))
592                                 goto missfit;
593                         break;
594                 case 'b':
595                         if (store)
596                                 pi = va_arg(args, int *);
597
598                         if (!ignore) {
599                                 if (!json_object_is_type(obj, json_type_boolean))
600                                         goto missfit;
601                                 if (store && pi)
602                                         *pi = json_object_get_boolean(obj);
603                         }
604                         break;
605                 case 'i':
606                         if (store)
607                                 pi = va_arg(args, int *);
608
609                         if (!ignore) {
610                                 if (!json_object_is_type(obj, json_type_int))
611                                         goto missfit;
612                                 if (store && pi)
613                                         *pi = json_object_get_int(obj);
614                         }
615                         break;
616                 case 'I':
617                         if (store)
618                                 pI = va_arg(args, int64_t *);
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_int64(obj);
625                         }
626                         break;
627                 case 'f':
628                 case 'F':
629                         if (store)
630                                 pf = va_arg(args, double *);
631
632                         if (!ignore) {
633                                 if (!(json_object_is_type(obj, json_type_double) || (c == 'F' && json_object_is_type(obj, json_type_int))))
634                                         goto missfit;
635                                 if (store && pf)
636                                         *pf = json_object_get_double(obj);
637                         }
638                         break;
639                 case 'o':
640                 case 'O':
641                         if (store) {
642                                 po = va_arg(args, struct json_object **);
643                                 if (!ignore && po) {
644                                         if (c == 'O')
645                                                 obj = json_object_get(obj);
646                                         *po = obj;
647                                 }
648                         }
649                         break;
650                 case 'y':
651                 case 'Y':
652                         if (store) {
653                                 py = va_arg(args, uint8_t **);
654                                 pz = va_arg(args, size_t *);
655                         }
656                         if (!ignore) {
657                                 if (!json_object_is_type(obj, json_type_string))
658                                         goto missfit;
659                                 if (store && py && pz) {
660                                         rc = decode_base64(
661                                                 json_object_get_string(obj),
662                                                 (size_t)json_object_get_string_len(obj),
663                                                 py, pz, c == 'y');
664                                         if (rc)
665                                                 goto error;
666                                 }
667                         }
668                         break;
669
670                 case '[':
671                 case '{':
672                         if (!top)
673                                 top = stack;
674                         else if (++top  >= &stack[STACKCOUNT])
675                                 goto too_deep;
676
677                         top->acc = acc;
678                         top->type = xacc[0];
679                         top->index = 0;
680                         top->parent = obj;
681                         if (ignore)
682                                 ignore++;
683                         if (c == '[') {
684                                 if (!ignore) {
685                                         if (!json_object_is_type(obj, json_type_array))
686                                                 goto missfit;
687                                         top->count = json_object_array_length(obj);
688                                 }
689                                 xacc[0] = ']';
690                                 acc = unpack_accept_arr;
691                         } else {
692                                 if (!ignore) {
693                                         if (!json_object_is_type(obj, json_type_object))
694                                                 goto missfit;
695                                         top->count = json_object_object_length(obj);
696                                 }
697                                 xacc[0] = '}';
698                                 acc = unpack_accept_key;
699                                 continue;
700                         }
701                         break;
702                 case '}':
703                 case ']':
704                         if (!top || c != xacc[0])
705                                 goto internal_error;
706                         acc = top->acc;
707                         xacc[0] = top->type;
708                         top = top == stack ? NULL : top - 1;
709                         if (ignore)
710                                 ignore--;
711                         break;
712                 case '!':
713                         if (*d != xacc[0])
714                                 goto invalid_character;
715                         if (!ignore && top->index != top->count)
716                                 goto incomplete;
717                         /*@fallthrough@*/
718                 case '*':
719                         acc = xacc;
720                         continue;
721                 default:
722                         goto internal_error;
723                 }
724                 switch (xacc[0]) {
725                 case 0:
726                         if (top)
727                                 goto internal_error;
728                         if (*d)
729                                 goto invalid_character;
730                         return 0;
731                 case ']':
732                         if (!ignore) {
733                                 key = strchr(unpack_accept_arr, *d);
734                                 if (key && key >= unpack_accept_any) {
735                                         if (top->index >= top->count)
736                                                 goto out_of_range;
737                                         obj = json_object_array_get_idx(top->parent, top->index++);
738                                 }
739                         }
740                         break;
741                 case ':':
742                         acc = unpack_accept_key;
743                         xacc[0] = '}';
744                         if (ignore)
745                                 ignore--;
746                         break;
747                 default:
748                         goto internal_error;
749                 }
750         }
751 truncated:
752         rc = wrap_json_error_truncated;
753         goto error;
754 internal_error:
755         rc = wrap_json_error_internal_error;
756         goto error;
757 invalid_character:
758         rc = wrap_json_error_invalid_character;
759         goto error;
760 too_deep:
761         rc = wrap_json_error_too_deep;
762         goto error;
763 null_spec:
764         rc = wrap_json_error_null_spec;
765         goto error;
766 null_key:
767         rc = wrap_json_error_null_key;
768         goto error;
769 out_of_range:
770         rc = wrap_json_error_out_of_range;
771         goto error;
772 incomplete:
773         rc = wrap_json_error_incomplete;
774         goto error;
775 missfit:
776         rc = wrap_json_error_missfit_type;
777         goto errorfit;
778 key_not_found:
779         rc = wrap_json_error_key_not_found;
780         goto error;
781 errorfit:
782         d = fit;
783 error:
784         rc = rc | (int)((d - desc) << 4);
785         return -rc;
786 }
787
788 int wrap_json_vcheck(struct json_object *object, const char *desc, va_list args)
789 {
790         return vunpack(object, desc, args, 0);
791 }
792
793 int wrap_json_check(struct json_object *object, const char *desc, ...)
794 {
795         int rc;
796         va_list args;
797
798         va_start(args, desc);
799         rc = vunpack(object, desc, args, 0);
800         va_end(args);
801         return rc;
802 }
803
804 int wrap_json_vmatch(struct json_object *object, const char *desc, va_list args)
805 {
806         return !vunpack(object, desc, args, 0);
807 }
808
809 int wrap_json_match(struct json_object *object, const char *desc, ...)
810 {
811         int rc;
812         va_list args;
813
814         va_start(args, desc);
815         rc = vunpack(object, desc, args, 0);
816         va_end(args);
817         return !rc;
818 }
819
820 int wrap_json_vunpack(struct json_object *object, const char *desc, va_list args)
821 {
822         return vunpack(object, desc, args, 1);
823 }
824
825 int wrap_json_unpack(struct json_object *object, const char *desc, ...)
826 {
827         int rc;
828         va_list args;
829
830         va_start(args, desc);
831         rc = vunpack(object, desc, args, 1);
832         va_end(args);
833         return rc;
834 }
835
836 static void object_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
837 {
838         struct json_object_iterator it = json_object_iter_begin(object);
839         struct json_object_iterator end = json_object_iter_end(object);
840         while (!json_object_iter_equal(&it, &end)) {
841                 callback(closure, json_object_iter_peek_value(&it), json_object_iter_peek_name(&it));
842                 json_object_iter_next(&it);
843         }
844 }
845
846 static void array_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
847 {
848         size_t n = json_object_array_length(object);
849         int i = 0;
850         while(i < n)
851                 callback(closure, json_object_array_get_idx(object, i++));
852 }
853
854 void wrap_json_optarray_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
855 {
856         if (json_object_is_type(object, json_type_array))
857                 array_for_all(object, callback, closure);
858         else
859                 callback(closure, object);
860 }
861
862 void wrap_json_array_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
863 {
864         if (json_object_is_type(object, json_type_array))
865                 array_for_all(object, callback, closure);
866 }
867
868 void wrap_json_object_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
869 {
870         if (json_object_is_type(object, json_type_object))
871                 object_for_all(object, callback, closure);
872 }
873
874 void wrap_json_optobject_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
875 {
876         if (json_object_is_type(object, json_type_object))
877                 object_for_all(object, callback, closure);
878         else
879                 callback(closure, object, NULL);
880 }
881
882 void wrap_json_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
883 {
884         if (!object)
885                 /* do nothing */;
886         else if (json_object_is_type(object, json_type_object))
887                 object_for_all(object, callback, closure);
888         else if (!json_object_is_type(object, json_type_array))
889                 callback(closure, object, NULL);
890         else {
891                 size_t n = json_object_array_length(object);
892                 int i = 0;
893                 while(i < n)
894                         callback(closure, json_object_array_get_idx(object, i++), NULL);
895         }
896 }
897
898 #if defined(WRAP_JSON_TEST)
899 #include <stdio.h>
900
901 void p(const char *desc, ...)
902 {
903         int rc;
904         va_list args;
905         struct json_object *result;
906
907         va_start(args, desc);
908         rc = wrap_json_vpack(&result, desc, args);
909         va_end(args);
910         if (!rc)
911                 printf("  SUCCESS %s\n\n", json_object_to_json_string(result));
912         else
913                 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));
914         json_object_put(result);
915 }
916
917 const char *xs[10];
918 int *xi[10];
919 int64_t *xI[10];
920 double *xf[10];
921 struct json_object *xo[10];
922 size_t xz[10];
923 uint8_t *xy[10];
924
925 void u(const char *value, const char *desc, ...)
926 {
927         unsigned m, k;
928         int rc;
929         va_list args;
930         struct json_object *obj, *o;
931
932         memset(xs, 0, sizeof xs);
933         memset(xi, 0, sizeof xi);
934         memset(xI, 0, sizeof xI);
935         memset(xf, 0, sizeof xf);
936         memset(xo, 0, sizeof xo);
937         memset(xz, 0, sizeof xz);
938         obj = json_tokener_parse(value);
939         va_start(args, desc);
940         rc = wrap_json_vunpack(obj, desc, args);
941         va_end(args);
942         if (rc)
943                 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));
944         else {
945                 value = NULL;
946                 printf("  SUCCESS");
947                 va_start(args, desc);
948                 k = m = 0;
949                 while(*desc) {
950                         switch(*desc) {
951                         case '{': m = (m << 1) | 1; k = 1; break;
952                         case '}': m = m >> 1; k = m&1; break;
953                         case '[': m = m << 1; k = 0; break;
954                         case ']': m = m >> 1; k = m&1; break;
955                         case 's': printf(" s:%s", k ? va_arg(args, const char*) : *(va_arg(args, const char**)?:&value)); k ^= m&1; break;
956                         case '%': printf(" %%:%zu", *va_arg(args, size_t*)); k = m&1; break;
957                         case 'n': printf(" n"); k = m&1; break;
958                         case 'b': printf(" b:%d", *va_arg(args, int*)); k = m&1; break;
959                         case 'i': printf(" i:%d", *va_arg(args, int*)); k = m&1; break;
960                         case 'I': printf(" I:%lld", *va_arg(args, int64_t*)); k = m&1; break;
961                         case 'f': printf(" f:%f", *va_arg(args, double*)); k = m&1; break;
962                         case 'F': printf(" F:%f", *va_arg(args, double*)); k = m&1; break;
963                         case 'o': printf(" o:%s", json_object_to_json_string(*va_arg(args, struct json_object**))); k = m&1; break;
964                         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;
965                         case 'y':
966                         case 'Y': {
967                                 uint8_t *p = *va_arg(args, uint8_t**);
968                                 size_t s = *va_arg(args, size_t*);
969                                 printf(" y/%d:%.*s", (int)s, (int)s, (char*)p);
970                                 k ^= m&1;
971                                 break;
972                                 }
973                         default: break;
974                         }
975                         desc++;
976                 }
977                 va_end(args);
978                 printf("\n\n");
979         }
980         json_object_put(obj);
981 }
982
983 #define P(...) do{ printf("pack(%s)\n",#__VA_ARGS__); p(__VA_ARGS__); } while(0)
984 #define U(...) do{ printf("unpack(%s)\n",#__VA_ARGS__); u(__VA_ARGS__); } while(0)
985
986 int main()
987 {
988         char buffer[4] = {'t', 'e', 's', 't'};
989
990         P("n");
991         P("b", 1);
992         P("b", 0);
993         P("i", 1);
994         P("I", (uint64_t)0x123456789abcdef);
995         P("f", 3.14);
996         P("s", "test");
997         P("s?", "test");
998         P("s?", NULL);
999         P("s#", "test asdf", 4);
1000         P("s%", "test asdf", (size_t)4);
1001         P("s#", buffer, 4);
1002         P("s%", buffer, (size_t)4);
1003         P("s++", "te", "st", "ing");
1004         P("s#+#+", "test", 1, "test", 2, "test");
1005         P("s%+%+", "test", (size_t)1, "test", (size_t)2, "test");
1006         P("{}", 1.0);
1007         P("[]", 1.0);
1008         P("o", json_object_new_int(1));
1009         P("o?", json_object_new_int(1));
1010         P("o?", NULL);
1011         P("O", json_object_new_int(1));
1012         P("O?", json_object_new_int(1));
1013         P("O?", NULL);
1014         P("{s:[]}", "foo");
1015         P("{s+#+: []}", "foo", "barbar", 3, "baz");
1016         P("{s:s,s:o,s:O}", "a", NULL, "b", NULL, "c", NULL);
1017         P("{s:**}", "a", NULL);
1018         P("{s:s*,s:o*,s:O*}", "a", NULL, "b", NULL, "c", NULL);
1019         P("[i,i,i]", 0, 1, 2);
1020         P("[s,o,O]", NULL, NULL, NULL);
1021         P("[**]", NULL);
1022         P("[s*,o*,O*]", NULL, NULL, NULL);
1023         P(" s ", "test");
1024         P("[ ]");
1025         P("[ i , i,  i ] ", 1, 2, 3);
1026         P("{\n\n1");
1027         P("[}");
1028         P("{]");
1029         P("[");
1030         P("{");
1031         P("[i]a", 42);
1032         P("ia", 42);
1033         P("s", NULL);
1034         P("+", NULL);
1035         P(NULL);
1036         P("{s:i}", NULL, 1);
1037         P("{ {}: s }", "foo");
1038         P("{ s: {},  s:[ii{} }", "foo", "bar", 12, 13);
1039         P("[[[[[   [[[[[  [[[[ }]]]] ]]]] ]]]]]");
1040         P("y", "???????hello>>>>>>>", (size_t)19);
1041         P("Y", "???????hello>>>>>>>", (size_t)19);
1042
1043         U("true", "b", &xi[0]);
1044         U("false", "b", &xi[0]);
1045         U("null", "n");
1046         U("42", "i", &xi[0]);
1047         U("123456789", "I", &xI[0]);
1048         U("3.14", "f", &xf[0]);
1049         U("12345", "F", &xf[0]);
1050         U("3.14", "F", &xf[0]);
1051         U("\"foo\"", "s", &xs[0]);
1052         U("\"foo\"", "s%", &xs[0], &xz[0]);
1053         U("{}", "{}");
1054         U("[]", "[]");
1055         U("{}", "o", &xo[0]);
1056         U("{}", "O", &xo[0]);
1057         U("{\"foo\":42}", "{si}", "foo", &xi[0]);
1058         U("[1,2,3]", "[i,i,i]", &xi[0], &xi[1], &xi[2]);
1059         U("{\"a\":1,\"b\":2,\"c\":3}", "{s:i, s:i, s:i}", "a", &xi[0], "b", &xi[1], "c", &xi[2]);
1060         U("42", "z");
1061         U("null", "[i]");
1062         U("[]", "[}");
1063         U("{}", "{]");
1064         U("[]", "[");
1065         U("{}", "{");
1066         U("[42]", "[i]a", &xi[0]);
1067         U("42", "ia", &xi[0]);
1068         U("[]", NULL);
1069         U("\"foo\"", "s", NULL);
1070         U("42", "s", NULL);
1071         U("42", "n");
1072         U("42", "b", NULL);
1073         U("42", "f", NULL);
1074         U("42", "[i]", NULL);
1075         U("42", "{si}", "foo", NULL);
1076         U("\"foo\"", "n");
1077         U("\"foo\"", "b", NULL);
1078         U("\"foo\"", "i", NULL);
1079         U("\"foo\"", "I", NULL);
1080         U("\"foo\"", "f", NULL);
1081         U("\"foo\"", "F", NULL);
1082         U("true", "s", NULL);
1083         U("true", "n");
1084         U("true", "i", NULL);
1085         U("true", "I", NULL);
1086         U("true", "f", NULL);
1087         U("true", "F", NULL);
1088         U("[42]", "[ii]", &xi[0], &xi[1]);
1089         U("{\"foo\":42}", "{si}", NULL, &xi[0]);
1090         U("{\"foo\":42}", "{si}", "baz", &xi[0]);
1091         U("[1,2,3]", "[iii!]", &xi[0], &xi[1], &xi[2]);
1092         U("[1,2,3]", "[ii!]", &xi[0], &xi[1]);
1093         U("[1,2,3]", "[ii]", &xi[0], &xi[1]);
1094         U("[1,2,3]", "[ii*]", &xi[0], &xi[1]);
1095         U("{\"foo\":42,\"baz\":45}", "{sisi}", "baz", &xi[0], "foo", &xi[1]);
1096         U("{\"foo\":42,\"baz\":45}", "{sisi*}", "baz", &xi[0], "foo", &xi[1]);
1097         U("{\"foo\":42,\"baz\":45}", "{sisi!}", "baz", &xi[0], "foo", &xi[1]);
1098         U("{\"foo\":42,\"baz\":45}", "{si}", "baz", &xi[0], "foo", &xi[1]);
1099         U("{\"foo\":42,\"baz\":45}", "{si*}", "baz", &xi[0], "foo", &xi[1]);
1100         U("{\"foo\":42,\"baz\":45}", "{si!}", "baz", &xi[0], "foo", &xi[1]);
1101         U("[1,{\"foo\":2,\"bar\":null},[3,4]]", "[i{sisn}[ii]]", &xi[0], "foo", &xi[1], "bar", &xi[2], &xi[3]);
1102         U("[1,2,3]", "[ii!i]", &xi[0], &xi[1], &xi[2]);
1103         U("[1,2,3]", "[ii*i]", &xi[0], &xi[1], &xi[2]);
1104         U("{\"foo\":1,\"bar\":2}", "{si!si}", "foo", &xi[1], "bar", &xi[2]);
1105         U("{\"foo\":1,\"bar\":2}", "{si*si}", "foo", &xi[1], "bar", &xi[2]);
1106         U("{\"foo\":{\"baz\":null,\"bar\":null}}", "{s{sn!}}", "foo", "bar");
1107         U("[[1,2,3]]", "[[ii!]]", &xi[0], &xi[1]);
1108         U("{}", "{s?i}", "foo", &xi[0]);
1109         U("{\"foo\":1}", "{s?i}", "foo", &xi[0]);
1110         U("{}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
1111         U("{\"foo\":[1,2]}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
1112         U("{\"bar\":{\"baz\":{\"quux\":15}}}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
1113         U("{\"foo\":{\"bar\":4}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
1114         U("{\"foo\":{}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
1115         U("{}", "{s?{s?i}}", "foo", "bar", &xi[0]);
1116         U("{\"foo\":42,\"baz\":45}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
1117         U("{\"foo\":42}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
1118
1119         U("\"Pz8_Pz8_P2hlbGxvPj4-Pj4-Pg\"", "y", &xy[0], &xz[0]);
1120         return 0;
1121 }
1122
1123 #endif
1124
1125 #if 0
1126
1127
1128     /* Unpack the same item twice */
1129     j = json_pack("{s:s, s:i, s:b}", "foo", "bar", "baz", 42, "quux", 1);
1130     if(!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s))
1131         fail("json_unpack object with strict validation failed");
1132     {
1133         const char *possible_errors[] = {
1134             "2 object item(s) left unpacked: baz, quux",
1135             "2 object item(s) left unpacked: quux, baz"
1136         };
1137         check_errors(possible_errors, 2, "<validation>", 1, 10, 10);
1138     }
1139     json_decref(j);
1140
1141 #endif