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  virtual ~json_sax() = default;
130 };
131 
132 
133 namespace detail
134 {
148 template<typename BasicJsonType>
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 
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;
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 
174  bool null()
175  {
176  handle_value(nullptr);
177  return true;
178  }
179 
180  bool boolean(bool val)
181  {
182  handle_value(val);
183  return true;
184  }
185 
186  bool number_integer(number_integer_t val)
187  {
188  handle_value(val);
189  return true;
190  }
191 
192  bool number_unsigned(number_unsigned_t val)
193  {
194  handle_value(val);
195  return true;
196  }
197 
198  bool number_float(number_float_t val, const string_t& /*unused*/)
199  {
200  handle_value(val);
201  return true;
202  }
203 
204  bool string(string_t& val)
205  {
206  handle_value(val);
207  return true;
208  }
209 
210  bool binary(binary_t& val)
211  {
212  handle_value(std::move(val));
213  return true;
214  }
215 
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 
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 
236  bool end_object()
237  {
238  ref_stack.pop_back();
239  return true;
240  }
241 
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 
255  bool end_array()
256  {
257  ref_stack.pop_back();
258  return true;
259  }
260 
261  template<class Exception>
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 
274  constexpr bool is_errored() const
275  {
276  return errored;
277  }
278 
279  private:
286  template<typename Value>
287  JSON_HEDLEY_RETURNS_NON_NULL
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 
311  BasicJsonType& root;
313  std::vector<BasicJsonType*> ref_stack {};
315  BasicJsonType* object_element = nullptr;
317  bool errored = false;
319  const bool allow_exceptions = true;
320 };
321 
322 template<typename BasicJsonType>
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 
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
347  ~json_sax_dom_callback_parser() = default;
348 
349  bool null()
350  {
351  handle_value(nullptr);
352  return true;
353  }
354 
355  bool boolean(bool val)
356  {
357  handle_value(val);
358  return true;
359  }
360 
361  bool number_integer(number_integer_t val)
362  {
363  handle_value(val);
364  return true;
365  }
366 
367  bool number_unsigned(number_unsigned_t val)
368  {
369  handle_value(val);
370  return true;
371  }
372 
373  bool number_float(number_float_t val, const string_t& /*unused*/)
374  {
375  handle_value(val);
376  return true;
377  }
378 
379  bool string(string_t& val)
380  {
381  handle_value(val);
382  return true;
383  }
384 
385  bool binary(binary_t& val)
386  {
387  handle_value(std::move(val));
388  return true;
389  }
390 
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 
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 
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 
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 
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>
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 
513  constexpr bool is_errored() const
514  {
515  return errored;
516  }
517 
518  private:
534  template<typename Value>
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 
599  BasicJsonType& root;
601  std::vector<BasicJsonType*> ref_stack {};
603  std::vector<bool> keep_stack {};
605  std::vector<bool> key_keep_stack {};
607  BasicJsonType* object_element = nullptr;
609  bool errored = false;
611  const parser_callback_t callback = nullptr;
613  const bool allow_exceptions = true;
615  BasicJsonType discarded = BasicJsonType::value_t::discarded;
616 };
617 
618 template<typename BasicJsonType>
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 
628  bool null()
629  {
630  return true;
631  }
632 
633  bool boolean(bool /*unused*/)
634  {
635  return true;
636  }
637 
638  bool number_integer(number_integer_t /*unused*/)
639  {
640  return true;
641  }
642 
643  bool number_unsigned(number_unsigned_t /*unused*/)
644  {
645  return true;
646  }
647 
648  bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)
649  {
650  return true;
651  }
652 
653  bool string(string_t& /*unused*/)
654  {
655  return true;
656  }
657 
658  bool binary(binary_t& /*unused*/)
659  {
660  return true;
661  }
662 
663  bool start_object(std::size_t /*unused*/ = std::size_t(-1))
664  {
665  return true;
666  }
667 
668  bool key(string_t& /*unused*/)
669  {
670  return true;
671  }
672 
673  bool end_object()
674  {
675  return true;
676  }
677 
678  bool start_array(std::size_t /*unused*/ = std::size_t(-1))
679  {
680  return true;
681  }
682 
683  bool end_array()
684  {
685  return true;
686  }
687 
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
general exception of the basic_json class
Definition: exceptions.hpp:47
Definition: json_sax.hpp:620
SAX implementation to create a JSON value from SAX events.
Definition: json_sax.hpp:150
json_sax_dom_parser(BasicJsonType &r, const bool allow_exceptions_=true)
Definition: json_sax.hpp:163
exception indicating a parse error
Definition: exceptions.hpp:119
@ value
the parser finished reading a JSON value
@ key
the parser read a key of a value in an object
@ array_end
the parser read ] and finished processing a JSON array
@ array_start
the parser read [ and started to process a JSON array
@ object_start
the parser read { and started to process a JSON object
@ object_end
the parser read } and finished processing a JSON object
namespace for Niels Lohmann
Definition: adl_serializer.hpp:9
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