wrap-json: sync with upstream
[src/app-framework-main.git] / src / wrap-json.c
1 /*
2  Copyright (C) 2016, 2017, 2018 "IoT.bzh"
3
4  author: José Bollo <jose.bollo@iot.bzh>
5
6  Licensed under the Apache License, Version 2.0 (the "License");
7  you may not use this file except in compliance with the License.
8  You may obtain a copy of the License at
9
10      http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  See the License for the specific language governing permissions and
16  limitations under the License.
17 */
18
19 #include <string.h>
20 #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 static struct json_object *clone_any(struct json_object *object, int deep);
918
919 static struct json_object *clone_object(struct json_object *object, int subdeep)
920 {
921         struct json_object *r = json_object_new_object();
922         struct json_object_iterator it = json_object_iter_begin(object);
923         struct json_object_iterator end = json_object_iter_end(object);
924         while (!json_object_iter_equal(&it, &end)) {
925                 json_object_object_add(r,
926                         json_object_iter_peek_name(&it),
927                         clone_any(json_object_iter_peek_value(&it), subdeep));
928                 json_object_iter_next(&it);
929         }
930         return r;
931 }
932
933 static struct json_object *clone_array(struct json_object *object, int subdeep)
934 {
935         int n = json_object_array_length(object);
936         struct json_object *r = json_object_new_array();
937         while (n) {
938                 n--;
939                 json_object_array_put_idx(r, n,
940                         clone_any(json_object_array_get_idx(object, n), subdeep));
941         }
942         return r;
943 }
944
945 static struct json_object *clone_any(struct json_object *object, int deep)
946 {
947         if (deep) {
948                 switch (json_object_get_type(object)) {
949                 case json_type_object:
950                         return clone_object(object, deep - 1);
951                 case json_type_array:
952                         return clone_array(object, deep - 1);
953                 default:
954                         break;
955                 }
956         }
957         return json_object_get(object);
958 }
959
960 struct json_object *wrap_json_clone(struct json_object *object)
961 {
962         return clone_any(object, 1);
963 }
964
965 struct json_object *wrap_json_clone_deep(struct json_object *object)
966 {
967         return clone_any(object, INT_MAX);
968 }
969
970 void wrap_json_object_add(struct json_object *dest, struct json_object *added)
971 {
972         struct json_object_iterator it, end;
973         if (json_object_is_type(dest, json_type_object) && json_object_is_type(added, json_type_object)) {
974                 it = json_object_iter_begin(added);
975                 end = json_object_iter_end(added);
976                 while (!json_object_iter_equal(&it, &end)) {
977                         json_object_object_add(dest,
978                                 json_object_iter_peek_name(&it),
979                                 json_object_get(json_object_iter_peek_value(&it)));
980                         json_object_iter_next(&it);
981                 }
982         }
983 }
984
985 #if defined(WRAP_JSON_TEST)
986 #include <stdio.h>
987
988 void tclone(struct json_object *obj)
989 {
990         struct json_object *o;
991
992         o = wrap_json_clone(obj);
993         if (strcmp(json_object_to_json_string(obj), json_object_to_json_string(o)))
994                 printf("ERROR in clone: %s VERSUS %s\n", json_object_to_json_string(obj), json_object_to_json_string(o));
995         json_object_put(o);
996
997         o = wrap_json_clone_deep(obj);
998         if (strcmp(json_object_to_json_string(obj), json_object_to_json_string(o)))
999                 printf("ERROR in clone_deep: %s VERSUS %s\n", json_object_to_json_string(obj), json_object_to_json_string(o));
1000         json_object_put(o);
1001 }
1002
1003 void p(const char *desc, ...)
1004 {
1005         int rc;
1006         va_list args;
1007         struct json_object *result;
1008
1009         va_start(args, desc);
1010         rc = wrap_json_vpack(&result, desc, args);
1011         va_end(args);
1012         if (!rc)
1013                 printf("  SUCCESS %s\n\n", json_object_to_json_string(result));
1014         else
1015                 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));
1016         tclone(result);
1017         json_object_put(result);
1018 }
1019
1020 const char *xs[10];
1021 int *xi[10];
1022 int64_t *xI[10];
1023 double *xf[10];
1024 struct json_object *xo[10];
1025 size_t xz[10];
1026 uint8_t *xy[10];
1027
1028 void u(const char *value, const char *desc, ...)
1029 {
1030         unsigned m, k;
1031         int rc;
1032         va_list args;
1033         struct json_object *obj, *o;
1034
1035         memset(xs, 0, sizeof xs);
1036         memset(xi, 0, sizeof xi);
1037         memset(xI, 0, sizeof xI);
1038         memset(xf, 0, sizeof xf);
1039         memset(xo, 0, sizeof xo);
1040         memset(xy, 0, sizeof xy);
1041         memset(xz, 0, sizeof xz);
1042         obj = json_tokener_parse(value);
1043         va_start(args, desc);
1044         rc = wrap_json_vunpack(obj, desc, args);
1045         va_end(args);
1046         if (rc)
1047                 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));
1048         else {
1049                 value = NULL;
1050                 printf("  SUCCESS");
1051                 va_start(args, desc);
1052                 k = m = 0;
1053                 while(*desc) {
1054                         switch(*desc) {
1055                         case '{': m = (m << 1) | 1; k = 1; break;
1056                         case '}': m = m >> 1; k = m&1; break;
1057                         case '[': m = m << 1; k = 0; break;
1058                         case ']': m = m >> 1; k = m&1; break;
1059                         case 's': printf(" s:%s", k ? va_arg(args, const char*) : *(va_arg(args, const char**)?:&value)); k ^= m&1; break;
1060                         case '%': printf(" %%:%zu", *va_arg(args, size_t*)); k = m&1; break;
1061                         case 'n': printf(" n"); k = m&1; break;
1062                         case 'b': printf(" b:%d", *va_arg(args, int*)); k = m&1; break;
1063                         case 'i': printf(" i:%d", *va_arg(args, int*)); k = m&1; break;
1064                         case 'I': printf(" I:%lld", *va_arg(args, int64_t*)); k = m&1; break;
1065                         case 'f': printf(" f:%f", *va_arg(args, double*)); k = m&1; break;
1066                         case 'F': printf(" F:%f", *va_arg(args, double*)); k = m&1; break;
1067                         case 'o': printf(" o:%s", json_object_to_json_string(*va_arg(args, struct json_object**))); k = m&1; break;
1068                         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;
1069                         case 'y':
1070                         case 'Y': {
1071                                 uint8_t *p = *va_arg(args, uint8_t**);
1072                                 size_t s = *va_arg(args, size_t*);
1073                                 printf(" y/%d:%.*s", (int)s, (int)s, (char*)p);
1074                                 k ^= m&1;
1075                                 break;
1076                                 }
1077                         default: break;
1078                         }
1079                         desc++;
1080                 }
1081                 va_end(args);
1082                 printf("\n\n");
1083         }
1084         tclone(obj);
1085         json_object_put(obj);
1086 }
1087
1088 #define P(...) do{ printf("pack(%s)\n",#__VA_ARGS__); p(__VA_ARGS__); } while(0)
1089 #define U(...) do{ printf("unpack(%s)\n",#__VA_ARGS__); u(__VA_ARGS__); } while(0)
1090
1091 int main()
1092 {
1093         char buffer[4] = {'t', 'e', 's', 't'};
1094
1095         P("n");
1096         P("b", 1);
1097         P("b", 0);
1098         P("i", 1);
1099         P("I", (uint64_t)0x123456789abcdef);
1100         P("f", 3.14);
1101         P("s", "test");
1102         P("s?", "test");
1103         P("s?", NULL);
1104         P("s#", "test asdf", 4);
1105         P("s%", "test asdf", (size_t)4);
1106         P("s#", buffer, 4);
1107         P("s%", buffer, (size_t)4);
1108         P("s++", "te", "st", "ing");
1109         P("s#+#+", "test", 1, "test", 2, "test");
1110         P("s%+%+", "test", (size_t)1, "test", (size_t)2, "test");
1111         P("{}", 1.0);
1112         P("[]", 1.0);
1113         P("o", json_object_new_int(1));
1114         P("o?", json_object_new_int(1));
1115         P("o?", NULL);
1116         P("O", json_object_new_int(1));
1117         P("O?", json_object_new_int(1));
1118         P("O?", NULL);
1119         P("{s:[]}", "foo");
1120         P("{s+#+: []}", "foo", "barbar", 3, "baz");
1121         P("{s:s,s:o,s:O}", "a", NULL, "b", NULL, "c", NULL);
1122         P("{s:**}", "a", NULL);
1123         P("{s:s*,s:o*,s:O*}", "a", NULL, "b", NULL, "c", NULL);
1124         P("[i,i,i]", 0, 1, 2);
1125         P("[s,o,O]", NULL, NULL, NULL);
1126         P("[**]", NULL);
1127         P("[s*,o*,O*]", NULL, NULL, NULL);
1128         P(" s ", "test");
1129         P("[ ]");
1130         P("[ i , i,  i ] ", 1, 2, 3);
1131         P("{\n\n1");
1132         P("[}");
1133         P("{]");
1134         P("[");
1135         P("{");
1136         P("[i]a", 42);
1137         P("ia", 42);
1138         P("s", NULL);
1139         P("+", NULL);
1140         P(NULL);
1141         P("{s:i}", NULL, 1);
1142         P("{ {}: s }", "foo");
1143         P("{ s: {},  s:[ii{} }", "foo", "bar", 12, 13);
1144         P("[[[[[   [[[[[  [[[[ }]]]] ]]]] ]]]]]");
1145         P("y", "???????hello>>>>>>>", (size_t)19);
1146         P("Y", "???????hello>>>>>>>", (size_t)19);
1147         P("{sy?}", "foo", "hi", (size_t)2);
1148         P("{sy?}", "foo", NULL, 0);
1149         P("{sy*}", "foo", "hi", (size_t)2);
1150         P("{sy*}", "foo", NULL, 0);
1151
1152         U("true", "b", &xi[0]);
1153         U("false", "b", &xi[0]);
1154         U("null", "n");
1155         U("42", "i", &xi[0]);
1156         U("123456789", "I", &xI[0]);
1157         U("3.14", "f", &xf[0]);
1158         U("12345", "F", &xf[0]);
1159         U("3.14", "F", &xf[0]);
1160         U("\"foo\"", "s", &xs[0]);
1161         U("\"foo\"", "s%", &xs[0], &xz[0]);
1162         U("{}", "{}");
1163         U("[]", "[]");
1164         U("{}", "o", &xo[0]);
1165         U("{}", "O", &xo[0]);
1166         U("{\"foo\":42}", "{si}", "foo", &xi[0]);
1167         U("[1,2,3]", "[i,i,i]", &xi[0], &xi[1], &xi[2]);
1168         U("{\"a\":1,\"b\":2,\"c\":3}", "{s:i, s:i, s:i}", "a", &xi[0], "b", &xi[1], "c", &xi[2]);
1169         U("42", "z");
1170         U("null", "[i]");
1171         U("[]", "[}");
1172         U("{}", "{]");
1173         U("[]", "[");
1174         U("{}", "{");
1175         U("[42]", "[i]a", &xi[0]);
1176         U("42", "ia", &xi[0]);
1177         U("[]", NULL);
1178         U("\"foo\"", "s", NULL);
1179         U("42", "s", NULL);
1180         U("42", "n");
1181         U("42", "b", NULL);
1182         U("42", "f", NULL);
1183         U("42", "[i]", NULL);
1184         U("42", "{si}", "foo", NULL);
1185         U("\"foo\"", "n");
1186         U("\"foo\"", "b", NULL);
1187         U("\"foo\"", "i", NULL);
1188         U("\"foo\"", "I", NULL);
1189         U("\"foo\"", "f", NULL);
1190         U("\"foo\"", "F", NULL);
1191         U("true", "s", NULL);
1192         U("true", "n");
1193         U("true", "i", NULL);
1194         U("true", "I", NULL);
1195         U("true", "f", NULL);
1196         U("true", "F", NULL);
1197         U("[42]", "[ii]", &xi[0], &xi[1]);
1198         U("{\"foo\":42}", "{si}", NULL, &xi[0]);
1199         U("{\"foo\":42}", "{si}", "baz", &xi[0]);
1200         U("[1,2,3]", "[iii!]", &xi[0], &xi[1], &xi[2]);
1201         U("[1,2,3]", "[ii!]", &xi[0], &xi[1]);
1202         U("[1,2,3]", "[ii]", &xi[0], &xi[1]);
1203         U("[1,2,3]", "[ii*]", &xi[0], &xi[1]);
1204         U("{\"foo\":42,\"baz\":45}", "{sisi}", "baz", &xi[0], "foo", &xi[1]);
1205         U("{\"foo\":42,\"baz\":45}", "{sisi*}", "baz", &xi[0], "foo", &xi[1]);
1206         U("{\"foo\":42,\"baz\":45}", "{sisi!}", "baz", &xi[0], "foo", &xi[1]);
1207         U("{\"foo\":42,\"baz\":45}", "{si}", "baz", &xi[0], "foo", &xi[1]);
1208         U("{\"foo\":42,\"baz\":45}", "{si*}", "baz", &xi[0], "foo", &xi[1]);
1209         U("{\"foo\":42,\"baz\":45}", "{si!}", "baz", &xi[0], "foo", &xi[1]);
1210         U("[1,{\"foo\":2,\"bar\":null},[3,4]]", "[i{sisn}[ii]]", &xi[0], "foo", &xi[1], "bar", &xi[2], &xi[3]);
1211         U("[1,2,3]", "[ii!i]", &xi[0], &xi[1], &xi[2]);
1212         U("[1,2,3]", "[ii*i]", &xi[0], &xi[1], &xi[2]);
1213         U("{\"foo\":1,\"bar\":2}", "{si!si}", "foo", &xi[1], "bar", &xi[2]);
1214         U("{\"foo\":1,\"bar\":2}", "{si*si}", "foo", &xi[1], "bar", &xi[2]);
1215         U("{\"foo\":{\"baz\":null,\"bar\":null}}", "{s{sn!}}", "foo", "bar");
1216         U("[[1,2,3]]", "[[ii!]]", &xi[0], &xi[1]);
1217         U("{}", "{s?i}", "foo", &xi[0]);
1218         U("{\"foo\":1}", "{s?i}", "foo", &xi[0]);
1219         U("{}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
1220         U("{\"foo\":[1,2]}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
1221         U("{\"bar\":{\"baz\":{\"quux\":15}}}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
1222         U("{\"foo\":{\"bar\":4}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
1223         U("{\"foo\":{}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
1224         U("{}", "{s?{s?i}}", "foo", "bar", &xi[0]);
1225         U("{\"foo\":42,\"baz\":45}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
1226         U("{\"foo\":42}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
1227
1228         U("\"Pz8_Pz8_P2hlbGxvPj4-Pj4-Pg\"", "y", &xy[0], &xz[0]);
1229         U("\"\"", "y", &xy[0], &xz[0]);
1230         U("null", "y", &xy[0], &xz[0]);
1231         U("{\"foo\":\"Pz8_Pz8_P2hlbGxvPj4-Pj4-Pg\"}", "{s?y}", "foo", &xy[0], &xz[0]);
1232         U("{\"foo\":\"\"}", "{s?y}", "foo", &xy[0], &xz[0]);
1233         U("{}", "{s?y}", "foo", &xy[0], &xz[0]);
1234         return 0;
1235 }
1236
1237 #endif
1238
1239 #if 0
1240
1241
1242     /* Unpack the same item twice */
1243     j = json_pack("{s:s, s:i, s:b}", "foo", "bar", "baz", 42, "quux", 1);
1244     if(!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s))
1245         fail("json_unpack object with strict validation failed");
1246     {
1247         const char *possible_errors[] = {
1248             "2 object item(s) left unpacked: baz, quux",
1249             "2 object item(s) left unpacked: quux, baz"
1250         };
1251         check_errors(possible_errors, 2, "<validation>", 1, 10, 10);
1252     }
1253     json_decref(j);
1254
1255 #endif