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