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