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