1 /*
2  * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
3  * Copyright (c) 2011-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
4  *
5  * Jansson is free software; you can redistribute it and/or modify
6  * it under the terms of the MIT license. See LICENSE for details.
7  */
8 /**
9  * License: MIT
10  */
11 module jansson_d.pack_unpack;
12 
13 
14 package:
15 
16 private static import core.stdc.config;
17 private static import core.stdc.stdarg;
18 private static import core.stdc.string;
19 private static import jansson_d.hashtable;
20 private static import jansson_d.jansson;
21 private static import jansson_d.jansson_private;
22 private static import jansson_d.strbuffer;
23 private static import jansson_d.utf;
24 private static import jansson_d.value;
25 
26 struct token_t
27 {
28 	int line;
29 	int column;
30 	size_t pos;
31 	char token = '\0';
32 }
33 
34 struct scanner_t
35 {
36 	const (char)* start;
37 	const (char)* fmt;
38 	.token_t prev_token;
39 	.token_t token;
40 	.token_t next_token;
41 	jansson_d.jansson.json_error_t* error;
42 	size_t flags;
43 	int line;
44 	int column;
45 	size_t pos;
46 	int has_error;
47 }
48 
49 private template token(string scanner)
50 {
51 	enum token = "((" ~ scanner ~ ").token.token)";
52 }
53 
54 private static immutable string[] type_names = ["object\0", "array\0", "string\0", "integer\0", "real\0", "true\0", "false\0", "null\0"];
55 
56 private template type_name(string x)
57 {
58 	enum type_name = "&(.type_names[mixin (jansson_d.jansson.json_typeof!(\"" ~ x ~ "\"))][0])";
59 }
60 
61 private static immutable char[] unpack_value_starters = "{[siIbfFOon\0";
62 
63 pure nothrow @trusted @nogc @live
64 private void scanner_init(scope scanner_t* s, scope jansson_d.jansson.json_error_t* error, size_t flags, scope const char* fmt)
65 
66 	in
67 	{
68 		assert(s != null);
69 	}
70 
71 	do
72 	{
73 		s.error = error;
74 		s.flags = flags;
75 		s.start = fmt;
76 		s.fmt = fmt;
77 		core.stdc..string.memset(&s.prev_token, 0, .token_t.sizeof);
78 		core.stdc..string.memset(&s.token, 0, .token_t.sizeof);
79 		core.stdc..string.memset(&s.next_token, 0, .token_t.sizeof);
80 		s.line = 1;
81 		s.column = 0;
82 		s.pos = 0;
83 		s.has_error = 0;
84 	}
85 
86 pure nothrow @trusted @nogc @live
87 private void next_token(scope .scanner_t* s)
88 
89 	in
90 	{
91 		assert(s != null);
92 	}
93 
94 	do
95 	{
96 		s.prev_token = s.token;
97 
98 		if (s.next_token.line) {
99 			s.token = s.next_token;
100 			s.next_token.line = 0;
101 
102 			return;
103 		}
104 
105 		if ((!mixin (.token!("s"))) && (*s.fmt == '\0')) {
106 			return;
107 		}
108 
109 		const (char)* t = s.fmt;
110 		s.column++;
111 		s.pos++;
112 
113 		/* skip space and ignored chars */
114 		while ((*t == ' ') || (*t == '\t') || (*t == '\n') || (*t == ',') || (*t == ':')) {
115 			if (*t == '\n') {
116 				s.line++;
117 				s.column = 1;
118 			} else {
119 				s.column++;
120 			}
121 
122 			s.pos++;
123 			t++;
124 		}
125 
126 		s.token.token = *t;
127 		s.token.line = s.line;
128 		s.token.column = s.column;
129 		s.token.pos = s.pos;
130 
131 		if (*t != '\0') {
132 			t++;
133 		}
134 
135 		s.fmt = t;
136 	}
137 
138 pure nothrow @trusted @nogc @live
139 private void prev_token(scope .scanner_t* s)
140 
141 	in
142 	{
143 		assert(s != null);
144 	}
145 
146 	do
147 	{
148 		s.next_token = s.token;
149 		s.token = s.prev_token;
150 	}
151 
152 nothrow @nogc @live
153 private void set_error(F ...)(scope .scanner_t* s, scope const char* source, jansson_d.jansson.json_error_code_t code, scope const char* fmt, F f)
154 
155 	in
156 	{
157 		assert(s != null);
158 	}
159 
160 	do
161 	{
162 		static if (f.length != 0) {
163 			jansson_d.jansson_private.jsonp_error_vset(s.error, s.token.line, s.token.column, s.token.pos, code, fmt, f[0 .. $]);
164 		} else {
165 			jansson_d.jansson_private.jsonp_error_vset(s.error, s.token.line, s.token.column, s.token.pos, code, fmt);
166 		}
167 
168 		jansson_d.jansson_private.jsonp_error_set_source(s.error, source);
169 	}
170 
171 /*
172  * ours will be set to 1 if jsonp_free() must be called for the result
173  * afterwards
174  */
175 nothrow @nogc
176 private char* read_string(scope .scanner_t* s, scope core.stdc.stdarg.va_list* ap, scope const char* purpose, scope size_t* out_len, scope int* ours, int optional)
177 
178 	in
179 	{
180 		assert(s != null);
181 		assert(out_len != null);
182 		assert(ours != null);
183 	}
184 
185 	do
186 	{
187 		.next_token(s);
188 		char t = mixin (.token!("s"));
189 		.prev_token(s);
190 
191 		*ours = 0;
192 
193 		if ((t != '#') && (t != '%') && (t != '+')) {
194 			/* Optimize the simple case */
195 			const char* str = core.stdc.stdarg.va_arg!(const char*)(*ap);
196 
197 			if (str == null) {
198 				if (!optional) {
199 					.set_error(s, "<args>", jansson_d.jansson.json_error_code_t.json_error_null_value, "null %s", purpose);
200 					s.has_error = 1;
201 				}
202 
203 				return null;
204 			}
205 
206 			size_t length_ = core.stdc..string.strlen(str);
207 
208 			if (!jansson_d.utf.utf8_check_string(str, length_)) {
209 				.set_error(s, "<args>", jansson_d.jansson.json_error_code_t.json_error_invalid_utf8, "Invalid UTF-8 %s", purpose);
210 				s.has_error = 1;
211 
212 				return null;
213 			}
214 
215 			*out_len = length_;
216 
217 			return cast(char*)(str);
218 		} else if (optional) {
219 			.set_error(s, "<format>", jansson_d.jansson.json_error_code_t.json_error_invalid_format, "Cannot use '%c' on optional strings", t);
220 			s.has_error = 1;
221 
222 			return null;
223 		}
224 
225 		jansson_d.strbuffer.strbuffer_t strbuff = void;
226 
227 		if (jansson_d.strbuffer.strbuffer_init(&strbuff)) {
228 			.set_error(s, "<internal>", jansson_d.jansson.json_error_code_t.json_error_out_of_memory, "Out of memory");
229 			s.has_error = 1;
230 		}
231 
232 		while (true) {
233 			const char* str = core.stdc.stdarg.va_arg!(const char*)(*ap);
234 
235 			if (str == null) {
236 				.set_error(s, "<args>", jansson_d.jansson.json_error_code_t.json_error_null_value, "null %s", purpose);
237 				s.has_error = 1;
238 			}
239 
240 			.next_token(s);
241 
242 			size_t length_ = void;
243 
244 			if (mixin (.token!("s")) == '#') {
245 				length_ = core.stdc.stdarg.va_arg!(int)(*ap);
246 			} else if (mixin (.token!("s")) == '%') {
247 				length_ = core.stdc.stdarg.va_arg!(size_t)(*ap);
248 			} else {
249 				.prev_token(s);
250 				length_ = (s.has_error) ? (0) : (core.stdc..string.strlen(str));
251 			}
252 
253 			if ((!s.has_error) && (jansson_d.strbuffer.strbuffer_append_bytes(&strbuff, str, length_) == -1)) {
254 				.set_error(s, "<internal>", jansson_d.jansson.json_error_code_t.json_error_out_of_memory, "Out of memory");
255 				s.has_error = 1;
256 			}
257 
258 			.next_token(s);
259 
260 			if (mixin (.token!("s")) != '+') {
261 				.prev_token(s);
262 
263 				break;
264 			}
265 		}
266 
267 		if (s.has_error) {
268 			jansson_d.strbuffer.strbuffer_close(&strbuff);
269 
270 			return null;
271 		}
272 
273 		if (!jansson_d.utf.utf8_check_string(strbuff.value, strbuff.length_)) {
274 			.set_error(s, "<args>", jansson_d.jansson.json_error_code_t.json_error_invalid_utf8, "Invalid UTF-8 %s", purpose);
275 			jansson_d.strbuffer.strbuffer_close(&strbuff);
276 			s.has_error = 1;
277 
278 			return null;
279 		}
280 
281 		*out_len = strbuff.length_;
282 		*ours = 1;
283 
284 		return jansson_d.strbuffer.strbuffer_steal_value(&strbuff);
285 	}
286 
287 nothrow @nogc
288 private jansson_d.jansson.json_t* pack_object(scope .scanner_t* s, scope core.stdc.stdarg.va_list* ap)
289 
290 	do
291 	{
292 		jansson_d.jansson.json_t* object = jansson_d.value.json_object();
293 		.next_token(s);
294 
295 		while (mixin (.token!("s")) != '}') {
296 			if (!mixin (.token!("s"))) {
297 				.set_error(s, "<format>", jansson_d.jansson.json_error_code_t.json_error_invalid_format, "Unexpected end of format string");
298 
299 				goto error_;
300 			}
301 
302 			if (mixin (.token!("s")) != 's') {
303 				.set_error(s, "<format>", jansson_d.jansson.json_error_code_t.json_error_invalid_format, "Expected format 's', got '%c'", mixin (.token!("s")));
304 
305 				goto error_;
306 			}
307 
308 			size_t len = void;
309 			int ours = void;
310 			char* key = .read_string(s, ap, "object key", &len, &ours, 0);
311 
312 			.next_token(s);
313 
314 			.next_token(s);
315 			char valueOptional = mixin (.token!("s"));
316 			.prev_token(s);
317 
318 			jansson_d.jansson.json_t* value = .pack(s, ap);
319 
320 			if (value == null) {
321 				if (ours) {
322 					jansson_d.jansson_private.jsonp_free(key);
323 				}
324 
325 				if (valueOptional != '*') {
326 					.set_error(s, "<args>", jansson_d.jansson.json_error_code_t.json_error_null_value, "null object value");
327 					s.has_error = 1;
328 				}
329 
330 				.next_token(s);
331 
332 				continue;
333 			}
334 
335 			if (s.has_error) {
336 				jansson_d.jansson.json_decref(value);
337 			}
338 
339 			if ((!s.has_error) && (jansson_d.value.json_object_set_new_nocheck(object, key, value))) {
340 				.set_error(s, "<internal>", jansson_d.jansson.json_error_code_t.json_error_out_of_memory, "Unable to add key \"%s\"", key);
341 				s.has_error = 1;
342 			}
343 
344 			if (ours) {
345 				jansson_d.jansson_private.jsonp_free(key);
346 			}
347 
348 			.next_token(s);
349 		}
350 
351 		if (!s.has_error) {
352 			return object;
353 		}
354 
355 	error_:
356 		jansson_d.jansson.json_decref(object);
357 
358 		return null;
359 	}
360 
361 nothrow @nogc
362 private jansson_d.jansson.json_t* pack_array(scope .scanner_t* s, scope core.stdc.stdarg.va_list* ap)
363 
364 	do
365 	{
366 		jansson_d.jansson.json_t* array = jansson_d.value.json_array();
367 		.next_token(s);
368 
369 		while (mixin (.token!("s")) != ']') {
370 			if (!mixin (.token!("s"))) {
371 				.set_error(s, "<format>", jansson_d.jansson.json_error_code_t.json_error_invalid_format, "Unexpected end of format string");
372 				/* Format string errors are unrecoverable. */
373 				goto error_;
374 			}
375 
376 			.next_token(s);
377 			char valueOptional = mixin (.token!("s"));
378 			.prev_token(s);
379 
380 			jansson_d.jansson.json_t* value = .pack(s, ap);
381 
382 			if (value == null) {
383 				if (valueOptional != '*') {
384 					s.has_error = 1;
385 				}
386 
387 				.next_token(s);
388 
389 				continue;
390 			}
391 
392 			if (s.has_error) {
393 				jansson_d.jansson.json_decref(value);
394 			}
395 
396 			if ((!s.has_error) && (jansson_d.value.json_array_append_new(array, value))) {
397 				.set_error(s, "<internal>", jansson_d.jansson.json_error_code_t.json_error_out_of_memory, "Unable to append to array");
398 				s.has_error = 1;
399 			}
400 
401 			.next_token(s);
402 		}
403 
404 		if (!s.has_error) {
405 			return array;
406 		}
407 
408 	error_:
409 		jansson_d.jansson.json_decref(array);
410 
411 		return null;
412 	}
413 
414 nothrow @nogc
415 private jansson_d.jansson.json_t* pack_string(scope .scanner_t* s, scope core.stdc.stdarg.va_list* ap)
416 
417 	do
418 	{
419 		.next_token(s);
420 		char t = mixin (.token!("s"));
421 		int optional = (t == '?') || (t == '*');
422 
423 		if (!optional) {
424 			.prev_token(s);
425 		}
426 
427 		size_t len = void;
428 		int ours = void;
429 		char* str = .read_string(s, ap, "string", &len, &ours, optional);
430 
431 		if (str == null) {
432 			return (t == '?') && (!s.has_error) ? (jansson_d.value.json_null()) : (null);
433 		}
434 
435 		if (s.has_error) {
436 			/* It's impossible to reach this point if ours != 0, do not free str. */
437 			return null;
438 		}
439 
440 		if (ours) {
441 			return jansson_d.jansson_private.jsonp_stringn_nocheck_own(str, len);
442 		}
443 
444 		return jansson_d.value.json_stringn_nocheck(str, len);
445 	}
446 
447 nothrow @nogc @live
448 private jansson_d.jansson.json_t* pack_object_inter(scope .scanner_t* s, scope core.stdc.stdarg.va_list* ap, int need_incref)
449 
450 	do
451 	{
452 		.next_token(s);
453 		char ntoken = mixin (.token!("s"));
454 
455 		if ((ntoken != '?') && (ntoken != '*')) {
456 			.prev_token(s);
457 		}
458 
459 		jansson_d.jansson.json_t* json = core.stdc.stdarg.va_arg!(jansson_d.jansson.json_t*)(*ap);
460 
461 		if (json != null) {
462 			return (need_incref) ? (jansson_d.jansson.json_incref(json)) : (json);
463 		}
464 
465 		switch (ntoken) {
466 			case '?':
467 				return jansson_d.value.json_null();
468 
469 			case '*':
470 				return null;
471 
472 			default:
473 				break;
474 		}
475 
476 		.set_error(s, "<args>", jansson_d.jansson.json_error_code_t.json_error_null_value, "null object");
477 		s.has_error = 1;
478 
479 		return null;
480 	}
481 
482 nothrow @trusted @nogc
483 private jansson_d.jansson.json_t* pack_integer(scope .scanner_t* s, jansson_d.jansson.json_int_t value)
484 
485 	do
486 	{
487 		jansson_d.jansson.json_t* json = jansson_d.value.json_integer(value);
488 
489 		if (json == null) {
490 			.set_error(s, "<internal>", jansson_d.jansson.json_error_code_t.json_error_out_of_memory, "Out of memory");
491 			s.has_error = 1;
492 		}
493 
494 		return json;
495 	}
496 
497 nothrow @trusted @nogc
498 private jansson_d.jansson.json_t* pack_real(scope .scanner_t* s, double value)
499 
500 	in
501 	{
502 		assert(s != null);
503 	}
504 
505 	do
506 	{
507 		/* Allocate without setting value so we can identify OOM error. */
508 		jansson_d.jansson.json_t* json = jansson_d.value.json_real(0.0);
509 
510 		if (json == null) {
511 			.set_error(s, "<internal>", jansson_d.jansson.json_error_code_t.json_error_out_of_memory, "Out of memory");
512 			s.has_error = 1;
513 
514 			return null;
515 		}
516 
517 		if (jansson_d.value.json_real_set(json, value)) {
518 			jansson_d.jansson.json_decref(json);
519 
520 			.set_error(s, "<args>", jansson_d.jansson.json_error_code_t.json_error_numeric_overflow, "Invalid floating point value");
521 			s.has_error = 1;
522 
523 			return null;
524 		}
525 
526 		return json;
527 	}
528 
529 nothrow @nogc
530 private jansson_d.jansson.json_t* pack(scope .scanner_t* s, scope core.stdc.stdarg.va_list* ap)
531 
532 	in
533 	{
534 		assert(s != null);
535 	}
536 
537 	do
538 	{
539 		switch (mixin (.token!("s"))) {
540 			case '{':
541 				return .pack_object(s, ap);
542 
543 			case '[':
544 				return .pack_array(s, ap);
545 
546 			/* string */
547 			case 's':
548 				return .pack_string(s, ap);
549 
550 			/* null */
551 			case 'n':
552 				return jansson_d.value.json_null();
553 
554 			/* boolean */
555 			case 'b':
556 				return (core.stdc.stdarg.va_arg!(int)(*ap)) ? (jansson_d.value.json_true()) : (jansson_d.value.json_false());
557 
558 			/* integer from int */
559 			case 'i':
560 				return .pack_integer(s, core.stdc.stdarg.va_arg!(int)(*ap));
561 
562 			/* integer from json_int_t */
563 			case 'I':
564 				return .pack_integer(s, core.stdc.stdarg.va_arg!(jansson_d.jansson.json_int_t)(*ap));
565 
566 			/* real */
567 			case 'f':
568 				return .pack_real(s, core.stdc.stdarg.va_arg!(double)(*ap));
569 
570 			/* a json_t object; increments refcount */
571 			case 'O':
572 				return .pack_object_inter(s, ap, 1);
573 
574 			/* a json_t object; doesn't increment refcount */
575 			case 'o':
576 				return .pack_object_inter(s, ap, 0);
577 
578 			default:
579 				.set_error(s, "<format>", jansson_d.jansson.json_error_code_t.json_error_invalid_format, "Unexpected format character '%c'", mixin (.token!("s")));
580 				s.has_error = 1;
581 
582 				return null;
583 		}
584 	}
585 
586 nothrow @nogc
587 private int unpack_object(scope .scanner_t* s, scope jansson_d.jansson.json_t* root, scope core.stdc.stdarg.va_list* ap)
588 
589 	do
590 	{
591 		int ret = -1;
592 		int strict = 0;
593 		bool gotopt = false;
594 
595 		/*
596 		 * Use a set (emulated by a hashtable) to check that all object
597 		 *    keys are accessed. Checking that the correct number of keys
598 		 *    were accessed is not enough, as the same key can be unpacked
599 		 *    multiple times.
600 		 */
601 		jansson_d.hashtable.hashtable_t key_set = void;
602 
603 		if (jansson_d.hashtable.hashtable_init(&key_set)) {
604 			.set_error(s, "<internal>", jansson_d.jansson.json_error_code_t.json_error_out_of_memory, "Out of memory");
605 
606 			return -1;
607 		}
608 
609 		if ((root != null) && (!mixin (jansson_d.jansson.json_is_object!("root")))) {
610 			.set_error(s, "<validation>", jansson_d.jansson.json_error_code_t.json_error_wrong_type, "Expected object, got %s", mixin (.type_name!("root")));
611 
612 			goto out_;
613 		}
614 
615 		.next_token(s);
616 
617 		while (mixin (.token!("s")) != '}') {
618 			bool opt = false;
619 
620 			if (strict != 0) {
621 				.set_error(s, "<format>", jansson_d.jansson.json_error_code_t.json_error_invalid_format, "Expected '}' after '%c', got '%c'", (strict == 1) ? ('!') : ('*'), mixin (.token!("s")));
622 
623 				goto out_;
624 			}
625 
626 			if (!mixin (.token!("s"))) {
627 				.set_error(s, "<format>", jansson_d.jansson.json_error_code_t.json_error_invalid_format, "Unexpected end of format string");
628 
629 				goto out_;
630 			}
631 
632 			if ((mixin (.token!("s")) == '!') || (mixin (.token!("s")) == '*')) {
633 				strict = (mixin (.token!("s")) == '!') ? (1) : (-1);
634 				.next_token(s);
635 
636 				continue;
637 			}
638 
639 			if (mixin (.token!("s")) != 's') {
640 				.set_error(s, "<format>", jansson_d.jansson.json_error_code_t.json_error_invalid_format, "Expected format 's', got '%c'", mixin (.token!("s")));
641 
642 				goto out_;
643 			}
644 
645 			const char* key = core.stdc.stdarg.va_arg!(const char*)(*ap);
646 
647 			if (key == null) {
648 				.set_error(s, "<args>", jansson_d.jansson.json_error_code_t.json_error_null_value, "null object key");
649 
650 				goto out_;
651 			}
652 
653 			.next_token(s);
654 
655 			if (mixin (.token!("s")) == '?') {
656 				gotopt = true;
657 				opt = true;
658 				.next_token(s);
659 			}
660 
661 			jansson_d.jansson.json_t* value = void;
662 
663 			if (root == null) {
664 				/* skipping */
665 				value = null;
666 			} else {
667 				value = jansson_d.value.json_object_get(root, key);
668 
669 				if ((value == null) && (!opt)) {
670 					.set_error(s, "<validation>", jansson_d.jansson.json_error_code_t.json_error_item_not_found, "Object item not found: %s", key);
671 
672 					goto out_;
673 				}
674 			}
675 
676 			if (.unpack(s, value, ap)) {
677 				goto out_;
678 			}
679 
680 			jansson_d.hashtable.hashtable_set(&key_set, key, core.stdc..string.strlen(key), jansson_d.value.json_null());
681 			.next_token(s);
682 		}
683 
684 		if ((strict == 0) && (s.flags & jansson_d.jansson.JSON_STRICT)) {
685 			strict = 1;
686 		}
687 
688 		if ((root != null) && (strict == 1)) {
689 			/* We need to check that all non optional items have been parsed */
690 
691 			/* keys_res is 1 for uninitialized, 0 for success, -1 for error. */
692 			int keys_res = 1;
693 
694 			jansson_d.strbuffer.strbuffer_t unrecognized_keys = void;
695 			jansson_d.jansson.json_t* value = void;
696 			core.stdc.config.c_long unpacked = 0;
697 
698 			if ((gotopt) || (jansson_d.value.json_object_size(root) != key_set.size)) {
699 				const (char)* key = void;
700 
701 				//jansson_d.jansson.json_object_foreach(root, key, value)
702 				for (key = jansson_d.value.json_object_iter_key(jansson_d.value.json_object_iter(root)); (key != null) && ((value = jansson_d.value.json_object_iter_value(jansson_d.value.json_object_key_to_iter(key))) != null); key = jansson_d.value.json_object_iter_key(jansson_d.value.json_object_iter_next(root, jansson_d.value.json_object_key_to_iter(key)))) {
703 					size_t key_len = core.stdc..string.strlen(key);
704 
705 					if (jansson_d.hashtable.hashtable_get(&key_set, key, key_len) == null) {
706 						unpacked++;
707 
708 						/* Save unrecognized keys for the error message */
709 						if (keys_res == 1) {
710 							keys_res = jansson_d.strbuffer.strbuffer_init(&unrecognized_keys);
711 						} else if (!keys_res) {
712 							keys_res = jansson_d.strbuffer.strbuffer_append_bytes(&unrecognized_keys, ", ", 2);
713 						}
714 
715 						if (!keys_res) {
716 							keys_res = jansson_d.strbuffer.strbuffer_append_bytes(&unrecognized_keys, key, key_len);
717 						}
718 					}
719 				}
720 			}
721 
722 			if (unpacked) {
723 				.set_error(s, "<validation>", jansson_d.jansson.json_error_code_t.json_error_end_of_input_expected, "%li object item(s) left unpacked: %s", unpacked, (keys_res) ? (&("<unknown>\0"[0])) : (jansson_d.strbuffer.strbuffer_value(&unrecognized_keys)));
724 				jansson_d.strbuffer.strbuffer_close(&unrecognized_keys);
725 
726 				goto out_;
727 			}
728 		}
729 
730 		ret = 0;
731 
732 	out_:
733 		jansson_d.hashtable.hashtable_close(&key_set);
734 
735 		return ret;
736 	}
737 
738 nothrow @nogc
739 private int unpack_array(scope .scanner_t* s, scope jansson_d.jansson.json_t* root, scope core.stdc.stdarg.va_list* ap)
740 
741 	do
742 	{
743 		size_t i = 0;
744 		int strict = 0;
745 
746 		if ((root != null) && (!mixin (jansson_d.jansson.json_is_array!("root")))) {
747 			.set_error(s, "<validation>", jansson_d.jansson.json_error_code_t.json_error_wrong_type, "Expected array, got %s", mixin (.type_name!("root")));
748 
749 			return -1;
750 		}
751 
752 		.next_token(s);
753 
754 		while (mixin (.token!("s")) != ']') {
755 			if (strict != 0) {
756 				.set_error(s, "<format>", jansson_d.jansson.json_error_code_t.json_error_invalid_format, "Expected ']' after '%c', got '%c'", (strict == 1) ? ('!') : ('*'), mixin (.token!("s")));
757 
758 				return -1;
759 			}
760 
761 			if (!mixin (.token!("s"))) {
762 				.set_error(s, "<format>", jansson_d.jansson.json_error_code_t.json_error_invalid_format, "Unexpected end of format string");
763 
764 				return -1;
765 			}
766 
767 			if ((mixin (.token!("s")) == '!') || (mixin (.token!("s")) == '*')) {
768 				strict = (mixin (.token!("s")) == '!') ? (1) : (-1);
769 				.next_token(s);
770 
771 				continue;
772 			}
773 
774 			if (!core.stdc..string.strchr(&(.unpack_value_starters[0]), mixin (.token!("s")))) {
775 				.set_error(s, "<format>", jansson_d.jansson.json_error_code_t.json_error_invalid_format, "Unexpected format character '%c'", mixin (.token!("s")));
776 
777 				return -1;
778 			}
779 
780 			jansson_d.jansson.json_t* value = void;
781 
782 			if (root == null) {
783 				/* skipping */
784 				value = null;
785 			} else {
786 				value = jansson_d.value.json_array_get(root, i);
787 
788 				if (value == null) {
789 					.set_error(s, "<validation>", jansson_d.jansson.json_error_code_t.json_error_index_out_of_range, "Array index %lu out of range", cast(core.stdc.config.c_ulong)(i));
790 
791 					return -1;
792 				}
793 			}
794 
795 			if (.unpack(s, value, ap)) {
796 				return -1;
797 			}
798 
799 			.next_token(s);
800 			i++;
801 		}
802 
803 		if ((strict == 0) && (s.flags & jansson_d.jansson.JSON_STRICT)) {
804 			strict = 1;
805 		}
806 
807 		if ((root != null) && (strict == 1) && (i != jansson_d.value.json_array_size(root))) {
808 			core.stdc.config.c_long diff = cast(core.stdc.config.c_long)(jansson_d.value.json_array_size(root)) - cast(core.stdc.config.c_long)(i);
809 			.set_error(s, "<validation>", jansson_d.jansson.json_error_code_t.json_error_end_of_input_expected, "%li array item(s) left unpacked", diff);
810 
811 			return -1;
812 		}
813 
814 		return 0;
815 	}
816 
817 nothrow @nogc
818 private int unpack(scope .scanner_t* s, scope jansson_d.jansson.json_t* root, scope core.stdc.stdarg.va_list* ap)
819 
820 	in
821 	{
822 		assert(s != null);
823 	}
824 
825 	do
826 	{
827 		switch (mixin (.token!("s"))) {
828 			case '{':
829 				return .unpack_object(s, root, ap);
830 
831 			case '[':
832 				return .unpack_array(s, root, ap);
833 
834 			case 's':
835 				if ((root != null) && (!mixin (jansson_d.jansson.json_is_string!("root")))) {
836 					.set_error(s, "<validation>", jansson_d.jansson.json_error_code_t.json_error_wrong_type, "Expected string, got %s", mixin (.type_name!("root")));
837 
838 					return -1;
839 				}
840 
841 				if (!(s.flags & jansson_d.jansson.JSON_VALIDATE_ONLY)) {
842 					size_t* len_target = null;
843 
844 					const (char)** str_target = core.stdc.stdarg.va_arg!(const (char)**)(*ap);
845 
846 					if (str_target == null) {
847 						.set_error(s, "<args>", jansson_d.jansson.json_error_code_t.json_error_null_value, "null string argument");
848 
849 						return -1;
850 					}
851 
852 					.next_token(s);
853 
854 					if (mixin (.token!("s")) == '%') {
855 						len_target = core.stdc.stdarg.va_arg!(size_t*)(*ap);
856 
857 						if (len_target == null) {
858 							.set_error(s, "<args>", jansson_d.jansson.json_error_code_t.json_error_null_value, "null string length argument");
859 
860 							return -1;
861 						}
862 					} else {
863 						.prev_token(s);
864 					}
865 
866 					if (root != null) {
867 						*str_target = jansson_d.value.json_string_value(root);
868 
869 						if (len_target != null) {
870 							*len_target = jansson_d.value.json_string_length(root);
871 						}
872 					}
873 				}
874 
875 				return 0;
876 
877 			case 'i':
878 				if ((root != null) && (!mixin (jansson_d.jansson.json_is_integer!("root")))) {
879 					.set_error(s, "<validation>", jansson_d.jansson.json_error_code_t.json_error_wrong_type, "Expected integer, got %s", mixin (.type_name!("root")));
880 
881 					return -1;
882 				}
883 
884 				if (!(s.flags & jansson_d.jansson.JSON_VALIDATE_ONLY)) {
885 					int* target = core.stdc.stdarg.va_arg!(int*)(*ap);
886 
887 					if (root != null) {
888 						*target = cast(int)(jansson_d.value.json_integer_value(root));
889 					}
890 				}
891 
892 				return 0;
893 
894 			case 'I':
895 				if ((root != null) && (!mixin (jansson_d.jansson.json_is_integer!("root")))) {
896 					.set_error(s, "<validation>", jansson_d.jansson.json_error_code_t.json_error_wrong_type, "Expected integer, got %s", mixin (.type_name!("root")));
897 
898 					return -1;
899 				}
900 
901 				if (!(s.flags & jansson_d.jansson.JSON_VALIDATE_ONLY)) {
902 					jansson_d.jansson.json_int_t* target = core.stdc.stdarg.va_arg!(jansson_d.jansson.json_int_t*)(*ap);
903 
904 					if (root != null) {
905 						*target = jansson_d.value.json_integer_value(root);
906 					}
907 				}
908 
909 				return 0;
910 
911 			case 'b':
912 				if ((root != null) && (!mixin (jansson_d.jansson.json_is_boolean!("root")))) {
913 					.set_error(s, "<validation>", jansson_d.jansson.json_error_code_t.json_error_wrong_type, "Expected true or false, got %s", mixin (.type_name!("root")));
914 
915 					return -1;
916 				}
917 
918 				if (!(s.flags & jansson_d.jansson.JSON_VALIDATE_ONLY)) {
919 					int* target = core.stdc.stdarg.va_arg!(int*)(*ap);
920 
921 					if (root != null) {
922 						*target = mixin (jansson_d.jansson.json_is_true!("root"));
923 					}
924 				}
925 
926 				return 0;
927 
928 			case 'f':
929 				if ((root != null) && (!mixin (jansson_d.jansson.json_is_real!("root")))) {
930 					.set_error(s, "<validation>", jansson_d.jansson.json_error_code_t.json_error_wrong_type, "Expected real, got %s", mixin (.type_name!("root")));
931 
932 					return -1;
933 				}
934 
935 				if (!(s.flags & jansson_d.jansson.JSON_VALIDATE_ONLY)) {
936 					double* target = core.stdc.stdarg.va_arg!(double*)(*ap);
937 
938 					if (root != null) {
939 						*target = jansson_d.value.json_real_value(root);
940 					}
941 				}
942 
943 				return 0;
944 
945 			case 'F':
946 				if ((root != null) && (!mixin (jansson_d.jansson.json_is_number!("root")))) {
947 					.set_error(s, "<validation>", jansson_d.jansson.json_error_code_t.json_error_wrong_type, "Expected real or integer, got %s", mixin (.type_name!("root")));
948 
949 					return -1;
950 				}
951 
952 				if (!(s.flags & jansson_d.jansson.JSON_VALIDATE_ONLY)) {
953 					double* target = core.stdc.stdarg.va_arg!(double*)(*ap);
954 
955 					if (root != null) {
956 						*target = jansson_d.value.json_number_value(root);
957 					}
958 				}
959 
960 				return 0;
961 
962 			case 'O':
963 				if ((root != null) && (!(s.flags & jansson_d.jansson.JSON_VALIDATE_ONLY))) {
964 					jansson_d.jansson.json_incref(root);
965 				}
966 
967 				/* Fall through */
968 				goto case;
969 
970 			case 'o':
971 				if (!(s.flags & jansson_d.jansson.JSON_VALIDATE_ONLY)) {
972 					jansson_d.jansson.json_t** target = core.stdc.stdarg.va_arg!(jansson_d.jansson.json_t**)(*ap);
973 
974 					if (root != null) {
975 						*target = root;
976 					}
977 				}
978 
979 				return 0;
980 
981 			case 'n':
982 				/* Never assign, just validate */
983 				if ((root != null) && (!mixin (jansson_d.jansson.json_is_null!("root")))) {
984 					.set_error(s, "<validation>", jansson_d.jansson.json_error_code_t.json_error_wrong_type, "Expected null, got %s", mixin (.type_name!("root")));
985 
986 					return -1;
987 				}
988 
989 				return 0;
990 
991 			default:
992 				.set_error(s, "<format>", jansson_d.jansson.json_error_code_t.json_error_invalid_format, "Unexpected format character '%c'", mixin (.token!("s")));
993 
994 				return -1;
995 		}
996 	}
997 
998 ///
999 extern (C)
1000 nothrow @nogc //ToDo: @nodiscard
1001 public jansson_d.jansson.json_t* json_vpack_ex(scope jansson_d.jansson.json_error_t* error, size_t flags, scope const char* fmt, core.stdc.stdarg.va_list ap)
1002 
1003 	do
1004 	{
1005 		if ((fmt == null) || (*fmt == '\0')) {
1006 			jansson_d.jansson_private.jsonp_error_init(error, "<format>");
1007 			jansson_d.jansson_private.jsonp_error_set(error, -1, -1, 0, jansson_d.jansson.json_error_code_t.json_error_invalid_argument, "null or empty format string");
1008 
1009 			return null;
1010 		}
1011 
1012 		jansson_d.jansson_private.jsonp_error_init(error, null);
1013 
1014 		.scanner_t s = void;
1015 		.scanner_init(&s, error, flags, fmt);
1016 		.next_token(&s);
1017 
1018 		core.stdc.stdarg.va_list ap_copy;
1019 		jansson_d.jansson_private.va_copy(ap_copy, ap);
1020 		jansson_d.jansson.json_t* value = .pack(&s, &ap_copy);
1021 		core.stdc.stdarg.va_end(ap_copy);
1022 
1023 		/* This will cover all situations where s.has_error is true */
1024 		if (value == null) {
1025 			return null;
1026 		}
1027 
1028 		.next_token(&s);
1029 
1030 		if (mixin (.token!("&s"))) {
1031 			jansson_d.jansson.json_decref(value);
1032 			.set_error(&s, "<format>", jansson_d.jansson.json_error_code_t.json_error_invalid_format, "Garbage after format string");
1033 
1034 			return null;
1035 		}
1036 
1037 		return value;
1038 	}
1039 
1040 ///
1041 extern (C)
1042 nothrow @nogc //ToDo: @nodiscard
1043 public jansson_d.jansson.json_t* json_pack_ex(scope jansson_d.jansson.json_error_t* error, size_t flags, scope const char* fmt, ...)
1044 
1045 	do
1046 	{
1047 		core.stdc.stdarg.va_list ap;
1048 		core.stdc.stdarg.va_start(ap, fmt);
1049 		jansson_d.jansson.json_t* value = .json_vpack_ex(error, flags, fmt, ap);
1050 		core.stdc.stdarg.va_end(ap);
1051 
1052 		return value;
1053 	}
1054 
1055 ///
1056 extern (C)
1057 nothrow @nogc //ToDo: @nodiscard
1058 public jansson_d.jansson.json_t* json_pack(scope const char* fmt, ...)
1059 
1060 	do
1061 	{
1062 		core.stdc.stdarg.va_list ap;
1063 		core.stdc.stdarg.va_start(ap, fmt);
1064 		jansson_d.jansson.json_t* value = .json_vpack_ex(null, 0, fmt, ap);
1065 		core.stdc.stdarg.va_end(ap);
1066 
1067 		return value;
1068 	}
1069 
1070 ///
1071 extern (C)
1072 nothrow @nogc
1073 public int json_vunpack_ex(scope jansson_d.jansson.json_t* root, scope jansson_d.jansson.json_error_t* error, size_t flags, scope const char* fmt, core.stdc.stdarg.va_list ap)
1074 
1075 	do
1076 	{
1077 		if (root == null) {
1078 			jansson_d.jansson_private.jsonp_error_init(error, "<root>");
1079 			jansson_d.jansson_private.jsonp_error_set(error, -1, -1, 0, jansson_d.jansson.json_error_code_t.json_error_null_value, "null root value");
1080 
1081 			return -1;
1082 		}
1083 
1084 		if ((fmt == null) || (*fmt == '\0')) {
1085 			jansson_d.jansson_private.jsonp_error_init(error, "<format>");
1086 			jansson_d.jansson_private.jsonp_error_set(error, -1, -1, 0, jansson_d.jansson.json_error_code_t.json_error_invalid_argument, "null or empty format string");
1087 
1088 			return -1;
1089 		}
1090 
1091 		jansson_d.jansson_private.jsonp_error_init(error, null);
1092 
1093 		.scanner_t s = void;
1094 		.scanner_init(&s, error, flags, fmt);
1095 		.next_token(&s);
1096 
1097 		core.stdc.stdarg.va_list ap_copy;
1098 		jansson_d.jansson_private.va_copy(ap_copy, ap);
1099 
1100 		if (.unpack(&s, root, &ap_copy)) {
1101 			core.stdc.stdarg.va_end(ap_copy);
1102 
1103 			return -1;
1104 		}
1105 
1106 		core.stdc.stdarg.va_end(ap_copy);
1107 
1108 		.next_token(&s);
1109 
1110 		if (mixin (.token!("&s"))) {
1111 			.set_error(&s, "<format>", jansson_d.jansson.json_error_code_t.json_error_invalid_format, "Garbage after format string");
1112 
1113 			return -1;
1114 		}
1115 
1116 		return 0;
1117 	}
1118 
1119 ///
1120 extern (C)
1121 nothrow @nogc
1122 public int json_unpack_ex(scope jansson_d.jansson.json_t* root, scope jansson_d.jansson.json_error_t* error, size_t flags, scope const char* fmt, ...)
1123 
1124 	do
1125 	{
1126 		core.stdc.stdarg.va_list ap;
1127 		core.stdc.stdarg.va_start(ap, fmt);
1128 		int ret = .json_vunpack_ex(root, error, flags, fmt, ap);
1129 		core.stdc.stdarg.va_end(ap);
1130 
1131 		return ret;
1132 	}
1133 
1134 ///
1135 extern (C)
1136 nothrow @nogc
1137 public int json_unpack(scope jansson_d.jansson.json_t* root, scope const char* fmt, ...)
1138 
1139 	do
1140 	{
1141 		core.stdc.stdarg.va_list ap;
1142 		core.stdc.stdarg.va_start(ap, fmt);
1143 		int ret = .json_vunpack_ex(root, null, 0, fmt, ap);
1144 		core.stdc.stdarg.va_end(ap);
1145 
1146 		return ret;
1147 	}