RflySimSDK v4.10
RflySimSDK说明文档
载入中...
搜索中...
未找到
binary_reader.hpp
1// __ _____ _____ _____
2// __| | __| | | | JSON for Modern C++
3// | | |__ | | | | | | version 3.12.0
4// |_____|_____|_____|_|___| https://github.com/nlohmann/json
5//
6// SPDX-FileCopyrightText: 2013-2025 Niels Lohmann <https://nlohmann.me>
7// SPDX-License-Identifier: MIT
8
9#pragma once
10
11#include <algorithm> // generate_n
12#include <array> // array
13#include <cmath> // ldexp
14#include <cstddef> // size_t
15#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
16#include <cstdio> // snprintf
17#include <cstring> // memcpy
18#include <iterator> // back_inserter
19#include <limits> // numeric_limits
20#include <string> // char_traits, string
21#include <utility> // make_pair, move
22#include <vector> // vector
23#ifdef __cpp_lib_byteswap
24 #include <bit> //byteswap
25#endif
26
27#include <nlohmann/detail/exceptions.hpp>
28#include <nlohmann/detail/input/input_adapters.hpp>
29#include <nlohmann/detail/input/json_sax.hpp>
30#include <nlohmann/detail/input/lexer.hpp>
31#include <nlohmann/detail/macro_scope.hpp>
32#include <nlohmann/detail/meta/is_sax.hpp>
33#include <nlohmann/detail/meta/type_traits.hpp>
34#include <nlohmann/detail/string_concat.hpp>
35#include <nlohmann/detail/value_t.hpp>
36
37NLOHMANN_JSON_NAMESPACE_BEGIN
38namespace detail
39{
40
41/// how to treat CBOR tags
43{
44 error, ///< throw a parse_error exception in case of a tag
45 ignore, ///< ignore tags
46 store ///< store tags as binary type
47};
48
49/*!
50@brief determine system byte order
51
52@return true if and only if system's byte order is little endian
53
54@note from https://stackoverflow.com/a/1001328/266378
55*/
56inline bool little_endianness(int num = 1) noexcept
57{
58 return *reinterpret_cast<char*>(&num) == 1;
59}
60
61///////////////////
62// binary reader //
63///////////////////
64
65/*!
66@brief deserialization of CBOR, MessagePack, and UBJSON values
67*/
68template<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType, InputAdapterType>>
70{
71 using number_integer_t = typename BasicJsonType::number_integer_t;
72 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
73 using number_float_t = typename BasicJsonType::number_float_t;
74 using string_t = typename BasicJsonType::string_t;
75 using binary_t = typename BasicJsonType::binary_t;
76 using json_sax_t = SAX;
77 using char_type = typename InputAdapterType::char_type;
78 using char_int_type = typename char_traits<char_type>::int_type;
79
80 public:
81 /*!
82 @brief create a binary reader
83
84 @param[in] adapter input adapter to read from
85 */
86 explicit binary_reader(InputAdapterType&& adapter, const input_format_t format = input_format_t::json) noexcept : ia(std::move(adapter)), input_format(format)
87 {
89 }
90
91 // make class move-only
92 binary_reader(const binary_reader&) = delete;
93 binary_reader(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
94 binary_reader& operator=(const binary_reader&) = delete;
95 binary_reader& operator=(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
96 ~binary_reader() = default;
97
98 /*!
99 @param[in] format the binary format to parse
100 @param[in] sax_ a SAX event processor
101 @param[in] strict whether to expect the input to be consumed completed
102 @param[in] tag_handler how to treat CBOR tags
103
104 @return whether parsing was successful
105 */
106 JSON_HEDLEY_NON_NULL(3)
107 bool sax_parse(const input_format_t format,
108 json_sax_t* sax_,
109 const bool strict = true,
110 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
111 {
112 sax = sax_;
113 bool result = false;
114
115 switch (format)
116 {
117 case input_format_t::bson:
118 result = parse_bson_internal();
119 break;
120
121 case input_format_t::cbor:
122 result = parse_cbor_internal(true, tag_handler);
123 break;
124
125 case input_format_t::msgpack:
126 result = parse_msgpack_internal();
127 break;
128
129 case input_format_t::ubjson:
130 case input_format_t::bjdata:
131 result = parse_ubjson_internal();
132 break;
133
134 case input_format_t::json: // LCOV_EXCL_LINE
135 default: // LCOV_EXCL_LINE
136 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
137 }
138
139 // strict mode: next byte must be EOF
140 if (result && strict)
141 {
142 if (input_format == input_format_t::ubjson || input_format == input_format_t::bjdata)
143 {
144 get_ignore_noop();
145 }
146 else
147 {
148 get();
149 }
150
151 if (JSON_HEDLEY_UNLIKELY(current != char_traits<char_type>::eof()))
152 {
153 return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read,
154 exception_message(input_format, concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr));
155 }
156 }
157
158 return result;
159 }
160
161 private:
162 //////////
163 // BSON //
164 //////////
165
166 /*!
167 @brief Reads in a BSON-object and passes it to the SAX-parser.
168 @return whether a valid BSON-value was passed to the SAX parser
169 */
170 bool parse_bson_internal()
171 {
172 std::int32_t document_size{};
173 get_number<std::int32_t, true>(input_format_t::bson, document_size);
174
175 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size())))
176 {
177 return false;
178 }
179
180 if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false)))
181 {
182 return false;
183 }
184
185 return sax->end_object();
186 }
187
188 /*!
189 @brief Parses a C-style string from the BSON input.
190 @param[in,out] result A reference to the string variable where the read
191 string is to be stored.
192 @return `true` if the \x00-byte indicating the end of the string was
193 encountered before the EOF; false` indicates an unexpected EOF.
194 */
195 bool get_bson_cstr(string_t& result)
196 {
197 auto out = std::back_inserter(result);
198 while (true)
199 {
200 get();
201 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring")))
202 {
203 return false;
204 }
205 if (current == 0x00)
206 {
207 return true;
208 }
209 *out++ = static_cast<typename string_t::value_type>(current);
210 }
211 }
212
213 /*!
214 @brief Parses a zero-terminated string of length @a len from the BSON
215 input.
216 @param[in] len The length (including the zero-byte at the end) of the
217 string to be read.
218 @param[in,out] result A reference to the string variable where the read
219 string is to be stored.
220 @tparam NumberType The type of the length @a len
221 @pre len >= 1
222 @return `true` if the string was successfully parsed
223 */
224 template<typename NumberType>
225 bool get_bson_string(const NumberType len, string_t& result)
226 {
227 if (JSON_HEDLEY_UNLIKELY(len < 1))
228 {
229 auto last_token = get_token_string();
230 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
231 exception_message(input_format_t::bson, concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr));
232 }
233
234 return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != char_traits<char_type>::eof();
235 }
236
237 /*!
238 @brief Parses a byte array input of length @a len from the BSON input.
239 @param[in] len The length of the byte array to be read.
240 @param[in,out] result A reference to the binary variable where the read
241 array is to be stored.
242 @tparam NumberType The type of the length @a len
243 @pre len >= 0
244 @return `true` if the byte array was successfully parsed
245 */
246 template<typename NumberType>
247 bool get_bson_binary(const NumberType len, binary_t& result)
248 {
249 if (JSON_HEDLEY_UNLIKELY(len < 0))
250 {
251 auto last_token = get_token_string();
252 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
253 exception_message(input_format_t::bson, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"), nullptr));
254 }
255
256 // All BSON binary values have a subtype
257 std::uint8_t subtype{};
258 get_number<std::uint8_t>(input_format_t::bson, subtype);
259 result.set_subtype(subtype);
260
261 return get_binary(input_format_t::bson, len, result);
262 }
263
264 /*!
265 @brief Read a BSON document element of the given @a element_type.
266 @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html
267 @param[in] element_type_parse_position The position in the input stream,
268 where the `element_type` was read.
269 @warning Not all BSON element types are supported yet. An unsupported
270 @a element_type will give rise to a parse_error.114:
271 Unsupported BSON record type 0x...
272 @return whether a valid BSON-object/array was passed to the SAX parser
273 */
274 bool parse_bson_element_internal(const char_int_type element_type,
275 const std::size_t element_type_parse_position)
276 {
277 switch (element_type)
278 {
279 case 0x01: // double
280 {
281 double number{};
282 return get_number<double, true>(input_format_t::bson, number) && sax->number_float(static_cast<number_float_t>(number), "");
283 }
284
285 case 0x02: // string
286 {
287 std::int32_t len{};
288 string_t value;
289 return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value);
290 }
291
292 case 0x03: // object
293 {
294 return parse_bson_internal();
295 }
296
297 case 0x04: // array
298 {
299 return parse_bson_array();
300 }
301
302 case 0x05: // binary
303 {
304 std::int32_t len{};
305 binary_t value;
306 return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value);
307 }
308
309 case 0x08: // boolean
310 {
311 return sax->boolean(get() != 0);
312 }
313
314 case 0x0A: // null
315 {
316 return sax->null();
317 }
318
319 case 0x10: // int32
320 {
321 std::int32_t value{};
322 return get_number<std::int32_t, true>(input_format_t::bson, value) && sax->number_integer(value);
323 }
324
325 case 0x12: // int64
326 {
327 std::int64_t value{};
328 return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value);
329 }
330
331 case 0x11: // uint64
332 {
333 std::uint64_t value{};
334 return get_number<std::uint64_t, true>(input_format_t::bson, value) && sax->number_unsigned(value);
335 }
336
337 default: // anything else is not supported (yet)
338 {
339 std::array<char, 3> cr{{}};
340 static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
341 const std::string cr_str{cr.data()};
342 return sax->parse_error(element_type_parse_position, cr_str,
343 parse_error::create(114, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr));
344 }
345 }
346 }
347
348 /*!
349 @brief Read a BSON element list (as specified in the BSON-spec)
350
351 The same binary layout is used for objects and arrays, hence it must be
352 indicated with the argument @a is_array which one is expected
353 (true --> array, false --> object).
354
355 @param[in] is_array Determines if the element list being read is to be
356 treated as an object (@a is_array == false), or as an
357 array (@a is_array == true).
358 @return whether a valid BSON-object/array was passed to the SAX parser
359 */
360 bool parse_bson_element_list(const bool is_array)
361 {
362 string_t key;
363
364 while (auto element_type = get())
365 {
366 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list")))
367 {
368 return false;
369 }
370
371 const std::size_t element_type_parse_position = chars_read;
372 if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key)))
373 {
374 return false;
375 }
376
377 if (!is_array && !sax->key(key))
378 {
379 return false;
380 }
381
382 if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position)))
383 {
384 return false;
385 }
386
387 // get_bson_cstr only appends
388 key.clear();
389 }
390
391 return true;
392 }
393
394 /*!
395 @brief Reads an array from the BSON input and passes it to the SAX-parser.
396 @return whether a valid BSON-array was passed to the SAX parser
397 */
398 bool parse_bson_array()
399 {
400 std::int32_t document_size{};
401 get_number<std::int32_t, true>(input_format_t::bson, document_size);
402
403 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size())))
404 {
405 return false;
406 }
407
408 if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true)))
409 {
410 return false;
411 }
412
413 return sax->end_array();
414 }
415
416 //////////
417 // CBOR //
418 //////////
419
420 /*!
421 @param[in] get_char whether a new character should be retrieved from the
422 input (true) or whether the last read character should
423 be considered instead (false)
424 @param[in] tag_handler how CBOR tags should be treated
425
426 @return whether a valid CBOR value was passed to the SAX parser
427 */
428 bool parse_cbor_internal(const bool get_char,
429 const cbor_tag_handler_t tag_handler)
430 {
431 switch (get_char ? get() : current)
432 {
433 // EOF
434 case char_traits<char_type>::eof():
435 return unexpect_eof(input_format_t::cbor, "value");
436
437 // Integer 0x00..0x17 (0..23)
438 case 0x00:
439 case 0x01:
440 case 0x02:
441 case 0x03:
442 case 0x04:
443 case 0x05:
444 case 0x06:
445 case 0x07:
446 case 0x08:
447 case 0x09:
448 case 0x0A:
449 case 0x0B:
450 case 0x0C:
451 case 0x0D:
452 case 0x0E:
453 case 0x0F:
454 case 0x10:
455 case 0x11:
456 case 0x12:
457 case 0x13:
458 case 0x14:
459 case 0x15:
460 case 0x16:
461 case 0x17:
462 return sax->number_unsigned(static_cast<number_unsigned_t>(current));
463
464 case 0x18: // Unsigned integer (one-byte uint8_t follows)
465 {
466 std::uint8_t number{};
467 return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
468 }
469
470 case 0x19: // Unsigned integer (two-byte uint16_t follows)
471 {
472 std::uint16_t number{};
473 return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
474 }
475
476 case 0x1A: // Unsigned integer (four-byte uint32_t follows)
477 {
478 std::uint32_t number{};
479 return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
480 }
481
482 case 0x1B: // Unsigned integer (eight-byte uint64_t follows)
483 {
484 std::uint64_t number{};
485 return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
486 }
487
488 // Negative integer -1-0x00..-1-0x17 (-1..-24)
489 case 0x20:
490 case 0x21:
491 case 0x22:
492 case 0x23:
493 case 0x24:
494 case 0x25:
495 case 0x26:
496 case 0x27:
497 case 0x28:
498 case 0x29:
499 case 0x2A:
500 case 0x2B:
501 case 0x2C:
502 case 0x2D:
503 case 0x2E:
504 case 0x2F:
505 case 0x30:
506 case 0x31:
507 case 0x32:
508 case 0x33:
509 case 0x34:
510 case 0x35:
511 case 0x36:
512 case 0x37:
513 return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));
514
515 case 0x38: // Negative integer (one-byte uint8_t follows)
516 {
517 std::uint8_t number{};
518 return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
519 }
520
521 case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
522 {
523 std::uint16_t number{};
524 return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
525 }
526
527 case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
528 {
529 std::uint32_t number{};
530 return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
531 }
532
533 case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
534 {
535 std::uint64_t number{};
536 return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1)
537 - static_cast<number_integer_t>(number));
538 }
539
540 // Binary data (0x00..0x17 bytes follow)
541 case 0x40:
542 case 0x41:
543 case 0x42:
544 case 0x43:
545 case 0x44:
546 case 0x45:
547 case 0x46:
548 case 0x47:
549 case 0x48:
550 case 0x49:
551 case 0x4A:
552 case 0x4B:
553 case 0x4C:
554 case 0x4D:
555 case 0x4E:
556 case 0x4F:
557 case 0x50:
558 case 0x51:
559 case 0x52:
560 case 0x53:
561 case 0x54:
562 case 0x55:
563 case 0x56:
564 case 0x57:
565 case 0x58: // Binary data (one-byte uint8_t for n follows)
566 case 0x59: // Binary data (two-byte uint16_t for n follow)
567 case 0x5A: // Binary data (four-byte uint32_t for n follow)
568 case 0x5B: // Binary data (eight-byte uint64_t for n follow)
569 case 0x5F: // Binary data (indefinite length)
570 {
571 binary_t b;
572 return get_cbor_binary(b) && sax->binary(b);
573 }
574
575 // UTF-8 string (0x00..0x17 bytes follow)
576 case 0x60:
577 case 0x61:
578 case 0x62:
579 case 0x63:
580 case 0x64:
581 case 0x65:
582 case 0x66:
583 case 0x67:
584 case 0x68:
585 case 0x69:
586 case 0x6A:
587 case 0x6B:
588 case 0x6C:
589 case 0x6D:
590 case 0x6E:
591 case 0x6F:
592 case 0x70:
593 case 0x71:
594 case 0x72:
595 case 0x73:
596 case 0x74:
597 case 0x75:
598 case 0x76:
599 case 0x77:
600 case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
601 case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
602 case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
603 case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
604 case 0x7F: // UTF-8 string (indefinite length)
605 {
606 string_t s;
607 return get_cbor_string(s) && sax->string(s);
608 }
609
610 // array (0x00..0x17 data items follow)
611 case 0x80:
612 case 0x81:
613 case 0x82:
614 case 0x83:
615 case 0x84:
616 case 0x85:
617 case 0x86:
618 case 0x87:
619 case 0x88:
620 case 0x89:
621 case 0x8A:
622 case 0x8B:
623 case 0x8C:
624 case 0x8D:
625 case 0x8E:
626 case 0x8F:
627 case 0x90:
628 case 0x91:
629 case 0x92:
630 case 0x93:
631 case 0x94:
632 case 0x95:
633 case 0x96:
634 case 0x97:
635 return get_cbor_array(
636 conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
637
638 case 0x98: // array (one-byte uint8_t for n follows)
639 {
640 std::uint8_t len{};
641 return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
642 }
643
644 case 0x99: // array (two-byte uint16_t for n follow)
645 {
646 std::uint16_t len{};
647 return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
648 }
649
650 case 0x9A: // array (four-byte uint32_t for n follow)
651 {
652 std::uint32_t len{};
653 return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler);
654 }
655
656 case 0x9B: // array (eight-byte uint64_t for n follow)
657 {
658 std::uint64_t len{};
659 return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler);
660 }
661
662 case 0x9F: // array (indefinite length)
663 return get_cbor_array(detail::unknown_size(), tag_handler);
664
665 // map (0x00..0x17 pairs of data items follow)
666 case 0xA0:
667 case 0xA1:
668 case 0xA2:
669 case 0xA3:
670 case 0xA4:
671 case 0xA5:
672 case 0xA6:
673 case 0xA7:
674 case 0xA8:
675 case 0xA9:
676 case 0xAA:
677 case 0xAB:
678 case 0xAC:
679 case 0xAD:
680 case 0xAE:
681 case 0xAF:
682 case 0xB0:
683 case 0xB1:
684 case 0xB2:
685 case 0xB3:
686 case 0xB4:
687 case 0xB5:
688 case 0xB6:
689 case 0xB7:
690 return get_cbor_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
691
692 case 0xB8: // map (one-byte uint8_t for n follows)
693 {
694 std::uint8_t len{};
695 return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
696 }
697
698 case 0xB9: // map (two-byte uint16_t for n follow)
699 {
700 std::uint16_t len{};
701 return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
702 }
703
704 case 0xBA: // map (four-byte uint32_t for n follow)
705 {
706 std::uint32_t len{};
707 return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler);
708 }
709
710 case 0xBB: // map (eight-byte uint64_t for n follow)
711 {
712 std::uint64_t len{};
713 return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler);
714 }
715
716 case 0xBF: // map (indefinite length)
717 return get_cbor_object(detail::unknown_size(), tag_handler);
718
719 case 0xC6: // tagged item
720 case 0xC7:
721 case 0xC8:
722 case 0xC9:
723 case 0xCA:
724 case 0xCB:
725 case 0xCC:
726 case 0xCD:
727 case 0xCE:
728 case 0xCF:
729 case 0xD0:
730 case 0xD1:
731 case 0xD2:
732 case 0xD3:
733 case 0xD4:
734 case 0xD8: // tagged item (1 byte follows)
735 case 0xD9: // tagged item (2 bytes follow)
736 case 0xDA: // tagged item (4 bytes follow)
737 case 0xDB: // tagged item (8 bytes follow)
738 {
739 switch (tag_handler)
740 {
742 {
743 auto last_token = get_token_string();
744 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
745 exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr));
746 }
747
749 {
750 // ignore binary subtype
751 switch (current)
752 {
753 case 0xD8:
754 {
755 std::uint8_t subtype_to_ignore{};
756 get_number(input_format_t::cbor, subtype_to_ignore);
757 break;
758 }
759 case 0xD9:
760 {
761 std::uint16_t subtype_to_ignore{};
762 get_number(input_format_t::cbor, subtype_to_ignore);
763 break;
764 }
765 case 0xDA:
766 {
767 std::uint32_t subtype_to_ignore{};
768 get_number(input_format_t::cbor, subtype_to_ignore);
769 break;
770 }
771 case 0xDB:
772 {
773 std::uint64_t subtype_to_ignore{};
774 get_number(input_format_t::cbor, subtype_to_ignore);
775 break;
776 }
777 default:
778 break;
779 }
780 return parse_cbor_internal(true, tag_handler);
781 }
782
784 {
785 binary_t b;
786 // use binary subtype and store in a binary container
787 switch (current)
788 {
789 case 0xD8:
790 {
791 std::uint8_t subtype{};
792 get_number(input_format_t::cbor, subtype);
793 b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
794 break;
795 }
796 case 0xD9:
797 {
798 std::uint16_t subtype{};
799 get_number(input_format_t::cbor, subtype);
800 b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
801 break;
802 }
803 case 0xDA:
804 {
805 std::uint32_t subtype{};
806 get_number(input_format_t::cbor, subtype);
807 b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
808 break;
809 }
810 case 0xDB:
811 {
812 std::uint64_t subtype{};
813 get_number(input_format_t::cbor, subtype);
814 b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
815 break;
816 }
817 default:
818 return parse_cbor_internal(true, tag_handler);
819 }
820 get();
821 return get_cbor_binary(b) && sax->binary(b);
822 }
823
824 default: // LCOV_EXCL_LINE
825 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
826 return false; // LCOV_EXCL_LINE
827 }
828 }
829
830 case 0xF4: // false
831 return sax->boolean(false);
832
833 case 0xF5: // true
834 return sax->boolean(true);
835
836 case 0xF6: // null
837 return sax->null();
838
839 case 0xF9: // Half-Precision Float (two-byte IEEE 754)
840 {
841 const auto byte1_raw = get();
842 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number")))
843 {
844 return false;
845 }
846 const auto byte2_raw = get();
847 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number")))
848 {
849 return false;
850 }
851
852 const auto byte1 = static_cast<unsigned char>(byte1_raw);
853 const auto byte2 = static_cast<unsigned char>(byte2_raw);
854
855 // Code from RFC 7049, Appendix D, Figure 3:
856 // As half-precision floating-point numbers were only added
857 // to IEEE 754 in 2008, today's programming platforms often
858 // still only have limited support for them. It is very
859 // easy to include at least decoding support for them even
860 // without such support. An example of a small decoder for
861 // half-precision floating-point numbers in the C language
862 // is shown in Fig. 3.
863 const auto half = static_cast<unsigned int>((byte1 << 8u) + byte2);
864 const double val = [&half]
865 {
866 const int exp = (half >> 10u) & 0x1Fu;
867 const unsigned int mant = half & 0x3FFu;
868 JSON_ASSERT(0 <= exp&& exp <= 32);
869 JSON_ASSERT(mant <= 1024);
870 switch (exp)
871 {
872 case 0:
873 return std::ldexp(mant, -24);
874 case 31:
875 return (mant == 0)
876 ? std::numeric_limits<double>::infinity()
877 : std::numeric_limits<double>::quiet_NaN();
878 default:
879 return std::ldexp(mant + 1024, exp - 25);
880 }
881 }();
882 return sax->number_float((half & 0x8000u) != 0
883 ? static_cast<number_float_t>(-val)
884 : static_cast<number_float_t>(val), "");
885 }
886
887 case 0xFA: // Single-Precision Float (four-byte IEEE 754)
888 {
889 float number{};
890 return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), "");
891 }
892
893 case 0xFB: // Double-Precision Float (eight-byte IEEE 754)
894 {
895 double number{};
896 return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), "");
897 }
898
899 default: // anything else (0xFF is handled inside the other types)
900 {
901 auto last_token = get_token_string();
902 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
903 exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr));
904 }
905 }
906 }
907
908 /*!
909 @brief reads a CBOR string
910
911 This function first reads starting bytes to determine the expected
912 string length and then copies this number of bytes into a string.
913 Additionally, CBOR's strings with indefinite lengths are supported.
914
915 @param[out] result created string
916
917 @return whether string creation completed
918 */
919 bool get_cbor_string(string_t& result)
920 {
921 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string")))
922 {
923 return false;
924 }
925
926 switch (current)
927 {
928 // UTF-8 string (0x00..0x17 bytes follow)
929 case 0x60:
930 case 0x61:
931 case 0x62:
932 case 0x63:
933 case 0x64:
934 case 0x65:
935 case 0x66:
936 case 0x67:
937 case 0x68:
938 case 0x69:
939 case 0x6A:
940 case 0x6B:
941 case 0x6C:
942 case 0x6D:
943 case 0x6E:
944 case 0x6F:
945 case 0x70:
946 case 0x71:
947 case 0x72:
948 case 0x73:
949 case 0x74:
950 case 0x75:
951 case 0x76:
952 case 0x77:
953 {
954 return get_string(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
955 }
956
957 case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
958 {
959 std::uint8_t len{};
960 return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
961 }
962
963 case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
964 {
965 std::uint16_t len{};
966 return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
967 }
968
969 case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
970 {
971 std::uint32_t len{};
972 return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
973 }
974
975 case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
976 {
977 std::uint64_t len{};
978 return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
979 }
980
981 case 0x7F: // UTF-8 string (indefinite length)
982 {
983 while (get() != 0xFF)
984 {
985 string_t chunk;
986 if (!get_cbor_string(chunk))
987 {
988 return false;
989 }
990 result.append(chunk);
991 }
992 return true;
993 }
994
995 default:
996 {
997 auto last_token = get_token_string();
998 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
999 exception_message(input_format_t::cbor, concat("expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x", last_token), "string"), nullptr));
1000 }
1001 }
1002 }
1003
1004 /*!
1005 @brief reads a CBOR byte array
1006
1007 This function first reads starting bytes to determine the expected
1008 byte array length and then copies this number of bytes into the byte array.
1009 Additionally, CBOR's byte arrays with indefinite lengths are supported.
1010
1011 @param[out] result created byte array
1012
1013 @return whether byte array creation completed
1014 */
1015 bool get_cbor_binary(binary_t& result)
1016 {
1017 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary")))
1018 {
1019 return false;
1020 }
1021
1022 switch (current)
1023 {
1024 // Binary data (0x00..0x17 bytes follow)
1025 case 0x40:
1026 case 0x41:
1027 case 0x42:
1028 case 0x43:
1029 case 0x44:
1030 case 0x45:
1031 case 0x46:
1032 case 0x47:
1033 case 0x48:
1034 case 0x49:
1035 case 0x4A:
1036 case 0x4B:
1037 case 0x4C:
1038 case 0x4D:
1039 case 0x4E:
1040 case 0x4F:
1041 case 0x50:
1042 case 0x51:
1043 case 0x52:
1044 case 0x53:
1045 case 0x54:
1046 case 0x55:
1047 case 0x56:
1048 case 0x57:
1049 {
1050 return get_binary(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
1051 }
1052
1053 case 0x58: // Binary data (one-byte uint8_t for n follows)
1054 {
1055 std::uint8_t len{};
1056 return get_number(input_format_t::cbor, len) &&
1057 get_binary(input_format_t::cbor, len, result);
1058 }
1059
1060 case 0x59: // Binary data (two-byte uint16_t for n follow)
1061 {
1062 std::uint16_t len{};
1063 return get_number(input_format_t::cbor, len) &&
1064 get_binary(input_format_t::cbor, len, result);
1065 }
1066
1067 case 0x5A: // Binary data (four-byte uint32_t for n follow)
1068 {
1069 std::uint32_t len{};
1070 return get_number(input_format_t::cbor, len) &&
1071 get_binary(input_format_t::cbor, len, result);
1072 }
1073
1074 case 0x5B: // Binary data (eight-byte uint64_t for n follow)
1075 {
1076 std::uint64_t len{};
1077 return get_number(input_format_t::cbor, len) &&
1078 get_binary(input_format_t::cbor, len, result);
1079 }
1080
1081 case 0x5F: // Binary data (indefinite length)
1082 {
1083 while (get() != 0xFF)
1084 {
1085 binary_t chunk;
1086 if (!get_cbor_binary(chunk))
1087 {
1088 return false;
1089 }
1090 result.insert(result.end(), chunk.begin(), chunk.end());
1091 }
1092 return true;
1093 }
1094
1095 default:
1096 {
1097 auto last_token = get_token_string();
1098 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
1099 exception_message(input_format_t::cbor, concat("expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x", last_token), "binary"), nullptr));
1100 }
1101 }
1102 }
1103
1104 /*!
1105 @param[in] len the length of the array or detail::unknown_size() for an
1106 array of indefinite size
1107 @param[in] tag_handler how CBOR tags should be treated
1108 @return whether array creation completed
1109 */
1110 bool get_cbor_array(const std::size_t len,
1111 const cbor_tag_handler_t tag_handler)
1112 {
1113 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))
1114 {
1115 return false;
1116 }
1117
1118 if (len != detail::unknown_size())
1119 {
1120 for (std::size_t i = 0; i < len; ++i)
1121 {
1122 if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
1123 {
1124 return false;
1125 }
1126 }
1127 }
1128 else
1129 {
1130 while (get() != 0xFF)
1131 {
1132 if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler)))
1133 {
1134 return false;
1135 }
1136 }
1137 }
1138
1139 return sax->end_array();
1140 }
1141
1142 /*!
1143 @param[in] len the length of the object or detail::unknown_size() for an
1144 object of indefinite size
1145 @param[in] tag_handler how CBOR tags should be treated
1146 @return whether object creation completed
1147 */
1148 bool get_cbor_object(const std::size_t len,
1149 const cbor_tag_handler_t tag_handler)
1150 {
1151 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))
1152 {
1153 return false;
1154 }
1155
1156 if (len != 0)
1157 {
1158 string_t key;
1159 if (len != detail::unknown_size())
1160 {
1161 for (std::size_t i = 0; i < len; ++i)
1162 {
1163 get();
1164 if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
1165 {
1166 return false;
1167 }
1168
1169 if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
1170 {
1171 return false;
1172 }
1173 key.clear();
1174 }
1175 }
1176 else
1177 {
1178 while (get() != 0xFF)
1179 {
1180 if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
1181 {
1182 return false;
1183 }
1184
1185 if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
1186 {
1187 return false;
1188 }
1189 key.clear();
1190 }
1191 }
1192 }
1193
1194 return sax->end_object();
1195 }
1196
1197 /////////////
1198 // MsgPack //
1199 /////////////
1200
1201 /*!
1202 @return whether a valid MessagePack value was passed to the SAX parser
1203 */
1204 bool parse_msgpack_internal()
1205 {
1206 switch (get())
1207 {
1208 // EOF
1209 case char_traits<char_type>::eof():
1210 return unexpect_eof(input_format_t::msgpack, "value");
1211
1212 // positive fixint
1213 case 0x00:
1214 case 0x01:
1215 case 0x02:
1216 case 0x03:
1217 case 0x04:
1218 case 0x05:
1219 case 0x06:
1220 case 0x07:
1221 case 0x08:
1222 case 0x09:
1223 case 0x0A:
1224 case 0x0B:
1225 case 0x0C:
1226 case 0x0D:
1227 case 0x0E:
1228 case 0x0F:
1229 case 0x10:
1230 case 0x11:
1231 case 0x12:
1232 case 0x13:
1233 case 0x14:
1234 case 0x15:
1235 case 0x16:
1236 case 0x17:
1237 case 0x18:
1238 case 0x19:
1239 case 0x1A:
1240 case 0x1B:
1241 case 0x1C:
1242 case 0x1D:
1243 case 0x1E:
1244 case 0x1F:
1245 case 0x20:
1246 case 0x21:
1247 case 0x22:
1248 case 0x23:
1249 case 0x24:
1250 case 0x25:
1251 case 0x26:
1252 case 0x27:
1253 case 0x28:
1254 case 0x29:
1255 case 0x2A:
1256 case 0x2B:
1257 case 0x2C:
1258 case 0x2D:
1259 case 0x2E:
1260 case 0x2F:
1261 case 0x30:
1262 case 0x31:
1263 case 0x32:
1264 case 0x33:
1265 case 0x34:
1266 case 0x35:
1267 case 0x36:
1268 case 0x37:
1269 case 0x38:
1270 case 0x39:
1271 case 0x3A:
1272 case 0x3B:
1273 case 0x3C:
1274 case 0x3D:
1275 case 0x3E:
1276 case 0x3F:
1277 case 0x40:
1278 case 0x41:
1279 case 0x42:
1280 case 0x43:
1281 case 0x44:
1282 case 0x45:
1283 case 0x46:
1284 case 0x47:
1285 case 0x48:
1286 case 0x49:
1287 case 0x4A:
1288 case 0x4B:
1289 case 0x4C:
1290 case 0x4D:
1291 case 0x4E:
1292 case 0x4F:
1293 case 0x50:
1294 case 0x51:
1295 case 0x52:
1296 case 0x53:
1297 case 0x54:
1298 case 0x55:
1299 case 0x56:
1300 case 0x57:
1301 case 0x58:
1302 case 0x59:
1303 case 0x5A:
1304 case 0x5B:
1305 case 0x5C:
1306 case 0x5D:
1307 case 0x5E:
1308 case 0x5F:
1309 case 0x60:
1310 case 0x61:
1311 case 0x62:
1312 case 0x63:
1313 case 0x64:
1314 case 0x65:
1315 case 0x66:
1316 case 0x67:
1317 case 0x68:
1318 case 0x69:
1319 case 0x6A:
1320 case 0x6B:
1321 case 0x6C:
1322 case 0x6D:
1323 case 0x6E:
1324 case 0x6F:
1325 case 0x70:
1326 case 0x71:
1327 case 0x72:
1328 case 0x73:
1329 case 0x74:
1330 case 0x75:
1331 case 0x76:
1332 case 0x77:
1333 case 0x78:
1334 case 0x79:
1335 case 0x7A:
1336 case 0x7B:
1337 case 0x7C:
1338 case 0x7D:
1339 case 0x7E:
1340 case 0x7F:
1341 return sax->number_unsigned(static_cast<number_unsigned_t>(current));
1342
1343 // fixmap
1344 case 0x80:
1345 case 0x81:
1346 case 0x82:
1347 case 0x83:
1348 case 0x84:
1349 case 0x85:
1350 case 0x86:
1351 case 0x87:
1352 case 0x88:
1353 case 0x89:
1354 case 0x8A:
1355 case 0x8B:
1356 case 0x8C:
1357 case 0x8D:
1358 case 0x8E:
1359 case 0x8F:
1360 return get_msgpack_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
1361
1362 // fixarray
1363 case 0x90:
1364 case 0x91:
1365 case 0x92:
1366 case 0x93:
1367 case 0x94:
1368 case 0x95:
1369 case 0x96:
1370 case 0x97:
1371 case 0x98:
1372 case 0x99:
1373 case 0x9A:
1374 case 0x9B:
1375 case 0x9C:
1376 case 0x9D:
1377 case 0x9E:
1378 case 0x9F:
1379 return get_msgpack_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
1380
1381 // fixstr
1382 case 0xA0:
1383 case 0xA1:
1384 case 0xA2:
1385 case 0xA3:
1386 case 0xA4:
1387 case 0xA5:
1388 case 0xA6:
1389 case 0xA7:
1390 case 0xA8:
1391 case 0xA9:
1392 case 0xAA:
1393 case 0xAB:
1394 case 0xAC:
1395 case 0xAD:
1396 case 0xAE:
1397 case 0xAF:
1398 case 0xB0:
1399 case 0xB1:
1400 case 0xB2:
1401 case 0xB3:
1402 case 0xB4:
1403 case 0xB5:
1404 case 0xB6:
1405 case 0xB7:
1406 case 0xB8:
1407 case 0xB9:
1408 case 0xBA:
1409 case 0xBB:
1410 case 0xBC:
1411 case 0xBD:
1412 case 0xBE:
1413 case 0xBF:
1414 case 0xD9: // str 8
1415 case 0xDA: // str 16
1416 case 0xDB: // str 32
1417 {
1418 string_t s;
1419 return get_msgpack_string(s) && sax->string(s);
1420 }
1421
1422 case 0xC0: // nil
1423 return sax->null();
1424
1425 case 0xC2: // false
1426 return sax->boolean(false);
1427
1428 case 0xC3: // true
1429 return sax->boolean(true);
1430
1431 case 0xC4: // bin 8
1432 case 0xC5: // bin 16
1433 case 0xC6: // bin 32
1434 case 0xC7: // ext 8
1435 case 0xC8: // ext 16
1436 case 0xC9: // ext 32
1437 case 0xD4: // fixext 1
1438 case 0xD5: // fixext 2
1439 case 0xD6: // fixext 4
1440 case 0xD7: // fixext 8
1441 case 0xD8: // fixext 16
1442 {
1443 binary_t b;
1444 return get_msgpack_binary(b) && sax->binary(b);
1445 }
1446
1447 case 0xCA: // float 32
1448 {
1449 float number{};
1450 return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), "");
1451 }
1452
1453 case 0xCB: // float 64
1454 {
1455 double number{};
1456 return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), "");
1457 }
1458
1459 case 0xCC: // uint 8
1460 {
1461 std::uint8_t number{};
1462 return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
1463 }
1464
1465 case 0xCD: // uint 16
1466 {
1467 std::uint16_t number{};
1468 return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
1469 }
1470
1471 case 0xCE: // uint 32
1472 {
1473 std::uint32_t number{};
1474 return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
1475 }
1476
1477 case 0xCF: // uint 64
1478 {
1479 std::uint64_t number{};
1480 return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
1481 }
1482
1483 case 0xD0: // int 8
1484 {
1485 std::int8_t number{};
1486 return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
1487 }
1488
1489 case 0xD1: // int 16
1490 {
1491 std::int16_t number{};
1492 return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
1493 }
1494
1495 case 0xD2: // int 32
1496 {
1497 std::int32_t number{};
1498 return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
1499 }
1500
1501 case 0xD3: // int 64
1502 {
1503 std::int64_t number{};
1504 return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
1505 }
1506
1507 case 0xDC: // array 16
1508 {
1509 std::uint16_t len{};
1510 return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len));
1511 }
1512
1513 case 0xDD: // array 32
1514 {
1515 std::uint32_t len{};
1516 return get_number(input_format_t::msgpack, len) && get_msgpack_array(conditional_static_cast<std::size_t>(len));
1517 }
1518
1519 case 0xDE: // map 16
1520 {
1521 std::uint16_t len{};
1522 return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len));
1523 }
1524
1525 case 0xDF: // map 32
1526 {
1527 std::uint32_t len{};
1528 return get_number(input_format_t::msgpack, len) && get_msgpack_object(conditional_static_cast<std::size_t>(len));
1529 }
1530
1531 // negative fixint
1532 case 0xE0:
1533 case 0xE1:
1534 case 0xE2:
1535 case 0xE3:
1536 case 0xE4:
1537 case 0xE5:
1538 case 0xE6:
1539 case 0xE7:
1540 case 0xE8:
1541 case 0xE9:
1542 case 0xEA:
1543 case 0xEB:
1544 case 0xEC:
1545 case 0xED:
1546 case 0xEE:
1547 case 0xEF:
1548 case 0xF0:
1549 case 0xF1:
1550 case 0xF2:
1551 case 0xF3:
1552 case 0xF4:
1553 case 0xF5:
1554 case 0xF6:
1555 case 0xF7:
1556 case 0xF8:
1557 case 0xF9:
1558 case 0xFA:
1559 case 0xFB:
1560 case 0xFC:
1561 case 0xFD:
1562 case 0xFE:
1563 case 0xFF:
1564 return sax->number_integer(static_cast<std::int8_t>(current));
1565
1566 default: // anything else
1567 {
1568 auto last_token = get_token_string();
1569 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
1570 exception_message(input_format_t::msgpack, concat("invalid byte: 0x", last_token), "value"), nullptr));
1571 }
1572 }
1573 }
1574
1575 /*!
1576 @brief reads a MessagePack string
1577
1578 This function first reads starting bytes to determine the expected
1579 string length and then copies this number of bytes into a string.
1580
1581 @param[out] result created string
1582
1583 @return whether string creation completed
1584 */
1585 bool get_msgpack_string(string_t& result)
1586 {
1587 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string")))
1588 {
1589 return false;
1590 }
1591
1592 switch (current)
1593 {
1594 // fixstr
1595 case 0xA0:
1596 case 0xA1:
1597 case 0xA2:
1598 case 0xA3:
1599 case 0xA4:
1600 case 0xA5:
1601 case 0xA6:
1602 case 0xA7:
1603 case 0xA8:
1604 case 0xA9:
1605 case 0xAA:
1606 case 0xAB:
1607 case 0xAC:
1608 case 0xAD:
1609 case 0xAE:
1610 case 0xAF:
1611 case 0xB0:
1612 case 0xB1:
1613 case 0xB2:
1614 case 0xB3:
1615 case 0xB4:
1616 case 0xB5:
1617 case 0xB6:
1618 case 0xB7:
1619 case 0xB8:
1620 case 0xB9:
1621 case 0xBA:
1622 case 0xBB:
1623 case 0xBC:
1624 case 0xBD:
1625 case 0xBE:
1626 case 0xBF:
1627 {
1628 return get_string(input_format_t::msgpack, static_cast<unsigned int>(current) & 0x1Fu, result);
1629 }
1630
1631 case 0xD9: // str 8
1632 {
1633 std::uint8_t len{};
1634 return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
1635 }
1636
1637 case 0xDA: // str 16
1638 {
1639 std::uint16_t len{};
1640 return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
1641 }
1642
1643 case 0xDB: // str 32
1644 {
1645 std::uint32_t len{};
1646 return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
1647 }
1648
1649 default:
1650 {
1651 auto last_token = get_token_string();
1652 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
1653 exception_message(input_format_t::msgpack, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", last_token), "string"), nullptr));
1654 }
1655 }
1656 }
1657
1658 /*!
1659 @brief reads a MessagePack byte array
1660
1661 This function first reads starting bytes to determine the expected
1662 byte array length and then copies this number of bytes into a byte array.
1663
1664 @param[out] result created byte array
1665
1666 @return whether byte array creation completed
1667 */
1668 bool get_msgpack_binary(binary_t& result)
1669 {
1670 // helper function to set the subtype
1671 auto assign_and_return_true = [&result](std::int8_t subtype)
1672 {
1673 result.set_subtype(static_cast<std::uint8_t>(subtype));
1674 return true;
1675 };
1676
1677 switch (current)
1678 {
1679 case 0xC4: // bin 8
1680 {
1681 std::uint8_t len{};
1682 return get_number(input_format_t::msgpack, len) &&
1683 get_binary(input_format_t::msgpack, len, result);
1684 }
1685
1686 case 0xC5: // bin 16
1687 {
1688 std::uint16_t len{};
1689 return get_number(input_format_t::msgpack, len) &&
1690 get_binary(input_format_t::msgpack, len, result);
1691 }
1692
1693 case 0xC6: // bin 32
1694 {
1695 std::uint32_t len{};
1696 return get_number(input_format_t::msgpack, len) &&
1697 get_binary(input_format_t::msgpack, len, result);
1698 }
1699
1700 case 0xC7: // ext 8
1701 {
1702 std::uint8_t len{};
1703 std::int8_t subtype{};
1704 return get_number(input_format_t::msgpack, len) &&
1705 get_number(input_format_t::msgpack, subtype) &&
1706 get_binary(input_format_t::msgpack, len, result) &&
1707 assign_and_return_true(subtype);
1708 }
1709
1710 case 0xC8: // ext 16
1711 {
1712 std::uint16_t len{};
1713 std::int8_t subtype{};
1714 return get_number(input_format_t::msgpack, len) &&
1715 get_number(input_format_t::msgpack, subtype) &&
1716 get_binary(input_format_t::msgpack, len, result) &&
1717 assign_and_return_true(subtype);
1718 }
1719
1720 case 0xC9: // ext 32
1721 {
1722 std::uint32_t len{};
1723 std::int8_t subtype{};
1724 return get_number(input_format_t::msgpack, len) &&
1725 get_number(input_format_t::msgpack, subtype) &&
1726 get_binary(input_format_t::msgpack, len, result) &&
1727 assign_and_return_true(subtype);
1728 }
1729
1730 case 0xD4: // fixext 1
1731 {
1732 std::int8_t subtype{};
1733 return get_number(input_format_t::msgpack, subtype) &&
1734 get_binary(input_format_t::msgpack, 1, result) &&
1735 assign_and_return_true(subtype);
1736 }
1737
1738 case 0xD5: // fixext 2
1739 {
1740 std::int8_t subtype{};
1741 return get_number(input_format_t::msgpack, subtype) &&
1742 get_binary(input_format_t::msgpack, 2, result) &&
1743 assign_and_return_true(subtype);
1744 }
1745
1746 case 0xD6: // fixext 4
1747 {
1748 std::int8_t subtype{};
1749 return get_number(input_format_t::msgpack, subtype) &&
1750 get_binary(input_format_t::msgpack, 4, result) &&
1751 assign_and_return_true(subtype);
1752 }
1753
1754 case 0xD7: // fixext 8
1755 {
1756 std::int8_t subtype{};
1757 return get_number(input_format_t::msgpack, subtype) &&
1758 get_binary(input_format_t::msgpack, 8, result) &&
1759 assign_and_return_true(subtype);
1760 }
1761
1762 case 0xD8: // fixext 16
1763 {
1764 std::int8_t subtype{};
1765 return get_number(input_format_t::msgpack, subtype) &&
1766 get_binary(input_format_t::msgpack, 16, result) &&
1767 assign_and_return_true(subtype);
1768 }
1769
1770 default: // LCOV_EXCL_LINE
1771 return false; // LCOV_EXCL_LINE
1772 }
1773 }
1774
1775 /*!
1776 @param[in] len the length of the array
1777 @return whether array creation completed
1778 */
1779 bool get_msgpack_array(const std::size_t len)
1780 {
1781 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))
1782 {
1783 return false;
1784 }
1785
1786 for (std::size_t i = 0; i < len; ++i)
1787 {
1788 if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))
1789 {
1790 return false;
1791 }
1792 }
1793
1794 return sax->end_array();
1795 }
1796
1797 /*!
1798 @param[in] len the length of the object
1799 @return whether object creation completed
1800 */
1801 bool get_msgpack_object(const std::size_t len)
1802 {
1803 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))
1804 {
1805 return false;
1806 }
1807
1808 string_t key;
1809 for (std::size_t i = 0; i < len; ++i)
1810 {
1811 get();
1812 if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key)))
1813 {
1814 return false;
1815 }
1816
1817 if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))
1818 {
1819 return false;
1820 }
1821 key.clear();
1822 }
1823
1824 return sax->end_object();
1825 }
1826
1827 ////////////
1828 // UBJSON //
1829 ////////////
1830
1831 /*!
1832 @param[in] get_char whether a new character should be retrieved from the
1833 input (true, default) or whether the last read
1834 character should be considered instead
1835
1836 @return whether a valid UBJSON value was passed to the SAX parser
1837 */
1838 bool parse_ubjson_internal(const bool get_char = true)
1839 {
1840 return get_ubjson_value(get_char ? get_ignore_noop() : current);
1841 }
1842
1843 /*!
1844 @brief reads a UBJSON string
1845
1846 This function is either called after reading the 'S' byte explicitly
1847 indicating a string, or in case of an object key where the 'S' byte can be
1848 left out.
1849
1850 @param[out] result created string
1851 @param[in] get_char whether a new character should be retrieved from the
1852 input (true, default) or whether the last read
1853 character should be considered instead
1854
1855 @return whether string creation completed
1856 */
1857 bool get_ubjson_string(string_t& result, const bool get_char = true)
1858 {
1859 if (get_char)
1860 {
1861 get(); // TODO(niels): may we ignore N here?
1862 }
1863
1864 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
1865 {
1866 return false;
1867 }
1868
1869 switch (current)
1870 {
1871 case 'U':
1872 {
1873 std::uint8_t len{};
1874 return get_number(input_format, len) && get_string(input_format, len, result);
1875 }
1876
1877 case 'i':
1878 {
1879 std::int8_t len{};
1880 return get_number(input_format, len) && get_string(input_format, len, result);
1881 }
1882
1883 case 'I':
1884 {
1885 std::int16_t len{};
1886 return get_number(input_format, len) && get_string(input_format, len, result);
1887 }
1888
1889 case 'l':
1890 {
1891 std::int32_t len{};
1892 return get_number(input_format, len) && get_string(input_format, len, result);
1893 }
1894
1895 case 'L':
1896 {
1897 std::int64_t len{};
1898 return get_number(input_format, len) && get_string(input_format, len, result);
1899 }
1900
1901 case 'u':
1902 {
1903 if (input_format != input_format_t::bjdata)
1904 {
1905 break;
1906 }
1907 std::uint16_t len{};
1908 return get_number(input_format, len) && get_string(input_format, len, result);
1909 }
1910
1911 case 'm':
1912 {
1913 if (input_format != input_format_t::bjdata)
1914 {
1915 break;
1916 }
1917 std::uint32_t len{};
1918 return get_number(input_format, len) && get_string(input_format, len, result);
1919 }
1920
1921 case 'M':
1922 {
1923 if (input_format != input_format_t::bjdata)
1924 {
1925 break;
1926 }
1927 std::uint64_t len{};
1928 return get_number(input_format, len) && get_string(input_format, len, result);
1929 }
1930
1931 default:
1932 break;
1933 }
1934 auto last_token = get_token_string();
1935 std::string message;
1936
1937 if (input_format != input_format_t::bjdata)
1938 {
1939 message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token;
1940 }
1941 else
1942 {
1943 message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token;
1944 }
1945 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "string"), nullptr));
1946 }
1947
1948 /*!
1949 @param[out] dim an integer vector storing the ND array dimensions
1950 @return whether reading ND array size vector is successful
1951 */
1952 bool get_ubjson_ndarray_size(std::vector<size_t>& dim)
1953 {
1954 std::pair<std::size_t, char_int_type> size_and_type;
1955 size_t dimlen = 0;
1956 bool no_ndarray = true;
1957
1958 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type, no_ndarray)))
1959 {
1960 return false;
1961 }
1962
1963 if (size_and_type.first != npos)
1964 {
1965 if (size_and_type.second != 0)
1966 {
1967 if (size_and_type.second != 'N')
1968 {
1969 for (std::size_t i = 0; i < size_and_type.first; ++i)
1970 {
1971 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, size_and_type.second)))
1972 {
1973 return false;
1974 }
1975 dim.push_back(dimlen);
1976 }
1977 }
1978 }
1979 else
1980 {
1981 for (std::size_t i = 0; i < size_and_type.first; ++i)
1982 {
1983 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray)))
1984 {
1985 return false;
1986 }
1987 dim.push_back(dimlen);
1988 }
1989 }
1990 }
1991 else
1992 {
1993 while (current != ']')
1994 {
1995 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, current)))
1996 {
1997 return false;
1998 }
1999 dim.push_back(dimlen);
2000 get_ignore_noop();
2001 }
2002 }
2003 return true;
2004 }
2005
2006 /*!
2007 @param[out] result determined size
2008 @param[in,out] is_ndarray for input, `true` means already inside an ndarray vector
2009 or ndarray dimension is not allowed; `false` means ndarray
2010 is allowed; for output, `true` means an ndarray is found;
2011 is_ndarray can only return `true` when its initial value
2012 is `false`
2013 @param[in] prefix type marker if already read, otherwise set to 0
2014
2015 @return whether size determination completed
2016 */
2017 bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0)
2018 {
2019 if (prefix == 0)
2020 {
2021 prefix = get_ignore_noop();
2022 }
2023
2024 switch (prefix)
2025 {
2026 case 'U':
2027 {
2028 std::uint8_t number{};
2029 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
2030 {
2031 return false;
2032 }
2033 result = static_cast<std::size_t>(number);
2034 return true;
2035 }
2036
2037 case 'i':
2038 {
2039 std::int8_t number{};
2040 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
2041 {
2042 return false;
2043 }
2044 if (number < 0)
2045 {
2046 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
2047 exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
2048 }
2049 result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char
2050 return true;
2051 }
2052
2053 case 'I':
2054 {
2055 std::int16_t number{};
2056 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
2057 {
2058 return false;
2059 }
2060 if (number < 0)
2061 {
2062 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
2063 exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
2064 }
2065 result = static_cast<std::size_t>(number);
2066 return true;
2067 }
2068
2069 case 'l':
2070 {
2071 std::int32_t number{};
2072 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
2073 {
2074 return false;
2075 }
2076 if (number < 0)
2077 {
2078 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
2079 exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
2080 }
2081 result = static_cast<std::size_t>(number);
2082 return true;
2083 }
2084
2085 case 'L':
2086 {
2087 std::int64_t number{};
2088 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
2089 {
2090 return false;
2091 }
2092 if (number < 0)
2093 {
2094 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
2095 exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
2096 }
2097 if (!value_in_range_of<std::size_t>(number))
2098 {
2099 return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,
2100 exception_message(input_format, "integer value overflow", "size"), nullptr));
2101 }
2102 result = static_cast<std::size_t>(number);
2103 return true;
2104 }
2105
2106 case 'u':
2107 {
2108 if (input_format != input_format_t::bjdata)
2109 {
2110 break;
2111 }
2112 std::uint16_t number{};
2113 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
2114 {
2115 return false;
2116 }
2117 result = static_cast<std::size_t>(number);
2118 return true;
2119 }
2120
2121 case 'm':
2122 {
2123 if (input_format != input_format_t::bjdata)
2124 {
2125 break;
2126 }
2127 std::uint32_t number{};
2128 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
2129 {
2130 return false;
2131 }
2132 result = conditional_static_cast<std::size_t>(number);
2133 return true;
2134 }
2135
2136 case 'M':
2137 {
2138 if (input_format != input_format_t::bjdata)
2139 {
2140 break;
2141 }
2142 std::uint64_t number{};
2143 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
2144 {
2145 return false;
2146 }
2147 if (!value_in_range_of<std::size_t>(number))
2148 {
2149 return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,
2150 exception_message(input_format, "integer value overflow", "size"), nullptr));
2151 }
2152 result = detail::conditional_static_cast<std::size_t>(number);
2153 return true;
2154 }
2155
2156 case '[':
2157 {
2158 if (input_format != input_format_t::bjdata)
2159 {
2160 break;
2161 }
2162 if (is_ndarray) // ndarray dimensional vector can only contain integers and cannot embed another array
2163 {
2164 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimensional vector is not allowed", "size"), nullptr));
2165 }
2166 std::vector<size_t> dim;
2167 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim)))
2168 {
2169 return false;
2170 }
2171 if (dim.size() == 1 || (dim.size() == 2 && dim.at(0) == 1)) // return normal array size if 1D row vector
2172 {
2173 result = dim.at(dim.size() - 1);
2174 return true;
2175 }
2176 if (!dim.empty()) // if ndarray, convert to an object in JData annotated array format
2177 {
2178 for (auto i : dim) // test if any dimension in an ndarray is 0, if so, return a 1D empty container
2179 {
2180 if ( i == 0 )
2181 {
2182 result = 0;
2183 return true;
2184 }
2185 }
2186
2187 string_t key = "_ArraySize_";
2188 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3) || !sax->key(key) || !sax->start_array(dim.size())))
2189 {
2190 return false;
2191 }
2192 result = 1;
2193 for (auto i : dim)
2194 {
2195 // Pre-multiplication overflow check: if i > 0 and result > SIZE_MAX/i, then result*i would overflow.
2196 // This check must happen before multiplication since overflow detection after the fact is unreliable
2197 // as modular arithmetic can produce any value, not just 0 or SIZE_MAX.
2198 if (JSON_HEDLEY_UNLIKELY(i > 0 && result > (std::numeric_limits<std::size_t>::max)() / i))
2199 {
2200 return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr));
2201 }
2202 result *= i;
2203 // Additional post-multiplication check to catch any edge cases the pre-check might miss
2204 if (result == 0 || result == npos)
2205 {
2206 return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr));
2207 }
2208 if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(static_cast<number_unsigned_t>(i))))
2209 {
2210 return false;
2211 }
2212 }
2213 is_ndarray = true;
2214 return sax->end_array();
2215 }
2216 result = 0;
2217 return true;
2218 }
2219
2220 default:
2221 break;
2222 }
2223 auto last_token = get_token_string();
2224 std::string message;
2225
2226 if (input_format != input_format_t::bjdata)
2227 {
2228 message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token;
2229 }
2230 else
2231 {
2232 message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token;
2233 }
2234 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "size"), nullptr));
2235 }
2236
2237 /*!
2238 @brief determine the type and size for a container
2239
2240 In the optimized UBJSON format, a type and a size can be provided to allow
2241 for a more compact representation.
2242
2243 @param[out] result pair of the size and the type
2244 @param[in] inside_ndarray whether the parser is parsing an ND array dimensional vector
2245
2246 @return whether pair creation completed
2247 */
2248 bool get_ubjson_size_type(std::pair<std::size_t, char_int_type>& result, bool inside_ndarray = false)
2249 {
2250 result.first = npos; // size
2251 result.second = 0; // type
2252 bool is_ndarray = false;
2253
2254 get_ignore_noop();
2255
2256 if (current == '$')
2257 {
2258 result.second = get(); // must not ignore 'N', because 'N' maybe the type
2259 if (input_format == input_format_t::bjdata
2260 && JSON_HEDLEY_UNLIKELY(std::binary_search(bjd_optimized_type_markers.begin(), bjd_optimized_type_markers.end(), result.second)))
2261 {
2262 auto last_token = get_token_string();
2263 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
2264 exception_message(input_format, concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr));
2265 }
2266
2267 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "type")))
2268 {
2269 return false;
2270 }
2271
2272 get_ignore_noop();
2273 if (JSON_HEDLEY_UNLIKELY(current != '#'))
2274 {
2275 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
2276 {
2277 return false;
2278 }
2279 auto last_token = get_token_string();
2280 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
2281 exception_message(input_format, concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr));
2282 }
2283
2284 const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
2285 if (input_format == input_format_t::bjdata && is_ndarray)
2286 {
2287 if (inside_ndarray)
2288 {
2289 return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
2290 exception_message(input_format, "ndarray can not be recursive", "size"), nullptr));
2291 }
2292 result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters
2293 }
2294 return is_error;
2295 }
2296
2297 if (current == '#')
2298 {
2299 const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
2300 if (input_format == input_format_t::bjdata && is_ndarray)
2301 {
2302 return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
2303 exception_message(input_format, "ndarray requires both type and size", "size"), nullptr));
2304 }
2305 return is_error;
2306 }
2307
2308 return true;
2309 }
2310
2311 /*!
2312 @param prefix the previously read or set type prefix
2313 @return whether value creation completed
2314 */
2315 bool get_ubjson_value(const char_int_type prefix)
2316 {
2317 switch (prefix)
2318 {
2319 case char_traits<char_type>::eof(): // EOF
2320 return unexpect_eof(input_format, "value");
2321
2322 case 'T': // true
2323 return sax->boolean(true);
2324 case 'F': // false
2325 return sax->boolean(false);
2326
2327 case 'Z': // null
2328 return sax->null();
2329
2330 case 'B': // byte
2331 {
2332 if (input_format != input_format_t::bjdata)
2333 {
2334 break;
2335 }
2336 std::uint8_t number{};
2337 return get_number(input_format, number) && sax->number_unsigned(number);
2338 }
2339
2340 case 'U':
2341 {
2342 std::uint8_t number{};
2343 return get_number(input_format, number) && sax->number_unsigned(number);
2344 }
2345
2346 case 'i':
2347 {
2348 std::int8_t number{};
2349 return get_number(input_format, number) && sax->number_integer(number);
2350 }
2351
2352 case 'I':
2353 {
2354 std::int16_t number{};
2355 return get_number(input_format, number) && sax->number_integer(number);
2356 }
2357
2358 case 'l':
2359 {
2360 std::int32_t number{};
2361 return get_number(input_format, number) && sax->number_integer(number);
2362 }
2363
2364 case 'L':
2365 {
2366 std::int64_t number{};
2367 return get_number(input_format, number) && sax->number_integer(number);
2368 }
2369
2370 case 'u':
2371 {
2372 if (input_format != input_format_t::bjdata)
2373 {
2374 break;
2375 }
2376 std::uint16_t number{};
2377 return get_number(input_format, number) && sax->number_unsigned(number);
2378 }
2379
2380 case 'm':
2381 {
2382 if (input_format != input_format_t::bjdata)
2383 {
2384 break;
2385 }
2386 std::uint32_t number{};
2387 return get_number(input_format, number) && sax->number_unsigned(number);
2388 }
2389
2390 case 'M':
2391 {
2392 if (input_format != input_format_t::bjdata)
2393 {
2394 break;
2395 }
2396 std::uint64_t number{};
2397 return get_number(input_format, number) && sax->number_unsigned(number);
2398 }
2399
2400 case 'h':
2401 {
2402 if (input_format != input_format_t::bjdata)
2403 {
2404 break;
2405 }
2406 const auto byte1_raw = get();
2407 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
2408 {
2409 return false;
2410 }
2411 const auto byte2_raw = get();
2412 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
2413 {
2414 return false;
2415 }
2416
2417 const auto byte1 = static_cast<unsigned char>(byte1_raw);
2418 const auto byte2 = static_cast<unsigned char>(byte2_raw);
2419
2420 // Code from RFC 7049, Appendix D, Figure 3:
2421 // As half-precision floating-point numbers were only added
2422 // to IEEE 754 in 2008, today's programming platforms often
2423 // still only have limited support for them. It is very
2424 // easy to include at least decoding support for them even
2425 // without such support. An example of a small decoder for
2426 // half-precision floating-point numbers in the C language
2427 // is shown in Fig. 3.
2428 const auto half = static_cast<unsigned int>((byte2 << 8u) + byte1);
2429 const double val = [&half]
2430 {
2431 const int exp = (half >> 10u) & 0x1Fu;
2432 const unsigned int mant = half & 0x3FFu;
2433 JSON_ASSERT(0 <= exp&& exp <= 32);
2434 JSON_ASSERT(mant <= 1024);
2435 switch (exp)
2436 {
2437 case 0:
2438 return std::ldexp(mant, -24);
2439 case 31:
2440 return (mant == 0)
2441 ? std::numeric_limits<double>::infinity()
2442 : std::numeric_limits<double>::quiet_NaN();
2443 default:
2444 return std::ldexp(mant + 1024, exp - 25);
2445 }
2446 }();
2447 return sax->number_float((half & 0x8000u) != 0
2448 ? static_cast<number_float_t>(-val)
2449 : static_cast<number_float_t>(val), "");
2450 }
2451
2452 case 'd':
2453 {
2454 float number{};
2455 return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), "");
2456 }
2457
2458 case 'D':
2459 {
2460 double number{};
2461 return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), "");
2462 }
2463
2464 case 'H':
2465 {
2466 return get_ubjson_high_precision_number();
2467 }
2468
2469 case 'C': // char
2470 {
2471 get();
2472 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "char")))
2473 {
2474 return false;
2475 }
2476 if (JSON_HEDLEY_UNLIKELY(current > 127))
2477 {
2478 auto last_token = get_token_string();
2479 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
2480 exception_message(input_format, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr));
2481 }
2482 string_t s(1, static_cast<typename string_t::value_type>(current));
2483 return sax->string(s);
2484 }
2485
2486 case 'S': // string
2487 {
2488 string_t s;
2489 return get_ubjson_string(s) && sax->string(s);
2490 }
2491
2492 case '[': // array
2493 return get_ubjson_array();
2494
2495 case '{': // object
2496 return get_ubjson_object();
2497
2498 default: // anything else
2499 break;
2500 }
2501 auto last_token = get_token_string();
2502 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format, "invalid byte: 0x" + last_token, "value"), nullptr));
2503 }
2504
2505 /*!
2506 @return whether array creation completed
2507 */
2508 bool get_ubjson_array()
2509 {
2510 std::pair<std::size_t, char_int_type> size_and_type;
2511 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))
2512 {
2513 return false;
2514 }
2515
2516 // if bit-8 of size_and_type.second is set to 1, encode bjdata ndarray as an object in JData annotated array format (https://github.com/NeuroJSON/jdata):
2517 // {"_ArrayType_" : "typeid", "_ArraySize_" : [n1, n2, ...], "_ArrayData_" : [v1, v2, ...]}
2518
2519 if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
2520 {
2521 size_and_type.second &= ~(static_cast<char_int_type>(1) << 8); // use bit 8 to indicate ndarray, here we remove the bit to restore the type marker
2522 auto it = std::lower_bound(bjd_types_map.begin(), bjd_types_map.end(), size_and_type.second, [](const bjd_type & p, char_int_type t)
2523 {
2524 return p.first < t;
2525 });
2526 string_t key = "_ArrayType_";
2527 if (JSON_HEDLEY_UNLIKELY(it == bjd_types_map.end() || it->first != size_and_type.second))
2528 {
2529 auto last_token = get_token_string();
2530 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
2531 exception_message(input_format, "invalid byte: 0x" + last_token, "type"), nullptr));
2532 }
2533
2534 string_t type = it->second; // sax->string() takes a reference
2535 if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type)))
2536 {
2537 return false;
2538 }
2539
2540 if (size_and_type.second == 'C' || size_and_type.second == 'B')
2541 {
2542 size_and_type.second = 'U';
2543 }
2544
2545 key = "_ArrayData_";
2546 if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(size_and_type.first) ))
2547 {
2548 return false;
2549 }
2550
2551 for (std::size_t i = 0; i < size_and_type.first; ++i)
2552 {
2553 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
2554 {
2555 return false;
2556 }
2557 }
2558
2559 return (sax->end_array() && sax->end_object());
2560 }
2561
2562 // If BJData type marker is 'B' decode as binary
2563 if (input_format == input_format_t::bjdata && size_and_type.first != npos && size_and_type.second == 'B')
2564 {
2565 binary_t result;
2566 return get_binary(input_format, size_and_type.first, result) && sax->binary(result);
2567 }
2568
2569 if (size_and_type.first != npos)
2570 {
2571 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first)))
2572 {
2573 return false;
2574 }
2575
2576 if (size_and_type.second != 0)
2577 {
2578 if (size_and_type.second != 'N')
2579 {
2580 for (std::size_t i = 0; i < size_and_type.first; ++i)
2581 {
2582 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
2583 {
2584 return false;
2585 }
2586 }
2587 }
2588 }
2589 else
2590 {
2591 for (std::size_t i = 0; i < size_and_type.first; ++i)
2592 {
2593 if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
2594 {
2595 return false;
2596 }
2597 }
2598 }
2599 }
2600 else
2601 {
2602 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size())))
2603 {
2604 return false;
2605 }
2606
2607 while (current != ']')
2608 {
2609 if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false)))
2610 {
2611 return false;
2612 }
2613 get_ignore_noop();
2614 }
2615 }
2616
2617 return sax->end_array();
2618 }
2619
2620 /*!
2621 @return whether object creation completed
2622 */
2623 bool get_ubjson_object()
2624 {
2625 std::pair<std::size_t, char_int_type> size_and_type;
2626 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))
2627 {
2628 return false;
2629 }
2630
2631 // do not accept ND-array size in objects in BJData
2632 if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
2633 {
2634 auto last_token = get_token_string();
2635 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
2636 exception_message(input_format, "BJData object does not support ND-array size in optimized format", "object"), nullptr));
2637 }
2638
2639 string_t key;
2640 if (size_and_type.first != npos)
2641 {
2642 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first)))
2643 {
2644 return false;
2645 }
2646
2647 if (size_and_type.second != 0)
2648 {
2649 for (std::size_t i = 0; i < size_and_type.first; ++i)
2650 {
2651 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))
2652 {
2653 return false;
2654 }
2655 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
2656 {
2657 return false;
2658 }
2659 key.clear();
2660 }
2661 }
2662 else
2663 {
2664 for (std::size_t i = 0; i < size_and_type.first; ++i)
2665 {
2666 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))
2667 {
2668 return false;
2669 }
2670 if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
2671 {
2672 return false;
2673 }
2674 key.clear();
2675 }
2676 }
2677 }
2678 else
2679 {
2680 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size())))
2681 {
2682 return false;
2683 }
2684
2685 while (current != '}')
2686 {
2687 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key)))
2688 {
2689 return false;
2690 }
2691 if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
2692 {
2693 return false;
2694 }
2695 get_ignore_noop();
2696 key.clear();
2697 }
2698 }
2699
2700 return sax->end_object();
2701 }
2702
2703 // Note, no reader for UBJSON binary types is implemented because they do
2704 // not exist
2705
2706 bool get_ubjson_high_precision_number()
2707 {
2708 // get the size of the following number string
2709 std::size_t size{};
2710 bool no_ndarray = true;
2711 auto res = get_ubjson_size_value(size, no_ndarray);
2712 if (JSON_HEDLEY_UNLIKELY(!res))
2713 {
2714 return res;
2715 }
2716
2717 // get number string
2718 std::vector<char> number_vector;
2719 for (std::size_t i = 0; i < size; ++i)
2720 {
2721 get();
2722 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
2723 {
2724 return false;
2725 }
2726 number_vector.push_back(static_cast<char>(current));
2727 }
2728
2729 // parse number string
2730 using ia_type = decltype(detail::input_adapter(number_vector));
2731 auto number_lexer = detail::lexer<BasicJsonType, ia_type>(detail::input_adapter(number_vector), false);
2732 const auto result_number = number_lexer.scan();
2733 const auto number_string = number_lexer.get_token_string();
2734 const auto result_remainder = number_lexer.scan();
2735
2736 using token_type = typename detail::lexer_base<BasicJsonType>::token_type;
2737
2738 if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input))
2739 {
2740 return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read,
2741 exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr));
2742 }
2743
2744 switch (result_number)
2745 {
2746 case token_type::value_integer:
2747 return sax->number_integer(number_lexer.get_number_integer());
2748 case token_type::value_unsigned:
2749 return sax->number_unsigned(number_lexer.get_number_unsigned());
2750 case token_type::value_float:
2751 return sax->number_float(number_lexer.get_number_float(), std::move(number_string));
2752 case token_type::uninitialized:
2753 case token_type::literal_true:
2754 case token_type::literal_false:
2755 case token_type::literal_null:
2756 case token_type::value_string:
2757 case token_type::begin_array:
2758 case token_type::begin_object:
2759 case token_type::end_array:
2760 case token_type::end_object:
2761 case token_type::name_separator:
2762 case token_type::value_separator:
2763 case token_type::parse_error:
2764 case token_type::end_of_input:
2765 case token_type::literal_or_value:
2766 default:
2767 return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read,
2768 exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr));
2769 }
2770 }
2771
2772 ///////////////////////
2773 // Utility functions //
2774 ///////////////////////
2775
2776 /*!
2777 @brief get next character from the input
2778
2779 This function provides the interface to the used input adapter. It does
2780 not throw in case the input reached EOF, but returns a -'ve valued
2781 `char_traits<char_type>::eof()` in that case.
2782
2783 @return character read from the input
2784 */
2785 char_int_type get()
2786 {
2787 ++chars_read;
2788 return current = ia.get_character();
2789 }
2790
2791 /*!
2792 @brief get_to read into a primitive type
2793
2794 This function provides the interface to the used input adapter. It does
2795 not throw in case the input reached EOF, but returns false instead
2796
2797 @return bool, whether the read was successful
2798 */
2799 template<class T>
2800 bool get_to(T& dest, const input_format_t format, const char* context)
2801 {
2802 auto new_chars_read = ia.get_elements(&dest);
2803 chars_read += new_chars_read;
2804 if (JSON_HEDLEY_UNLIKELY(new_chars_read < sizeof(T)))
2805 {
2806 // in case of failure, advance position by 1 to report the failing location
2807 ++chars_read;
2808 sax->parse_error(chars_read, "<end of file>", parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr));
2809 return false;
2810 }
2811 return true;
2812 }
2813
2814 /*!
2815 @return character read from the input after ignoring all 'N' entries
2816 */
2817 char_int_type get_ignore_noop()
2818 {
2819 do
2820 {
2821 get();
2822 }
2823 while (current == 'N');
2824
2825 return current;
2826 }
2827
2828 template<class NumberType>
2829 static void byte_swap(NumberType& number)
2830 {
2831 constexpr std::size_t sz = sizeof(number);
2832#ifdef __cpp_lib_byteswap
2833 if constexpr (sz == 1)
2834 {
2835 return;
2836 }
2837 else if constexpr(std::is_integral_v<NumberType>)
2838 {
2839 number = std::byteswap(number);
2840 return;
2841 }
2842 else
2843 {
2844#endif
2845 auto* ptr = reinterpret_cast<std::uint8_t*>(&number);
2846 for (std::size_t i = 0; i < sz / 2; ++i)
2847 {
2848 std::swap(ptr[i], ptr[sz - i - 1]);
2849 }
2850#ifdef __cpp_lib_byteswap
2851 }
2852#endif
2853 }
2854
2855 /*
2856 @brief read a number from the input
2857
2858 @tparam NumberType the type of the number
2859 @param[in] format the current format (for diagnostics)
2860 @param[out] result number of type @a NumberType
2861
2862 @return whether conversion completed
2863
2864 @note This function needs to respect the system's endianness, because
2865 bytes in CBOR, MessagePack, and UBJSON are stored in network order
2866 (big endian) and therefore need reordering on little endian systems.
2867 On the other hand, BSON and BJData use little endian and should reorder
2868 on big endian systems.
2869 */
2870 template<typename NumberType, bool InputIsLittleEndian = false>
2871 bool get_number(const input_format_t format, NumberType& result)
2872 {
2873 // read in the original format
2874
2875 if (JSON_HEDLEY_UNLIKELY(!get_to(result, format, "number")))
2876 {
2877 return false;
2878 }
2879 if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata))
2880 {
2881 byte_swap(result);
2882 }
2883 return true;
2884 }
2885
2886 /*!
2887 @brief create a string by reading characters from the input
2888
2889 @tparam NumberType the type of the number
2890 @param[in] format the current format (for diagnostics)
2891 @param[in] len number of characters to read
2892 @param[out] result string created by reading @a len bytes
2893
2894 @return whether string creation completed
2895
2896 @note We can not reserve @a len bytes for the result, because @a len
2897 may be too large. Usually, @ref unexpect_eof() detects the end of
2898 the input before we run out of string memory.
2899 */
2900 template<typename NumberType>
2901 bool get_string(const input_format_t format,
2902 const NumberType len,
2903 string_t& result)
2904 {
2905 bool success = true;
2906 for (NumberType i = 0; i < len; i++)
2907 {
2908 get();
2909 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string")))
2910 {
2911 success = false;
2912 break;
2913 }
2914 result.push_back(static_cast<typename string_t::value_type>(current));
2915 }
2916 return success;
2917 }
2918
2919 /*!
2920 @brief create a byte array by reading bytes from the input
2921
2922 @tparam NumberType the type of the number
2923 @param[in] format the current format (for diagnostics)
2924 @param[in] len number of bytes to read
2925 @param[out] result byte array created by reading @a len bytes
2926
2927 @return whether byte array creation completed
2928
2929 @note We can not reserve @a len bytes for the result, because @a len
2930 may be too large. Usually, @ref unexpect_eof() detects the end of
2931 the input before we run out of memory.
2932 */
2933 template<typename NumberType>
2934 bool get_binary(const input_format_t format,
2935 const NumberType len,
2936 binary_t& result)
2937 {
2938 bool success = true;
2939 for (NumberType i = 0; i < len; i++)
2940 {
2941 get();
2942 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary")))
2943 {
2944 success = false;
2945 break;
2946 }
2947 result.push_back(static_cast<typename binary_t::value_type>(current));
2948 }
2949 return success;
2950 }
2951
2952 /*!
2953 @param[in] format the current format (for diagnostics)
2954 @param[in] context further context information (for diagnostics)
2955 @return whether the last read character is not EOF
2956 */
2957 JSON_HEDLEY_NON_NULL(3)
2958 bool unexpect_eof(const input_format_t format, const char* context) const
2959 {
2960 if (JSON_HEDLEY_UNLIKELY(current == char_traits<char_type>::eof()))
2961 {
2962 return sax->parse_error(chars_read, "<end of file>",
2963 parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr));
2964 }
2965 return true;
2966 }
2967
2968 /*!
2969 @return a string representation of the last read byte
2970 */
2971 std::string get_token_string() const
2972 {
2973 std::array<char, 3> cr{{}};
2974 static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
2975 return std::string{cr.data()};
2976 }
2977
2978 /*!
2979 @param[in] format the current format
2980 @param[in] detail a detailed error message
2981 @param[in] context further context information
2982 @return a message string to use in the parse_error exceptions
2983 */
2984 std::string exception_message(const input_format_t format,
2985 const std::string& detail,
2986 const std::string& context) const
2987 {
2988 std::string error_msg = "syntax error while parsing ";
2989
2990 switch (format)
2991 {
2992 case input_format_t::cbor:
2993 error_msg += "CBOR";
2994 break;
2995
2996 case input_format_t::msgpack:
2997 error_msg += "MessagePack";
2998 break;
2999
3000 case input_format_t::ubjson:
3001 error_msg += "UBJSON";
3002 break;
3003
3004 case input_format_t::bson:
3005 error_msg += "BSON";
3006 break;
3007
3008 case input_format_t::bjdata:
3009 error_msg += "BJData";
3010 break;
3011
3012 case input_format_t::json: // LCOV_EXCL_LINE
3013 default: // LCOV_EXCL_LINE
3014 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
3015 }
3016
3017 return concat(error_msg, ' ', context, ": ", detail);
3018 }
3019
3020 private:
3021 static JSON_INLINE_VARIABLE constexpr std::size_t npos = detail::unknown_size();
3022
3023 /// input adapter
3024 InputAdapterType ia;
3025
3026 /// the current character
3027 char_int_type current = char_traits<char_type>::eof();
3028
3029 /// the number of characters read
3030 std::size_t chars_read = 0;
3031
3032 /// whether we can assume little endianness
3033 const bool is_little_endian = little_endianness();
3034
3035 /// input format
3036 const input_format_t input_format = input_format_t::json;
3037
3038 /// the SAX parser
3039 json_sax_t* sax = nullptr;
3040
3041 // excluded markers in bjdata optimized type
3042#define JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ \
3043 make_array<char_int_type>('F', 'H', 'N', 'S', 'T', 'Z', '[', '{')
3044
3045#define JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ \
3046 make_array<bjd_type>( \
3047 bjd_type{'B', "byte"}, \
3048 bjd_type{'C', "char"}, \
3049 bjd_type{'D', "double"}, \
3050 bjd_type{'I', "int16"}, \
3051 bjd_type{'L', "int64"}, \
3052 bjd_type{'M', "uint64"}, \
3053 bjd_type{'U', "uint8"}, \
3054 bjd_type{'d', "single"}, \
3055 bjd_type{'i', "int8"}, \
3056 bjd_type{'l', "int32"}, \
3057 bjd_type{'m', "uint32"}, \
3058 bjd_type{'u', "uint16"})
3059
3060 JSON_PRIVATE_UNLESS_TESTED:
3061 // lookup tables
3062 // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
3063 const decltype(JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_) bjd_optimized_type_markers =
3064 JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_;
3065
3066 using bjd_type = std::pair<char_int_type, string_t>;
3067 // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
3068 const decltype(JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_) bjd_types_map =
3069 JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_;
3070
3071#undef JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_
3072#undef JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_
3073};
3074
3075#ifndef JSON_HAS_CPP_17
3076 template<typename BasicJsonType, typename InputAdapterType, typename SAX>
3077 constexpr std::size_t binary_reader<BasicJsonType, InputAdapterType, SAX>::npos;
3078#endif
3079
3080} // namespace detail
3081NLOHMANN_JSON_NAMESPACE_END
deserialization of CBOR, MessagePack, and UBJSON values
定义 binary_reader.hpp:70
bool sax_parse(const input_format_t format, json_sax_t *sax_, const bool strict=true, const cbor_tag_handler_t tag_handler=cbor_tag_handler_t::error)
定义 binary_reader.hpp:107
binary_reader(InputAdapterType &&adapter, const input_format_t format=input_format_t::json) noexcept
create a binary reader
定义 binary_reader.hpp:86
token_type
token types for the parser
定义 lexer.hpp:40
static parse_error create(int id_, const position_t &pos, const std::string &what_arg, BasicJsonContext context)
create a parse error exception
定义 exceptions.hpp:179
detail namespace with internal helper functions
定义 from_json.hpp:43
bool little_endianness(int num=1) noexcept
determine system byte order
定义 binary_reader.hpp:56
cbor_tag_handler_t
how to treat CBOR tags
定义 binary_reader.hpp:43
@ ignore
ignore tags
定义 binary_reader.hpp:45
@ store
store tags as binary type
定义 binary_reader.hpp:46
@ error
throw a parse_error exception in case of a tag
定义 binary_reader.hpp:44
@ key
the parser read a key of a value in an object
定义 parser.hpp:45
@ strict
throw a type_error exception in case of invalid UTF-8
定义 serializer.hpp:45
input_format_t
the supported input formats
定义 input_adapters.hpp:37
定义 type_traits.hpp:194
定义 is_sax.hpp:106