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