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;
132 if (!strchr(top->acc, c))
133 goto invalid_character;
142 strs[nstr].str = va_arg(args, const char*);
150 case '%': strs[nstr].sz = va_arg(args, size_t); d = skip(++d); break;
151 case '#': strs[nstr].sz = (size_t)va_arg(args, int); d = skip(++d); break;
152 default: strs[nstr].sz = strs[nstr].str ? strlen(strs[nstr].str) : 0; break;
154 sz += strs[nstr++].sz;
161 if (nstr >= STRCOUNT)
177 dsz -= strs[nstr].sz;
178 memcpy(&s[dsz], strs[nstr].str, strs[nstr].sz);
180 obj = json_object_new_string_len(s, (int)sz);
192 obj = json_object_new_boolean(va_arg(args, int));
197 obj = json_object_new_int(va_arg(args, int));
202 obj = json_object_new_int64(va_arg(args, int64_t));
207 obj = json_object_new_double(va_arg(args, double));
213 obj = va_arg(args, struct json_object*);
216 else if (*d != '*' && !obj)
219 json_object_get(obj);
223 if (++top >= &stack[STACKCOUNT])
228 top->acc = pack_accept_arr;
229 top->cont = json_object_new_array();
232 top->acc = pack_accept_key;
233 top->cont = json_object_new_object();
240 if (c != top->type || top <= stack)
243 if (*d == '*' && !(c == '}' ? json_object_object_length(obj) : json_object_array_length(obj))) {
244 json_object_put(obj);
256 goto invalid_character;
260 if (obj || *d != '*')
261 json_object_array_add(top->cont, obj);
269 top->acc = pack_accept_any;
273 if (obj || *d != '*')
274 json_object_object_add(top->cont, json_object_get_string(top->key), obj);
277 json_object_put(top->key);
279 top->acc = pack_accept_key;
288 rc = wrap_json_error_null_object;
291 rc = wrap_json_error_truncated;
294 rc = wrap_json_error_internal_error;
297 rc = wrap_json_error_out_of_memory;
300 rc = wrap_json_error_invalid_character;
303 rc = wrap_json_error_too_long;
306 rc = wrap_json_error_too_deep;
309 rc = wrap_json_error_null_spec;
312 rc = wrap_json_error_null_key;
315 rc = wrap_json_error_null_string;
319 json_object_put(top->key);
320 json_object_put(top->cont);
321 } while (--top >= stack);
323 rc = rc | (int)((d - desc) << 4);
327 int wrap_json_pack(struct json_object **result, const char *desc, ...)
332 va_start(args, desc);
333 rc = wrap_json_vpack(result, desc, args);
338 static int vunpack(struct json_object *object, const char *desc, va_list args, int store)
340 int rc = 0, optionnal, ignore;
341 char c, xacc[2] = { 0, 0 };
343 const char *d, *fit = NULL;
344 const char *key = NULL;
345 const char **ps = NULL;
350 struct { struct json_object *parent; const char *acc; int index, count; char type; } stack[STACKCOUNT], *top;
351 struct json_object *obj;
352 struct json_object **po;
357 acc = unpack_accept_any;
369 goto invalid_character;
373 if (xacc[0] == '}') {
375 key = va_arg(args, const char *);
387 if (json_object_object_get_ex(top->parent, key, &obj)) {
399 acc = unpack_accept_any;
404 ps = va_arg(args, const char **);
406 if (!json_object_is_type(obj, json_type_string))
409 *ps = json_object_get_string(obj);
414 pz = va_arg(args, size_t *);
416 *pz = (size_t)json_object_get_string_len(obj);
421 if (!ignore && !json_object_is_type(obj, json_type_null))
426 pi = va_arg(args, int *);
429 if (!json_object_is_type(obj, json_type_boolean))
432 *pi = json_object_get_boolean(obj);
437 pi = va_arg(args, int *);
440 if (!json_object_is_type(obj, json_type_int))
443 *pi = json_object_get_int(obj);
448 pI = va_arg(args, int64_t *);
451 if (!json_object_is_type(obj, json_type_int))
454 *pI = json_object_get_int64(obj);
460 pf = va_arg(args, double *);
463 if (!(json_object_is_type(obj, json_type_double) || (c == 'F' && json_object_is_type(obj, json_type_int))))
466 *pf = json_object_get_double(obj);
472 po = va_arg(args, struct json_object **);
475 obj = json_object_get(obj);
485 else if (++top >= &stack[STACKCOUNT])
496 if (!json_object_is_type(obj, json_type_array))
498 top->count = json_object_array_length(obj);
501 acc = unpack_accept_arr;
504 if (!json_object_is_type(obj, json_type_object))
506 top->count = json_object_object_length(obj);
509 acc = unpack_accept_key;
515 if (!top || c != xacc[0])
519 top = top == stack ? NULL : top - 1;
525 goto invalid_character;
526 if (!ignore && top->index != top->count)
539 goto invalid_character;
543 key = strchr(unpack_accept_arr, *d);
544 if (key && key >= unpack_accept_any) {
545 if (top->index >= top->count)
547 obj = json_object_array_get_idx(top->parent, top->index++);
552 acc = unpack_accept_key;
562 rc = wrap_json_error_truncated;
565 rc = wrap_json_error_internal_error;
568 rc = wrap_json_error_invalid_character;
571 rc = wrap_json_error_too_deep;
574 rc = wrap_json_error_null_spec;
577 rc = wrap_json_error_null_key;
580 rc = wrap_json_error_out_of_range;
583 rc = wrap_json_error_incomplete;
586 rc = wrap_json_error_missfit_type;
589 rc = wrap_json_error_key_not_found;
594 rc = rc | (int)((d - desc) << 4);
598 int wrap_json_vcheck(struct json_object *object, const char *desc, va_list args)
600 return vunpack(object, desc, args, 0);
603 int wrap_json_check(struct json_object *object, const char *desc, ...)
608 va_start(args, desc);
609 rc = vunpack(object, desc, args, 0);
614 int wrap_json_vmatch(struct json_object *object, const char *desc, va_list args)
616 return !vunpack(object, desc, args, 0);
619 int wrap_json_match(struct json_object *object, const char *desc, ...)
624 va_start(args, desc);
625 rc = vunpack(object, desc, args, 0);
630 int wrap_json_vunpack(struct json_object *object, const char *desc, va_list args)
632 return vunpack(object, desc, args, 1);
635 int wrap_json_unpack(struct json_object *object, const char *desc, ...)
640 va_start(args, desc);
641 rc = vunpack(object, desc, args, 1);
646 #if defined(WRAP_JSON_TEST)
649 void p(const char *desc, ...)
653 struct json_object *result;
655 va_start(args, desc);
656 rc = wrap_json_vpack(&result, desc, args);
659 printf(" SUCCESS %s\n\n", json_object_to_json_string(result));
661 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));
662 json_object_put(result);
669 struct json_object *xo[10];
672 void u(const char *value, const char *desc, ...)
677 struct json_object *obj, *o;
679 memset(xs, 0, sizeof xs);
680 memset(xi, 0, sizeof xi);
681 memset(xI, 0, sizeof xI);
682 memset(xf, 0, sizeof xf);
683 memset(xo, 0, sizeof xo);
684 memset(xz, 0, sizeof xz);
685 obj = json_tokener_parse(value);
686 va_start(args, desc);
687 rc = wrap_json_vunpack(obj, desc, args);
690 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));
694 va_start(args, desc);
698 case '{': m = (m << 1) | 1; k = 1; break;
699 case '}': m = m >> 1; k = m&1; break;
700 case '[': m = m << 1; k = 0; break;
701 case ']': m = m >> 1; k = m&1; break;
702 case 's': printf(" s:%s", k ? va_arg(args, const char*) : *(va_arg(args, const char**)?:&value)); k ^= m&1; break;
703 case '%': printf(" %%:%zu", *va_arg(args, size_t*)); k = m&1; break;
704 case 'n': printf(" n"); k = m&1; break;
705 case 'b': printf(" b:%d", *va_arg(args, int*)); k = m&1; break;
706 case 'i': printf(" i:%d", *va_arg(args, int*)); k = m&1; break;
707 case 'I': printf(" I:%lld", *va_arg(args, int64_t*)); k = m&1; break;
708 case 'f': printf(" f:%f", *va_arg(args, double*)); k = m&1; break;
709 case 'F': printf(" F:%f", *va_arg(args, double*)); k = m&1; break;
710 case 'o': printf(" o:%s", json_object_to_json_string(*va_arg(args, struct json_object**))); k = m&1; break;
711 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;
719 json_object_put(obj);
722 #define P(...) do{ printf("pack(%s)\n",#__VA_ARGS__); p(__VA_ARGS__); } while(0)
723 #define U(...) do{ printf("unpack(%s)\n",#__VA_ARGS__); u(__VA_ARGS__); } while(0)
727 char buffer[4] = {'t', 'e', 's', 't'};
733 P("I", (uint64_t)0x123456789abcdef);
738 P("s#", "test asdf", 4);
739 P("s%", "test asdf", (size_t)4);
741 P("s%", buffer, (size_t)4);
742 P("s++", "te", "st", "ing");
743 P("s#+#+", "test", 1, "test", 2, "test");
744 P("s%+%+", "test", (size_t)1, "test", (size_t)2, "test");
747 P("o", json_object_new_int(1));
748 P("o?", json_object_new_int(1));
750 P("O", json_object_new_int(1));
751 P("O?", json_object_new_int(1));
754 P("{s+#+: []}", "foo", "barbar", 3, "baz");
755 P("{s:s,s:o,s:O}", "a", NULL, "b", NULL, "c", NULL);
756 P("{s:**}", "a", NULL);
757 P("{s:s*,s:o*,s:O*}", "a", NULL, "b", NULL, "c", NULL);
758 P("[i,i,i]", 0, 1, 2);
759 P("[s,o,O]", NULL, NULL, NULL);
761 P("[s*,o*,O*]", NULL, NULL, NULL);
764 P("[ i , i, i ] ", 1, 2, 3);
776 P("{ {}: s }", "foo");
777 P("{ s: {}, s:[ii{} }", "foo", "bar", 12, 13);
778 P("[[[[[ [[[[[ [[[[ }]]]] ]]]] ]]]]]");
780 U("true", "b", &xi[0]);
781 U("false", "b", &xi[0]);
783 U("42", "i", &xi[0]);
784 U("123456789", "I", &xI[0]);
785 U("3.14", "f", &xf[0]);
786 U("12345", "F", &xf[0]);
787 U("3.14", "F", &xf[0]);
788 U("\"foo\"", "s", &xs[0]);
789 U("\"foo\"", "s%", &xs[0], &xz[0]);
792 U("{}", "o", &xo[0]);
793 U("{}", "O", &xo[0]);
794 U("{\"foo\":42}", "{si}", "foo", &xi[0]);
795 U("[1,2,3]", "[i,i,i]", &xi[0], &xi[1], &xi[2]);
796 U("{\"a\":1,\"b\":2,\"c\":3}", "{s:i, s:i, s:i}", "a", &xi[0], "b", &xi[1], "c", &xi[2]);
803 U("[42]", "[i]a", &xi[0]);
804 U("42", "ia", &xi[0]);
806 U("\"foo\"", "s", NULL);
811 U("42", "[i]", NULL);
812 U("42", "{si}", "foo", NULL);
814 U("\"foo\"", "b", NULL);
815 U("\"foo\"", "i", NULL);
816 U("\"foo\"", "I", NULL);
817 U("\"foo\"", "f", NULL);
818 U("\"foo\"", "F", NULL);
819 U("true", "s", NULL);
821 U("true", "i", NULL);
822 U("true", "I", NULL);
823 U("true", "f", NULL);
824 U("true", "F", NULL);
825 U("[42]", "[ii]", &xi[0], &xi[1]);
826 U("{\"foo\":42}", "{si}", NULL, &xi[0]);
827 U("{\"foo\":42}", "{si}", "baz", &xi[0]);
828 U("[1,2,3]", "[iii!]", &xi[0], &xi[1], &xi[2]);
829 U("[1,2,3]", "[ii!]", &xi[0], &xi[1]);
830 U("[1,2,3]", "[ii]", &xi[0], &xi[1]);
831 U("[1,2,3]", "[ii*]", &xi[0], &xi[1]);
832 U("{\"foo\":42,\"baz\":45}", "{sisi}", "baz", &xi[0], "foo", &xi[1]);
833 U("{\"foo\":42,\"baz\":45}", "{sisi*}", "baz", &xi[0], "foo", &xi[1]);
834 U("{\"foo\":42,\"baz\":45}", "{sisi!}", "baz", &xi[0], "foo", &xi[1]);
835 U("{\"foo\":42,\"baz\":45}", "{si}", "baz", &xi[0], "foo", &xi[1]);
836 U("{\"foo\":42,\"baz\":45}", "{si*}", "baz", &xi[0], "foo", &xi[1]);
837 U("{\"foo\":42,\"baz\":45}", "{si!}", "baz", &xi[0], "foo", &xi[1]);
838 U("[1,{\"foo\":2,\"bar\":null},[3,4]]", "[i{sisn}[ii]]", &xi[0], "foo", &xi[1], "bar", &xi[2], &xi[3]);
839 U("[1,2,3]", "[ii!i]", &xi[0], &xi[1], &xi[2]);
840 U("[1,2,3]", "[ii*i]", &xi[0], &xi[1], &xi[2]);
841 U("{\"foo\":1,\"bar\":2}", "{si!si}", "foo", &xi[1], "bar", &xi[2]);
842 U("{\"foo\":1,\"bar\":2}", "{si*si}", "foo", &xi[1], "bar", &xi[2]);
843 U("{\"foo\":{\"baz\":null,\"bar\":null}}", "{s{sn!}}", "foo", "bar");
844 U("[[1,2,3]]", "[[ii!]]", &xi[0], &xi[1]);
845 U("{}", "{s?i}", "foo", &xi[0]);
846 U("{\"foo\":1}", "{s?i}", "foo", &xi[0]);
847 U("{}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
848 U("{\"foo\":[1,2]}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
849 U("{\"bar\":{\"baz\":{\"quux\":15}}}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
850 U("{\"foo\":{\"bar\":4}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
851 U("{\"foo\":{}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
852 U("{}", "{s?{s?i}}", "foo", "bar", &xi[0]);
853 U("{\"foo\":42,\"baz\":45}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
854 U("{\"foo\":42}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
863 /* Unpack the same item twice */
864 j = json_pack("{s:s, s:i, s:b}", "foo", "bar", "baz", 42, "quux", 1);
865 if(!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s))
866 fail("json_unpack object with strict validation failed");
868 const char *possible_errors[] = {
869 "2 object item(s) left unpacked: baz, quux",
870 "2 object item(s) left unpacked: quux, baz"
872 check_errors(possible_errors, 2, "<validation>", 1, 10, 10);