Horizon
Loading...
Searching...
No Matches
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
11namespace nlohmann
12{
13
22template<typename BasicJsonType>
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
138namespace detail
139{
153template<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
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
327template<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)
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
634template<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
exception indicating a parse error
Definition exceptions.hpp:185
@ number_integer
number value (signed integer)
@ discarded
discarded by the parser callback function
@ binary
binary array (ordered collection of bytes)
@ number_float
number value (floating-point)
@ number_unsigned
number value (unsigned integer)
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 null()=0
a null value 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