wrap-json: add unpacking tool for json
[src/app-framework-binder.git] / src / wrap-json.c
1 /*
2  Copyright (C) 2016, 2017 "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_count_
43 };
44
45 static const char ignore_all[] = " \t\n\r,:";
46 static const char pack_accept_arr[] = "][{snbiIfoO";
47 static const char pack_accept_key[] = "s}";
48 #define pack_accept_any (&pack_accept_arr[1])
49
50 static const char unpack_accept_arr[] = "*!][{snbiIfFoO";
51 static const char unpack_accept_key[] = "*!s}";
52 #define unpack_accept_any (&unpack_accept_arr[3])
53
54 static const char *pack_errors[_wrap_json_error_count_] =
55 {
56         [wrap_json_error_none] = "unknown error",
57         [wrap_json_error_null_object] = "null object",
58         [wrap_json_error_truncated] = "truncated",
59         [wrap_json_error_internal_error] = "internal error",
60         [wrap_json_error_out_of_memory] = "out of memory",
61         [wrap_json_error_invalid_character] = "invalid character",
62         [wrap_json_error_too_long] = "too long",
63         [wrap_json_error_too_deep] = "too deep",
64         [wrap_json_error_null_spec] = "spec is NULL",
65         [wrap_json_error_null_key] = "key is NULL",
66         [wrap_json_error_null_string] = "string is NULL",
67         [wrap_json_error_out_of_range] = "array too small",
68         [wrap_json_error_incomplete] = "incomplete container",
69         [wrap_json_error_missfit_type] = "missfit of type",
70         [wrap_json_error_key_not_found] = "key not found"
71 };
72
73 int wrap_json_get_error_position(int rc)
74 {
75         if (rc < 0)
76                 rc = -rc;
77         return (rc >> 4) + 1;
78 }
79
80 int wrap_json_get_error_code(int rc)
81 {
82         if (rc < 0)
83                 rc = -rc;
84         return rc & 15;
85 }
86
87 const char *wrap_json_get_error_string(int rc)
88 {
89         rc = wrap_json_get_error_code(rc);
90         if (rc >= sizeof pack_errors / sizeof *pack_errors)
91                 rc = 0;
92         return pack_errors[rc];
93 }
94
95
96
97 static inline const char *skip(const char *d)
98 {
99         while (*d && strchr(ignore_all, *d))
100                 d++;
101         return d;
102 }
103
104 int wrap_json_vpack(struct json_object **result, const char *desc, va_list args)
105 {
106         /* TODO: the case of structs with key being single char should be optimized */
107         int nstr, notnull, nullable, rc;
108         size_t sz, dsz, ssz;
109         char *s;
110         char c;
111         const char *d;
112         char buffer[256];
113         struct { const char *str; size_t sz; } strs[STRCOUNT];
114         struct { struct json_object *cont, *key; const char *acc; char type; } stack[STACKCOUNT], *top;
115         struct json_object *obj;
116
117         ssz = sizeof buffer;
118         s = buffer;
119         top = stack;
120         top->key = NULL;
121         top->cont = NULL;
122         top->acc = pack_accept_any;
123         top->type = 0;
124         if (!desc)
125                 goto null_spec;
126         d = skip(desc);
127         for(;;) {
128                 c = *d;
129                 if (!c)
130                         goto truncated;
131                 if (!strchr(top->acc, c))
132                         goto invalid_character;
133                 d = skip(++d);
134                 switch(c) {
135                 case 's':
136                         nullable = 0;
137                         notnull = 0;
138                         nstr = 0;
139                         sz = 0;
140                         for (;;) {
141                                 strs[nstr].str = va_arg(args, const char*);
142                                 if (strs[nstr].str)
143                                         notnull = 1;
144                                 if (*d == '?') {
145                                         d = skip(++d);
146                                         nullable = 1;
147                                 }
148                                 switch(*d) {
149                                 case '%': strs[nstr].sz = va_arg(args, size_t); d = skip(++d); break;
150                                 case '#': strs[nstr].sz = (size_t)va_arg(args, int); d = skip(++d); break;
151                                 default: strs[nstr].sz = strs[nstr].str ? strlen(strs[nstr].str) : 0; break;
152                                 }
153                                 sz += strs[nstr++].sz;
154                                 if (*d == '?') {
155                                         d = skip(++d);
156                                         nullable = 1;
157                                 }
158                                 if (*d != '+')
159                                         break;
160                                 if (nstr >= STRCOUNT)
161                                         goto too_long;
162                                 d = skip(++d);
163                         }
164                         if (*d == '*')
165                                 nullable = 1;
166                         if (notnull) {
167                                 if (sz > ssz) {
168                                         ssz += ssz;
169                                         if (ssz < sz)
170                                                 ssz = sz;
171                                         s = alloca(sz);
172                                 }
173                                 dsz = sz;
174                                 while (nstr) {
175                                         nstr--;
176                                         dsz -= strs[nstr].sz;
177                                         memcpy(&s[dsz], strs[nstr].str, strs[nstr].sz);
178                                 }
179                                 obj = json_object_new_string_len(s, (int)sz);
180                                 if (!obj)
181                                         goto out_of_memory;
182                         } else if (nullable)
183                                 obj = NULL;
184                         else
185                                 goto null_string;
186                         break;
187                 case 'n':
188                         obj = NULL;
189                         break;
190                 case 'b':
191                         obj = json_object_new_boolean(va_arg(args, int));
192                         if (!obj)
193                                 goto out_of_memory;
194                         break;
195                 case 'i':
196                         obj = json_object_new_int(va_arg(args, int));
197                         if (!obj)
198                                 goto out_of_memory;
199                         break;
200                 case 'I':
201                         obj = json_object_new_int64(va_arg(args, int64_t));
202                         if (!obj)
203                                 goto out_of_memory;
204                         break;
205                 case 'f':
206                         obj = json_object_new_double(va_arg(args, double));
207                         if (!obj)
208                                 goto out_of_memory;
209                         break;
210                 case 'o':
211                 case 'O':
212                         obj = va_arg(args, struct json_object*);
213                         if (*d == '?')
214                                 d = skip(++d);
215                         else if (*d != '*' && !obj)
216                                 goto null_object;
217                         if (c == 'O')
218                                 json_object_get(obj);
219                         break;
220                 case '[':
221                 case '{':
222                         if (++top >= &stack[STACKCOUNT])
223                                 goto too_deep;
224                         top->key = NULL;
225                         if (c == '[') {
226                                 top->type = ']';
227                                 top->acc = pack_accept_arr;
228                                 top->cont = json_object_new_array();
229                         } else {
230                                 top->type = '}';
231                                 top->acc = pack_accept_key;
232                                 top->cont = json_object_new_object();
233                         }
234                         if (!top->cont)
235                                 goto out_of_memory;
236                         continue;
237                 case '}':
238                 case ']':
239                         if (c != top->type || top <= stack)
240                                 goto internal_error;
241                         obj = (top--)->cont;
242                         if (*d == '*' && !(c == '}' ? json_object_object_length(obj) : json_object_array_length(obj))) {
243                                 json_object_put(obj);
244                                 obj = NULL;
245                         }
246                         break;
247                 default:
248                         goto internal_error;
249                 }
250                 switch (top->type) {
251                 case 0:
252                         if (top != stack)
253                                 goto internal_error;
254                         if (*d)
255                                 goto invalid_character;
256                         *result = obj;
257                         return 0;
258                 case ']':
259                         if (obj || *d != '*')
260                                 json_object_array_add(top->cont, obj);
261                         if (*d == '*')
262                                 d = skip(++d);
263                         break;
264                 case '}':
265                         if (!obj)
266                                 goto null_key;
267                         top->key = obj;
268                         top->acc = pack_accept_any;
269                         top->type = ':';
270                         break;
271                 case ':':
272                         if (obj || *d != '*')
273                                 json_object_object_add(top->cont, json_object_get_string(top->key), obj);
274                         if (*d == '*')
275                                 d = skip(++d);
276                         json_object_put(top->key);
277                         top->key = NULL;
278                         top->acc = pack_accept_key;
279                         top->type = '}';
280                         break;
281                 default:
282                         goto internal_error;
283                 }
284         }
285
286 null_object:
287         rc = wrap_json_error_null_object;
288         goto error;
289 truncated:
290         rc = wrap_json_error_truncated;
291         goto error;
292 internal_error:
293         rc = wrap_json_error_internal_error;
294         goto error;
295 out_of_memory:
296         rc = wrap_json_error_out_of_memory;
297         goto error;
298 invalid_character:
299         rc = wrap_json_error_invalid_character;
300         goto error;
301 too_long:
302         rc = wrap_json_error_too_long;
303         goto error;
304 too_deep:
305         rc = wrap_json_error_too_deep;
306         goto error;
307 null_spec:
308         rc = wrap_json_error_null_spec;
309         goto error;
310 null_key:
311         rc = wrap_json_error_null_key;
312         goto error;
313 null_string:
314         rc = wrap_json_error_null_string;
315         goto error;
316 error:
317         do {
318                 json_object_put(top->key);
319                 json_object_put(top->cont);
320         } while (--top >= stack);
321         *result = NULL;
322         rc = rc | (int)((d - desc) << 4);
323         return -rc;
324 }
325
326 int wrap_json_pack(struct json_object **result, const char *desc, ...)
327 {
328         int rc;
329         va_list args;
330
331         va_start(args, desc);
332         rc = wrap_json_vpack(result, desc, args);
333         va_end(args);
334         return rc;
335 }
336
337 static int vunpack(struct json_object *object, const char *desc, va_list args, int store)
338 {
339         int rc, optionnal, ignore;
340         char c, xacc[2] = { 0, 0 };
341         const char *acc;
342         const char *d, *fit;
343         const char *key;
344         const char **ps;
345         double *pf;
346         int *pi;
347         int64_t *pI;
348         size_t *pz;
349         struct { struct json_object *parent; const char *acc; int index, count; char type; } stack[STACKCOUNT], *top;
350         struct json_object *obj;
351         struct json_object **po;
352
353         xacc[0] = 0;
354         ignore = 0;
355         top = NULL;
356         acc = unpack_accept_any;
357         if (!desc)
358                 goto null_spec;
359         d = skip(desc);
360         obj = object;
361         for(;;) {
362                 fit = d;
363                 c = *d;
364                 if (!c)
365                         goto truncated;
366                 if (!strchr(acc, c))
367                         goto invalid_character;
368                 d = skip(++d);
369                 switch(c) {
370                 case 's':
371                         if (xacc[0] == '}') {
372                                 /* expects a key */
373                                 key = va_arg(args, const char *);
374                                 if (!key)
375                                         goto null_key;
376                                 if (*d != '?')
377                                         optionnal = 0;
378                                 else {
379                                         optionnal = 1;
380                                         d = skip(++d);
381                                 }
382                                 if (ignore)
383                                         ignore++;
384                                 else {
385                                         if (json_object_object_get_ex(top->parent, key, &obj)) {
386                                                 /* found */
387                                                 top->index++;
388                                         } else {
389                                                 /* not found */
390                                                 if (!optionnal)
391                                                         goto key_not_found;
392                                                 ignore = 1;
393                                                 obj = NULL;
394                                         }
395                                 }
396                                 xacc[0] = ':';
397                                 acc = unpack_accept_any;
398                                 continue;
399                         }
400                         /* get a string */
401                         if (store)
402                                 ps = va_arg(args, const char **);
403                         if (!ignore) {
404                                 if (!json_object_is_type(obj, json_type_string))
405                                         goto missfit;
406                                 if (store && ps)
407                                         *ps = json_object_get_string(obj);
408                         }
409                         if (*d == '%') {
410                                 d = skip(++d);
411                                 if (store) {
412                                         pz = va_arg(args, size_t *);
413                                         if (!ignore && pz)
414                                                 *pz = (size_t)json_object_get_string_len(obj);
415                                 }
416                         }
417                         break;
418                 case 'n':
419                         if (!ignore && !json_object_is_type(obj, json_type_null))
420                                 goto missfit;
421                         break;
422                 case 'b':
423                         if (store)
424                                 pi = va_arg(args, int *);
425
426                         if (!ignore) {
427                                 if (!json_object_is_type(obj, json_type_boolean))
428                                         goto missfit;
429                                 if (store && pi)
430                                         *pi = json_object_get_boolean(obj);
431                         }
432                         break;
433                 case 'i':
434                         if (store)
435                                 pi = va_arg(args, int *);
436
437                         if (!ignore) {
438                                 if (!json_object_is_type(obj, json_type_int))
439                                         goto missfit;
440                                 if (store && pi)
441                                         *pi = json_object_get_int(obj);
442                         }
443                         break;
444                 case 'I':
445                         if (store)
446                                 pI = va_arg(args, int64_t *);
447
448                         if (!ignore) {
449                                 if (!json_object_is_type(obj, json_type_int))
450                                         goto missfit;
451                                 if (store && pI)
452                                         *pI = json_object_get_int64(obj);
453                         }
454                         break;
455                 case 'f':
456                 case 'F':
457                         if (store)
458                                 pf = va_arg(args, double *);
459
460                         if (!ignore) {
461                                 if (!(json_object_is_type(obj, json_type_double) || (c == 'F' && json_object_is_type(obj, json_type_int))))
462                                         goto missfit;
463                                 if (store && pf)
464                                         *pf = json_object_get_double(obj);
465                         }
466                         break;
467                 case 'o':
468                 case 'O':
469                         if (store) {
470                                 po = va_arg(args, struct json_object **);
471                                 if (!ignore && po) {
472                                         if (c == 'O')
473                                                 obj = json_object_get(obj);
474                                         *po = obj;
475                                 }
476                         }
477                         break;
478
479                 case '[':
480                 case '{':
481                         if (!top)
482                                 top = stack;
483                         else if (++top  >= &stack[STACKCOUNT])
484                                 goto too_deep;
485
486                         top->acc = acc;
487                         top->type = xacc[0];
488                         top->index = 0;
489                         top->parent = obj;
490                         if (ignore)
491                                 ignore++;
492                         if (c == '[') {
493                                 if (!ignore) {
494                                         if (!json_object_is_type(obj, json_type_array))
495                                                 goto missfit;
496                                         top->count = json_object_array_length(obj);
497                                 }
498                                 xacc[0] = ']';
499                                 acc = unpack_accept_arr;
500                         } else {
501                                 if (!ignore) {
502                                         if (!json_object_is_type(obj, json_type_object))
503                                                 goto missfit;
504                                         top->count = json_object_object_length(obj);
505                                 }
506                                 xacc[0] = '}';
507                                 acc = unpack_accept_key;
508                                 continue;
509                         }
510                         break;
511                 case '}':
512                 case ']':
513                         if (!top || c != xacc[0])
514                                 goto internal_error;
515                         acc = top->acc;
516                         xacc[0] = top->type;
517                         top = top == stack ? NULL : top - 1;
518                         if (ignore)
519                                 ignore--;
520                         break;
521                 case '!':
522                         if (*d != xacc[0])
523                                 goto invalid_character;
524                         if (!ignore && top->index != top->count)
525                                 goto incomplete;
526                 case '*':
527                         acc = xacc;
528                         continue;
529                 default:
530                         goto internal_error;
531                 }
532                 switch (xacc[0]) {
533                 case 0:
534                         if (top)
535                                 goto internal_error;
536                         if (*d)
537                                 goto invalid_character;
538                         return 0;
539                 case ']':
540                         if (!ignore) {
541                                 key = strchr(unpack_accept_arr, *d);
542                                 if (key && key >= unpack_accept_any) {
543                                         if (top->index >= top->count)
544                                                 goto out_of_range;
545                                         obj = json_object_array_get_idx(top->parent, top->index++);
546                                 }
547                         }
548                         break;
549                 case ':':
550                         acc = unpack_accept_key;
551                         xacc[0] = '}';
552                         if (ignore)
553                                 ignore--;
554                         break;
555                 default:
556                         goto internal_error;
557                 }
558         }
559 truncated:
560         rc = wrap_json_error_truncated;
561         goto error;
562 internal_error:
563         rc = wrap_json_error_internal_error;
564         goto error;
565 invalid_character:
566         rc = wrap_json_error_invalid_character;
567         goto error;
568 too_deep:
569         rc = wrap_json_error_too_deep;
570         goto error;
571 null_spec:
572         rc = wrap_json_error_null_spec;
573         goto error;
574 null_key:
575         rc = wrap_json_error_null_key;
576         goto error;
577 out_of_range:
578         rc = wrap_json_error_out_of_range;
579         goto error;
580 incomplete:
581         rc = wrap_json_error_incomplete;
582         goto error;
583 missfit:
584         rc = wrap_json_error_missfit_type;
585         goto errorfit;
586 key_not_found:
587         rc = wrap_json_error_key_not_found;
588         goto error;
589 errorfit:
590         d = fit;
591 error:
592         rc = rc | (int)((d - desc) << 4);
593         return -rc;
594 }
595
596 int wrap_json_vcheck(struct json_object *object, const char *desc, va_list args)
597 {
598         return vunpack(object, desc, args, 0);
599 }
600
601 int wrap_json_check(struct json_object *object, const char *desc, ...)
602 {
603         int rc;
604         va_list args;
605
606         va_start(args, desc);
607         rc = vunpack(object, desc, args, 0);
608         va_end(args);
609         return rc;
610 }
611
612 int wrap_json_vmatch(struct json_object *object, const char *desc, va_list args)
613 {
614         return !vunpack(object, desc, args, 0);
615 }
616
617 int wrap_json_match(struct json_object *object, const char *desc, ...)
618 {
619         int rc;
620         va_list args;
621
622         va_start(args, desc);
623         rc = vunpack(object, desc, args, 0);
624         va_end(args);
625         return !rc;
626 }
627
628 int wrap_json_vunpack(struct json_object *object, const char *desc, va_list args)
629 {
630         return vunpack(object, desc, args, 1);
631 }
632
633 int wrap_json_unpack(struct json_object *object, const char *desc, ...)
634 {
635         int rc;
636         va_list args;
637
638         va_start(args, desc);
639         rc = vunpack(object, desc, args, 1);
640         va_end(args);
641         return rc;
642 }
643
644 #if defined(WRAP_JSON_TEST)
645 #include <stdio.h>
646
647 void p(const char *desc, ...)
648 {
649         int rc;
650         va_list args;
651         struct json_object *result;
652
653         va_start(args, desc);
654         rc = wrap_json_vpack(&result, desc, args);
655         va_end(args);
656         if (!rc) 
657                 printf("  SUCCESS %s\n\n", json_object_to_json_string(result));
658         else
659                 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));
660         json_object_put(result);
661 }
662
663 const char *xs[10];
664 int *xi[10];
665 int64_t *xI[10];
666 double *xf[10];
667 struct json_object *xo[10];
668 size_t xz[10];
669
670 void u(const char *value, const char *desc, ...)
671 {
672         unsigned m, k;
673         int rc;
674         va_list args;
675         struct json_object *obj, *o;
676
677         memset(xs, 0, sizeof xs);
678         memset(xi, 0, sizeof xi);
679         memset(xI, 0, sizeof xI);
680         memset(xf, 0, sizeof xf);
681         memset(xo, 0, sizeof xo);
682         memset(xz, 0, sizeof xz);
683         obj = json_tokener_parse(value);
684         va_start(args, desc);
685         rc = wrap_json_vunpack(obj, desc, args);
686         va_end(args);
687         if (rc) 
688                 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));
689         else {
690                 value = NULL;
691                 printf("  SUCCESS");
692                 va_start(args, desc);
693                 k = m = 0;
694                 while(*desc) {
695                         switch(*desc) {
696                         case '{': m = (m << 1) | 1; k = 1; break;
697                         case '}': m = m >> 1; k = m&1; break;
698                         case '[': m = m << 1; k = 0; break;
699                         case ']': m = m >> 1; k = m&1; break;
700                         case 's': printf(" s:%s", k ? va_arg(args, const char*) : *(va_arg(args, const char**)?:&value)); k ^= m&1; break;
701                         case '%': printf(" %%:%zu", *va_arg(args, size_t*)); k = m&1; break;
702                         case 'n': printf(" n"); k = m&1; break;
703                         case 'b': printf(" b:%d", *va_arg(args, int*)); k = m&1; break;
704                         case 'i': printf(" i:%d", *va_arg(args, int*)); k = m&1; break;
705                         case 'I': printf(" I:%lld", *va_arg(args, int64_t*)); k = m&1; break;
706                         case 'f': printf(" f:%f", *va_arg(args, double*)); k = m&1; break;
707                         case 'F': printf(" F:%f", *va_arg(args, double*)); k = m&1; break;
708                         case 'o': printf(" o:%s", json_object_to_json_string(*va_arg(args, struct json_object**))); k = m&1; break;
709                         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;
710                         default: break;
711                         }
712                         desc++;
713                 }
714                 va_end(args);
715                 printf("\n\n");
716         }
717         json_object_put(obj);
718 }
719
720 #define P(...) do{ printf("pack(%s)\n",#__VA_ARGS__); p(__VA_ARGS__); } while(0)
721 #define U(...) do{ printf("unpack(%s)\n",#__VA_ARGS__); u(__VA_ARGS__); } while(0)
722
723 int main()
724 {
725         char buffer[4] = {'t', 'e', 's', 't'};
726
727         P("n");
728         P("b", 1);
729         P("b", 0);
730         P("i", 1);
731         P("I", (uint64_t)0x123456789abcdef);
732         P("f", 3.14);
733         P("s", "test");
734         P("s?", "test");
735         P("s?", NULL);
736         P("s#", "test asdf", 4);
737         P("s%", "test asdf", (size_t)4);
738         P("s#", buffer, 4);
739         P("s%", buffer, (size_t)4);
740         P("s++", "te", "st", "ing");
741         P("s#+#+", "test", 1, "test", 2, "test");
742         P("s%+%+", "test", (size_t)1, "test", (size_t)2, "test");
743         P("{}", 1.0);
744         P("[]", 1.0);
745         P("o", json_object_new_int(1));
746         P("o?", json_object_new_int(1));
747         P("o?", NULL);
748         P("O", json_object_new_int(1));
749         P("O?", json_object_new_int(1));
750         P("O?", NULL);
751         P("{s:[]}", "foo");
752         P("{s+#+: []}", "foo", "barbar", 3, "baz");
753         P("{s:s,s:o,s:O}", "a", NULL, "b", NULL, "c", NULL);
754         P("{s:**}", "a", NULL);
755         P("{s:s*,s:o*,s:O*}", "a", NULL, "b", NULL, "c", NULL);
756         P("[i,i,i]", 0, 1, 2);
757         P("[s,o,O]", NULL, NULL, NULL);
758         P("[**]", NULL);
759         P("[s*,o*,O*]", NULL, NULL, NULL);
760         P(" s ", "test");
761         P("[ ]");
762         P("[ i , i,  i ] ", 1, 2, 3);
763         P("{\n\n1");
764         P("[}");
765         P("{]");
766         P("[");
767         P("{");
768         P("[i]a", 42);
769         P("ia", 42);
770         P("s", NULL);
771         P("+", NULL);
772         P(NULL);
773         P("{s:i}", NULL, 1);
774         P("{ {}: s }", "foo");
775         P("{ s: {},  s:[ii{} }", "foo", "bar", 12, 13);
776         P("[[[[[   [[[[[  [[[[ }]]]] ]]]] ]]]]]");
777
778         U("true", "b", &xi[0]);
779         U("false", "b", &xi[0]);
780         U("null", "n");
781         U("42", "i", &xi[0]);
782         U("123456789", "I", &xI[0]);
783         U("3.14", "f", &xf[0]);
784         U("12345", "F", &xf[0]);
785         U("3.14", "F", &xf[0]);
786         U("\"foo\"", "s", &xs[0]);
787         U("\"foo\"", "s%", &xs[0], &xz[0]);
788         U("{}", "{}");
789         U("[]", "[]");
790         U("{}", "o", &xo[0]);
791         U("{}", "O", &xo[0]);
792         U("{\"foo\":42}", "{si}", "foo", &xi[0]);
793         U("[1,2,3]", "[i,i,i]", &xi[0], &xi[1], &xi[2]);
794         U("{\"a\":1,\"b\":2,\"c\":3}", "{s:i, s:i, s:i}", "a", &xi[0], "b", &xi[1], "c", &xi[2]);
795         U("42", "z");
796         U("null", "[i]");
797         U("[]", "[}");
798         U("{}", "{]");
799         U("[]", "[");
800         U("{}", "{");
801         U("[42]", "[i]a", &xi[0]);
802         U("42", "ia", &xi[0]);
803         U("[]", NULL);
804         U("\"foo\"", "s", NULL);
805         U("42", "s", NULL);
806         U("42", "n");
807         U("42", "b", NULL);
808         U("42", "f", NULL);
809         U("42", "[i]", NULL);
810         U("42", "{si}", "foo", NULL);
811         U("\"foo\"", "n");
812         U("\"foo\"", "b", NULL);
813         U("\"foo\"", "i", NULL);
814         U("\"foo\"", "I", NULL);
815         U("\"foo\"", "f", NULL);
816         U("\"foo\"", "F", NULL);
817         U("true", "s", NULL);
818         U("true", "n");
819         U("true", "i", NULL);
820         U("true", "I", NULL);
821         U("true", "f", NULL);
822         U("true", "F", NULL);
823         U("[42]", "[ii]", &xi[0], &xi[1]);
824         U("{\"foo\":42}", "{si}", NULL, &xi[0]);
825         U("{\"foo\":42}", "{si}", "baz", &xi[0]);
826         U("[1,2,3]", "[iii!]", &xi[0], &xi[1], &xi[2]);
827         U("[1,2,3]", "[ii!]", &xi[0], &xi[1]);
828         U("[1,2,3]", "[ii]", &xi[0], &xi[1]);
829         U("[1,2,3]", "[ii*]", &xi[0], &xi[1]);
830         U("{\"foo\":42,\"baz\":45}", "{sisi}", "baz", &xi[0], "foo", &xi[1]);
831         U("{\"foo\":42,\"baz\":45}", "{sisi*}", "baz", &xi[0], "foo", &xi[1]);
832         U("{\"foo\":42,\"baz\":45}", "{sisi!}", "baz", &xi[0], "foo", &xi[1]);
833         U("{\"foo\":42,\"baz\":45}", "{si}", "baz", &xi[0], "foo", &xi[1]);
834         U("{\"foo\":42,\"baz\":45}", "{si*}", "baz", &xi[0], "foo", &xi[1]);
835         U("{\"foo\":42,\"baz\":45}", "{si!}", "baz", &xi[0], "foo", &xi[1]);
836         U("[1,{\"foo\":2,\"bar\":null},[3,4]]", "[i{sisn}[ii]]", &xi[0], "foo", &xi[1], "bar", &xi[2], &xi[3]);
837         U("[1,2,3]", "[ii!i]", &xi[0], &xi[1], &xi[2]);
838         U("[1,2,3]", "[ii*i]", &xi[0], &xi[1], &xi[2]);
839         U("{\"foo\":1,\"bar\":2}", "{si!si}", "foo", &xi[1], "bar", &xi[2]);
840         U("{\"foo\":1,\"bar\":2}", "{si*si}", "foo", &xi[1], "bar", &xi[2]);
841         U("{\"foo\":{\"baz\":null,\"bar\":null}}", "{s{sn!}}", "foo", "bar");
842         U("[[1,2,3]]", "[[ii!]]", &xi[0], &xi[1]);
843         U("{}", "{s?i}", "foo", &xi[0]);
844         U("{\"foo\":1}", "{s?i}", "foo", &xi[0]);
845         U("{}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
846         U("{\"foo\":[1,2]}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
847         U("{\"bar\":{\"baz\":{\"quux\":15}}}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
848         U("{\"foo\":{\"bar\":4}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
849         U("{\"foo\":{}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
850         U("{}", "{s?{s?i}}", "foo", "bar", &xi[0]);
851         U("{\"foo\":42,\"baz\":45}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
852         U("{\"foo\":42}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
853         return 0;
854 }
855
856 #endif
857
858 #if 0
859
860
861     /* Unpack the same item twice */
862     j = json_pack("{s:s, s:i, s:b}", "foo", "bar", "baz", 42, "quux", 1);
863     if(!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s))
864         fail("json_unpack object with strict validation failed");
865     {
866         const char *possible_errors[] = {
867             "2 object item(s) left unpacked: baz, quux",
868             "2 object item(s) left unpacked: quux, baz"
869         };
870         check_errors(possible_errors, 2, "<validation>", 1, 10, 10);
871     }
872     json_decref(j);
873
874 #endif