2 Copyright (C) 2016, 2017 "IoT.bzh"
4 author: José Bollo <jose.bollo@iot.bzh>
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
10 http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include "wrap-json.h"
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_
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])
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])
54 static const char *pack_errors[_wrap_json_error_count_] =
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"
73 int wrap_json_get_error_position(int rc)
80 int wrap_json_get_error_code(int rc)
87 const char *wrap_json_get_error_string(int rc)
89 rc = wrap_json_get_error_code(rc);
90 if (rc >= sizeof pack_errors / sizeof *pack_errors)
92 return pack_errors[rc];
97 static inline const char *skip(const char *d)
99 while (*d && strchr(ignore_all, *d))
104 int wrap_json_vpack(struct json_object **result, const char *desc, va_list args)
106 /* TODO: the case of structs with key being single char should be optimized */
107 int nstr, notnull, nullable, rc;
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;
122 top->acc = pack_accept_any;
131 if (!strchr(top->acc, c))
132 goto invalid_character;
141 strs[nstr].str = va_arg(args, const char*);
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;
153 sz += strs[nstr++].sz;
160 if (nstr >= STRCOUNT)
176 dsz -= strs[nstr].sz;
177 memcpy(&s[dsz], strs[nstr].str, strs[nstr].sz);
179 obj = json_object_new_string_len(s, (int)sz);
191 obj = json_object_new_boolean(va_arg(args, int));
196 obj = json_object_new_int(va_arg(args, int));
201 obj = json_object_new_int64(va_arg(args, int64_t));
206 obj = json_object_new_double(va_arg(args, double));
212 obj = va_arg(args, struct json_object*);
215 else if (*d != '*' && !obj)
218 json_object_get(obj);
222 if (++top >= &stack[STACKCOUNT])
227 top->acc = pack_accept_arr;
228 top->cont = json_object_new_array();
231 top->acc = pack_accept_key;
232 top->cont = json_object_new_object();
239 if (c != top->type || top <= stack)
242 if (*d == '*' && !(c == '}' ? json_object_object_length(obj) : json_object_array_length(obj))) {
243 json_object_put(obj);
255 goto invalid_character;
259 if (obj || *d != '*')
260 json_object_array_add(top->cont, obj);
268 top->acc = pack_accept_any;
272 if (obj || *d != '*')
273 json_object_object_add(top->cont, json_object_get_string(top->key), obj);
276 json_object_put(top->key);
278 top->acc = pack_accept_key;
287 rc = wrap_json_error_null_object;
290 rc = wrap_json_error_truncated;
293 rc = wrap_json_error_internal_error;
296 rc = wrap_json_error_out_of_memory;
299 rc = wrap_json_error_invalid_character;
302 rc = wrap_json_error_too_long;
305 rc = wrap_json_error_too_deep;
308 rc = wrap_json_error_null_spec;
311 rc = wrap_json_error_null_key;
314 rc = wrap_json_error_null_string;
318 json_object_put(top->key);
319 json_object_put(top->cont);
320 } while (--top >= stack);
322 rc = rc | (int)((d - desc) << 4);
326 int wrap_json_pack(struct json_object **result, const char *desc, ...)
331 va_start(args, desc);
332 rc = wrap_json_vpack(result, desc, args);
337 static int vunpack(struct json_object *object, const char *desc, va_list args, int store)
339 int rc, optionnal, ignore;
340 char c, xacc[2] = { 0, 0 };
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;
356 acc = unpack_accept_any;
367 goto invalid_character;
371 if (xacc[0] == '}') {
373 key = va_arg(args, const char *);
385 if (json_object_object_get_ex(top->parent, key, &obj)) {
397 acc = unpack_accept_any;
402 ps = va_arg(args, const char **);
404 if (!json_object_is_type(obj, json_type_string))
407 *ps = json_object_get_string(obj);
412 pz = va_arg(args, size_t *);
414 *pz = (size_t)json_object_get_string_len(obj);
419 if (!ignore && !json_object_is_type(obj, json_type_null))
424 pi = va_arg(args, int *);
427 if (!json_object_is_type(obj, json_type_boolean))
430 *pi = json_object_get_boolean(obj);
435 pi = va_arg(args, int *);
438 if (!json_object_is_type(obj, json_type_int))
441 *pi = json_object_get_int(obj);
446 pI = va_arg(args, int64_t *);
449 if (!json_object_is_type(obj, json_type_int))
452 *pI = json_object_get_int64(obj);
458 pf = va_arg(args, double *);
461 if (!(json_object_is_type(obj, json_type_double) || (c == 'F' && json_object_is_type(obj, json_type_int))))
464 *pf = json_object_get_double(obj);
470 po = va_arg(args, struct json_object **);
473 obj = json_object_get(obj);
483 else if (++top >= &stack[STACKCOUNT])
494 if (!json_object_is_type(obj, json_type_array))
496 top->count = json_object_array_length(obj);
499 acc = unpack_accept_arr;
502 if (!json_object_is_type(obj, json_type_object))
504 top->count = json_object_object_length(obj);
507 acc = unpack_accept_key;
513 if (!top || c != xacc[0])
517 top = top == stack ? NULL : top - 1;
523 goto invalid_character;
524 if (!ignore && top->index != top->count)
537 goto invalid_character;
541 key = strchr(unpack_accept_arr, *d);
542 if (key && key >= unpack_accept_any) {
543 if (top->index >= top->count)
545 obj = json_object_array_get_idx(top->parent, top->index++);
550 acc = unpack_accept_key;
560 rc = wrap_json_error_truncated;
563 rc = wrap_json_error_internal_error;
566 rc = wrap_json_error_invalid_character;
569 rc = wrap_json_error_too_deep;
572 rc = wrap_json_error_null_spec;
575 rc = wrap_json_error_null_key;
578 rc = wrap_json_error_out_of_range;
581 rc = wrap_json_error_incomplete;
584 rc = wrap_json_error_missfit_type;
587 rc = wrap_json_error_key_not_found;
592 rc = rc | (int)((d - desc) << 4);
596 int wrap_json_vcheck(struct json_object *object, const char *desc, va_list args)
598 return vunpack(object, desc, args, 0);
601 int wrap_json_check(struct json_object *object, const char *desc, ...)
606 va_start(args, desc);
607 rc = vunpack(object, desc, args, 0);
612 int wrap_json_vmatch(struct json_object *object, const char *desc, va_list args)
614 return !vunpack(object, desc, args, 0);
617 int wrap_json_match(struct json_object *object, const char *desc, ...)
622 va_start(args, desc);
623 rc = vunpack(object, desc, args, 0);
628 int wrap_json_vunpack(struct json_object *object, const char *desc, va_list args)
630 return vunpack(object, desc, args, 1);
633 int wrap_json_unpack(struct json_object *object, const char *desc, ...)
638 va_start(args, desc);
639 rc = vunpack(object, desc, args, 1);
644 #if defined(WRAP_JSON_TEST)
647 void p(const char *desc, ...)
651 struct json_object *result;
653 va_start(args, desc);
654 rc = wrap_json_vpack(&result, desc, args);
657 printf(" SUCCESS %s\n\n", json_object_to_json_string(result));
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);
667 struct json_object *xo[10];
670 void u(const char *value, const char *desc, ...)
675 struct json_object *obj, *o;
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);
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));
692 va_start(args, 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;
717 json_object_put(obj);
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)
725 char buffer[4] = {'t', 'e', 's', 't'};
731 P("I", (uint64_t)0x123456789abcdef);
736 P("s#", "test asdf", 4);
737 P("s%", "test asdf", (size_t)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");
745 P("o", json_object_new_int(1));
746 P("o?", json_object_new_int(1));
748 P("O", json_object_new_int(1));
749 P("O?", json_object_new_int(1));
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);
759 P("[s*,o*,O*]", NULL, NULL, NULL);
762 P("[ i , i, i ] ", 1, 2, 3);
774 P("{ {}: s }", "foo");
775 P("{ s: {}, s:[ii{} }", "foo", "bar", 12, 13);
776 P("[[[[[ [[[[[ [[[[ }]]]] ]]]] ]]]]]");
778 U("true", "b", &xi[0]);
779 U("false", "b", &xi[0]);
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]);
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]);
801 U("[42]", "[i]a", &xi[0]);
802 U("42", "ia", &xi[0]);
804 U("\"foo\"", "s", NULL);
809 U("42", "[i]", NULL);
810 U("42", "{si}", "foo", NULL);
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);
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]);
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");
866 const char *possible_errors[] = {
867 "2 object item(s) left unpacked: baz, quux",
868 "2 object item(s) left unpacked: quux, baz"
870 check_errors(possible_errors, 2, "<validation>", 1, 10, 10);