Fix warnings due to json-c evolution
[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 #include <limits.h>
21
22 #include "wrap-json.h"
23
24 #define STACKCOUNT  32
25 #define STRCOUNT    8
26
27 enum {
28         wrap_json_error_none,
29         wrap_json_error_null_object,
30         wrap_json_error_truncated,
31         wrap_json_error_internal_error,
32         wrap_json_error_out_of_memory,
33         wrap_json_error_invalid_character,
34         wrap_json_error_too_long,
35         wrap_json_error_too_deep,
36         wrap_json_error_null_spec,
37         wrap_json_error_null_key,
38         wrap_json_error_null_string,
39         wrap_json_error_out_of_range,
40         wrap_json_error_incomplete,
41         wrap_json_error_missfit_type,
42         wrap_json_error_key_not_found,
43         wrap_json_error_bad_base64,
44         _wrap_json_error_count_
45 };
46
47 static const char ignore_all[] = " \t\n\r,:";
48 static const char pack_accept_arr[] = "][{snbiIfoOyY";
49 static const char pack_accept_key[] = "s}";
50 #define pack_accept_any (&pack_accept_arr[1])
51
52 static const char unpack_accept_arr[] = "*!][{snbiIfFoOyY";
53 static const char unpack_accept_key[] = "*!s}";
54 #define unpack_accept_any (&unpack_accept_arr[3])
55
56 static const char *pack_errors[_wrap_json_error_count_] =
57 {
58         [wrap_json_error_none] = "unknown error",
59         [wrap_json_error_null_object] = "null object",
60         [wrap_json_error_truncated] = "truncated",
61         [wrap_json_error_internal_error] = "internal error",
62         [wrap_json_error_out_of_memory] = "out of memory",
63         [wrap_json_error_invalid_character] = "invalid character",
64         [wrap_json_error_too_long] = "too long",
65         [wrap_json_error_too_deep] = "too deep",
66         [wrap_json_error_null_spec] = "spec is NULL",
67         [wrap_json_error_null_key] = "key is NULL",
68         [wrap_json_error_null_string] = "string is NULL",
69         [wrap_json_error_out_of_range] = "array too small",
70         [wrap_json_error_incomplete] = "incomplete container",
71         [wrap_json_error_missfit_type] = "missfit of type",
72         [wrap_json_error_key_not_found] = "key not found",
73         [wrap_json_error_bad_base64] = "bad base64 encoding"
74 };
75
76 int wrap_json_get_error_position(int rc)
77 {
78         if (rc < 0)
79                 rc = -rc;
80         return (rc >> 4) + 1;
81 }
82
83 int wrap_json_get_error_code(int rc)
84 {
85         if (rc < 0)
86                 rc = -rc;
87         return rc & 15;
88 }
89
90 const char *wrap_json_get_error_string(int rc)
91 {
92         rc = wrap_json_get_error_code(rc);
93         if (rc >= (int)(sizeof pack_errors / sizeof *pack_errors))
94                 rc = 0;
95         return pack_errors[rc];
96 }
97
98 static int encode_base64(
99                 const uint8_t *data,
100                 size_t datalen,
101                 char **encoded,
102                 size_t *encodedlen,
103                 int width,
104                 int pad,
105                 int url)
106 {
107         uint16_t u16 = 0;
108         uint8_t u8 = 0;
109         size_t in, out, rlen, n3, r3, iout, nout;
110         int iw;
111         char *result, c;
112
113         /* compute unformatted output length */
114         n3 = datalen / 3;
115         r3 = datalen % 3;
116         nout = 4 * n3 + r3 + !!r3;
117
118         /* deduce formatted output length */
119         rlen = nout;
120         if (pad)
121                 rlen += ((~rlen) + 1) & 3;
122         if (width)
123                 rlen += rlen / width;
124
125         /* allocate the output */
126         result = malloc(rlen + 1);
127         if (result == NULL)
128                 return wrap_json_error_out_of_memory;
129
130         /* compute the formatted output */
131         iw = width;
132         for (in = out = iout = 0 ; iout < nout ; iout++) {
133                 /* get in 'u8' the 6 bits value to add */
134                 switch (iout & 3) {
135                 case 0:
136                         u16 = (uint16_t)data[in++];
137                         u8 = (uint8_t)(u16 >> 2);
138                         break;
139                 case 1:
140                         u16 = (uint16_t)(u16 << 8);
141                         if (in < datalen)
142                                 u16 = (uint16_t)(u16 | data[in++]);
143                         u8 = (uint8_t)(u16 >> 4);
144                         break;
145                 case 2:
146                         u16 = (uint16_t)(u16 << 8);
147                         if (in < datalen)
148                                 u16 = (uint16_t)(u16 | data[in++]);
149                         u8 = (uint8_t)(u16 >> 6);
150                         break;
151                 case 3:
152                         u8 = (uint8_t)u16;
153                         break;
154                 }
155                 u8 &= 63;
156
157                 /* encode 'u8' to the char 'c' */
158                 if (u8 < 52) {
159                         if (u8 < 26)
160                                 c = (char)('A' + u8);
161                         else
162                                 c = (char)('a' + u8 - 26);
163                 } else {
164                         if (u8 < 62)
165                                 c = (char)('0' + u8 - 52);
166                         else if (u8 == 62)
167                                 c = url ? '-' : '+';
168                         else
169                                 c = url ? '_' : '/';
170                 }
171
172                 /* put to output with format */
173                 result[out++] = c;
174                 if (iw && !--iw) {
175                         result[out++] = '\n';
176                         iw = width;
177                 }
178         }
179
180         /* pad the output */
181         while (out < rlen) {
182                 result[out++] = '=';
183                 if (iw && !--iw) {
184                         result[out++] = '\n';
185                         iw = width;
186                 }
187         }
188
189         /* terminate */
190         result[out] = 0;
191         *encoded = result;
192         *encodedlen = rlen;
193         return 0;
194 }
195
196 static int decode_base64(
197                 const char *data,
198                 size_t datalen,
199                 uint8_t **decoded,
200                 size_t *decodedlen,
201                 int url)
202 {
203         uint16_t u16;
204         uint8_t u8, *result;
205         size_t in, out, iin;
206         char c;
207
208         /* allocate enougth output */
209         result = malloc(datalen);
210         if (result == NULL)
211                 return wrap_json_error_out_of_memory;
212
213         /* decode the input */
214         for (iin = in = out = 0 ; in < datalen ; in++) {
215                 c = data[in];
216                 if (c != '\n' && c != '\r' && c != '=') {
217                         if ('A' <= c && c <= 'Z')
218                                 u8 = (uint8_t)(c - 'A');
219                         else if ('a' <= c && c <= 'z')
220                                 u8 = (uint8_t)(c - 'a' + 26);
221                         else if ('0' <= c && c <= '9')
222                                 u8 = (uint8_t)(c - '0' + 52);
223                         else if (c == '+' || c == '-')
224                                 u8 = (uint8_t)62;
225                         else if (c == '/' || c == '_')
226                                 u8 = (uint8_t)63;
227                         else {
228                                 free(result);
229                                 return wrap_json_error_bad_base64;
230                         }
231                         if (!iin) {
232                                 u16 = (uint16_t)u8;
233                                 iin = 6;
234                         } else {
235                                 u16 = (uint16_t)((u16 << 6) | u8);
236                                 iin -= 2;
237                                 u8 = (uint8_t)(u16 >> iin);
238                                 result[out++] = u8;
239                         }
240                 }
241         }
242
243         /* terminate */
244         *decoded = realloc(result, out);
245         if (out && *decoded == NULL) {
246                 free(result);
247                 return wrap_json_error_out_of_memory;
248         }
249         *decodedlen = out;
250         return 0;
251 }
252
253 static inline const char *skip(const char *d)
254 {
255         while (*d && strchr(ignore_all, *d))
256                 d++;
257         return d;
258 }
259
260 int wrap_json_vpack(struct json_object **result, const char *desc, va_list args)
261 {
262         /* TODO: the case of structs with key being single char should be optimized */
263         int nstr, notnull, nullable, rc;
264         size_t sz, dsz, ssz;
265         char *s;
266         char c;
267         const char *d;
268         char buffer[256];
269         struct { const uint8_t *in; size_t insz; char *out; size_t outsz; } bytes;
270         struct { const char *str; size_t sz; } strs[STRCOUNT];
271         struct { struct json_object *cont, *key; const char *acc; char type; } stack[STACKCOUNT], *top;
272         struct json_object *obj;
273
274         ssz = sizeof buffer;
275         s = buffer;
276         top = stack;
277         top->key = NULL;
278         top->cont = NULL;
279         top->acc = pack_accept_any;
280         top->type = 0;
281         d = desc;
282         if (!d)
283                 goto null_spec;
284         d = skip(d);
285         for(;;) {
286                 c = *d;
287                 if (!c)
288                         goto truncated;
289                 if (!strchr(top->acc, c))
290                         goto invalid_character;
291                 d = skip(++d);
292                 switch(c) {
293                 case 's':
294                         nullable = 0;
295                         notnull = 0;
296                         nstr = 0;
297                         sz = 0;
298                         for (;;) {
299                                 strs[nstr].str = va_arg(args, const char*);
300                                 if (strs[nstr].str)
301                                         notnull = 1;
302                                 if (*d == '?') {
303                                         d = skip(++d);
304                                         nullable = 1;
305                                 }
306                                 switch(*d) {
307                                 case '%': strs[nstr].sz = va_arg(args, size_t); d = skip(++d); break;
308                                 case '#': strs[nstr].sz = (size_t)va_arg(args, int); d = skip(++d); break;
309                                 default: strs[nstr].sz = strs[nstr].str ? strlen(strs[nstr].str) : 0; break;
310                                 }
311                                 sz += strs[nstr++].sz;
312                                 if (*d == '?') {
313                                         d = skip(++d);
314                                         nullable = 1;
315                                 }
316                                 if (*d != '+')
317                                         break;
318                                 if (nstr >= STRCOUNT)
319                                         goto too_long;
320                                 d = skip(++d);
321                         }
322                         if (*d == '*')
323                                 nullable = 1;
324                         if (notnull) {
325                                 if (sz > ssz) {
326                                         ssz += ssz;
327                                         if (ssz < sz)
328                                                 ssz = sz;
329                                         s = alloca(sz);
330                                 }
331                                 dsz = sz;
332                                 while (nstr) {
333                                         nstr--;
334                                         dsz -= strs[nstr].sz;
335                                         memcpy(&s[dsz], strs[nstr].str, strs[nstr].sz);
336                                 }
337                                 obj = json_object_new_string_len(s, (int)sz);
338                                 if (!obj)
339                                         goto out_of_memory;
340                         } else if (nullable)
341                                 obj = NULL;
342                         else
343                                 goto null_string;
344                         break;
345                 case 'n':
346                         obj = NULL;
347                         break;
348                 case 'b':
349                         obj = json_object_new_boolean(va_arg(args, int));
350                         if (!obj)
351                                 goto out_of_memory;
352                         break;
353                 case 'i':
354                         obj = json_object_new_int(va_arg(args, int));
355                         if (!obj)
356                                 goto out_of_memory;
357                         break;
358                 case 'I':
359                         obj = json_object_new_int64(va_arg(args, int64_t));
360                         if (!obj)
361                                 goto out_of_memory;
362                         break;
363                 case 'f':
364                         obj = json_object_new_double(va_arg(args, double));
365                         if (!obj)
366                                 goto out_of_memory;
367                         break;
368                 case 'o':
369                 case 'O':
370                         obj = va_arg(args, struct json_object*);
371                         if (*d == '?')
372                                 d = skip(++d);
373                         else if (*d != '*' && !obj)
374                                 goto null_object;
375                         if (c == 'O')
376                                 json_object_get(obj);
377                         break;
378                 case 'y':
379                 case 'Y':
380                         bytes.in = va_arg(args, const uint8_t*);
381                         bytes.insz = va_arg(args, size_t);
382                         if (bytes.in == NULL || bytes.insz == 0)
383                                 obj = NULL;
384                         else {
385                                 rc = encode_base64(bytes.in, bytes.insz,
386                                         &bytes.out, &bytes.outsz, 0, 0, c == 'y');
387                                 if (rc)
388                                         goto error;
389                                 obj = json_object_new_string_len(bytes.out, (int)bytes.outsz);
390                                 free(bytes.out);
391                                 if (!obj)
392                                         goto out_of_memory;
393                         }
394                         if (*d == '?')
395                                 d = skip(++d);
396                         else if (*d != '*' && !obj) {
397                                 obj = json_object_new_string_len(d, 0);
398                                 if (!obj)
399                                         goto out_of_memory;
400                         }
401                         break;
402                 case '[':
403                 case '{':
404                         if (++top >= &stack[STACKCOUNT])
405                                 goto too_deep;
406                         top->key = NULL;
407                         if (c == '[') {
408                                 top->type = ']';
409                                 top->acc = pack_accept_arr;
410                                 top->cont = json_object_new_array();
411                         } else {
412                                 top->type = '}';
413                                 top->acc = pack_accept_key;
414                                 top->cont = json_object_new_object();
415                         }
416                         if (!top->cont)
417                                 goto out_of_memory;
418                         continue;
419                 case '}':
420                 case ']':
421                         if (c != top->type || top <= stack)
422                                 goto internal_error;
423                         obj = (top--)->cont;
424                         if (*d == '*' && !(c == '}' ? json_object_object_length(obj) : json_object_array_length(obj))) {
425                                 json_object_put(obj);
426                                 obj = NULL;
427                         }
428                         break;
429                 default:
430                         goto internal_error;
431                 }
432                 switch (top->type) {
433                 case 0:
434                         if (top != stack)
435                                 goto internal_error;
436                         if (*d)
437                                 goto invalid_character;
438                         *result = obj;
439                         return 0;
440                 case ']':
441                         if (obj || *d != '*')
442                                 json_object_array_add(top->cont, obj);
443                         if (*d == '*')
444                                 d = skip(++d);
445                         break;
446                 case '}':
447                         if (!obj)
448                                 goto null_key;
449                         top->key = obj;
450                         top->acc = pack_accept_any;
451                         top->type = ':';
452                         break;
453                 case ':':
454                         if (obj || *d != '*')
455                                 json_object_object_add(top->cont, json_object_get_string(top->key), obj);
456                         if (*d == '*')
457                                 d = skip(++d);
458                         json_object_put(top->key);
459                         top->key = NULL;
460                         top->acc = pack_accept_key;
461                         top->type = '}';
462                         break;
463                 default:
464                         goto internal_error;
465                 }
466         }
467
468 null_object:
469         rc = wrap_json_error_null_object;
470         goto error;
471 truncated:
472         rc = wrap_json_error_truncated;
473         goto error;
474 internal_error:
475         rc = wrap_json_error_internal_error;
476         goto error;
477 out_of_memory:
478         rc = wrap_json_error_out_of_memory;
479         goto error;
480 invalid_character:
481         rc = wrap_json_error_invalid_character;
482         goto error;
483 too_long:
484         rc = wrap_json_error_too_long;
485         goto error;
486 too_deep:
487         rc = wrap_json_error_too_deep;
488         goto error;
489 null_spec:
490         rc = wrap_json_error_null_spec;
491         goto error;
492 null_key:
493         rc = wrap_json_error_null_key;
494         goto error;
495 null_string:
496         rc = wrap_json_error_null_string;
497         goto error;
498 error:
499         do {
500                 json_object_put(top->key);
501                 json_object_put(top->cont);
502         } while (--top >= stack);
503         *result = NULL;
504         rc = rc | (int)((d - desc) << 4);
505         return -rc;
506 }
507
508 int wrap_json_pack(struct json_object **result, const char *desc, ...)
509 {
510         int rc;
511         va_list args;
512
513         va_start(args, desc);
514         rc = wrap_json_vpack(result, desc, args);
515         va_end(args);
516         return rc;
517 }
518
519 static int vunpack(struct json_object *object, const char *desc, va_list args, int store)
520 {
521         int rc = 0, optionnal, ignore;
522         char c, xacc[2] = { 0, 0 };
523         const char *acc;
524         const char *d, *fit = NULL;
525         const char *key = NULL;
526         const char **ps = NULL;
527         double *pf = NULL;
528         int *pi = NULL;
529         int64_t *pI = NULL;
530         size_t *pz = NULL;
531         uint8_t **py = NULL;
532         struct { struct json_object *parent; const char *acc; int index; int count; char type; } stack[STACKCOUNT], *top;
533         struct json_object *obj;
534         struct json_object **po;
535
536         xacc[0] = 0;
537         ignore = 0;
538         top = NULL;
539         acc = unpack_accept_any;
540         d = desc;
541         if (!d)
542                 goto null_spec;
543         d = skip(d);
544         obj = object;
545         for(;;) {
546                 fit = d;
547                 c = *d;
548                 if (!c)
549                         goto truncated;
550                 if (!strchr(acc, c))
551                         goto invalid_character;
552                 d = skip(++d);
553                 switch(c) {
554                 case 's':
555                         if (xacc[0] == '}') {
556                                 /* expects a key */
557                                 key = va_arg(args, const char *);
558                                 if (!key)
559                                         goto null_key;
560                                 if (*d != '?')
561                                         optionnal = 0;
562                                 else {
563                                         optionnal = 1;
564                                         d = skip(++d);
565                                 }
566                                 if (ignore)
567                                         ignore++;
568                                 else {
569                                         if (json_object_object_get_ex(top->parent, key, &obj)) {
570                                                 /* found */
571                                                 top->index++;
572                                         } else {
573                                                 /* not found */
574                                                 if (!optionnal)
575                                                         goto key_not_found;
576                                                 ignore = 1;
577                                                 obj = NULL;
578                                         }
579                                 }
580                                 xacc[0] = ':';
581                                 acc = unpack_accept_any;
582                                 continue;
583                         }
584                         /* get a string */
585                         if (store)
586                                 ps = va_arg(args, const char **);
587                         if (!ignore) {
588                                 if (!json_object_is_type(obj, json_type_string))
589                                         goto missfit;
590                                 if (store && ps)
591                                         *ps = json_object_get_string(obj);
592                         }
593                         if (*d == '%') {
594                                 d = skip(++d);
595                                 if (store) {
596                                         pz = va_arg(args, size_t *);
597                                         if (!ignore && pz)
598                                                 *pz = (size_t)json_object_get_string_len(obj);
599                                 }
600                         }
601                         break;
602                 case 'n':
603                         if (!ignore && !json_object_is_type(obj, json_type_null))
604                                 goto missfit;
605                         break;
606                 case 'b':
607                         if (store)
608                                 pi = va_arg(args, int *);
609
610                         if (!ignore) {
611                                 if (!json_object_is_type(obj, json_type_boolean))
612                                         goto missfit;
613                                 if (store && pi)
614                                         *pi = json_object_get_boolean(obj);
615                         }
616                         break;
617                 case 'i':
618                         if (store)
619                                 pi = va_arg(args, int *);
620
621                         if (!ignore) {
622                                 if (!json_object_is_type(obj, json_type_int))
623                                         goto missfit;
624                                 if (store && pi)
625                                         *pi = json_object_get_int(obj);
626                         }
627                         break;
628                 case 'I':
629                         if (store)
630                                 pI = va_arg(args, int64_t *);
631
632                         if (!ignore) {
633                                 if (!json_object_is_type(obj, json_type_int))
634                                         goto missfit;
635                                 if (store && pI)
636                                         *pI = json_object_get_int64(obj);
637                         }
638                         break;
639                 case 'f':
640                 case 'F':
641                         if (store)
642                                 pf = va_arg(args, double *);
643
644                         if (!ignore) {
645                                 if (!(json_object_is_type(obj, json_type_double) || (c == 'F' && json_object_is_type(obj, json_type_int))))
646                                         goto missfit;
647                                 if (store && pf)
648                                         *pf = json_object_get_double(obj);
649                         }
650                         break;
651                 case 'o':
652                 case 'O':
653                         if (store) {
654                                 po = va_arg(args, struct json_object **);
655                                 if (!ignore && po) {
656                                         if (c == 'O')
657                                                 obj = json_object_get(obj);
658                                         *po = obj;
659                                 }
660                         }
661                         break;
662                 case 'y':
663                 case 'Y':
664                         if (store) {
665                                 py = va_arg(args, uint8_t **);
666                                 pz = va_arg(args, size_t *);
667                         }
668                         if (!ignore) {
669                                 if (obj == NULL) {
670                                         if (store && py && pz) {
671                                                 *py = NULL;
672                                                 *pz = 0;
673                                         }
674                                 } else {
675                                         if (!json_object_is_type(obj, json_type_string))
676                                                 goto missfit;
677                                         if (store && py && pz) {
678                                                 rc = decode_base64(
679                                                         json_object_get_string(obj),
680                                                         (size_t)json_object_get_string_len(obj),
681                                                         py, pz, c == 'y');
682                                                 if (rc)
683                                                         goto error;
684                                         }
685                                 }
686                         }
687                         break;
688
689                 case '[':
690                 case '{':
691                         if (!top)
692                                 top = stack;
693                         else if (++top  >= &stack[STACKCOUNT])
694                                 goto too_deep;
695
696                         top->acc = acc;
697                         top->type = xacc[0];
698                         top->index = 0;
699                         top->parent = obj;
700                         if (ignore)
701                                 ignore++;
702                         if (c == '[') {
703                                 if (!ignore) {
704                                         if (!json_object_is_type(obj, json_type_array))
705                                                 goto missfit;
706                                         top->count = (int)json_object_array_length(obj);
707                                 }
708                                 xacc[0] = ']';
709                                 acc = unpack_accept_arr;
710                         } else {
711                                 if (!ignore) {
712                                         if (!json_object_is_type(obj, json_type_object))
713                                                 goto missfit;
714                                         top->count = json_object_object_length(obj);
715                                 }
716                                 xacc[0] = '}';
717                                 acc = unpack_accept_key;
718                                 continue;
719                         }
720                         break;
721                 case '}':
722                 case ']':
723                         if (!top || c != xacc[0])
724                                 goto internal_error;
725                         acc = top->acc;
726                         xacc[0] = top->type;
727                         top = top == stack ? NULL : top - 1;
728                         if (ignore)
729                                 ignore--;
730                         break;
731                 case '!':
732                         if (*d != xacc[0])
733                                 goto invalid_character;
734                         if (!ignore && top->index != top->count)
735                                 goto incomplete;
736                         /*@fallthrough@*/
737                 case '*':
738                         acc = xacc;
739                         continue;
740                 default:
741                         goto internal_error;
742                 }
743                 switch (xacc[0]) {
744                 case 0:
745                         if (top)
746                                 goto internal_error;
747                         if (*d)
748                                 goto invalid_character;
749                         return 0;
750                 case ']':
751                         if (!ignore) {
752                                 key = strchr(unpack_accept_arr, *d);
753                                 if (key && key >= unpack_accept_any) {
754                                         if (top->index >= top->count)
755                                                 goto out_of_range;
756                                         obj = json_object_array_get_idx(top->parent, top->index++);
757                                 }
758                         }
759                         break;
760                 case ':':
761                         acc = unpack_accept_key;
762                         xacc[0] = '}';
763                         if (ignore)
764                                 ignore--;
765                         break;
766                 default:
767                         goto internal_error;
768                 }
769         }
770 truncated:
771         rc = wrap_json_error_truncated;
772         goto error;
773 internal_error:
774         rc = wrap_json_error_internal_error;
775         goto error;
776 invalid_character:
777         rc = wrap_json_error_invalid_character;
778         goto error;
779 too_deep:
780         rc = wrap_json_error_too_deep;
781         goto error;
782 null_spec:
783         rc = wrap_json_error_null_spec;
784         goto error;
785 null_key:
786         rc = wrap_json_error_null_key;
787         goto error;
788 out_of_range:
789         rc = wrap_json_error_out_of_range;
790         goto error;
791 incomplete:
792         rc = wrap_json_error_incomplete;
793         goto error;
794 missfit:
795         rc = wrap_json_error_missfit_type;
796         goto errorfit;
797 key_not_found:
798         rc = wrap_json_error_key_not_found;
799         goto error;
800 errorfit:
801         d = fit;
802 error:
803         rc = rc | (int)((d - desc) << 4);
804         return -rc;
805 }
806
807 int wrap_json_vcheck(struct json_object *object, const char *desc, va_list args)
808 {
809         return vunpack(object, desc, args, 0);
810 }
811
812 int wrap_json_check(struct json_object *object, const char *desc, ...)
813 {
814         int rc;
815         va_list args;
816
817         va_start(args, desc);
818         rc = vunpack(object, desc, args, 0);
819         va_end(args);
820         return rc;
821 }
822
823 int wrap_json_vmatch(struct json_object *object, const char *desc, va_list args)
824 {
825         return !vunpack(object, desc, args, 0);
826 }
827
828 int wrap_json_match(struct json_object *object, const char *desc, ...)
829 {
830         int rc;
831         va_list args;
832
833         va_start(args, desc);
834         rc = vunpack(object, desc, args, 0);
835         va_end(args);
836         return !rc;
837 }
838
839 int wrap_json_vunpack(struct json_object *object, const char *desc, va_list args)
840 {
841         return vunpack(object, desc, args, 1);
842 }
843
844 int wrap_json_unpack(struct json_object *object, const char *desc, ...)
845 {
846         int rc;
847         va_list args;
848
849         va_start(args, desc);
850         rc = vunpack(object, desc, args, 1);
851         va_end(args);
852         return rc;
853 }
854
855 static void object_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
856 {
857         struct json_object_iterator it = json_object_iter_begin(object);
858         struct json_object_iterator end = json_object_iter_end(object);
859         while (!json_object_iter_equal(&it, &end)) {
860                 callback(closure, json_object_iter_peek_value(&it), json_object_iter_peek_name(&it));
861                 json_object_iter_next(&it);
862         }
863 }
864
865 static void array_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
866 {
867         int n = (int)json_object_array_length(object);
868         int i = 0;
869         while(i < n)
870                 callback(closure, json_object_array_get_idx(object, i++));
871 }
872
873 void wrap_json_optarray_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
874 {
875         if (json_object_is_type(object, json_type_array))
876                 array_for_all(object, callback, closure);
877         else
878                 callback(closure, object);
879 }
880
881 void wrap_json_array_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
882 {
883         if (json_object_is_type(object, json_type_array))
884                 array_for_all(object, callback, closure);
885 }
886
887 void wrap_json_object_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
888 {
889         if (json_object_is_type(object, json_type_object))
890                 object_for_all(object, callback, closure);
891 }
892
893 void wrap_json_optobject_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
894 {
895         if (json_object_is_type(object, json_type_object))
896                 object_for_all(object, callback, closure);
897         else
898                 callback(closure, object, NULL);
899 }
900
901 void wrap_json_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
902 {
903         if (!object)
904                 /* do nothing */;
905         else if (json_object_is_type(object, json_type_object))
906                 object_for_all(object, callback, closure);
907         else if (!json_object_is_type(object, json_type_array))
908                 callback(closure, object, NULL);
909         else {
910                 int n = (int)json_object_array_length(object);
911                 int i = 0;
912                 while(i < n)
913                         callback(closure, json_object_array_get_idx(object, i++), NULL);
914         }
915 }
916
917 /**
918  * Clones the 'object' for the depth 'subdepth'. The object 'object' is
919  * duplicated and all its fields are cloned with the depth 'subdepth'.
920  *
921  * @param object the object to clone. MUST be an **object**.
922  * @param subdepth the depth to use when cloning the fields of the object.
923  *
924  * @return the cloned object.
925  */
926 static struct json_object *clone_object(struct json_object *object, int subdepth)
927 {
928         struct json_object *r = json_object_new_object();
929         struct json_object_iterator it = json_object_iter_begin(object);
930         struct json_object_iterator end = json_object_iter_end(object);
931         while (!json_object_iter_equal(&it, &end)) {
932                 json_object_object_add(r,
933                         json_object_iter_peek_name(&it),
934                         wrap_json_clone_depth(json_object_iter_peek_value(&it), subdepth));
935                 json_object_iter_next(&it);
936         }
937         return r;
938 }
939
940 /**
941  * Clones the 'array' for the depth 'subdepth'. The array 'array' is
942  * duplicated and all its fields are cloned with the depth 'subdepth'.
943  *
944  * @param array the array to clone. MUST be an **array**.
945  * @param subdepth the depth to use when cloning the items of the array.
946  *
947  * @return the cloned array.
948  */
949 static struct json_object *clone_array(struct json_object *array, int subdepth)
950 {
951         int n = (int)json_object_array_length(array);
952         struct json_object *r = json_object_new_array();
953         while (n) {
954                 n--;
955                 json_object_array_put_idx(r, n,
956                         wrap_json_clone_depth(json_object_array_get_idx(array, n), subdepth));
957         }
958         return r;
959 }
960
961 /**
962  * Clones any json 'item' for the depth 'depth'. The item is duplicated
963  * and if 'depth' is not zero, its contents is recursively cloned with
964  * the depth 'depth' - 1.
965  *
966  * Be aware that this implementation doesn't copies the primitive json
967  * items (numbers, nulls, booleans, strings) but instead increments their
968  * use count. This can cause issues with newer versions of libjson-c that
969  * now unfortunately allows to change their values.
970  *
971  * @param item the item to clone. Can be of any kind.
972  * @param depth the depth to use when cloning composites: object or arrays.
973  *
974  * @return the cloned array.
975  *
976  * @see wrap_json_clone
977  * @see wrap_json_clone_deep
978  */
979 struct json_object *wrap_json_clone_depth(struct json_object *item, int depth)
980 {
981         if (depth) {
982                 switch (json_object_get_type(item)) {
983                 case json_type_object:
984                         return clone_object(item, depth - 1);
985                 case json_type_array:
986                         return clone_array(item, depth - 1);
987                 default:
988                         break;
989                 }
990         }
991         return json_object_get(item);
992 }
993
994 /**
995  * Clones the 'object': returns a copy of it. But doen't clones
996  * the content. Synonym of wrap_json_clone_depth(object, 1).
997  *
998  * @param object the object to clone
999  *
1000  * @return a copy of the object.
1001  *
1002  * @see wrap_json_clone_depth
1003  * @see wrap_json_clone_deep
1004  */
1005 struct json_object *wrap_json_clone(struct json_object *object)
1006 {
1007         return wrap_json_clone_depth(object, 1);
1008 }
1009
1010 /**
1011  * Clones the 'object': returns a copy of it. Also clones all
1012  * the content recursively. Synonym of wrap_json_clone_depth(object, INT_MAX).
1013  *
1014  * @param object the object to clone
1015  *
1016  * @return a copy of the object.
1017  *
1018  * @see wrap_json_clone_depth
1019  * @see wrap_json_clone
1020  */
1021 struct json_object *wrap_json_clone_deep(struct json_object *object)
1022 {
1023         return wrap_json_clone_depth(object, INT_MAX);
1024 }
1025
1026 /**
1027  * Adds the items of the object 'added' to the object 'dest'.
1028  *
1029  * @param dest the object to complete this object is modified
1030  * @added the object containing fields to add
1031  *
1032  * @return the destination object 'dest'
1033  *
1034  * @example wrap_json_object_add({"a":"a"},{"X":"X"}) -> {"a":"a","X":"X"}
1035  */
1036 struct json_object *wrap_json_object_add(struct json_object *dest, struct json_object *added)
1037 {
1038         struct json_object_iterator it, end;
1039         if (json_object_is_type(dest, json_type_object) && json_object_is_type(added, json_type_object)) {
1040                 it = json_object_iter_begin(added);
1041                 end = json_object_iter_end(added);
1042                 while (!json_object_iter_equal(&it, &end)) {
1043                         json_object_object_add(dest,
1044                                 json_object_iter_peek_name(&it),
1045                                 json_object_get(json_object_iter_peek_value(&it)));
1046                         json_object_iter_next(&it);
1047                 }
1048         }
1049         return dest;
1050 }
1051
1052 /**
1053  * Sort the 'array' and returns it. Sorting is done accordingly to the
1054  * order given by the function 'wrap_json_cmp'. If the paramater isn't
1055  * an array, nothing is done and the parameter is returned unchanged.
1056  *
1057  * @param array the array to sort
1058  *
1059  * @returns the array sorted
1060  */
1061 struct json_object *wrap_json_sort(struct json_object *array)
1062 {
1063         if (json_object_is_type(array, json_type_array))
1064                 json_object_array_sort(array, (int(*)(const void*, const void*))wrap_json_cmp);
1065
1066         return array;
1067 }
1068
1069 /**
1070  * Returns a json array of the sorted keys of 'object' or null if 'object' has no keys.
1071  *
1072  * @param object the object whose keys are to be returned
1073  *
1074  * @return either NULL is 'object' isn't an object or a sorted array of the key's strings.
1075  */
1076 struct json_object *wrap_json_keys(struct json_object *object)
1077 {
1078         struct json_object *r;
1079         struct json_object_iterator it, end;
1080         if (!json_object_is_type(object, json_type_object))
1081                 r = NULL;
1082         else {
1083                 r = json_object_new_array();
1084                 it = json_object_iter_begin(object);
1085                 end = json_object_iter_end(object);
1086                 while (!json_object_iter_equal(&it, &end)) {
1087                         json_object_array_add(r, json_object_new_string(json_object_iter_peek_name(&it)));
1088                         json_object_iter_next(&it);
1089                 }
1090                 wrap_json_sort(r);
1091         }
1092         return r;
1093 }
1094
1095 /**
1096  * Internal comparison of 'x' with 'y'
1097  *
1098  * @param x first object to compare
1099  * @param y second object to compare
1100  * @param inc boolean true if should test for inclusion of y in x
1101  * @param sort boolean true if comparison used for sorting
1102  *
1103  * @return an integer indicating the computed result. Refer to
1104  * the table below for meaning of the returned value.
1105  *
1106  * inc | sort |  x < y  |  x == y  |  x > y  |  y in x
1107  * ----+------+---------+----------+---------+---------
1108  *  0  |  0   |  != 0   |     0    |  != 0   |   > 0
1109  *  0  |  1   |   < 0   |     0    |   > 0   |   > 0
1110  *  1  |  0   |  != 0   |     0    |  != 0   |    0
1111  *  1  |  1   |   < 0   |     0    |   > 0   |    0
1112  *
1113  *
1114  * if 'x' is found, respectively, to be less  than,  to match,
1115  * or be greater than 'y'. This is valid when 'sort'
1116  */
1117 static int jcmp(struct json_object *x, struct json_object *y, int inc, int sort)
1118 {
1119         double dx, dy;
1120         int64_t ix, iy;
1121         const char *sx, *sy;
1122         enum json_type tx, ty;
1123         int r, nx, ny, i;
1124         struct json_object_iterator it, end;
1125         struct json_object *jx, *jy;
1126
1127         /* check equality of pointers */
1128         if (x == y)
1129                 return 0;
1130
1131         /* get the types */
1132         tx = json_object_get_type(x);
1133         ty = json_object_get_type(y);
1134         r = (int)tx - (int)ty;
1135         if (r)
1136                 return r;
1137
1138         /* compare following the type */
1139         switch (tx) {
1140         default:
1141         case json_type_null:
1142                 break;
1143
1144         case json_type_boolean:
1145                 r = (int)json_object_get_boolean(x)
1146                         - (int)json_object_get_boolean(y);
1147                 break;
1148
1149         case json_type_double:
1150                 dx = json_object_get_double(x);
1151                 dy = json_object_get_double(y);
1152                 r =  dx < dy ? -1 : dx > dy;
1153                 break;
1154
1155         case json_type_int:
1156                 ix = json_object_get_int64(x);
1157                 iy = json_object_get_int64(y);
1158                 r = ix < iy ? -1 : ix > iy;
1159                 break;
1160
1161         case json_type_object:
1162                 it = json_object_iter_begin(y);
1163                 end = json_object_iter_end(y);
1164                 nx = json_object_object_length(x);
1165                 ny = json_object_object_length(y);
1166                 r = nx - ny;
1167                 if (r > 0 && inc)
1168                         r = 0;
1169                 while (!r && !json_object_iter_equal(&it, &end)) {
1170                         if (json_object_object_get_ex(x, json_object_iter_peek_name(&it), &jx)) {
1171                                 jy = json_object_iter_peek_value(&it);
1172                                 json_object_iter_next(&it);
1173                                 r = jcmp(jx, jy, inc, sort);
1174                         } else if (sort) {
1175                                 jx = wrap_json_keys(x);
1176                                 jy = wrap_json_keys(y);
1177                                 r = wrap_json_cmp(jx, jy);
1178                                 json_object_put(jx);
1179                                 json_object_put(jy);
1180                         } else
1181                                 r = 1;
1182                 }
1183                 break;
1184
1185         case json_type_array:
1186                 nx = (int)json_object_array_length(x);
1187                 ny = (int)json_object_array_length(y);
1188                 r = nx - ny;
1189                 if (r > 0 && inc)
1190                         r = 0;
1191                 for (i = 0 ; !r && i < ny ; i++) {
1192                         jx = json_object_array_get_idx(x, i);
1193                         jy = json_object_array_get_idx(y, i);
1194                         r = jcmp(jx, jy, inc, sort);
1195                 }
1196                 break;
1197
1198         case json_type_string:
1199                 sx = json_object_get_string(x);
1200                 sy = json_object_get_string(y);
1201                 r = strcmp(sx, sy);
1202                 break;
1203         }
1204         return r;
1205 }
1206
1207 /**
1208  * Compares 'x' with 'y'
1209  *
1210  * @param x first object to compare
1211  * @param y second object to compare
1212  *
1213  * @return an integer less than, equal to, or greater than zero
1214  * if 'x' is found, respectively, to be less than, to match,
1215  * or be greater than 'y'.
1216  */
1217 int wrap_json_cmp(struct json_object *x, struct json_object *y)
1218 {
1219         return jcmp(x, y, 0, 1);
1220 }
1221
1222 /**
1223  * Searchs wether 'x' equals 'y'
1224  *
1225  * @param x first object to compare
1226  * @param y second object to compare
1227  *
1228  * @return an integer equal to zero when 'x' != 'y' or 1 when 'x' == 'y'.
1229  */
1230 int wrap_json_equal(struct json_object *x, struct json_object *y)
1231 {
1232         return !jcmp(x, y, 0, 0);
1233 }
1234
1235 /**
1236  * Searchs wether 'x' contains 'y'
1237  *
1238  * @param x first object to compare
1239  * @param y second object to compare
1240  *
1241  * @return an integer equal to 1 when 'y' is a subset of 'x' or zero otherwise
1242  */
1243 int wrap_json_contains(struct json_object *x, struct json_object *y)
1244 {
1245         return !jcmp(x, y, 1, 0);
1246 }
1247
1248 #if defined(WRAP_JSON_TEST)
1249 #include <stdio.h>
1250
1251 void tclone(struct json_object *object)
1252 {
1253         struct json_object *o;
1254
1255         o = wrap_json_clone(object);
1256         if (!wrap_json_equal(object, o))
1257                 printf("ERROR in clone or equal: %s VERSUS %s\n", json_object_to_json_string(object), json_object_to_json_string(o));
1258         json_object_put(o);
1259
1260         o = wrap_json_clone_deep(object);
1261         if (!wrap_json_equal(object, o))
1262                 printf("ERROR in clone_deep or equal: %s VERSUS %s\n", json_object_to_json_string(object), json_object_to_json_string(o));
1263         json_object_put(o);
1264 }
1265
1266 void p(const char *desc, ...)
1267 {
1268         int rc;
1269         va_list args;
1270         struct json_object *result;
1271
1272         va_start(args, desc);
1273         rc = wrap_json_vpack(&result, desc, args);
1274         va_end(args);
1275         if (!rc)
1276                 printf("  SUCCESS %s\n\n", json_object_to_json_string(result));
1277         else
1278                 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));
1279         tclone(result);
1280         json_object_put(result);
1281 }
1282
1283 const char *xs[10];
1284 int *xi[10];
1285 int64_t *xI[10];
1286 double *xf[10];
1287 struct json_object *xo[10];
1288 size_t xz[10];
1289 uint8_t *xy[10];
1290
1291 void u(const char *value, const char *desc, ...)
1292 {
1293         unsigned m, k;
1294         int rc;
1295         va_list args;
1296         struct json_object *object, *o;
1297
1298         memset(xs, 0, sizeof xs);
1299         memset(xi, 0, sizeof xi);
1300         memset(xI, 0, sizeof xI);
1301         memset(xf, 0, sizeof xf);
1302         memset(xo, 0, sizeof xo);
1303         memset(xy, 0, sizeof xy);
1304         memset(xz, 0, sizeof xz);
1305         object = json_tokener_parse(value);
1306         va_start(args, desc);
1307         rc = wrap_json_vunpack(object, desc, args);
1308         va_end(args);
1309         if (rc)
1310                 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));
1311         else {
1312                 value = NULL;
1313                 printf("  SUCCESS");
1314                 va_start(args, desc);
1315                 k = m = 0;
1316                 while(*desc) {
1317                         switch(*desc) {
1318                         case '{': m = (m << 1) | 1; k = 1; break;
1319                         case '}': m = m >> 1; k = m&1; break;
1320                         case '[': m = m << 1; k = 0; break;
1321                         case ']': m = m >> 1; k = m&1; break;
1322                         case 's': printf(" s:%s", k ? va_arg(args, const char*) : *(va_arg(args, const char**)?:&value)); k ^= m&1; break;
1323                         case '%': printf(" %%:%zu", *va_arg(args, size_t*)); k = m&1; break;
1324                         case 'n': printf(" n"); k = m&1; break;
1325                         case 'b': printf(" b:%d", *va_arg(args, int*)); k = m&1; break;
1326                         case 'i': printf(" i:%d", *va_arg(args, int*)); k = m&1; break;
1327                         case 'I': printf(" I:%lld", *va_arg(args, int64_t*)); k = m&1; break;
1328                         case 'f': printf(" f:%f", *va_arg(args, double*)); k = m&1; break;
1329                         case 'F': printf(" F:%f", *va_arg(args, double*)); k = m&1; break;
1330                         case 'o': printf(" o:%s", json_object_to_json_string(*va_arg(args, struct json_object**))); k = m&1; break;
1331                         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;
1332                         case 'y':
1333                         case 'Y': {
1334                                 uint8_t *p = *va_arg(args, uint8_t**);
1335                                 size_t s = *va_arg(args, size_t*);
1336                                 printf(" y/%d:%.*s", (int)s, (int)s, (char*)p);
1337                                 k ^= m&1;
1338                                 break;
1339                                 }
1340                         default: break;
1341                         }
1342                         desc++;
1343                 }
1344                 va_end(args);
1345                 printf("\n\n");
1346         }
1347         tclone(object);
1348         json_object_put(object);
1349 }
1350
1351 void c(const char *sx, const char *sy, int e, int c)
1352 {
1353         int re, rc;
1354         struct json_object *jx, *jy;
1355
1356         jx = json_tokener_parse(sx);
1357         jy = json_tokener_parse(sy);
1358
1359         re = wrap_json_cmp(jx, jy);
1360         rc = wrap_json_contains(jx, jy);
1361
1362         printf("compare(%s)(%s)\n", sx, sy);
1363         printf("   -> %d / %d\n", re, rc);
1364
1365         if (!re != !!e)
1366                 printf("  ERROR should be %s\n", e ? "equal" : "different");
1367         if (!rc != !c)
1368                 printf("  ERROR should %scontain\n", c ? "" : "not ");
1369
1370         printf("\n");
1371 }
1372
1373 #define P(...) do{ printf("pack(%s)\n",#__VA_ARGS__); p(__VA_ARGS__); } while(0)
1374 #define U(...) do{ printf("unpack(%s)\n",#__VA_ARGS__); u(__VA_ARGS__); } while(0)
1375
1376 int main()
1377 {
1378         char buffer[4] = {'t', 'e', 's', 't'};
1379
1380         P("n");
1381         P("b", 1);
1382         P("b", 0);
1383         P("i", 1);
1384         P("I", (uint64_t)0x123456789abcdef);
1385         P("f", 3.14);
1386         P("s", "test");
1387         P("s?", "test");
1388         P("s?", NULL);
1389         P("s#", "test asdf", 4);
1390         P("s%", "test asdf", (size_t)4);
1391         P("s#", buffer, 4);
1392         P("s%", buffer, (size_t)4);
1393         P("s++", "te", "st", "ing");
1394         P("s#+#+", "test", 1, "test", 2, "test");
1395         P("s%+%+", "test", (size_t)1, "test", (size_t)2, "test");
1396         P("{}", 1.0);
1397         P("[]", 1.0);
1398         P("o", json_object_new_int(1));
1399         P("o?", json_object_new_int(1));
1400         P("o?", NULL);
1401         P("O", json_object_new_int(1));
1402         P("O?", json_object_new_int(1));
1403         P("O?", NULL);
1404         P("{s:[]}", "foo");
1405         P("{s+#+: []}", "foo", "barbar", 3, "baz");
1406         P("{s:s,s:o,s:O}", "a", NULL, "b", NULL, "c", NULL);
1407         P("{s:**}", "a", NULL);
1408         P("{s:s*,s:o*,s:O*}", "a", NULL, "b", NULL, "c", NULL);
1409         P("[i,i,i]", 0, 1, 2);
1410         P("[s,o,O]", NULL, NULL, NULL);
1411         P("[**]", NULL);
1412         P("[s*,o*,O*]", NULL, NULL, NULL);
1413         P(" s ", "test");
1414         P("[ ]");
1415         P("[ i , i,  i ] ", 1, 2, 3);
1416         P("{\n\n1");
1417         P("[}");
1418         P("{]");
1419         P("[");
1420         P("{");
1421         P("[i]a", 42);
1422         P("ia", 42);
1423         P("s", NULL);
1424         P("+", NULL);
1425         P(NULL);
1426         P("{s:i}", NULL, 1);
1427         P("{ {}: s }", "foo");
1428         P("{ s: {},  s:[ii{} }", "foo", "bar", 12, 13);
1429         P("[[[[[   [[[[[  [[[[ }]]]] ]]]] ]]]]]");
1430         P("y", "???????hello>>>>>>>", (size_t)19);
1431         P("Y", "???????hello>>>>>>>", (size_t)19);
1432         P("{sy?}", "foo", "hi", (size_t)2);
1433         P("{sy?}", "foo", NULL, 0);
1434         P("{sy*}", "foo", "hi", (size_t)2);
1435         P("{sy*}", "foo", NULL, 0);
1436
1437         U("true", "b", &xi[0]);
1438         U("false", "b", &xi[0]);
1439         U("null", "n");
1440         U("42", "i", &xi[0]);
1441         U("123456789", "I", &xI[0]);
1442         U("3.14", "f", &xf[0]);
1443         U("12345", "F", &xf[0]);
1444         U("3.14", "F", &xf[0]);
1445         U("\"foo\"", "s", &xs[0]);
1446         U("\"foo\"", "s%", &xs[0], &xz[0]);
1447         U("{}", "{}");
1448         U("[]", "[]");
1449         U("{}", "o", &xo[0]);
1450         U("{}", "O", &xo[0]);
1451         U("{\"foo\":42}", "{si}", "foo", &xi[0]);
1452         U("[1,2,3]", "[i,i,i]", &xi[0], &xi[1], &xi[2]);
1453         U("{\"a\":1,\"b\":2,\"c\":3}", "{s:i, s:i, s:i}", "a", &xi[0], "b", &xi[1], "c", &xi[2]);
1454         U("42", "z");
1455         U("null", "[i]");
1456         U("[]", "[}");
1457         U("{}", "{]");
1458         U("[]", "[");
1459         U("{}", "{");
1460         U("[42]", "[i]a", &xi[0]);
1461         U("42", "ia", &xi[0]);
1462         U("[]", NULL);
1463         U("\"foo\"", "s", NULL);
1464         U("42", "s", NULL);
1465         U("42", "n");
1466         U("42", "b", NULL);
1467         U("42", "f", NULL);
1468         U("42", "[i]", NULL);
1469         U("42", "{si}", "foo", NULL);
1470         U("\"foo\"", "n");
1471         U("\"foo\"", "b", NULL);
1472         U("\"foo\"", "i", NULL);
1473         U("\"foo\"", "I", NULL);
1474         U("\"foo\"", "f", NULL);
1475         U("\"foo\"", "F", NULL);
1476         U("true", "s", NULL);
1477         U("true", "n");
1478         U("true", "i", NULL);
1479         U("true", "I", NULL);
1480         U("true", "f", NULL);
1481         U("true", "F", NULL);
1482         U("[42]", "[ii]", &xi[0], &xi[1]);
1483         U("{\"foo\":42}", "{si}", NULL, &xi[0]);
1484         U("{\"foo\":42}", "{si}", "baz", &xi[0]);
1485         U("[1,2,3]", "[iii!]", &xi[0], &xi[1], &xi[2]);
1486         U("[1,2,3]", "[ii!]", &xi[0], &xi[1]);
1487         U("[1,2,3]", "[ii]", &xi[0], &xi[1]);
1488         U("[1,2,3]", "[ii*]", &xi[0], &xi[1]);
1489         U("{\"foo\":42,\"baz\":45}", "{sisi}", "baz", &xi[0], "foo", &xi[1]);
1490         U("{\"foo\":42,\"baz\":45}", "{sisi*}", "baz", &xi[0], "foo", &xi[1]);
1491         U("{\"foo\":42,\"baz\":45}", "{sisi!}", "baz", &xi[0], "foo", &xi[1]);
1492         U("{\"foo\":42,\"baz\":45}", "{si}", "baz", &xi[0], "foo", &xi[1]);
1493         U("{\"foo\":42,\"baz\":45}", "{si*}", "baz", &xi[0], "foo", &xi[1]);
1494         U("{\"foo\":42,\"baz\":45}", "{si!}", "baz", &xi[0], "foo", &xi[1]);
1495         U("[1,{\"foo\":2,\"bar\":null},[3,4]]", "[i{sisn}[ii]]", &xi[0], "foo", &xi[1], "bar", &xi[2], &xi[3]);
1496         U("[1,2,3]", "[ii!i]", &xi[0], &xi[1], &xi[2]);
1497         U("[1,2,3]", "[ii*i]", &xi[0], &xi[1], &xi[2]);
1498         U("{\"foo\":1,\"bar\":2}", "{si!si}", "foo", &xi[1], "bar", &xi[2]);
1499         U("{\"foo\":1,\"bar\":2}", "{si*si}", "foo", &xi[1], "bar", &xi[2]);
1500         U("{\"foo\":{\"baz\":null,\"bar\":null}}", "{s{sn!}}", "foo", "bar");
1501         U("[[1,2,3]]", "[[ii!]]", &xi[0], &xi[1]);
1502         U("{}", "{s?i}", "foo", &xi[0]);
1503         U("{\"foo\":1}", "{s?i}", "foo", &xi[0]);
1504         U("{}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
1505         U("{\"foo\":[1,2]}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
1506         U("{\"bar\":{\"baz\":{\"quux\":15}}}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
1507         U("{\"foo\":{\"bar\":4}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
1508         U("{\"foo\":{}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
1509         U("{}", "{s?{s?i}}", "foo", "bar", &xi[0]);
1510         U("{\"foo\":42,\"baz\":45}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
1511         U("{\"foo\":42}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
1512
1513         U("\"Pz8_Pz8_P2hlbGxvPj4-Pj4-Pg\"", "y", &xy[0], &xz[0]);
1514         U("\"\"", "y", &xy[0], &xz[0]);
1515         U("null", "y", &xy[0], &xz[0]);
1516         U("{\"foo\":\"Pz8_Pz8_P2hlbGxvPj4-Pj4-Pg\"}", "{s?y}", "foo", &xy[0], &xz[0]);
1517         U("{\"foo\":\"\"}", "{s?y}", "foo", &xy[0], &xz[0]);
1518         U("{}", "{s?y}", "foo", &xy[0], &xz[0]);
1519
1520         c("null", "null", 1, 1);
1521         c("true", "true", 1, 1);
1522         c("false", "false", 1, 1);
1523         c("1", "1", 1, 1);
1524         c("1.0", "1.0", 1, 1);
1525         c("\"\"", "\"\"", 1, 1);
1526         c("\"hi\"", "\"hi\"", 1, 1);
1527         c("{}", "{}", 1, 1);
1528         c("{\"a\":true,\"b\":false}", "{\"b\":false,\"a\":true}", 1, 1);
1529         c("[]", "[]", 1, 1);
1530         c("[1,true,null]", "[1,true,null]", 1, 1);
1531
1532         c("null", "true", 0, 0);
1533         c("null", "false", 0, 0);
1534         c("0", "1", 0, 0);
1535         c("1", "0", 0, 0);
1536         c("0", "true", 0, 0);
1537         c("0", "false", 0, 0);
1538         c("0", "null", 0, 0);
1539
1540         c("\"hi\"", "\"hello\"", 0, 0);
1541         c("\"hello\"", "\"hi\"", 0, 0);
1542
1543         c("{}", "null", 0, 0);
1544         c("{}", "true", 0, 0);
1545         c("{}", "1", 0, 0);
1546         c("{}", "1.0", 0, 0);
1547         c("{}", "[]", 0, 0);
1548         c("{}", "\"x\"", 0, 0);
1549
1550         c("[1,true,null]", "[1,true]", 0, 1);
1551         c("{\"a\":true,\"b\":false}", "{\"a\":true}", 0, 1);
1552         c("{\"a\":true,\"b\":false}", "{\"a\":true,\"c\":false}", 0, 0);
1553         c("{\"a\":true,\"c\":false}", "{\"a\":true,\"b\":false}", 0, 0);
1554         return 0;
1555 }
1556
1557 #endif
1558
1559 #if 0
1560
1561
1562     /* Unpack the same item twice */
1563     j = json_pack("{s:s, s:i, s:b}", "foo", "bar", "baz", 42, "quux", 1);
1564     if(!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s))
1565         fail("json_unpack object with strict validation failed");
1566     {
1567         const char *possible_errors[] = {
1568             "2 object item(s) left unpacked: baz, quux",
1569             "2 object item(s) left unpacked: quux, baz"
1570         };
1571         check_errors(possible_errors, 2, "<validation>", 1, 10, 10);
1572     }
1573     json_decref(j);
1574
1575 #endif