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