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"
27 wrap_json_pack_error_none,
28 wrap_json_pack_error_null_object,
29 wrap_json_pack_error_truncated,
30 wrap_json_pack_error_internal_error,
31 wrap_json_pack_error_out_of_memory,
32 wrap_json_pack_error_invalid_character,
33 wrap_json_pack_error_too_long,
34 wrap_json_pack_error_too_deep,
35 wrap_json_pack_error_null_spec,
36 wrap_json_pack_error_null_key,
37 wrap_json_pack_error_null_string,
38 _wrap_json_pack_error_count_
41 static const char ignore_all[] = " \t\n\r,:";
42 static const char accept_arr[] = "][{snbiIfoO";
43 static const char accept_key[] = "s}";
44 #define accept_any (&accept_arr[1])
46 static const char *pack_errors[_wrap_json_pack_error_count_] =
48 [wrap_json_pack_error_none] = "unknown error",
49 [wrap_json_pack_error_null_object] = "null object",
50 [wrap_json_pack_error_truncated] = "truncated",
51 [wrap_json_pack_error_internal_error] = "internal error",
52 [wrap_json_pack_error_out_of_memory] = "out of memory",
53 [wrap_json_pack_error_invalid_character] = "invalid character",
54 [wrap_json_pack_error_too_long] = "too long",
55 [wrap_json_pack_error_too_deep] = "too deep",
56 [wrap_json_pack_error_null_spec] = "spec is NULL",
57 [wrap_json_pack_error_null_key] = "key is NULL",
58 [wrap_json_pack_error_null_string] = "string is NULL"
61 int wrap_json_pack_error_position(int rc)
68 int wrap_json_pack_error_code(int rc)
75 const char *wrap_json_pack_error_string(int rc)
77 rc = wrap_json_pack_error_code(rc);
78 if (rc >= sizeof pack_errors / sizeof *pack_errors)
80 return pack_errors[rc];
85 static inline const char *skip(const char *d)
87 while (*d && strchr(ignore_all, *d))
92 int wrap_json_vpack(struct json_object **result, const char *desc, va_list args)
94 int nstr, notnull, nullable, rc;
100 struct { const char *str; size_t sz; } strs[STRCOUNT];
101 struct { struct json_object *cont, *key; const char *acc; char type; } stack[STACKCOUNT], *top;
102 struct json_object *obj;
109 top->acc = accept_any;
118 if (!strchr(top->acc, c))
119 goto invalid_character;
128 strs[nstr].str = va_arg(args, const char*);
136 case '%': strs[nstr].sz = va_arg(args, size_t); d = skip(++d); break;
137 case '#': strs[nstr].sz = (size_t)va_arg(args, int); d = skip(++d); break;
138 default: strs[nstr].sz = strs[nstr].str ? strlen(strs[nstr].str) : 0; break;
140 sz += strs[nstr++].sz;
147 if (nstr >= STRCOUNT)
163 dsz -= strs[nstr].sz;
164 memcpy(&s[dsz], strs[nstr].str, strs[nstr].sz);
166 obj = json_object_new_string_len(s, sz);
178 obj = json_object_new_boolean(va_arg(args, int));
183 obj = json_object_new_int(va_arg(args, int));
188 obj = json_object_new_int64(va_arg(args, int64_t));
193 obj = json_object_new_double(va_arg(args, double));
199 obj = va_arg(args, struct json_object*);
202 else if (*d != '*' && !obj)
205 json_object_get(obj);
209 if (++top >= &stack[STACKCOUNT])
214 top->acc = accept_arr;
215 top->cont = json_object_new_array();
218 top->acc = accept_key;
219 top->cont = json_object_new_object();
226 if (c != top->type || top <= stack)
227 goto invalid_character;
229 if (*d == '*' && !(c == '}' ? json_object_object_length(obj) : json_object_array_length(obj))) {
230 json_object_put(obj);
242 goto invalid_character;
246 if (obj || *d != '*')
247 json_object_array_add(top->cont, obj);
255 top->acc = accept_any;
259 if (obj || *d != '*')
260 json_object_object_add(top->cont, json_object_get_string(top->key), obj);
263 json_object_put(top->key);
265 top->acc = accept_key;
272 rc = wrap_json_pack_error_null_object;
275 rc = wrap_json_pack_error_truncated;
278 rc = wrap_json_pack_error_internal_error;
281 rc = wrap_json_pack_error_out_of_memory;
284 rc = wrap_json_pack_error_invalid_character;
287 rc = wrap_json_pack_error_too_long;
290 rc = wrap_json_pack_error_too_deep;
293 rc = wrap_json_pack_error_null_spec;
296 rc = wrap_json_pack_error_null_key;
299 rc = wrap_json_pack_error_null_string;
303 json_object_put(top->key);
304 json_object_put(top->cont);
305 } while (--top >= stack);
307 rc = rc | (int)((d - desc) << 4);
311 int wrap_json_pack(struct json_object **result, const char *desc, ...)
316 va_start(args, desc);
317 rc = wrap_json_vpack(result, desc, args);
325 void T(const char *desc, ...)
329 struct json_object *result;
331 va_start(args, desc);
332 rc = wrap_json_vpack(&result, desc, args);
335 printf(" SUCCESS %s\n\n", json_object_to_json_string(result));
337 printf(" ERROR[char %d err %d] %s\n\n", wrap_json_pack_error_position(rc), wrap_json_pack_error_code(rc), wrap_json_pack_error_string(rc));
338 json_object_put(result);
341 #define t(...) printf("testing(%s)\n",#__VA_ARGS__); T(__VA_ARGS__);
345 char buffer[4] = {'t', 'e', 's', 't'};
351 t("I", (uint64_t)0x123456789abcdef);
356 t("s#", "test asdf", 4);
357 t("s%", "test asdf", (size_t)4);
359 t("s%", buffer, (size_t)4);
360 t("s++", "te", "st", "ing");
361 t("s#+#+", "test", 1, "test", 2, "test");
362 t("s%+%+", "test", (size_t)1, "test", (size_t)2, "test");
365 t("o", json_object_new_int(1));
366 t("o?", json_object_new_int(1));
368 t("O", json_object_new_int(1));
369 t("O?", json_object_new_int(1));
372 t("{s+#+: []}", "foo", "barbar", 3, "baz");
373 t("{s:s,s:o,s:O}", "a", NULL, "b", NULL, "c", NULL);
374 t("{s:**}", "a", NULL);
375 t("{s:s*,s:o*,s:O*}", "a", NULL, "b", NULL, "c", NULL);
376 t("[i,i,i]", 0, 1, 2);
377 t("[s,o,O]", NULL, NULL, NULL);
379 t("[s*,o*,O*]", NULL, NULL, NULL);
382 t("[ i , i, i ] ", 1, 2, 3);
394 t("{ {}: s }", "foo");
395 t("{ s: {}, s:[ii{} }", "foo", "bar", 12, 13);
396 t("[[[[[ [[[[[ [[[[ }]]]] ]]]] ]]]]]");