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