diff --git a/src/json.hpp b/src/json.hpp
index 7ecbe91d..d3f35710 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -4564,6 +4564,1820 @@ class json_reverse_iterator : public std::reverse_iterator
return it.operator * ();
}
};
+
+/////////////////////
+// output adapters //
+/////////////////////
+
+/// abstract output adapter interface
+template class output_adapter
+{
+ public:
+ virtual void write_character(CharType c) = 0;
+ virtual void write_characters(const CharType* s, size_t length) = 0;
+ virtual ~output_adapter() {}
+};
+
+/// a type to simplify interfaces
+template
+using output_adapter_t = std::shared_ptr>;
+
+/// output adapter for byte vectors
+template
+class output_vector_adapter : public output_adapter
+{
+ public:
+ output_vector_adapter(std::vector& vec) : v(vec) {}
+
+ void write_character(CharType c) override
+ {
+ v.push_back(c);
+ }
+
+ void write_characters(const CharType* s, size_t length) override
+ {
+ std::copy(s, s + length, std::back_inserter(v));
+ }
+
+ private:
+ std::vector& v;
+};
+
+/// output adapter for output streams
+template
+class output_stream_adapter : public output_adapter
+{
+ public:
+ output_stream_adapter(std::basic_ostream& s) : stream(s) {}
+
+ void write_character(CharType c) override
+ {
+ stream.put(c);
+ }
+
+ void write_characters(const CharType* s, size_t length) override
+ {
+ stream.write(s, static_cast(length));
+ }
+
+ private:
+ std::basic_ostream& stream;
+};
+
+/// output adapter for basic_string
+template
+class output_string_adapter : public output_adapter
+{
+ public:
+ output_string_adapter(std::string& s) : str(s) {}
+
+ void write_character(CharType c) override
+ {
+ str.push_back(c);
+ }
+
+ void write_characters(const CharType* s, size_t length) override
+ {
+ str.append(s, length);
+ }
+
+ private:
+ std::basic_string& str;
+};
+
+template struct output_adapter_factory
+{
+ static std::shared_ptr>
+ create(std::vector& vec)
+ {
+ return std::make_shared>(vec);
+ }
+
+ static std::shared_ptr> create(std::ostream& s)
+ {
+ return std::make_shared>(s);
+ }
+
+ static std::shared_ptr> create(std::string& s)
+ {
+ return std::make_shared>(s);
+ }
+};
+
+//////////////////////////////
+// binary reader and writer //
+//////////////////////////////
+
+/*!
+@brief deserialization of CBOR and MessagePack values
+*/
+template
+class binary_reader
+{
+ using number_integer_t = typename BasicJsonType::number_integer_t;
+ using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
+
+ public:
+ /*!
+ @brief create a binary reader
+
+ @param[in] adapter input adapter to read from
+ */
+ explicit binary_reader(input_adapter_t adapter)
+ : ia(adapter), is_little_endian(little_endianess())
+ {
+ assert(ia);
+ }
+
+ /*!
+ @brief create a JSON value from CBOR input
+
+ @param[in] get_char whether a new character should be retrieved from
+ the input (true, default) or whether the last
+ read character should be considered instead
+
+ @return JSON value created from CBOR input
+
+ @throw parse_error.110 if input ended unexpectedly
+ @throw parse_error.112 if unsupported byte was read
+ */
+ BasicJsonType parse_cbor(const bool get_char = true)
+ {
+ switch (get_char ? get() : current)
+ {
+ // EOF
+ case std::char_traits::eof():
+ {
+ JSON_THROW(
+ parse_error::create(110, chars_read, "unexpected end of input"));
+ }
+
+ // Integer 0x00..0x17 (0..23)
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ {
+ return static_cast(current);
+ }
+
+ case 0x18: // Unsigned integer (one-byte uint8_t follows)
+ {
+ return get_number();
+ }
+
+ case 0x19: // Unsigned integer (two-byte uint16_t follows)
+ {
+ return get_number();
+ }
+
+ case 0x1a: // Unsigned integer (four-byte uint32_t follows)
+ {
+ return get_number();
+ }
+
+ case 0x1b: // Unsigned integer (eight-byte uint64_t follows)
+ {
+ return get_number();
+ }
+
+ // Negative integer -1-0x00..-1-0x17 (-1..-24)
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f:
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ {
+ return static_cast(0x20 - 1 - current);
+ }
+
+ case 0x38: // Negative integer (one-byte uint8_t follows)
+ {
+ // must be uint8_t !
+ return static_cast(-1) - get_number();
+ }
+
+ case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
+ {
+ return static_cast(-1) - get_number();
+ }
+
+ case 0x3a: // Negative integer -1-n (four-byte uint32_t follows)
+ {
+ return static_cast(-1) - get_number();
+ }
+
+ case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows)
+ {
+ return static_cast(-1) -
+ static_cast(get_number());
+ }
+
+ // UTF-8 string (0x00..0x17 bytes follow)
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67:
+ case 0x68:
+ case 0x69:
+ case 0x6a:
+ case 0x6b:
+ case 0x6c:
+ case 0x6d:
+ case 0x6e:
+ case 0x6f:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77:
+ case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
+ case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
+ case 0x7a: // UTF-8 string (four-byte uint32_t for n follow)
+ case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow)
+ case 0x7f: // UTF-8 string (indefinite length)
+ {
+ return get_cbor_string();
+ }
+
+ // array (0x00..0x17 data items follow)
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0x8f:
+ case 0x90:
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ {
+ BasicJsonType result = value_t::array;
+ const auto len = static_cast(current & 0x1f);
+ for (size_t i = 0; i < len; ++i)
+ {
+ result.push_back(parse_cbor());
+ }
+ return result;
+ }
+
+ case 0x98: // array (one-byte uint8_t for n follows)
+ {
+ BasicJsonType result = value_t::array;
+ const auto len = static_cast(get_number());
+ for (size_t i = 0; i < len; ++i)
+ {
+ result.push_back(parse_cbor());
+ }
+ return result;
+ }
+
+ case 0x99: // array (two-byte uint16_t for n follow)
+ {
+ BasicJsonType result = value_t::array;
+ const auto len = static_cast(get_number());
+ for (size_t i = 0; i < len; ++i)
+ {
+ result.push_back(parse_cbor());
+ }
+ return result;
+ }
+
+ case 0x9a: // array (four-byte uint32_t for n follow)
+ {
+ BasicJsonType result = value_t::array;
+ const auto len = static_cast(get_number());
+ for (size_t i = 0; i < len; ++i)
+ {
+ result.push_back(parse_cbor());
+ }
+ return result;
+ }
+
+ case 0x9b: // array (eight-byte uint64_t for n follow)
+ {
+ BasicJsonType result = value_t::array;
+ const auto len = static_cast(get_number());
+ for (size_t i = 0; i < len; ++i)
+ {
+ result.push_back(parse_cbor());
+ }
+ return result;
+ }
+
+ case 0x9f: // array (indefinite length)
+ {
+ BasicJsonType result = value_t::array;
+ while (get() != 0xff)
+ {
+ result.push_back(parse_cbor(false));
+ }
+ return result;
+ }
+
+ // map (0x00..0x17 pairs of data items follow)
+ case 0xa0:
+ case 0xa1:
+ case 0xa2:
+ case 0xa3:
+ case 0xa4:
+ case 0xa5:
+ case 0xa6:
+ case 0xa7:
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf:
+ case 0xb0:
+ case 0xb1:
+ case 0xb2:
+ case 0xb3:
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ {
+ BasicJsonType result = value_t::object;
+ const auto len = static_cast(current & 0x1f);
+ for (size_t i = 0; i < len; ++i)
+ {
+ get();
+ auto key = get_cbor_string();
+ result[key] = parse_cbor();
+ }
+ return result;
+ }
+
+ case 0xb8: // map (one-byte uint8_t for n follows)
+ {
+ BasicJsonType result = value_t::object;
+ const auto len = static_cast(get_number());
+ for (size_t i = 0; i < len; ++i)
+ {
+ get();
+ auto key = get_cbor_string();
+ result[key] = parse_cbor();
+ }
+ return result;
+ }
+
+ case 0xb9: // map (two-byte uint16_t for n follow)
+ {
+ BasicJsonType result = value_t::object;
+ const auto len = static_cast(get_number());
+ for (size_t i = 0; i < len; ++i)
+ {
+ get();
+ auto key = get_cbor_string();
+ result[key] = parse_cbor();
+ }
+ return result;
+ }
+
+ case 0xba: // map (four-byte uint32_t for n follow)
+ {
+ BasicJsonType result = value_t::object;
+ const auto len = static_cast(get_number());
+ for (size_t i = 0; i < len; ++i)
+ {
+ get();
+ auto key = get_cbor_string();
+ result[key] = parse_cbor();
+ }
+ return result;
+ }
+
+ case 0xbb: // map (eight-byte uint64_t for n follow)
+ {
+ BasicJsonType result = value_t::object;
+ const auto len = static_cast(get_number());
+ for (size_t i = 0; i < len; ++i)
+ {
+ get();
+ auto key = get_cbor_string();
+ result[key] = parse_cbor();
+ }
+ return result;
+ }
+
+ case 0xbf: // map (indefinite length)
+ {
+ BasicJsonType result = value_t::object;
+ while (get() != 0xff)
+ {
+ auto key = get_cbor_string();
+ result[key] = parse_cbor();
+ }
+ return result;
+ }
+
+ case 0xf4: // false
+ {
+ return false;
+ }
+
+ case 0xf5: // true
+ {
+ return true;
+ }
+
+ case 0xf6: // null
+ {
+ return value_t::null;
+ }
+
+ case 0xf9: // Half-Precision Float (two-byte IEEE 754)
+ {
+ const int byte1 = get();
+ check_eof();
+ const int byte2 = get();
+ check_eof();
+
+ // code from RFC 7049, Appendix D, Figure 3:
+ // As half-precision floating-point numbers were only added
+ // to IEEE 754 in 2008, today's programming platforms often
+ // still only have limited support for them. It is very
+ // easy to include at least decoding support for them even
+ // without such support. An example of a small decoder for
+ // half-precision floating-point numbers in the C language
+ // is shown in Fig. 3.
+ const int half = (byte1 << 8) + byte2;
+ const int exp = (half >> 10) & 0x1f;
+ const int mant = half & 0x3ff;
+ double val;
+ if (exp == 0)
+ {
+ val = std::ldexp(mant, -24);
+ }
+ else if (exp != 31)
+ {
+ val = std::ldexp(mant + 1024, exp - 25);
+ }
+ else
+ {
+ val = (mant == 0) ? std::numeric_limits::infinity()
+ : std::numeric_limits::quiet_NaN();
+ }
+ return (half & 0x8000) != 0 ? -val : val;
+ }
+
+ case 0xfa: // Single-Precision Float (four-byte IEEE 754)
+ {
+ return get_number();
+ }
+
+ case 0xfb: // Double-Precision Float (eight-byte IEEE 754)
+ {
+ return get_number();
+ }
+
+ default: // anything else (0xFF is handled inside the other types)
+ {
+ std::stringstream ss;
+ ss << std::setw(2) << std::setfill('0') << std::hex << current;
+ JSON_THROW(parse_error::create(
+ 112, chars_read, "error reading CBOR; last byte: 0x" + ss.str()));
+ }
+ }
+ }
+
+ /*!
+ @brief create a JSON value from MessagePack input
+
+ @return JSON value created from MessagePack input
+
+ @throw parse_error.110 if input ended unexpectedly
+ @throw parse_error.112 if unsupported byte was read
+ */
+ BasicJsonType parse_msgpack()
+ {
+ switch (get())
+ {
+ // EOF
+ case std::char_traits::eof():
+ {
+ JSON_THROW(
+ parse_error::create(110, chars_read, "unexpected end of input"));
+ }
+
+ // positive fixint
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f:
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f:
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ case 0x48:
+ case 0x49:
+ case 0x4a:
+ case 0x4b:
+ case 0x4c:
+ case 0x4d:
+ case 0x4e:
+ case 0x4f:
+ case 0x50:
+ case 0x51:
+ case 0x52:
+ case 0x53:
+ case 0x54:
+ case 0x55:
+ case 0x56:
+ case 0x57:
+ case 0x58:
+ case 0x59:
+ case 0x5a:
+ case 0x5b:
+ case 0x5c:
+ case 0x5d:
+ case 0x5e:
+ case 0x5f:
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67:
+ case 0x68:
+ case 0x69:
+ case 0x6a:
+ case 0x6b:
+ case 0x6c:
+ case 0x6d:
+ case 0x6e:
+ case 0x6f:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77:
+ case 0x78:
+ case 0x79:
+ case 0x7a:
+ case 0x7b:
+ case 0x7c:
+ case 0x7d:
+ case 0x7e:
+ case 0x7f:
+ {
+ return static_cast(current);
+ }
+
+ // fixmap
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0x8f:
+ {
+ BasicJsonType result = value_t::object;
+ const auto len = static_cast(current & 0x0f);
+ for (size_t i = 0; i < len; ++i)
+ {
+ get();
+ auto key = get_msgpack_string();
+ result[key] = parse_msgpack();
+ }
+ return result;
+ }
+
+ // fixarray
+ case 0x90:
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ case 0x98:
+ case 0x99:
+ case 0x9a:
+ case 0x9b:
+ case 0x9c:
+ case 0x9d:
+ case 0x9e:
+ case 0x9f:
+ {
+ BasicJsonType result = value_t::array;
+ const auto len = static_cast(current & 0x0f);
+ for (size_t i = 0; i < len; ++i)
+ {
+ result.push_back(parse_msgpack());
+ }
+ return result;
+ }
+
+ // fixstr
+ case 0xa0:
+ case 0xa1:
+ case 0xa2:
+ case 0xa3:
+ case 0xa4:
+ case 0xa5:
+ case 0xa6:
+ case 0xa7:
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf:
+ case 0xb0:
+ case 0xb1:
+ case 0xb2:
+ case 0xb3:
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ case 0xb8:
+ case 0xb9:
+ case 0xba:
+ case 0xbb:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xbf:
+ {
+ return get_msgpack_string();
+ }
+
+ case 0xc0: // nil
+ {
+ return value_t::null;
+ }
+
+ case 0xc2: // false
+ {
+ return false;
+ }
+
+ case 0xc3: // true
+ {
+ return true;
+ }
+
+ case 0xca: // float 32
+ {
+ return get_number();
+ }
+
+ case 0xcb: // float 64
+ {
+ return get_number();
+ }
+
+ case 0xcc: // uint 8
+ {
+ return get_number();
+ }
+
+ case 0xcd: // uint 16
+ {
+ return get_number();
+ }
+
+ case 0xce: // uint 32
+ {
+ return get_number();
+ }
+
+ case 0xcf: // uint 64
+ {
+ return get_number();
+ }
+
+ case 0xd0: // int 8
+ {
+ return get_number();
+ }
+
+ case 0xd1: // int 16
+ {
+ return get_number();
+ }
+
+ case 0xd2: // int 32
+ {
+ return get_number();
+ }
+
+ case 0xd3: // int 64
+ {
+ return get_number();
+ }
+
+ case 0xd9: // str 8
+ case 0xda: // str 16
+ case 0xdb: // str 32
+ {
+ return get_msgpack_string();
+ }
+
+ case 0xdc: // array 16
+ {
+ BasicJsonType result = value_t::array;
+ const auto len = static_cast(get_number());
+ for (size_t i = 0; i < len; ++i)
+ {
+ result.push_back(parse_msgpack());
+ }
+ return result;
+ }
+
+ case 0xdd: // array 32
+ {
+ BasicJsonType result = value_t::array;
+ const auto len = static_cast(get_number());
+ for (size_t i = 0; i < len; ++i)
+ {
+ result.push_back(parse_msgpack());
+ }
+ return result;
+ }
+
+ case 0xde: // map 16
+ {
+ BasicJsonType result = value_t::object;
+ const auto len = static_cast(get_number());
+ for (size_t i = 0; i < len; ++i)
+ {
+ get();
+ auto key = get_msgpack_string();
+ result[key] = parse_msgpack();
+ }
+ return result;
+ }
+
+ case 0xdf: // map 32
+ {
+ BasicJsonType result = value_t::object;
+ const auto len = static_cast(get_number());
+ for (size_t i = 0; i < len; ++i)
+ {
+ get();
+ auto key = get_msgpack_string();
+ result[key] = parse_msgpack();
+ }
+ return result;
+ }
+
+ // positive fixint
+ case 0xe0:
+ case 0xe1:
+ case 0xe2:
+ case 0xe3:
+ case 0xe4:
+ case 0xe5:
+ case 0xe6:
+ case 0xe7:
+ case 0xe8:
+ case 0xe9:
+ case 0xea:
+ case 0xeb:
+ case 0xec:
+ case 0xed:
+ case 0xee:
+ case 0xef:
+ case 0xf0:
+ case 0xf1:
+ case 0xf2:
+ case 0xf3:
+ case 0xf4:
+ case 0xf5:
+ case 0xf6:
+ case 0xf7:
+ case 0xf8:
+ case 0xf9:
+ case 0xfa:
+ case 0xfb:
+ case 0xfc:
+ case 0xfd:
+ case 0xfe:
+ case 0xff:
+ {
+ return static_cast(current);
+ }
+
+ default: // anything else
+ {
+ std::stringstream ss;
+ ss << std::setw(2) << std::setfill('0') << std::hex << current;
+ JSON_THROW(parse_error::create(
+ 112, chars_read,
+ "error reading MessagePack; last byte: 0x" + ss.str()));
+ }
+ }
+ }
+
+ /*!
+ @brief determine system byte order
+
+ @return true iff system's byte order is little endian
+
+ @note from http://stackoverflow.com/a/1001328/266378
+ */
+ static bool little_endianess() noexcept
+ {
+ int num = 1;
+ return (*reinterpret_cast(&num) == 1);
+ }
+
+ private:
+ /*!
+ @brief get next character from the input
+
+ This function provides the interface to the used input adapter. It does
+ not throw in case the input reached EOF, but returns
+ `std::char_traits::eof()` in that case.
+
+ @return character read from the input
+ */
+ int get()
+ {
+ ++chars_read;
+ return (current = ia->get_character());
+ }
+
+ /*
+ @brief read a number from the input
+
+ @tparam NumberType the type of the number
+
+ @return number of type @a NumberType
+
+ @note This function needs to respect the system's endianess, because
+ bytes in CBOR and MessagePack are stored in network order (big
+ endian) and therefore need reordering on little endian systems.
+
+ @throw parse_error.110 if input has less than `sizeof(NumberType)`
+ bytes
+ */
+ template NumberType get_number()
+ {
+ // step 1: read input into array with system's byte order
+ std::array vec;
+ for (size_t i = 0; i < sizeof(NumberType); ++i)
+ {
+ get();
+ check_eof();
+
+ // reverse byte order prior to conversion if necessary
+ if (is_little_endian)
+ {
+ vec[sizeof(NumberType) - i - 1] = static_cast(current);
+ }
+ else
+ {
+ vec[i] = static_cast(current); // LCOV_EXCL_LINE
+ }
+ }
+
+ // step 2: convert array into number of type T and return
+ NumberType result;
+ std::memcpy(&result, vec.data(), sizeof(NumberType));
+ return result;
+ }
+
+ /*!
+ @brief create a string by reading characters from the input
+
+ @param[in] len number of bytes to read
+
+ @note We can not reserve @a len bytes for the result, because @a len
+ may be too large. Usually, @ref check_eof() detects the end of
+ the input before we run out of string memory.
+
+ @return string created by reading @a len bytes
+
+ @throw parse_error.110 if input has less than @a len bytes
+ */
+ std::string get_string(const size_t len)
+ {
+ std::string result;
+ for (size_t i = 0; i < len; ++i)
+ {
+ get();
+ check_eof();
+ result.append(1, static_cast(current));
+ }
+ return result;
+ }
+
+ /*!
+ @brief reads a CBOR string
+
+ This function first reads starting bytes to determine the expected
+ string length and then copies this number of bytes into a string.
+ Additionally, CBOR's strings with indefinite lengths are supported.
+
+ @return string
+
+ @throw parse_error.110 if input ended
+ @throw parse_error.113 if an unexpected byte is read
+ */
+ std::string get_cbor_string()
+ {
+ check_eof();
+
+ switch (current)
+ {
+ // UTF-8 string (0x00..0x17 bytes follow)
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67:
+ case 0x68:
+ case 0x69:
+ case 0x6a:
+ case 0x6b:
+ case 0x6c:
+ case 0x6d:
+ case 0x6e:
+ case 0x6f:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77:
+ {
+ const auto len = static_cast(current & 0x1f);
+ return get_string(len);
+ }
+
+ case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
+ {
+ const auto len = static_cast(get_number());
+ return get_string(len);
+ }
+
+ case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
+ {
+ const auto len = static_cast(get_number());
+ return get_string(len);
+ }
+
+ case 0x7a: // UTF-8 string (four-byte uint32_t for n follow)
+ {
+ const auto len = static_cast(get_number());
+ return get_string(len);
+ }
+
+ case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow)
+ {
+ const auto len = static_cast(get_number());
+ return get_string(len);
+ }
+
+ case 0x7f: // UTF-8 string (indefinite length)
+ {
+ std::string result;
+ while (get() != 0xff)
+ {
+ check_eof();
+ result.append(1, static_cast(current));
+ }
+ return result;
+ }
+
+ default:
+ {
+ std::stringstream ss;
+ ss << std::setw(2) << std::setfill('0') << std::hex << current;
+ JSON_THROW(parse_error::create(
+ 113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str()));
+ }
+ }
+ }
+
+ /*!
+ @brief reads a MessagePack string
+
+ This function first reads starting bytes to determine the expected
+ string length and then copies this number of bytes into a string.
+
+ @return string
+
+ @throw parse_error.110 if input ended
+ @throw parse_error.113 if an unexpected byte is read
+ */
+ std::string get_msgpack_string()
+ {
+ check_eof();
+
+ switch (current)
+ {
+ // fixstr
+ case 0xa0:
+ case 0xa1:
+ case 0xa2:
+ case 0xa3:
+ case 0xa4:
+ case 0xa5:
+ case 0xa6:
+ case 0xa7:
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf:
+ case 0xb0:
+ case 0xb1:
+ case 0xb2:
+ case 0xb3:
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ case 0xb8:
+ case 0xb9:
+ case 0xba:
+ case 0xbb:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xbf:
+ {
+ const auto len = static_cast(current & 0x1f);
+ return get_string(len);
+ }
+
+ case 0xd9: // str 8
+ {
+ const auto len = static_cast(get_number());
+ return get_string(len);
+ }
+
+ case 0xda: // str 16
+ {
+ const auto len = static_cast(get_number());
+ return get_string(len);
+ }
+
+ case 0xdb: // str 32
+ {
+ const auto len = static_cast(get_number());
+ return get_string(len);
+ }
+
+ default:
+ {
+ std::stringstream ss;
+ ss << std::setw(2) << std::setfill('0') << std::hex << current;
+ JSON_THROW(parse_error::create(
+ 113, chars_read,
+ "expected a MessagePack string; last byte: 0x" + ss.str()));
+ }
+ }
+ }
+
+ /*!
+ @brief check if input ended
+ @throw parse_error.110 if input ended
+ */
+ void check_eof() const
+ {
+ if (JSON_UNLIKELY(current == std::char_traits::eof()))
+ {
+ JSON_THROW(
+ parse_error::create(110, chars_read, "unexpected end of input"));
+ }
+ }
+
+ private:
+ /// input adapter
+ input_adapter_t ia = nullptr;
+
+ /// the current character
+ int current = std::char_traits::eof();
+
+ /// the number of characters read
+ size_t chars_read = 0;
+
+ /// whether we can assume little endianess
+ const bool is_little_endian = true;
+};
+
+/*!
+@brief serialization to CBOR and MessagePack values
+*/
+template
+class binary_writer
+{
+ public:
+ /*!
+ @brief create a binary writer
+
+ @param[in] adapter output adapter to write to
+ */
+ explicit binary_writer(output_adapter_t adapter)
+ : is_little_endian(binary_reader::little_endianess()), oa(adapter)
+ {
+ assert(oa);
+ }
+
+ /*!
+ @brief[in] j JSON value to serialize
+ */
+ void write_cbor(const BasicJsonType& j)
+ {
+ switch (j.type())
+ {
+ case value_t::null:
+ {
+ oa->write_character(0xf6);
+ break;
+ }
+
+ case value_t::boolean:
+ {
+ oa->write_character(j.m_value.boolean ? 0xf5 : 0xf4);
+ break;
+ }
+
+ case value_t::number_integer:
+ {
+ if (j.m_value.number_integer >= 0)
+ {
+ // CBOR does not differentiate between positive signed
+ // integers and unsigned integers. Therefore, we used the
+ // code from the value_t::number_unsigned case here.
+ if (j.m_value.number_integer <= 0x17)
+ {
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ else if (j.m_value.number_integer <=
+ (std::numeric_limits::max)())
+ {
+ oa->write_character(0x18);
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ else if (j.m_value.number_integer <=
+ (std::numeric_limits::max)())
+ {
+ oa->write_character(0x19);
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ else if (j.m_value.number_integer <=
+ (std::numeric_limits::max)())
+ {
+ oa->write_character(0x1a);
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ else
+ {
+ oa->write_character(0x1b);
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ }
+ else
+ {
+ // The conversions below encode the sign in the first
+ // byte, and the value is converted to a positive number.
+ const auto positive_number = -1 - j.m_value.number_integer;
+ if (j.m_value.number_integer >= -24)
+ {
+ write_number(static_cast(0x20 + positive_number));
+ }
+ else if (positive_number <= (std::numeric_limits::max)())
+ {
+ oa->write_character(0x38);
+ write_number(static_cast(positive_number));
+ }
+ else if (positive_number <= (std::numeric_limits::max)())
+ {
+ oa->write_character(0x39);
+ write_number(static_cast(positive_number));
+ }
+ else if (positive_number <= (std::numeric_limits::max)())
+ {
+ oa->write_character(0x3a);
+ write_number(static_cast(positive_number));
+ }
+ else
+ {
+ oa->write_character(0x3b);
+ write_number(static_cast(positive_number));
+ }
+ }
+ break;
+ }
+
+ case value_t::number_unsigned:
+ {
+ if (j.m_value.number_unsigned <= 0x17)
+ {
+ write_number(static_cast(j.m_value.number_unsigned));
+ }
+ else if (j.m_value.number_unsigned <=
+ (std::numeric_limits::max)())
+ {
+ oa->write_character(0x18);
+ write_number(static_cast(j.m_value.number_unsigned));
+ }
+ else if (j.m_value.number_unsigned <=
+ (std::numeric_limits::max)())
+ {
+ oa->write_character(0x19);
+ write_number(static_cast(j.m_value.number_unsigned));
+ }
+ else if (j.m_value.number_unsigned <=
+ (std::numeric_limits::max)())
+ {
+ oa->write_character(0x1a);
+ write_number(static_cast(j.m_value.number_unsigned));
+ }
+ else
+ {
+ oa->write_character(0x1b);
+ write_number(static_cast(j.m_value.number_unsigned));
+ }
+ break;
+ }
+
+ case value_t::number_float:
+ {
+ // Double-Precision Float
+ oa->write_character(0xfb);
+ write_number(j.m_value.number_float);
+ break;
+ }
+
+ case value_t::string:
+ {
+ // step 1: write control byte and the string length
+ const auto N = j.m_value.string->size();
+ if (N <= 0x17)
+ {
+ write_number(static_cast(0x60 + N));
+ }
+ else if (N <= 0xff)
+ {
+ oa->write_character(0x78);
+ write_number(static_cast(N));
+ }
+ else if (N <= 0xffff)
+ {
+ oa->write_character(0x79);
+ write_number(static_cast(N));
+ }
+ else if (N <= 0xffffffff)
+ {
+ oa->write_character(0x7a);
+ write_number(static_cast(N));
+ }
+ // LCOV_EXCL_START
+ else if (N <= 0xffffffffffffffff)
+ {
+ oa->write_character(0x7b);
+ write_number(static_cast(N));
+ }
+ // LCOV_EXCL_STOP
+
+ // step 2: write the string
+ oa->write_characters(
+ reinterpret_cast(j.m_value.string->c_str()),
+ j.m_value.string->size());
+ break;
+ }
+
+ case value_t::array:
+ {
+ // step 1: write control byte and the array size
+ const auto N = j.m_value.array->size();
+ if (N <= 0x17)
+ {
+ write_number(static_cast(0x80 + N));
+ }
+ else if (N <= 0xff)
+ {
+ oa->write_character(0x98);
+ write_number(static_cast(N));
+ }
+ else if (N <= 0xffff)
+ {
+ oa->write_character(0x99);
+ write_number(static_cast(N));
+ }
+ else if (N <= 0xffffffff)
+ {
+ oa->write_character(0x9a);
+ write_number(static_cast(N));
+ }
+ // LCOV_EXCL_START
+ else if (N <= 0xffffffffffffffff)
+ {
+ oa->write_character(0x9b);
+ write_number(static_cast(N));
+ }
+ // LCOV_EXCL_STOP
+
+ // step 2: write each element
+ for (const auto& el : *j.m_value.array)
+ {
+ write_cbor(el);
+ }
+ break;
+ }
+
+ case value_t::object:
+ {
+ // step 1: write control byte and the object size
+ const auto N = j.m_value.object->size();
+ if (N <= 0x17)
+ {
+ write_number(static_cast(0xa0 + N));
+ }
+ else if (N <= 0xff)
+ {
+ oa->write_character(0xb8);
+ write_number(static_cast(N));
+ }
+ else if (N <= 0xffff)
+ {
+ oa->write_character(0xb9);
+ write_number(static_cast(N));
+ }
+ else if (N <= 0xffffffff)
+ {
+ oa->write_character(0xba);
+ write_number(static_cast(N));
+ }
+ // LCOV_EXCL_START
+ else if (N <= 0xffffffffffffffff)
+ {
+ oa->write_character(0xbb);
+ write_number(static_cast(N));
+ }
+ // LCOV_EXCL_STOP
+
+ // step 2: write each element
+ for (const auto& el : *j.m_value.object)
+ {
+ write_cbor(el.first);
+ write_cbor(el.second);
+ }
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ /*!
+ @brief[in] j JSON value to serialize
+ */
+ void write_msgpack(const BasicJsonType& j)
+ {
+ switch (j.type())
+ {
+ case value_t::null:
+ {
+ // nil
+ oa->write_character(0xc0);
+ break;
+ }
+
+ case value_t::boolean:
+ {
+ // true and false
+ oa->write_character(j.m_value.boolean ? 0xc3 : 0xc2);
+ break;
+ }
+
+ case value_t::number_integer:
+ {
+ if (j.m_value.number_integer >= 0)
+ {
+ // MessagePack does not differentiate between positive
+ // signed integers and unsigned integers. Therefore, we
+ // used the code from the value_t::number_unsigned case
+ // here.
+ if (j.m_value.number_unsigned < 128)
+ {
+ // positive fixnum
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ else if (j.m_value.number_unsigned <=
+ (std::numeric_limits::max)())
+ {
+ // uint 8
+ oa->write_character(0xcc);
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ else if (j.m_value.number_unsigned <=
+ (std::numeric_limits::max)())
+ {
+ // uint 16
+ oa->write_character(0xcd);
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ else if (j.m_value.number_unsigned <=
+ (std::numeric_limits::max)())
+ {
+ // uint 32
+ oa->write_character(0xce);
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ else if (j.m_value.number_unsigned <=
+ (std::numeric_limits::max)())
+ {
+ // uint 64
+ oa->write_character(0xcf);
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ }
+ else
+ {
+ if (j.m_value.number_integer >= -32)
+ {
+ // negative fixnum
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ else if (j.m_value.number_integer >=
+ (std::numeric_limits::min)() and
+ j.m_value.number_integer <=
+ (std::numeric_limits::max)())
+ {
+ // int 8
+ oa->write_character(0xd0);
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ else if (j.m_value.number_integer >=
+ (std::numeric_limits::min)() and
+ j.m_value.number_integer <=
+ (std::numeric_limits::max)())
+ {
+ // int 16
+ oa->write_character(0xd1);
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ else if (j.m_value.number_integer >=
+ (std::numeric_limits::min)() and
+ j.m_value.number_integer <=
+ (std::numeric_limits::max)())
+ {
+ // int 32
+ oa->write_character(0xd2);
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ else if (j.m_value.number_integer >=
+ (std::numeric_limits::min)() and
+ j.m_value.number_integer <=
+ (std::numeric_limits::max)())
+ {
+ // int 64
+ oa->write_character(0xd3);
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ }
+ break;
+ }
+
+ case value_t::number_unsigned:
+ {
+ if (j.m_value.number_unsigned < 128)
+ {
+ // positive fixnum
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ else if (j.m_value.number_unsigned <=
+ (std::numeric_limits::max)())
+ {
+ // uint 8
+ oa->write_character(0xcc);
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ else if (j.m_value.number_unsigned <=
+ (std::numeric_limits::max)())
+ {
+ // uint 16
+ oa->write_character(0xcd);
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ else if (j.m_value.number_unsigned <=
+ (std::numeric_limits::max)())
+ {
+ // uint 32
+ oa->write_character(0xce);
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ else if (j.m_value.number_unsigned <=
+ (std::numeric_limits::max)())
+ {
+ // uint 64
+ oa->write_character(0xcf);
+ write_number(static_cast(j.m_value.number_integer));
+ }
+ break;
+ }
+
+ case value_t::number_float:
+ {
+ // float 64
+ oa->write_character(0xcb);
+ write_number(j.m_value.number_float);
+ break;
+ }
+
+ case value_t::string:
+ {
+ // step 1: write control byte and the string length
+ const auto N = j.m_value.string->size();
+ if (N <= 31)
+ {
+ // fixstr
+ write_number(static_cast(0xa0 | N));
+ }
+ else if (N <= 255)
+ {
+ // str 8
+ oa->write_character(0xd9);
+ write_number(static_cast(N));
+ }
+ else if (N <= 65535)
+ {
+ // str 16
+ oa->write_character(0xda);
+ write_number(static_cast(N));
+ }
+ else if (N <= 4294967295)
+ {
+ // str 32
+ oa->write_character(0xdb);
+ write_number(static_cast(N));
+ }
+
+ // step 2: write the string
+ oa->write_characters(
+ reinterpret_cast(j.m_value.string->c_str()),
+ j.m_value.string->size());
+ break;
+ }
+
+ case value_t::array:
+ {
+ // step 1: write control byte and the array size
+ const auto N = j.m_value.array->size();
+ if (N <= 15)
+ {
+ // fixarray
+ write_number(static_cast(0x90 | N));
+ }
+ else if (N <= 0xffff)
+ {
+ // array 16
+ oa->write_character(0xdc);
+ write_number(static_cast(N));
+ }
+ else if (N <= 0xffffffff)
+ {
+ // array 32
+ oa->write_character(0xdd);
+ write_number(static_cast(N));
+ }
+
+ // step 2: write each element
+ for (const auto& el : *j.m_value.array)
+ {
+ write_msgpack(el);
+ }
+ break;
+ }
+
+ case value_t::object:
+ {
+ // step 1: write control byte and the object size
+ const auto N = j.m_value.object->size();
+ if (N <= 15)
+ {
+ // fixmap
+ write_number(static_cast(0x80 | (N & 0xf)));
+ }
+ else if (N <= 65535)
+ {
+ // map 16
+ oa->write_character(0xde);
+ write_number(static_cast(N));
+ }
+ else if (N <= 4294967295)
+ {
+ // map 32
+ oa->write_character(0xdf);
+ write_number(static_cast(N));
+ }
+
+ // step 2: write each element
+ for (const auto& el : *j.m_value.object)
+ {
+ write_msgpack(el.first);
+ write_msgpack(el.second);
+ }
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ private:
+ /*
+ @brief write a number to output input
+
+ @param[in] n number of type @a NumberType
+ @tparam NumberType the type of the number
+
+ @note This function needs to respect the system's endianess, because
+ bytes in CBOR and MessagePack are stored in network order (big
+ endian) and therefore need reordering on little endian systems.
+ */
+ template void write_number(NumberType n)
+ {
+ // step 1: write number to array of length NumberType
+ std::array vec;
+ std::memcpy(vec.data(), &n, sizeof(NumberType));
+
+ // step 2: write array to output (with possible reordering)
+ if (is_little_endian)
+ {
+ // reverse byte order prior to conversion if necessary
+ std::reverse(vec.begin(), vec.end());
+ }
+
+ oa->write_characters(vec.data(), sizeof(NumberType));
+ }
+
+ private:
+ /// whether we can assume little endianess
+ const bool is_little_endian = true;
+
+ /// the output
+ output_adapter_t oa = nullptr;
+};
} // namespace detail
/// namespace to hold default `to_json` / `from_json` functions
@@ -5053,6 +6867,12 @@ class basic_json
using iteration_proxy = ::nlohmann::detail::iteration_proxy;
template using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator;
+ template
+ using output_adapter_t = ::nlohmann::detail::output_adapter_t;
+
+ using binary_reader = ::nlohmann::detail::binary_reader;
+ using binary_writer = ::nlohmann::detail::binary_writer;
+
public:
using value_t = detail::value_t;
// forward declarations
@@ -6621,7 +8441,7 @@ class basic_json
string_t dump(const int indent = -1, const char indent_char = ' ') const
{
string_t result;
- serializer s(output_adapter::create(result), indent_char);
+ serializer s(detail::output_adapter_factory::create(result), indent_char);
if (indent >= 0)
{
@@ -10250,110 +12070,6 @@ class basic_json
/// @}
- private:
- /////////////////////
- // output adapters //
- /////////////////////
-
- /// abstract output adapter interface
- template
- class output_adapter
- {
- public:
- virtual void write_character(CharType c) = 0;
- virtual void write_characters(const CharType* s, size_t length) = 0;
- virtual ~output_adapter() {}
-
- static std::shared_ptr> create(std::vector& vec)
- {
- return std::make_shared>(vec);
- }
-
- static std::shared_ptr> create(std::ostream& s)
- {
- return std::make_shared>(s);
- }
-
- static std::shared_ptr> create(std::string& s)
- {
- return std::make_shared>(s);
- }
- };
-
- /// a type to simplify interfaces
- template
- using output_adapter_t = std::shared_ptr>;
-
- /// output adapter for byte vectors
- template
- class output_vector_adapter : public output_adapter
- {
- public:
- output_vector_adapter(std::vector& vec)
- : v(vec)
- {}
-
- void write_character(CharType c) override
- {
- v.push_back(c);
- }
-
- void write_characters(const CharType* s, size_t length) override
- {
- std::copy(s, s + length, std::back_inserter(v));
- }
-
- private:
- std::vector& v;
- };
-
- /// output adapter for output streams
- template
- class output_stream_adapter : public output_adapter
- {
- public:
- output_stream_adapter(std::basic_ostream& s)
- : stream(s)
- {}
-
- void write_character(CharType c) override
- {
- stream.put(c);
- }
-
- void write_characters(const CharType* s, size_t length) override
- {
- stream.write(s, static_cast(length));
- }
-
- private:
- std::basic_ostream& stream;
- };
-
- /// output adapter for basic_string
- template
- class output_string_adapter : public output_adapter
- {
- public:
- output_string_adapter(std::string& s)
- : str(s)
- {}
-
- void write_character(CharType c) override
- {
- str.push_back(c);
- }
-
- void write_characters(const CharType* s, size_t length) override
- {
- str.append(s, length);
- }
-
- private:
- std::basic_string& str;
- };
-
-
///////////////////
// serialization //
///////////////////
@@ -10991,7 +12707,7 @@ class basic_json
o.width(0);
// do the actual serialization
- serializer s(output_adapter::create(o), o.fill());
+ serializer s(detail::output_adapter_factory::create(o), o.fill());
s.dump(j, pretty_print, static_cast(indentation));
return o;
}
@@ -11410,1677 +13126,6 @@ class basic_json
/// @name binary serialization/deserialization support
/// @{
- /*!
- @brief deserialization of CBOR and MessagePack values
- */
- class binary_reader
- {
- public:
- /*!
- @brief create a binary reader
-
- @param[in] adapter input adapter to read from
- */
- explicit binary_reader(detail::input_adapter_t adapter)
- : ia(adapter), is_little_endian(little_endianess())
- {
- assert(ia);
- }
-
- /*!
- @brief create a JSON value from CBOR input
-
- @param[in] get_char whether a new character should be retrieved from
- the input (true, default) or whether the last
- read character should be considered instead
-
- @return JSON value created from CBOR input
-
- @throw parse_error.110 if input ended unexpectedly
- @throw parse_error.112 if unsupported byte was read
- */
- basic_json parse_cbor(const bool get_char = true)
- {
- switch (get_char ? get() : current)
- {
- // EOF
- case std::char_traits::eof():
- {
- JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input"));
- }
-
- // Integer 0x00..0x17 (0..23)
- case 0x00:
- case 0x01:
- case 0x02:
- case 0x03:
- case 0x04:
- case 0x05:
- case 0x06:
- case 0x07:
- case 0x08:
- case 0x09:
- case 0x0a:
- case 0x0b:
- case 0x0c:
- case 0x0d:
- case 0x0e:
- case 0x0f:
- case 0x10:
- case 0x11:
- case 0x12:
- case 0x13:
- case 0x14:
- case 0x15:
- case 0x16:
- case 0x17:
- {
- return static_cast(current);
- }
-
- case 0x18: // Unsigned integer (one-byte uint8_t follows)
- {
- return get_number();
- }
-
- case 0x19: // Unsigned integer (two-byte uint16_t follows)
- {
- return get_number();
- }
-
- case 0x1a: // Unsigned integer (four-byte uint32_t follows)
- {
- return get_number();
- }
-
- case 0x1b: // Unsigned integer (eight-byte uint64_t follows)
- {
- return get_number();
- }
-
- // Negative integer -1-0x00..-1-0x17 (-1..-24)
- case 0x20:
- case 0x21:
- case 0x22:
- case 0x23:
- case 0x24:
- case 0x25:
- case 0x26:
- case 0x27:
- case 0x28:
- case 0x29:
- case 0x2a:
- case 0x2b:
- case 0x2c:
- case 0x2d:
- case 0x2e:
- case 0x2f:
- case 0x30:
- case 0x31:
- case 0x32:
- case 0x33:
- case 0x34:
- case 0x35:
- case 0x36:
- case 0x37:
- {
- return static_cast(0x20 - 1 - current);
- }
-
- case 0x38: // Negative integer (one-byte uint8_t follows)
- {
- // must be uint8_t !
- return static_cast(-1) - get_number();
- }
-
- case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
- {
- return static_cast(-1) - get_number();
- }
-
- case 0x3a: // Negative integer -1-n (four-byte uint32_t follows)
- {
- return static_cast(-1) - get_number();
- }
-
- case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows)
- {
- return static_cast(-1) - static_cast(get_number());
- }
-
- // UTF-8 string (0x00..0x17 bytes follow)
- case 0x60:
- case 0x61:
- case 0x62:
- case 0x63:
- case 0x64:
- case 0x65:
- case 0x66:
- case 0x67:
- case 0x68:
- case 0x69:
- case 0x6a:
- case 0x6b:
- case 0x6c:
- case 0x6d:
- case 0x6e:
- case 0x6f:
- case 0x70:
- case 0x71:
- case 0x72:
- case 0x73:
- case 0x74:
- case 0x75:
- case 0x76:
- case 0x77:
- case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
- case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
- case 0x7a: // UTF-8 string (four-byte uint32_t for n follow)
- case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow)
- case 0x7f: // UTF-8 string (indefinite length)
- {
- return get_cbor_string();
- }
-
- // array (0x00..0x17 data items follow)
- case 0x80:
- case 0x81:
- case 0x82:
- case 0x83:
- case 0x84:
- case 0x85:
- case 0x86:
- case 0x87:
- case 0x88:
- case 0x89:
- case 0x8a:
- case 0x8b:
- case 0x8c:
- case 0x8d:
- case 0x8e:
- case 0x8f:
- case 0x90:
- case 0x91:
- case 0x92:
- case 0x93:
- case 0x94:
- case 0x95:
- case 0x96:
- case 0x97:
- {
- basic_json result = value_t::array;
- const auto len = static_cast(current & 0x1f);
- for (size_t i = 0; i < len; ++i)
- {
- result.push_back(parse_cbor());
- }
- return result;
- }
-
- case 0x98: // array (one-byte uint8_t for n follows)
- {
- basic_json result = value_t::array;
- const auto len = static_cast(get_number());
- for (size_t i = 0; i < len; ++i)
- {
- result.push_back(parse_cbor());
- }
- return result;
- }
-
- case 0x99: // array (two-byte uint16_t for n follow)
- {
- basic_json result = value_t::array;
- const auto len = static_cast(get_number());
- for (size_t i = 0; i < len; ++i)
- {
- result.push_back(parse_cbor());
- }
- return result;
- }
-
- case 0x9a: // array (four-byte uint32_t for n follow)
- {
- basic_json result = value_t::array;
- const auto len = static_cast(get_number