Horizon
json_sax.hpp
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 
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 
35  virtual bool null() = 0;
36 
42  virtual bool boolean(bool val) = 0;
43 
49  virtual bool number_integer(number_integer_t val) = 0;
50 
56  virtual bool number_unsigned(number_unsigned_t val) = 0;
57 
64  virtual bool number_float(number_float_t val, const string_t& s) = 0;
65 
72  virtual bool string(string_t& val) = 0;
73 
80  virtual bool binary(binary_t& val) = 0;
81 
88  virtual bool start_object(std::size_t elements) = 0;
89 
96  virtual bool key(string_t& val) = 0;
97 
102  virtual bool end_object() = 0;
103 
110  virtual bool start_array(std::size_t elements) = 0;
111 
116  virtual bool end_array() = 0;
117 
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 {
153 template<typename BasicJsonType>
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 
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 
179  bool null()
180  {
181  handle_value(nullptr);
182  return true;
183  }
184 
185  bool boolean(bool val)
186  {
187  handle_value(val);
188  return true;
189  }
190 
191  bool number_integer(number_integer_t val)
192  {
193  handle_value(val);
194  return true;
195  }
196 
197  bool number_unsigned(number_unsigned_t val)
198  {
199  handle_value(val);
200  return true;
201  }
202 
203  bool number_float(number_float_t val, const string_t& /*unused*/)
204  {
205  handle_value(val);
206  return true;
207  }
208 
209  bool string(string_t& val)
210  {
211  handle_value(val);
212  return true;
213  }
214 
215  bool binary(binary_t& val)
216  {
217  handle_value(std::move(val));
218  return true;
219  }
220 
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 
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 
240  bool end_object()
241  {
242  ref_stack.back()->set_parents();
243  ref_stack.pop_back();
244  return true;
245  }
246 
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 
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>
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 
279  constexpr bool is_errored() const
280  {
281  return errored;
282  }
283 
284  private:
291  template<typename Value>
292  JSON_HEDLEY_RETURNS_NON_NULL
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 
316  BasicJsonType& root;
318  std::vector<BasicJsonType*> ref_stack {};
320  BasicJsonType* object_element = nullptr;
322  bool errored = false;
324  const bool allow_exceptions = true;
325 };
326 
327 template<typename BasicJsonType>
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 
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
349  json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
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 
354  bool null()
355  {
356  handle_value(nullptr);
357  return true;
358  }
359 
360  bool boolean(bool val)
361  {
362  handle_value(val);
363  return true;
364  }
365 
366  bool number_integer(number_integer_t val)
367  {
368  handle_value(val);
369  return true;
370  }
371 
372  bool number_unsigned(number_unsigned_t val)
373  {
374  handle_value(val);
375  return true;
376  }
377 
378  bool number_float(number_float_t val, const string_t& /*unused*/)
379  {
380  handle_value(val);
381  return true;
382  }
383 
384  bool string(string_t& val)
385  {
386  handle_value(val);
387  return true;
388  }
389 
390  bool binary(binary_t& val)
391  {
392  handle_value(std::move(val));
393  return true;
394  }
395 
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 
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 
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 
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 
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>
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 
529  constexpr bool is_errored() const
530  {
531  return errored;
532  }
533 
534  private:
550  template<typename Value>
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 
615  BasicJsonType& root;
617  std::vector<BasicJsonType*> ref_stack {};
619  std::vector<bool> keep_stack {};
621  std::vector<bool> key_keep_stack {};
623  BasicJsonType* object_element = nullptr;
625  bool errored = false;
627  const parser_callback_t callback = nullptr;
629  const bool allow_exceptions = true;
631  BasicJsonType discarded = BasicJsonType::value_t::discarded;
632 };
633 
634 template<typename BasicJsonType>
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 
644  bool null()
645  {
646  return true;
647  }
648 
649  bool boolean(bool /*unused*/)
650  {
651  return true;
652  }
653 
654  bool number_integer(number_integer_t /*unused*/)
655  {
656  return true;
657  }
658 
659  bool number_unsigned(number_unsigned_t /*unused*/)
660  {
661  return true;
662  }
663 
664  bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)
665  {
666  return true;
667  }
668 
669  bool string(string_t& /*unused*/)
670  {
671  return true;
672  }
673 
674  bool binary(binary_t& /*unused*/)
675  {
676  return true;
677  }
678 
679  bool start_object(std::size_t /*unused*/ = std::size_t(-1))
680  {
681  return true;
682  }
683 
684  bool key(string_t& /*unused*/)
685  {
686  return true;
687  }
688 
689  bool end_object()
690  {
691  return true;
692  }
693 
694  bool start_array(std::size_t /*unused*/ = std::size_t(-1))
695  {
696  return true;
697  }
698 
699  bool end_array()
700  {
701  return true;
702  }
703 
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
general exception of the basic_json class
Definition: exceptions.hpp:50
Definition: json_sax.hpp:636
SAX implementation to create a JSON value from SAX events.
Definition: json_sax.hpp:155
json_sax_dom_parser(BasicJsonType &r, const bool allow_exceptions_=true)
Definition: json_sax.hpp:168
@ discarded
discarded by the parser callback function
@ value
the parser finished reading a JSON value
namespace for Niels Lohmann
Definition: adl_serializer.hpp:12
SAX interface.
Definition: json_sax.hpp:24
virtual bool start_object(std::size_t elements)=0
the beginning of an object was read
virtual bool string(string_t &val)=0
a string was read
virtual bool end_array()=0
the end of an array was read
virtual bool key(string_t &val)=0
an object key was read
virtual bool binary(binary_t &val)=0
a binary string was read
virtual bool start_array(std::size_t elements)=0
the beginning of an array was read
virtual bool parse_error(std::size_t position, const std::string &last_token, const detail::exception &ex)=0
a parse error occurred
virtual bool boolean(bool val)=0
a boolean value was read
virtual bool end_object()=0
the end of an object was read
virtual bool number_unsigned(number_unsigned_t val)=0
an unsigned integer number was read
virtual bool number_float(number_float_t val, const string_t &s)=0
an floating-point number was read
virtual bool number_integer(number_integer_t val)=0
an integer number was read