2 Copyright (C) 2016, 2017, 2018 "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_bad_base64,
43 _wrap_json_error_count_
46 static const char ignore_all[] = " \t\n\r,:";
47 static const char pack_accept_arr[] = "][{snbiIfoOyY";
48 static const char pack_accept_key[] = "s}";
49 #define pack_accept_any (&pack_accept_arr[1])
51 static const char unpack_accept_arr[] = "*!][{snbiIfFoOyY";
52 static const char unpack_accept_key[] = "*!s}";
53 #define unpack_accept_any (&unpack_accept_arr[3])
55 static const char *pack_errors[_wrap_json_error_count_] =
57 [wrap_json_error_none] = "unknown error",
58 [wrap_json_error_null_object] = "null object",
59 [wrap_json_error_truncated] = "truncated",
60 [wrap_json_error_internal_error] = "internal error",
61 [wrap_json_error_out_of_memory] = "out of memory",
62 [wrap_json_error_invalid_character] = "invalid character",
63 [wrap_json_error_too_long] = "too long",
64 [wrap_json_error_too_deep] = "too deep",
65 [wrap_json_error_null_spec] = "spec is NULL",
66 [wrap_json_error_null_key] = "key is NULL",
67 [wrap_json_error_null_string] = "string is NULL",
68 [wrap_json_error_out_of_range] = "array too small",
69 [wrap_json_error_incomplete] = "incomplete container",
70 [wrap_json_error_missfit_type] = "missfit of type",
71 [wrap_json_error_key_not_found] = "key not found",
72 [wrap_json_error_bad_base64] = "bad base64 encoding"
75 int wrap_json_get_error_position(int rc)
82 int wrap_json_get_error_code(int rc)
89 const char *wrap_json_get_error_string(int rc)
91 rc = wrap_json_get_error_code(rc);
92 if (rc >= sizeof pack_errors / sizeof *pack_errors)
94 return pack_errors[rc];
97 static int encode_base64(
108 size_t in, out, rlen, n3, r3, iout, nout;
112 /* compute unformatted output length */
115 nout = 4 * n3 + r3 + !!r3;
117 /* deduce formatted output length */
120 rlen += ((~rlen) + 1) & 3;
122 rlen += rlen / width;
124 /* allocate the output */
125 result = malloc(rlen + 1);
127 return wrap_json_error_out_of_memory;
129 /* compute the formatted output */
131 for (in = out = iout = 0 ; iout < nout ; iout++) {
132 /* get in 'u8' the 6 bits value to add */
135 u16 = (uint16_t)data[in++];
136 u8 = (uint8_t)(u16 >> 2);
139 u16 = (uint16_t)(u16 << 8);
141 u16 = (uint16_t)(u16 | data[in++]);
142 u8 = (uint8_t)(u16 >> 4);
145 u16 = (uint16_t)(u16 << 8);
147 u16 = (uint16_t)(u16 | data[in++]);
148 u8 = (uint8_t)(u16 >> 6);
156 /* encode 'u8' to the char 'c' */
159 c = (char)('A' + u8);
161 c = (char)('a' + u8 - 26);
164 c = (char)('0' + u8 - 52);
171 /* put to output with format */
174 result[out++] = '\n';
183 result[out++] = '\n';
195 static int decode_base64(
207 /* allocate enougth output */
208 result = malloc(datalen);
210 return wrap_json_error_out_of_memory;
212 /* decode the input */
213 for (iin = in = out = 0 ; in < datalen ; in++) {
215 if (c != '\n' && c != '\r' && c != '=') {
216 if ('A' <= c && c <= 'Z')
217 u8 = (uint8_t)(c - 'A');
218 else if ('a' <= c && c <= 'z')
219 u8 = (uint8_t)(c - 'a' + 26);
220 else if ('0' <= c && c <= '9')
221 u8 = (uint8_t)(c - '0' + 52);
222 else if (c == '+' || c == '-')
224 else if (c == '/' || c == '_')
228 return wrap_json_error_bad_base64;
234 u16 = (uint16_t)((u16 << 6) | u8);
236 u8 = (uint8_t)(u16 >> iin);
243 *decoded = realloc(result, out);
244 if (*decoded == NULL) {
246 return wrap_json_error_out_of_memory;
252 static inline const char *skip(const char *d)
254 while (*d && strchr(ignore_all, *d))
259 int wrap_json_vpack(struct json_object **result, const char *desc, va_list args)
261 /* TODO: the case of structs with key being single char should be optimized */
262 int nstr, notnull, nullable, rc;
268 struct { const uint8_t *in; size_t insz; char *out; size_t outsz; } bytes;
269 struct { const char *str; size_t sz; } strs[STRCOUNT];
270 struct { struct json_object *cont, *key; const char *acc; char type; } stack[STACKCOUNT], *top;
271 struct json_object *obj;
278 top->acc = pack_accept_any;
288 if (!strchr(top->acc, c))
289 goto invalid_character;
298 strs[nstr].str = va_arg(args, const char*);
306 case '%': strs[nstr].sz = va_arg(args, size_t); d = skip(++d); break;
307 case '#': strs[nstr].sz = (size_t)va_arg(args, int); d = skip(++d); break;
308 default: strs[nstr].sz = strs[nstr].str ? strlen(strs[nstr].str) : 0; break;
310 sz += strs[nstr++].sz;
317 if (nstr >= STRCOUNT)
333 dsz -= strs[nstr].sz;
334 memcpy(&s[dsz], strs[nstr].str, strs[nstr].sz);
336 obj = json_object_new_string_len(s, (int)sz);
348 obj = json_object_new_boolean(va_arg(args, int));
353 obj = json_object_new_int(va_arg(args, int));
358 obj = json_object_new_int64(va_arg(args, int64_t));
363 obj = json_object_new_double(va_arg(args, double));
369 obj = va_arg(args, struct json_object*);
372 else if (*d != '*' && !obj)
375 json_object_get(obj);
379 bytes.in = va_arg(args, const uint8_t*);
380 bytes.insz = va_arg(args, size_t);
381 rc = encode_base64(bytes.in, bytes.insz,
382 &bytes.out, &bytes.outsz, 0, 0, c == 'y');
385 obj = json_object_new_string_len(bytes.out, (int)bytes.outsz);
392 if (++top >= &stack[STACKCOUNT])
397 top->acc = pack_accept_arr;
398 top->cont = json_object_new_array();
401 top->acc = pack_accept_key;
402 top->cont = json_object_new_object();
409 if (c != top->type || top <= stack)
412 if (*d == '*' && !(c == '}' ? json_object_object_length(obj) : json_object_array_length(obj))) {
413 json_object_put(obj);
425 goto invalid_character;
429 if (obj || *d != '*')
430 json_object_array_add(top->cont, obj);
438 top->acc = pack_accept_any;
442 if (obj || *d != '*')
443 json_object_object_add(top->cont, json_object_get_string(top->key), obj);
446 json_object_put(top->key);
448 top->acc = pack_accept_key;
457 rc = wrap_json_error_null_object;
460 rc = wrap_json_error_truncated;
463 rc = wrap_json_error_internal_error;
466 rc = wrap_json_error_out_of_memory;
469 rc = wrap_json_error_invalid_character;
472 rc = wrap_json_error_too_long;
475 rc = wrap_json_error_too_deep;
478 rc = wrap_json_error_null_spec;
481 rc = wrap_json_error_null_key;
484 rc = wrap_json_error_null_string;
488 json_object_put(top->key);
489 json_object_put(top->cont);
490 } while (--top >= stack);
492 rc = rc | (int)((d - desc) << 4);
496 int wrap_json_pack(struct json_object **result, const char *desc, ...)
501 va_start(args, desc);
502 rc = wrap_json_vpack(result, desc, args);
507 static int vunpack(struct json_object *object, const char *desc, va_list args, int store)
509 int rc = 0, optionnal, ignore;
510 char c, xacc[2] = { 0, 0 };
512 const char *d, *fit = NULL;
513 const char *key = NULL;
514 const char **ps = NULL;
520 struct { struct json_object *parent; const char *acc; int index; size_t count; char type; } stack[STACKCOUNT], *top;
521 struct json_object *obj;
522 struct json_object **po;
527 acc = unpack_accept_any;
539 goto invalid_character;
543 if (xacc[0] == '}') {
545 key = va_arg(args, const char *);
557 if (json_object_object_get_ex(top->parent, key, &obj)) {
569 acc = unpack_accept_any;
574 ps = va_arg(args, const char **);
576 if (!json_object_is_type(obj, json_type_string))
579 *ps = json_object_get_string(obj);
584 pz = va_arg(args, size_t *);
586 *pz = (size_t)json_object_get_string_len(obj);
591 if (!ignore && !json_object_is_type(obj, json_type_null))
596 pi = va_arg(args, int *);
599 if (!json_object_is_type(obj, json_type_boolean))
602 *pi = json_object_get_boolean(obj);
607 pi = va_arg(args, int *);
610 if (!json_object_is_type(obj, json_type_int))
613 *pi = json_object_get_int(obj);
618 pI = va_arg(args, int64_t *);
621 if (!json_object_is_type(obj, json_type_int))
624 *pI = json_object_get_int64(obj);
630 pf = va_arg(args, double *);
633 if (!(json_object_is_type(obj, json_type_double) || (c == 'F' && json_object_is_type(obj, json_type_int))))
636 *pf = json_object_get_double(obj);
642 po = va_arg(args, struct json_object **);
645 obj = json_object_get(obj);
653 py = va_arg(args, uint8_t **);
654 pz = va_arg(args, size_t *);
657 if (!json_object_is_type(obj, json_type_string))
659 if (store && py && pz) {
661 json_object_get_string(obj),
662 (size_t)json_object_get_string_len(obj),
674 else if (++top >= &stack[STACKCOUNT])
685 if (!json_object_is_type(obj, json_type_array))
687 top->count = json_object_array_length(obj);
690 acc = unpack_accept_arr;
693 if (!json_object_is_type(obj, json_type_object))
695 top->count = json_object_object_length(obj);
698 acc = unpack_accept_key;
704 if (!top || c != xacc[0])
708 top = top == stack ? NULL : top - 1;
714 goto invalid_character;
715 if (!ignore && top->index != top->count)
729 goto invalid_character;
733 key = strchr(unpack_accept_arr, *d);
734 if (key && key >= unpack_accept_any) {
735 if (top->index >= top->count)
737 obj = json_object_array_get_idx(top->parent, top->index++);
742 acc = unpack_accept_key;
752 rc = wrap_json_error_truncated;
755 rc = wrap_json_error_internal_error;
758 rc = wrap_json_error_invalid_character;
761 rc = wrap_json_error_too_deep;
764 rc = wrap_json_error_null_spec;
767 rc = wrap_json_error_null_key;
770 rc = wrap_json_error_out_of_range;
773 rc = wrap_json_error_incomplete;
776 rc = wrap_json_error_missfit_type;
779 rc = wrap_json_error_key_not_found;
784 rc = rc | (int)((d - desc) << 4);
788 int wrap_json_vcheck(struct json_object *object, const char *desc, va_list args)
790 return vunpack(object, desc, args, 0);
793 int wrap_json_check(struct json_object *object, const char *desc, ...)
798 va_start(args, desc);
799 rc = vunpack(object, desc, args, 0);
804 int wrap_json_vmatch(struct json_object *object, const char *desc, va_list args)
806 return !vunpack(object, desc, args, 0);
809 int wrap_json_match(struct json_object *object, const char *desc, ...)
814 va_start(args, desc);
815 rc = vunpack(object, desc, args, 0);
820 int wrap_json_vunpack(struct json_object *object, const char *desc, va_list args)
822 return vunpack(object, desc, args, 1);
825 int wrap_json_unpack(struct json_object *object, const char *desc, ...)
830 va_start(args, desc);
831 rc = vunpack(object, desc, args, 1);
836 static void object_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
838 struct json_object_iterator it = json_object_iter_begin(object);
839 struct json_object_iterator end = json_object_iter_end(object);
840 while (!json_object_iter_equal(&it, &end)) {
841 callback(closure, json_object_iter_peek_value(&it), json_object_iter_peek_name(&it));
842 json_object_iter_next(&it);
846 static void array_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
848 size_t n = json_object_array_length(object);
851 callback(closure, json_object_array_get_idx(object, i++));
854 void wrap_json_optarray_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
856 if (json_object_is_type(object, json_type_array))
857 array_for_all(object, callback, closure);
859 callback(closure, object);
862 void wrap_json_array_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
864 if (json_object_is_type(object, json_type_array))
865 array_for_all(object, callback, closure);
868 void wrap_json_object_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
870 if (json_object_is_type(object, json_type_object))
871 object_for_all(object, callback, closure);
874 void wrap_json_optobject_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
876 if (json_object_is_type(object, json_type_object))
877 object_for_all(object, callback, closure);
879 callback(closure, object, NULL);
882 void wrap_json_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
886 else if (json_object_is_type(object, json_type_object))
887 object_for_all(object, callback, closure);
888 else if (!json_object_is_type(object, json_type_array))
889 callback(closure, object, NULL);
891 size_t n = json_object_array_length(object);
894 callback(closure, json_object_array_get_idx(object, i++), NULL);
898 #if defined(WRAP_JSON_TEST)
901 void p(const char *desc, ...)
905 struct json_object *result;
907 va_start(args, desc);
908 rc = wrap_json_vpack(&result, desc, args);
911 printf(" SUCCESS %s\n\n", json_object_to_json_string(result));
913 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));
914 json_object_put(result);
921 struct json_object *xo[10];
925 void u(const char *value, const char *desc, ...)
930 struct json_object *obj, *o;
932 memset(xs, 0, sizeof xs);
933 memset(xi, 0, sizeof xi);
934 memset(xI, 0, sizeof xI);
935 memset(xf, 0, sizeof xf);
936 memset(xo, 0, sizeof xo);
937 memset(xz, 0, sizeof xz);
938 obj = json_tokener_parse(value);
939 va_start(args, desc);
940 rc = wrap_json_vunpack(obj, desc, args);
943 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));
947 va_start(args, desc);
951 case '{': m = (m << 1) | 1; k = 1; break;
952 case '}': m = m >> 1; k = m&1; break;
953 case '[': m = m << 1; k = 0; break;
954 case ']': m = m >> 1; k = m&1; break;
955 case 's': printf(" s:%s", k ? va_arg(args, const char*) : *(va_arg(args, const char**)?:&value)); k ^= m&1; break;
956 case '%': printf(" %%:%zu", *va_arg(args, size_t*)); k = m&1; break;
957 case 'n': printf(" n"); k = m&1; break;
958 case 'b': printf(" b:%d", *va_arg(args, int*)); k = m&1; break;
959 case 'i': printf(" i:%d", *va_arg(args, int*)); k = m&1; break;
960 case 'I': printf(" I:%lld", *va_arg(args, int64_t*)); k = m&1; break;
961 case 'f': printf(" f:%f", *va_arg(args, double*)); k = m&1; break;
962 case 'F': printf(" F:%f", *va_arg(args, double*)); k = m&1; break;
963 case 'o': printf(" o:%s", json_object_to_json_string(*va_arg(args, struct json_object**))); k = m&1; break;
964 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;
967 uint8_t *p = *va_arg(args, uint8_t**);
968 size_t s = *va_arg(args, size_t*);
969 printf(" y/%d:%.*s", (int)s, (int)s, (char*)p);
980 json_object_put(obj);
983 #define P(...) do{ printf("pack(%s)\n",#__VA_ARGS__); p(__VA_ARGS__); } while(0)
984 #define U(...) do{ printf("unpack(%s)\n",#__VA_ARGS__); u(__VA_ARGS__); } while(0)
988 char buffer[4] = {'t', 'e', 's', 't'};
994 P("I", (uint64_t)0x123456789abcdef);
999 P("s#", "test asdf", 4);
1000 P("s%", "test asdf", (size_t)4);
1002 P("s%", buffer, (size_t)4);
1003 P("s++", "te", "st", "ing");
1004 P("s#+#+", "test", 1, "test", 2, "test");
1005 P("s%+%+", "test", (size_t)1, "test", (size_t)2, "test");
1008 P("o", json_object_new_int(1));
1009 P("o?", json_object_new_int(1));
1011 P("O", json_object_new_int(1));
1012 P("O?", json_object_new_int(1));
1015 P("{s+#+: []}", "foo", "barbar", 3, "baz");
1016 P("{s:s,s:o,s:O}", "a", NULL, "b", NULL, "c", NULL);
1017 P("{s:**}", "a", NULL);
1018 P("{s:s*,s:o*,s:O*}", "a", NULL, "b", NULL, "c", NULL);
1019 P("[i,i,i]", 0, 1, 2);
1020 P("[s,o,O]", NULL, NULL, NULL);
1022 P("[s*,o*,O*]", NULL, NULL, NULL);
1025 P("[ i , i, i ] ", 1, 2, 3);
1036 P("{s:i}", NULL, 1);
1037 P("{ {}: s }", "foo");
1038 P("{ s: {}, s:[ii{} }", "foo", "bar", 12, 13);
1039 P("[[[[[ [[[[[ [[[[ }]]]] ]]]] ]]]]]");
1040 P("y", "???????hello>>>>>>>", (size_t)19);
1041 P("Y", "???????hello>>>>>>>", (size_t)19);
1043 U("true", "b", &xi[0]);
1044 U("false", "b", &xi[0]);
1046 U("42", "i", &xi[0]);
1047 U("123456789", "I", &xI[0]);
1048 U("3.14", "f", &xf[0]);
1049 U("12345", "F", &xf[0]);
1050 U("3.14", "F", &xf[0]);
1051 U("\"foo\"", "s", &xs[0]);
1052 U("\"foo\"", "s%", &xs[0], &xz[0]);
1055 U("{}", "o", &xo[0]);
1056 U("{}", "O", &xo[0]);
1057 U("{\"foo\":42}", "{si}", "foo", &xi[0]);
1058 U("[1,2,3]", "[i,i,i]", &xi[0], &xi[1], &xi[2]);
1059 U("{\"a\":1,\"b\":2,\"c\":3}", "{s:i, s:i, s:i}", "a", &xi[0], "b", &xi[1], "c", &xi[2]);
1066 U("[42]", "[i]a", &xi[0]);
1067 U("42", "ia", &xi[0]);
1069 U("\"foo\"", "s", NULL);
1074 U("42", "[i]", NULL);
1075 U("42", "{si}", "foo", NULL);
1077 U("\"foo\"", "b", NULL);
1078 U("\"foo\"", "i", NULL);
1079 U("\"foo\"", "I", NULL);
1080 U("\"foo\"", "f", NULL);
1081 U("\"foo\"", "F", NULL);
1082 U("true", "s", NULL);
1084 U("true", "i", NULL);
1085 U("true", "I", NULL);
1086 U("true", "f", NULL);
1087 U("true", "F", NULL);
1088 U("[42]", "[ii]", &xi[0], &xi[1]);
1089 U("{\"foo\":42}", "{si}", NULL, &xi[0]);
1090 U("{\"foo\":42}", "{si}", "baz", &xi[0]);
1091 U("[1,2,3]", "[iii!]", &xi[0], &xi[1], &xi[2]);
1092 U("[1,2,3]", "[ii!]", &xi[0], &xi[1]);
1093 U("[1,2,3]", "[ii]", &xi[0], &xi[1]);
1094 U("[1,2,3]", "[ii*]", &xi[0], &xi[1]);
1095 U("{\"foo\":42,\"baz\":45}", "{sisi}", "baz", &xi[0], "foo", &xi[1]);
1096 U("{\"foo\":42,\"baz\":45}", "{sisi*}", "baz", &xi[0], "foo", &xi[1]);
1097 U("{\"foo\":42,\"baz\":45}", "{sisi!}", "baz", &xi[0], "foo", &xi[1]);
1098 U("{\"foo\":42,\"baz\":45}", "{si}", "baz", &xi[0], "foo", &xi[1]);
1099 U("{\"foo\":42,\"baz\":45}", "{si*}", "baz", &xi[0], "foo", &xi[1]);
1100 U("{\"foo\":42,\"baz\":45}", "{si!}", "baz", &xi[0], "foo", &xi[1]);
1101 U("[1,{\"foo\":2,\"bar\":null},[3,4]]", "[i{sisn}[ii]]", &xi[0], "foo", &xi[1], "bar", &xi[2], &xi[3]);
1102 U("[1,2,3]", "[ii!i]", &xi[0], &xi[1], &xi[2]);
1103 U("[1,2,3]", "[ii*i]", &xi[0], &xi[1], &xi[2]);
1104 U("{\"foo\":1,\"bar\":2}", "{si!si}", "foo", &xi[1], "bar", &xi[2]);
1105 U("{\"foo\":1,\"bar\":2}", "{si*si}", "foo", &xi[1], "bar", &xi[2]);
1106 U("{\"foo\":{\"baz\":null,\"bar\":null}}", "{s{sn!}}", "foo", "bar");
1107 U("[[1,2,3]]", "[[ii!]]", &xi[0], &xi[1]);
1108 U("{}", "{s?i}", "foo", &xi[0]);
1109 U("{\"foo\":1}", "{s?i}", "foo", &xi[0]);
1110 U("{}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
1111 U("{\"foo\":[1,2]}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
1112 U("{\"bar\":{\"baz\":{\"quux\":15}}}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
1113 U("{\"foo\":{\"bar\":4}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
1114 U("{\"foo\":{}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
1115 U("{}", "{s?{s?i}}", "foo", "bar", &xi[0]);
1116 U("{\"foo\":42,\"baz\":45}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
1117 U("{\"foo\":42}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
1119 U("\"Pz8_Pz8_P2hlbGxvPj4-Pj4-Pg\"", "y", &xy[0], &xz[0]);
1128 /* Unpack the same item twice */
1129 j = json_pack("{s:s, s:i, s:b}", "foo", "bar", "baz", 42, "quux", 1);
1130 if(!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s))
1131 fail("json_unpack object with strict validation failed");
1133 const char *possible_errors[] = {
1134 "2 object item(s) left unpacked: baz, quux",
1135 "2 object item(s) left unpacked: quux, baz"
1137 check_errors(possible_errors, 2, "<validation>", 1, 10, 10);