1 // __ _____ _____ _____ 2 // __| | __| | | | JSON for Modern C++ 3 // | | |__ | | | | | | version 3.11.2 4 // |_____|_____|_____|_|___| https://github.com/nlohmann/json 5 // 6 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> 7 // SPDX-License-Identifier: MIT 8 9 #pragma once 10 11 #include <cstddef> 12 #include <string> // string 13 #include <utility> // move 14 #include <vector> // vector 15 16 #include <nlohmann/detail/exceptions.hpp> 17 #include <nlohmann/detail/macro_scope.hpp> 18 #include <nlohmann/detail/string_concat.hpp> 19 20 NLOHMANN_JSON_NAMESPACE_BEGIN 21 22 /*! 23 @brief SAX interface 24 25 This class describes the SAX interface used by @ref nlohmann::json::sax_parse. 26 Each function is called in different situations while the input is parsed. The 27 boolean return value informs the parser whether to continue processing the 28 input. 29 */ 30 template<typename BasicJsonType> 31 struct json_sax 32 { 33 using number_integer_t = typename BasicJsonType::number_integer_t; 34 using number_unsigned_t = typename BasicJsonType::number_unsigned_t; 35 using number_float_t = typename BasicJsonType::number_float_t; 36 using string_t = typename BasicJsonType::string_t; 37 using binary_t = typename BasicJsonType::binary_t; 38 39 /*! 40 @brief a null value was read 41 @return whether parsing should proceed 42 */ 43 virtual bool null() = 0; 44 45 /*! 46 @brief a boolean value was read 47 @param[in] val boolean value 48 @return whether parsing should proceed 49 */ 50 virtual bool boolean(bool val) = 0; 51 52 /*! 53 @brief an integer number was read 54 @param[in] val integer value 55 @return whether parsing should proceed 56 */ 57 virtual bool number_integer(number_integer_t val) = 0; 58 59 /*! 60 @brief an unsigned integer number was read 61 @param[in] val unsigned integer value 62 @return whether parsing should proceed 63 */ 64 virtual bool number_unsigned(number_unsigned_t val) = 0; 65 66 /*! 67 @brief a floating-point number was read 68 @param[in] val floating-point value 69 @param[in] s raw token value 70 @return whether parsing should proceed 71 */ 72 virtual bool number_float(number_float_t val, const string_t& s) = 0; 73 74 /*! 75 @brief a string value was read 76 @param[in] val string value 77 @return whether parsing should proceed 78 @note It is safe to move the passed string value. 79 */ 80 virtual bool string(string_t& val) = 0; 81 82 /*! 83 @brief a binary value was read 84 @param[in] val binary value 85 @return whether parsing should proceed 86 @note It is safe to move the passed binary value. 87 */ 88 virtual bool binary(binary_t& val) = 0; 89 90 /*! 91 @brief the beginning of an object was read 92 @param[in] elements number of object elements or -1 if unknown 93 @return whether parsing should proceed 94 @note binary formats may report the number of elements 95 */ 96 virtual bool start_object(std::size_t elements) = 0; 97 98 /*! 99 @brief an object key was read 100 @param[in] val object key 101 @return whether parsing should proceed 102 @note It is safe to move the passed string. 103 */ 104 virtual bool key(string_t& val) = 0; 105 106 /*! 107 @brief the end of an object was read 108 @return whether parsing should proceed 109 */ 110 virtual bool end_object() = 0; 111 112 /*! 113 @brief the beginning of an array was read 114 @param[in] elements number of array elements or -1 if unknown 115 @return whether parsing should proceed 116 @note binary formats may report the number of elements 117 */ 118 virtual bool start_array(std::size_t elements) = 0; 119 120 /*! 121 @brief the end of an array was read 122 @return whether parsing should proceed 123 */ 124 virtual bool end_array() = 0; 125 126 /*! 127 @brief a parse error occurred 128 @param[in] position the position in the input where the error occurs 129 @param[in] last_token the last read token 130 @param[in] ex an exception object describing the error 131 @return whether parsing should proceed (must return false) 132 */ 133 virtual bool parse_error(std::size_t position, 134 const std::string& last_token, 135 const detail::exception& ex) = 0; 136 137 json_sax() = default; 138 json_sax(const json_sax&) = default; 139 json_sax(json_sax&&) noexcept = default; 140 json_sax& operator=(const json_sax&) = default; 141 json_sax& operator=(json_sax&&) noexcept = default; 142 virtual ~json_sax() = default; 143 }; 144 145 146 namespace detail 147 { 148 /*! 149 @brief SAX implementation to create a JSON value from SAX events 150 151 This class implements the @ref json_sax interface and processes the SAX events 152 to create a JSON value which makes it basically a DOM parser. The structure or 153 hierarchy of the JSON value is managed by the stack `ref_stack` which contains 154 a pointer to the respective array or object for each recursion depth. 155 156 After successful parsing, the value that is passed by reference to the 157 constructor contains the parsed value. 158 159 @tparam BasicJsonType the JSON type 160 */ 161 template<typename BasicJsonType> 162 class json_sax_dom_parser 163 { 164 public: 165 using number_integer_t = typename BasicJsonType::number_integer_t; 166 using number_unsigned_t = typename BasicJsonType::number_unsigned_t; 167 using number_float_t = typename BasicJsonType::number_float_t; 168 using string_t = typename BasicJsonType::string_t; 169 using binary_t = typename BasicJsonType::binary_t; 170 171 /*! 172 @param[in,out] r reference to a JSON value that is manipulated while 173 parsing 174 @param[in] allow_exceptions_ whether parse errors yield exceptions 175 */ json_sax_dom_parser(BasicJsonType & r,const bool allow_exceptions_=true)176 explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true) 177 : root(r), allow_exceptions(allow_exceptions_) 178 {} 179 180 // make class move-only 181 json_sax_dom_parser(const json_sax_dom_parser&) = delete; 182 json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) 183 json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete; 184 json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) 185 ~json_sax_dom_parser() = default; 186 null()187 bool null() 188 { 189 handle_value(nullptr); 190 return true; 191 } 192 boolean(bool val)193 bool boolean(bool val) 194 { 195 handle_value(val); 196 return true; 197 } 198 number_integer(number_integer_t val)199 bool number_integer(number_integer_t val) 200 { 201 handle_value(val); 202 return true; 203 } 204 number_unsigned(number_unsigned_t val)205 bool number_unsigned(number_unsigned_t val) 206 { 207 handle_value(val); 208 return true; 209 } 210 number_float(number_float_t val,const string_t &)211 bool number_float(number_float_t val, const string_t& /*unused*/) 212 { 213 handle_value(val); 214 return true; 215 } 216 string(string_t & val)217 bool string(string_t& val) 218 { 219 handle_value(val); 220 return true; 221 } 222 binary(binary_t & val)223 bool binary(binary_t& val) 224 { 225 handle_value(std::move(val)); 226 return true; 227 } 228 start_object(std::size_t len)229 bool start_object(std::size_t len) 230 { 231 ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); 232 233 if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())) 234 { 235 JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); 236 } 237 238 return true; 239 } 240 key(string_t & val)241 bool key(string_t& val) 242 { 243 JSON_ASSERT(!ref_stack.empty()); 244 JSON_ASSERT(ref_stack.back()->is_object()); 245 246 // add null at given key and store the reference for later 247 object_element = &(ref_stack.back()->m_value.object->operator[](val)); 248 return true; 249 } 250 end_object()251 bool end_object() 252 { 253 JSON_ASSERT(!ref_stack.empty()); 254 JSON_ASSERT(ref_stack.back()->is_object()); 255 256 ref_stack.back()->set_parents(); 257 ref_stack.pop_back(); 258 return true; 259 } 260 start_array(std::size_t len)261 bool start_array(std::size_t len) 262 { 263 ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); 264 265 if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())) 266 { 267 JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); 268 } 269 270 return true; 271 } 272 end_array()273 bool end_array() 274 { 275 JSON_ASSERT(!ref_stack.empty()); 276 JSON_ASSERT(ref_stack.back()->is_array()); 277 278 ref_stack.back()->set_parents(); 279 ref_stack.pop_back(); 280 return true; 281 } 282 283 template<class Exception> parse_error(std::size_t,const std::string &,const Exception & ex)284 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, 285 const Exception& ex) 286 { 287 errored = true; 288 static_cast<void>(ex); 289 if (allow_exceptions) 290 { 291 JSON_THROW(ex); 292 } 293 return false; 294 } 295 is_errored() const296 constexpr bool is_errored() const 297 { 298 return errored; 299 } 300 301 private: 302 /*! 303 @invariant If the ref stack is empty, then the passed value will be the new 304 root. 305 @invariant If the ref stack contains a value, then it is an array or an 306 object to which we can add elements 307 */ 308 template<typename Value> 309 JSON_HEDLEY_RETURNS_NON_NULL handle_value(Value && v)310 BasicJsonType* handle_value(Value&& v) 311 { 312 if (ref_stack.empty()) 313 { 314 root = BasicJsonType(std::forward<Value>(v)); 315 return &root; 316 } 317 318 JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); 319 320 if (ref_stack.back()->is_array()) 321 { 322 ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v)); 323 return &(ref_stack.back()->m_value.array->back()); 324 } 325 326 JSON_ASSERT(ref_stack.back()->is_object()); 327 JSON_ASSERT(object_element); 328 *object_element = BasicJsonType(std::forward<Value>(v)); 329 return object_element; 330 } 331 332 /// the parsed JSON value 333 BasicJsonType& root; 334 /// stack to model hierarchy of values 335 std::vector<BasicJsonType*> ref_stack {}; 336 /// helper to hold the reference for the next object element 337 BasicJsonType* object_element = nullptr; 338 /// whether a syntax error occurred 339 bool errored = false; 340 /// whether to throw exceptions in case of errors 341 const bool allow_exceptions = true; 342 }; 343 344 template<typename BasicJsonType> 345 class json_sax_dom_callback_parser 346 { 347 public: 348 using number_integer_t = typename BasicJsonType::number_integer_t; 349 using number_unsigned_t = typename BasicJsonType::number_unsigned_t; 350 using number_float_t = typename BasicJsonType::number_float_t; 351 using string_t = typename BasicJsonType::string_t; 352 using binary_t = typename BasicJsonType::binary_t; 353 using parser_callback_t = typename BasicJsonType::parser_callback_t; 354 using parse_event_t = typename BasicJsonType::parse_event_t; 355 json_sax_dom_callback_parser(BasicJsonType & r,const parser_callback_t cb,const bool allow_exceptions_=true)356 json_sax_dom_callback_parser(BasicJsonType& r, 357 const parser_callback_t cb, 358 const bool allow_exceptions_ = true) 359 : root(r), callback(cb), allow_exceptions(allow_exceptions_) 360 { 361 keep_stack.push_back(true); 362 } 363 364 // make class move-only 365 json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete; 366 json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) 367 json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete; 368 json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) 369 ~json_sax_dom_callback_parser() = default; 370 null()371 bool null() 372 { 373 handle_value(nullptr); 374 return true; 375 } 376 boolean(bool val)377 bool boolean(bool val) 378 { 379 handle_value(val); 380 return true; 381 } 382 number_integer(number_integer_t val)383 bool number_integer(number_integer_t val) 384 { 385 handle_value(val); 386 return true; 387 } 388 number_unsigned(number_unsigned_t val)389 bool number_unsigned(number_unsigned_t val) 390 { 391 handle_value(val); 392 return true; 393 } 394 number_float(number_float_t val,const string_t &)395 bool number_float(number_float_t val, const string_t& /*unused*/) 396 { 397 handle_value(val); 398 return true; 399 } 400 string(string_t & val)401 bool string(string_t& val) 402 { 403 handle_value(val); 404 return true; 405 } 406 binary(binary_t & val)407 bool binary(binary_t& val) 408 { 409 handle_value(std::move(val)); 410 return true; 411 } 412 start_object(std::size_t len)413 bool start_object(std::size_t len) 414 { 415 // check callback for object start 416 const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded); 417 keep_stack.push_back(keep); 418 419 auto val = handle_value(BasicJsonType::value_t::object, true); 420 ref_stack.push_back(val.second); 421 422 // check object limit 423 if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())) 424 { 425 JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); 426 } 427 428 return true; 429 } 430 key(string_t & val)431 bool key(string_t& val) 432 { 433 BasicJsonType k = BasicJsonType(val); 434 435 // check callback for key 436 const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k); 437 key_keep_stack.push_back(keep); 438 439 // add discarded value at given key and store the reference for later 440 if (keep && ref_stack.back()) 441 { 442 object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded); 443 } 444 445 return true; 446 } 447 end_object()448 bool end_object() 449 { 450 if (ref_stack.back()) 451 { 452 if (!callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) 453 { 454 // discard object 455 *ref_stack.back() = discarded; 456 } 457 else 458 { 459 ref_stack.back()->set_parents(); 460 } 461 } 462 463 JSON_ASSERT(!ref_stack.empty()); 464 JSON_ASSERT(!keep_stack.empty()); 465 ref_stack.pop_back(); 466 keep_stack.pop_back(); 467 468 if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured()) 469 { 470 // remove discarded value 471 for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) 472 { 473 if (it->is_discarded()) 474 { 475 ref_stack.back()->erase(it); 476 break; 477 } 478 } 479 } 480 481 return true; 482 } 483 start_array(std::size_t len)484 bool start_array(std::size_t len) 485 { 486 const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded); 487 keep_stack.push_back(keep); 488 489 auto val = handle_value(BasicJsonType::value_t::array, true); 490 ref_stack.push_back(val.second); 491 492 // check array limit 493 if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())) 494 { 495 JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); 496 } 497 498 return true; 499 } 500 end_array()501 bool end_array() 502 { 503 bool keep = true; 504 505 if (ref_stack.back()) 506 { 507 keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); 508 if (keep) 509 { 510 ref_stack.back()->set_parents(); 511 } 512 else 513 { 514 // discard array 515 *ref_stack.back() = discarded; 516 } 517 } 518 519 JSON_ASSERT(!ref_stack.empty()); 520 JSON_ASSERT(!keep_stack.empty()); 521 ref_stack.pop_back(); 522 keep_stack.pop_back(); 523 524 // remove discarded value 525 if (!keep && !ref_stack.empty() && ref_stack.back()->is_array()) 526 { 527 ref_stack.back()->m_value.array->pop_back(); 528 } 529 530 return true; 531 } 532 533 template<class Exception> parse_error(std::size_t,const std::string &,const Exception & ex)534 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, 535 const Exception& ex) 536 { 537 errored = true; 538 static_cast<void>(ex); 539 if (allow_exceptions) 540 { 541 JSON_THROW(ex); 542 } 543 return false; 544 } 545 is_errored() const546 constexpr bool is_errored() const 547 { 548 return errored; 549 } 550 551 private: 552 /*! 553 @param[in] v value to add to the JSON value we build during parsing 554 @param[in] skip_callback whether we should skip calling the callback 555 function; this is required after start_array() and 556 start_object() SAX events, because otherwise we would call the 557 callback function with an empty array or object, respectively. 558 559 @invariant If the ref stack is empty, then the passed value will be the new 560 root. 561 @invariant If the ref stack contains a value, then it is an array or an 562 object to which we can add elements 563 564 @return pair of boolean (whether value should be kept) and pointer (to the 565 passed value in the ref_stack hierarchy; nullptr if not kept) 566 */ 567 template<typename Value> handle_value(Value && v,const bool skip_callback=false)568 std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false) 569 { 570 JSON_ASSERT(!keep_stack.empty()); 571 572 // do not handle this value if we know it would be added to a discarded 573 // container 574 if (!keep_stack.back()) 575 { 576 return {false, nullptr}; 577 } 578 579 // create value 580 auto value = BasicJsonType(std::forward<Value>(v)); 581 582 // check callback 583 const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value); 584 585 // do not handle this value if we just learnt it shall be discarded 586 if (!keep) 587 { 588 return {false, nullptr}; 589 } 590 591 if (ref_stack.empty()) 592 { 593 root = std::move(value); 594 return {true, &root}; 595 } 596 597 // skip this value if we already decided to skip the parent 598 // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) 599 if (!ref_stack.back()) 600 { 601 return {false, nullptr}; 602 } 603 604 // we now only expect arrays and objects 605 JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); 606 607 // array 608 if (ref_stack.back()->is_array()) 609 { 610 ref_stack.back()->m_value.array->emplace_back(std::move(value)); 611 return {true, &(ref_stack.back()->m_value.array->back())}; 612 } 613 614 // object 615 JSON_ASSERT(ref_stack.back()->is_object()); 616 // check if we should store an element for the current key 617 JSON_ASSERT(!key_keep_stack.empty()); 618 const bool store_element = key_keep_stack.back(); 619 key_keep_stack.pop_back(); 620 621 if (!store_element) 622 { 623 return {false, nullptr}; 624 } 625 626 JSON_ASSERT(object_element); 627 *object_element = std::move(value); 628 return {true, object_element}; 629 } 630 631 /// the parsed JSON value 632 BasicJsonType& root; 633 /// stack to model hierarchy of values 634 std::vector<BasicJsonType*> ref_stack {}; 635 /// stack to manage which values to keep 636 std::vector<bool> keep_stack {}; 637 /// stack to manage which object keys to keep 638 std::vector<bool> key_keep_stack {}; 639 /// helper to hold the reference for the next object element 640 BasicJsonType* object_element = nullptr; 641 /// whether a syntax error occurred 642 bool errored = false; 643 /// callback function 644 const parser_callback_t callback = nullptr; 645 /// whether to throw exceptions in case of errors 646 const bool allow_exceptions = true; 647 /// a discarded value for the callback 648 BasicJsonType discarded = BasicJsonType::value_t::discarded; 649 }; 650 651 template<typename BasicJsonType> 652 class json_sax_acceptor 653 { 654 public: 655 using number_integer_t = typename BasicJsonType::number_integer_t; 656 using number_unsigned_t = typename BasicJsonType::number_unsigned_t; 657 using number_float_t = typename BasicJsonType::number_float_t; 658 using string_t = typename BasicJsonType::string_t; 659 using binary_t = typename BasicJsonType::binary_t; 660 null()661 bool null() 662 { 663 return true; 664 } 665 boolean(bool)666 bool boolean(bool /*unused*/) 667 { 668 return true; 669 } 670 number_integer(number_integer_t)671 bool number_integer(number_integer_t /*unused*/) 672 { 673 return true; 674 } 675 number_unsigned(number_unsigned_t)676 bool number_unsigned(number_unsigned_t /*unused*/) 677 { 678 return true; 679 } 680 number_float(number_float_t,const string_t &)681 bool number_float(number_float_t /*unused*/, const string_t& /*unused*/) 682 { 683 return true; 684 } 685 string(string_t &)686 bool string(string_t& /*unused*/) 687 { 688 return true; 689 } 690 binary(binary_t &)691 bool binary(binary_t& /*unused*/) 692 { 693 return true; 694 } 695 start_object(std::size_t=static_cast<std::size_t> (-1))696 bool start_object(std::size_t /*unused*/ = static_cast<std::size_t>(-1)) 697 { 698 return true; 699 } 700 key(string_t &)701 bool key(string_t& /*unused*/) 702 { 703 return true; 704 } 705 end_object()706 bool end_object() 707 { 708 return true; 709 } 710 start_array(std::size_t=static_cast<std::size_t> (-1))711 bool start_array(std::size_t /*unused*/ = static_cast<std::size_t>(-1)) 712 { 713 return true; 714 } 715 end_array()716 bool end_array() 717 { 718 return true; 719 } 720 parse_error(std::size_t,const std::string &,const detail::exception &)721 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/) 722 { 723 return false; 724 } 725 }; 726 727 } // namespace detail 728 NLOHMANN_JSON_NAMESPACE_END 729