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 }