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