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