🚧 a lot of minor changes

- Removed unused headers.
- Added override where needed.
- Added description for parse_error.113 exception.
- Fixed some conversion warnings.
- Integrated cbor_expect_string function for CBOR maps.
- Added documentation on the supported CBOR/MessagePack features.
- Added test to check all initial bytes for CBOR input.
This commit is contained in:
Niels Lohmann 2017-03-16 18:39:33 +01:00
parent 483a58f625
commit c5711f3072
No known key found for this signature in database
GPG key ID: 7F3CEA63AE251B69
10 changed files with 385 additions and 90 deletions

View file

@ -32,7 +32,6 @@ SOFTWARE.
#include <algorithm> // all_of, copy, fill, find, for_each, none_of, remove, reverse, transform #include <algorithm> // all_of, copy, fill, find, for_each, none_of, remove, reverse, transform
#include <array> // array #include <array> // array
#include <cassert> // assert #include <cassert> // assert
#include <cctype> // isdigit
#include <ciso646> // and, not, or #include <ciso646> // and, not, or
#include <clocale> // lconv, localeconv #include <clocale> // lconv, localeconv
#include <cmath> // isfinite, labs, ldexp, signbit #include <cmath> // isfinite, labs, ldexp, signbit
@ -43,7 +42,6 @@ SOFTWARE.
#include <forward_list> // forward_list #include <forward_list> // forward_list
#include <functional> // function, hash, less #include <functional> // function, hash, less
#include <initializer_list> // initializer_list #include <initializer_list> // initializer_list
#include <iomanip> // setw
#include <iostream> // istream, ostream #include <iostream> // istream, ostream
#include <iterator> // advance, begin, back_inserter, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator #include <iterator> // advance, begin, back_inserter, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator
#include <limits> // numeric_limits #include <limits> // numeric_limits
@ -130,7 +128,7 @@ class exception : public std::exception
{} {}
/// returns the explanatory string /// returns the explanatory string
virtual const char* what() const noexcept virtual const char* what() const noexcept override
{ {
return what_arg.c_str(); return what_arg.c_str();
} }
@ -174,7 +172,7 @@ json.exception.parse_error.109 | parse error: array index 'one' is not a number
json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read.
json.exception.parse_error.111 | parse error: bad input stream | Parsing CBOR or MessagePack from an input stream where the [`badbit` or `failbit`](http://en.cppreference.com/w/cpp/io/ios_base/iostate) is set. json.exception.parse_error.111 | parse error: bad input stream | Parsing CBOR or MessagePack from an input stream where the [`badbit` or `failbit`](http://en.cppreference.com/w/cpp/io/ios_base/iostate) is set.
json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xf8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xf8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read.
json.exception.parse_error.113 | | While parsing a map key, a value that is not a string has been read. json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read.
@since version 3.0.0 @since version 3.0.0
*/ */
@ -6468,7 +6466,7 @@ class basic_json
auto i = val.m_value.object->cbegin(); auto i = val.m_value.object->cbegin();
for (size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) for (size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
{ {
o.write(indent_string.c_str(), new_indent); o.write(indent_string.c_str(), static_cast<std::streamsize>(new_indent));
o.put('\"'); o.put('\"');
dump_escaped(i->first); dump_escaped(i->first);
o.write("\": ", 3); o.write("\": ", 3);
@ -6478,14 +6476,14 @@ class basic_json
// last element // last element
assert(i != val.m_value.object->cend()); assert(i != val.m_value.object->cend());
o.write(indent_string.c_str(), new_indent); o.write(indent_string.c_str(), static_cast<std::streamsize>(new_indent));
o.put('\"'); o.put('\"');
dump_escaped(i->first); dump_escaped(i->first);
o.write("\": ", 3); o.write("\": ", 3);
dump(i->second, true, indent_step, new_indent); dump(i->second, true, indent_step, new_indent);
o.put('\n'); o.put('\n');
o.write(indent_string.c_str(), current_indent); o.write(indent_string.c_str(), static_cast<std::streamsize>(current_indent));
o.put('}'); o.put('}');
} }
else else
@ -6538,18 +6536,18 @@ class basic_json
// first n-1 elements // first n-1 elements
for (auto i = val.m_value.array->cbegin(); i != val.m_value.array->cend() - 1; ++i) for (auto i = val.m_value.array->cbegin(); i != val.m_value.array->cend() - 1; ++i)
{ {
o.write(indent_string.c_str(), new_indent); o.write(indent_string.c_str(), static_cast<std::streamsize>(new_indent));
dump(*i, true, indent_step, new_indent); dump(*i, true, indent_step, new_indent);
o.write(",\n", 2); o.write(",\n", 2);
} }
// last element // last element
assert(not val.m_value.array->empty()); assert(not val.m_value.array->empty());
o.write(indent_string.c_str(), new_indent); o.write(indent_string.c_str(), static_cast<std::streamsize>(new_indent));
dump(val.m_value.array->back(), true, indent_step, new_indent); dump(val.m_value.array->back(), true, indent_step, new_indent);
o.put('\n'); o.put('\n');
o.write(indent_string.c_str(), current_indent); o.write(indent_string.c_str(), static_cast<std::streamsize>(current_indent));
o.put(']'); o.put(']');
} }
else else
@ -7848,7 +7846,7 @@ class basic_json
const auto N = j.m_value.string->size(); const auto N = j.m_value.string->size();
if (N <= 0x17) if (N <= 0x17)
{ {
v.push_back(0x60 + static_cast<uint8_t>(N)); // 1 byte for string + size v.push_back(static_cast<uint8_t>(0x60 + N)); // 1 byte for string + size
} }
else if (N <= 0xff) else if (N <= 0xff)
{ {
@ -7884,7 +7882,7 @@ class basic_json
const auto N = j.m_value.array->size(); const auto N = j.m_value.array->size();
if (N <= 0x17) if (N <= 0x17)
{ {
v.push_back(0x80 + static_cast<uint8_t>(N)); // 1 byte for array + size v.push_back(static_cast<uint8_t>(0x80 + N)); // 1 byte for array + size
} }
else if (N <= 0xff) else if (N <= 0xff)
{ {
@ -7922,7 +7920,7 @@ class basic_json
const auto N = j.m_value.object->size(); const auto N = j.m_value.object->size();
if (N <= 0x17) if (N <= 0x17)
{ {
v.push_back(0xa0 + static_cast<uint8_t>(N)); // 1 byte for object + size v.push_back(static_cast<uint8_t>(0xa0 + N)); // 1 byte for object + size
} }
else if (N <= 0xff) else if (N <= 0xff)
{ {
@ -8653,6 +8651,7 @@ class basic_json
const auto len = static_cast<size_t>(v[current_idx] - 0xa0); const auto len = static_cast<size_t>(v[current_idx] - 0xa0);
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i)
{ {
cbor_expect_string(v, idx);
std::string key = from_cbor_internal(v, idx); std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx); result[key] = from_cbor_internal(v, idx);
} }
@ -8666,6 +8665,7 @@ class basic_json
idx += 1; // skip 1 size byte idx += 1; // skip 1 size byte
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i)
{ {
cbor_expect_string(v, idx);
std::string key = from_cbor_internal(v, idx); std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx); result[key] = from_cbor_internal(v, idx);
} }
@ -8679,6 +8679,7 @@ class basic_json
idx += 2; // skip 2 size bytes idx += 2; // skip 2 size bytes
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i)
{ {
cbor_expect_string(v, idx);
std::string key = from_cbor_internal(v, idx); std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx); result[key] = from_cbor_internal(v, idx);
} }
@ -8692,6 +8693,7 @@ class basic_json
idx += 4; // skip 4 size bytes idx += 4; // skip 4 size bytes
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i)
{ {
cbor_expect_string(v, idx);
std::string key = from_cbor_internal(v, idx); std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx); result[key] = from_cbor_internal(v, idx);
} }
@ -8705,6 +8707,7 @@ class basic_json
idx += 8; // skip 8 size bytes idx += 8; // skip 8 size bytes
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i)
{ {
cbor_expect_string(v, idx);
std::string key = from_cbor_internal(v, idx); std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx); result[key] = from_cbor_internal(v, idx);
} }
@ -8716,6 +8719,7 @@ class basic_json
basic_json result = value_t::object; basic_json result = value_t::object;
while (check_length(v.size(), 1, idx), v[idx] != 0xff) while (check_length(v.size(), 1, idx), v[idx] != 0xff)
{ {
cbor_expect_string(v, idx);
std::string key = from_cbor_internal(v, idx); std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx); result[key] = from_cbor_internal(v, idx);
} }
@ -8864,6 +8868,9 @@ class basic_json
- float 32 (0xca) - float 32 (0xca)
- fixext 1 - fixext 16 (0xd4..0xd8) - fixext 1 - fixext 16 (0xd4..0xd8)
@note Any MessagePack output created @ref to_msgpack can be successfully
parsed by @ref from_msgpack.
@param[in] j JSON value to serialize @param[in] j JSON value to serialize
@return MessagePack serialization as byte vector @return MessagePack serialization as byte vector
@ -8892,6 +8899,46 @@ class basic_json
Deserializes a given byte vector @a v to a JSON value using the MessagePack Deserializes a given byte vector @a v to a JSON value using the MessagePack
serialization format. serialization format.
The library maps MessagePack types to JSON value types as follows:
MessagePack type | JSON value type | first byte
---------------- | --------------- | ----------
positive fixint | number_unsigned | 0x00..0x7f
fixmap | object | 0x80..0x8f
fixarray | array | 0x90..0x9f
fixstr | string | 0xa0..0xbf
nil | `null` | 0xc0
false | `false` | 0xc2
true | `true` | 0xc3
float 32 | number_float | 0xca
float 64 | number_float | 0xcb
uint 8 | number_unsigned | 0xcc
uint 16 | number_unsigned | 0xcd
uint 32 | number_unsigned | 0xce
uint 64 | number_unsigned | 0xcf
int 8 | number_integer | 0xd0
int 16 | number_integer | 0xd1
int 32 | number_integer | 0xd2
int 64 | number_integer | 0xd3
str 8 | string | 0xd9
str 16 | string | 0xda
str 32 | string | 0xdb
array 16 | array | 0xdc
array 32 | array | 0xdd
map 16 | object | 0xde
map 32 | object | 0xdf
negative fixint | number_integer | 0xe0-0xff
@warning The mapping is **incomplete** in the sense that not all
MessagePack types can be converted to a JSON value. The following
MessagePack types are not supported and will yield parse errors:
- bin 8 - bin 32 (0xc4..0xc6)
- ext 8 - ext 32 (0xc7..0xc9)
- fixext 1 - fixext 16 (0xd4..0xd8)
@note Any MessagePack output created @ref to_msgpack can be successfully
parsed by @ref from_msgpack.
@param[in] v a byte vector in MessagePack format @param[in] v a byte vector in MessagePack format
@param[in] start_index the index to start reading from @a v (0 by default) @param[in] start_index the index to start reading from @a v (0 by default)
@return deserialized JSON value @return deserialized JSON value
@ -8899,6 +8946,7 @@ class basic_json
@throw parse_error.110 if the given vector ends prematurely @throw parse_error.110 if the given vector ends prematurely
@throw parse_error.112 if unsupported features from MessagePack were @throw parse_error.112 if unsupported features from MessagePack were
used in the given vector @a v or if the input is not valid MessagePack used in the given vector @a v or if the input is not valid MessagePack
@throw parse_error.113 if a string was expected as map key, but not found
@complexity Linear in the size of the byte vector @a v. @complexity Linear in the size of the byte vector @a v.
@ -9014,6 +9062,66 @@ class basic_json
Deserializes a given byte vector @a v to a JSON value using the CBOR Deserializes a given byte vector @a v to a JSON value using the CBOR
(Concise Binary Object Representation) serialization format. (Concise Binary Object Representation) serialization format.
The library maps CBOR types to JSON value types as follows:
CBOR type | JSON value type | first byte
---------------------- | --------------- | ----------
Integer | number_unsigned | 0x00..0x17
Unsigned integer | number_unsigned | 0x18
Unsigned integer | number_unsigned | 0x19
Unsigned integer | number_unsigned | 0x1a
Unsigned integer | number_unsigned | 0x1b
Negative integer | number_integer | 0x20..0x37
Negative integer | number_integer | 0x38
Negative integer | number_integer | 0x39
Negative integer | number_integer | 0x3a
Negative integer | number_integer | 0x3b
Negative integer | number_integer | 0x40..0x57
UTF-8 string | string | 0x60..0x77
UTF-8 string | string | 0x78
UTF-8 string | string | 0x79
UTF-8 string | string | 0x7a
UTF-8 string | string | 0x7b
UTF-8 string | string | 0x7f
array | array | 0x80..0x97
array | array | 0x98
array | array | 0x99
array | array | 0x9a
array | array | 0x9b
array | array | 0x9f
map | object | 0xa0..0xb7
map | object | 0xb8
map | object | 0xb9
map | object | 0xba
map | object | 0xbb
map | object | 0xbf
False | `false` | 0xf4
True | `true` | 0xf5
Nill | `null` | 0xf6
Half-Precision Float | number_float | 0xf9
Single-Precision Float | number_float | 0xfa
Double-Precision Float | number_float | 0xfb
@warning The mapping is **incomplete** in the sense that not all CBOR
types can be converted to a JSON value. The following CBOR types
are not supported and will yield parse errors (parse_error.112):
- byte strings (0x40..0x5f)
- date/time (0xc0..0xc1)
- bignum (0xc2..0xc3)
- decimal fraction (0xc4)
- bigfloat (0xc5)
- tagged items (0xc6..0xd4, 0xd8..0xdb)
- expected conversions (0xd5..0xd7)
- simple values (0xe0..0xf3, 0xf8)
- undefined (0xf7)
@warning CBOR allows map keys of any type, whereas JSON only allows
strings as keys in object values. Therefore, CBOR maps with keys
other than UTF-8 strings are rejected (parse_error.113).
@note Any CBOR output created @ref to_cbor can be successfully parsed by
@ref from_cbor.
@param[in] v a byte vector in CBOR format @param[in] v a byte vector in CBOR format
@param[in] start_index the index to start reading from @a v (0 by default) @param[in] start_index the index to start reading from @a v (0 by default)
@return deserialized JSON value @return deserialized JSON value
@ -9021,6 +9129,7 @@ class basic_json
@throw parse_error.110 if the given vector ends prematurely @throw parse_error.110 if the given vector ends prematurely
@throw parse_error.112 if unsupported features from CBOR were @throw parse_error.112 if unsupported features from CBOR were
used in the given vector @a v or if the input is not valid CBOR used in the given vector @a v or if the input is not valid CBOR
@throw parse_error.113 if a string was expected as map key, but not found
@complexity Linear in the size of the byte vector @a v. @complexity Linear in the size of the byte vector @a v.
@ -12423,7 +12532,7 @@ basic_json_parser_74:
reference_token.end(), reference_token.end(),
[](const char x) [](const char x)
{ {
return std::isdigit(x); return (x >= '0' and x <= '9');
}); });
// change value to array for numbers or "-" or to object // change value to array for numbers or "-" or to object

View file

@ -32,7 +32,6 @@ SOFTWARE.
#include <algorithm> // all_of, copy, fill, find, for_each, none_of, remove, reverse, transform #include <algorithm> // all_of, copy, fill, find, for_each, none_of, remove, reverse, transform
#include <array> // array #include <array> // array
#include <cassert> // assert #include <cassert> // assert
#include <cctype> // isdigit
#include <ciso646> // and, not, or #include <ciso646> // and, not, or
#include <clocale> // lconv, localeconv #include <clocale> // lconv, localeconv
#include <cmath> // isfinite, labs, ldexp, signbit #include <cmath> // isfinite, labs, ldexp, signbit
@ -43,7 +42,6 @@ SOFTWARE.
#include <forward_list> // forward_list #include <forward_list> // forward_list
#include <functional> // function, hash, less #include <functional> // function, hash, less
#include <initializer_list> // initializer_list #include <initializer_list> // initializer_list
#include <iomanip> // setw
#include <iostream> // istream, ostream #include <iostream> // istream, ostream
#include <iterator> // advance, begin, back_inserter, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator #include <iterator> // advance, begin, back_inserter, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator
#include <limits> // numeric_limits #include <limits> // numeric_limits
@ -130,7 +128,7 @@ class exception : public std::exception
{} {}
/// returns the explanatory string /// returns the explanatory string
virtual const char* what() const noexcept virtual const char* what() const noexcept override
{ {
return what_arg.c_str(); return what_arg.c_str();
} }
@ -174,7 +172,7 @@ json.exception.parse_error.109 | parse error: array index 'one' is not a number
json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read.
json.exception.parse_error.111 | parse error: bad input stream | Parsing CBOR or MessagePack from an input stream where the [`badbit` or `failbit`](http://en.cppreference.com/w/cpp/io/ios_base/iostate) is set. json.exception.parse_error.111 | parse error: bad input stream | Parsing CBOR or MessagePack from an input stream where the [`badbit` or `failbit`](http://en.cppreference.com/w/cpp/io/ios_base/iostate) is set.
json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xf8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xf8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read.
json.exception.parse_error.113 | | While parsing a map key, a value that is not a string has been read. json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read.
@since version 3.0.0 @since version 3.0.0
*/ */
@ -6468,7 +6466,7 @@ class basic_json
auto i = val.m_value.object->cbegin(); auto i = val.m_value.object->cbegin();
for (size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) for (size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
{ {
o.write(indent_string.c_str(), new_indent); o.write(indent_string.c_str(), static_cast<std::streamsize>(new_indent));
o.put('\"'); o.put('\"');
dump_escaped(i->first); dump_escaped(i->first);
o.write("\": ", 3); o.write("\": ", 3);
@ -6478,14 +6476,14 @@ class basic_json
// last element // last element
assert(i != val.m_value.object->cend()); assert(i != val.m_value.object->cend());
o.write(indent_string.c_str(), new_indent); o.write(indent_string.c_str(), static_cast<std::streamsize>(new_indent));
o.put('\"'); o.put('\"');
dump_escaped(i->first); dump_escaped(i->first);
o.write("\": ", 3); o.write("\": ", 3);
dump(i->second, true, indent_step, new_indent); dump(i->second, true, indent_step, new_indent);
o.put('\n'); o.put('\n');
o.write(indent_string.c_str(), current_indent); o.write(indent_string.c_str(), static_cast<std::streamsize>(current_indent));
o.put('}'); o.put('}');
} }
else else
@ -6538,18 +6536,18 @@ class basic_json
// first n-1 elements // first n-1 elements
for (auto i = val.m_value.array->cbegin(); i != val.m_value.array->cend() - 1; ++i) for (auto i = val.m_value.array->cbegin(); i != val.m_value.array->cend() - 1; ++i)
{ {
o.write(indent_string.c_str(), new_indent); o.write(indent_string.c_str(), static_cast<std::streamsize>(new_indent));
dump(*i, true, indent_step, new_indent); dump(*i, true, indent_step, new_indent);
o.write(",\n", 2); o.write(",\n", 2);
} }
// last element // last element
assert(not val.m_value.array->empty()); assert(not val.m_value.array->empty());
o.write(indent_string.c_str(), new_indent); o.write(indent_string.c_str(), static_cast<std::streamsize>(new_indent));
dump(val.m_value.array->back(), true, indent_step, new_indent); dump(val.m_value.array->back(), true, indent_step, new_indent);
o.put('\n'); o.put('\n');
o.write(indent_string.c_str(), current_indent); o.write(indent_string.c_str(), static_cast<std::streamsize>(current_indent));
o.put(']'); o.put(']');
} }
else else
@ -7848,7 +7846,7 @@ class basic_json
const auto N = j.m_value.string->size(); const auto N = j.m_value.string->size();
if (N <= 0x17) if (N <= 0x17)
{ {
v.push_back(0x60 + static_cast<uint8_t>(N)); // 1 byte for string + size v.push_back(static_cast<uint8_t>(0x60 + N)); // 1 byte for string + size
} }
else if (N <= 0xff) else if (N <= 0xff)
{ {
@ -7884,7 +7882,7 @@ class basic_json
const auto N = j.m_value.array->size(); const auto N = j.m_value.array->size();
if (N <= 0x17) if (N <= 0x17)
{ {
v.push_back(0x80 + static_cast<uint8_t>(N)); // 1 byte for array + size v.push_back(static_cast<uint8_t>(0x80 + N)); // 1 byte for array + size
} }
else if (N <= 0xff) else if (N <= 0xff)
{ {
@ -7922,7 +7920,7 @@ class basic_json
const auto N = j.m_value.object->size(); const auto N = j.m_value.object->size();
if (N <= 0x17) if (N <= 0x17)
{ {
v.push_back(0xa0 + static_cast<uint8_t>(N)); // 1 byte for object + size v.push_back(static_cast<uint8_t>(0xa0 + N)); // 1 byte for object + size
} }
else if (N <= 0xff) else if (N <= 0xff)
{ {
@ -8653,6 +8651,7 @@ class basic_json
const auto len = static_cast<size_t>(v[current_idx] - 0xa0); const auto len = static_cast<size_t>(v[current_idx] - 0xa0);
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i)
{ {
cbor_expect_string(v, idx);
std::string key = from_cbor_internal(v, idx); std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx); result[key] = from_cbor_internal(v, idx);
} }
@ -8666,6 +8665,7 @@ class basic_json
idx += 1; // skip 1 size byte idx += 1; // skip 1 size byte
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i)
{ {
cbor_expect_string(v, idx);
std::string key = from_cbor_internal(v, idx); std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx); result[key] = from_cbor_internal(v, idx);
} }
@ -8679,6 +8679,7 @@ class basic_json
idx += 2; // skip 2 size bytes idx += 2; // skip 2 size bytes
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i)
{ {
cbor_expect_string(v, idx);
std::string key = from_cbor_internal(v, idx); std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx); result[key] = from_cbor_internal(v, idx);
} }
@ -8692,6 +8693,7 @@ class basic_json
idx += 4; // skip 4 size bytes idx += 4; // skip 4 size bytes
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i)
{ {
cbor_expect_string(v, idx);
std::string key = from_cbor_internal(v, idx); std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx); result[key] = from_cbor_internal(v, idx);
} }
@ -8705,6 +8707,7 @@ class basic_json
idx += 8; // skip 8 size bytes idx += 8; // skip 8 size bytes
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i)
{ {
cbor_expect_string(v, idx);
std::string key = from_cbor_internal(v, idx); std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx); result[key] = from_cbor_internal(v, idx);
} }
@ -8716,6 +8719,7 @@ class basic_json
basic_json result = value_t::object; basic_json result = value_t::object;
while (check_length(v.size(), 1, idx), v[idx] != 0xff) while (check_length(v.size(), 1, idx), v[idx] != 0xff)
{ {
cbor_expect_string(v, idx);
std::string key = from_cbor_internal(v, idx); std::string key = from_cbor_internal(v, idx);
result[key] = from_cbor_internal(v, idx); result[key] = from_cbor_internal(v, idx);
} }
@ -8864,6 +8868,9 @@ class basic_json
- float 32 (0xca) - float 32 (0xca)
- fixext 1 - fixext 16 (0xd4..0xd8) - fixext 1 - fixext 16 (0xd4..0xd8)
@note Any MessagePack output created @ref to_msgpack can be successfully
parsed by @ref from_msgpack.
@param[in] j JSON value to serialize @param[in] j JSON value to serialize
@return MessagePack serialization as byte vector @return MessagePack serialization as byte vector
@ -8892,6 +8899,46 @@ class basic_json
Deserializes a given byte vector @a v to a JSON value using the MessagePack Deserializes a given byte vector @a v to a JSON value using the MessagePack
serialization format. serialization format.
The library maps MessagePack types to JSON value types as follows:
MessagePack type | JSON value type | first byte
---------------- | --------------- | ----------
positive fixint | number_unsigned | 0x00..0x7f
fixmap | object | 0x80..0x8f
fixarray | array | 0x90..0x9f
fixstr | string | 0xa0..0xbf
nil | `null` | 0xc0
false | `false` | 0xc2
true | `true` | 0xc3
float 32 | number_float | 0xca
float 64 | number_float | 0xcb
uint 8 | number_unsigned | 0xcc
uint 16 | number_unsigned | 0xcd
uint 32 | number_unsigned | 0xce
uint 64 | number_unsigned | 0xcf
int 8 | number_integer | 0xd0
int 16 | number_integer | 0xd1
int 32 | number_integer | 0xd2
int 64 | number_integer | 0xd3
str 8 | string | 0xd9
str 16 | string | 0xda
str 32 | string | 0xdb
array 16 | array | 0xdc
array 32 | array | 0xdd
map 16 | object | 0xde
map 32 | object | 0xdf
negative fixint | number_integer | 0xe0-0xff
@warning The mapping is **incomplete** in the sense that not all
MessagePack types can be converted to a JSON value. The following
MessagePack types are not supported and will yield parse errors:
- bin 8 - bin 32 (0xc4..0xc6)
- ext 8 - ext 32 (0xc7..0xc9)
- fixext 1 - fixext 16 (0xd4..0xd8)
@note Any MessagePack output created @ref to_msgpack can be successfully
parsed by @ref from_msgpack.
@param[in] v a byte vector in MessagePack format @param[in] v a byte vector in MessagePack format
@param[in] start_index the index to start reading from @a v (0 by default) @param[in] start_index the index to start reading from @a v (0 by default)
@return deserialized JSON value @return deserialized JSON value
@ -8899,6 +8946,7 @@ class basic_json
@throw parse_error.110 if the given vector ends prematurely @throw parse_error.110 if the given vector ends prematurely
@throw parse_error.112 if unsupported features from MessagePack were @throw parse_error.112 if unsupported features from MessagePack were
used in the given vector @a v or if the input is not valid MessagePack used in the given vector @a v or if the input is not valid MessagePack
@throw parse_error.113 if a string was expected as map key, but not found
@complexity Linear in the size of the byte vector @a v. @complexity Linear in the size of the byte vector @a v.
@ -9014,6 +9062,66 @@ class basic_json
Deserializes a given byte vector @a v to a JSON value using the CBOR Deserializes a given byte vector @a v to a JSON value using the CBOR
(Concise Binary Object Representation) serialization format. (Concise Binary Object Representation) serialization format.
The library maps CBOR types to JSON value types as follows:
CBOR type | JSON value type | first byte
---------------------- | --------------- | ----------
Integer | number_unsigned | 0x00..0x17
Unsigned integer | number_unsigned | 0x18
Unsigned integer | number_unsigned | 0x19
Unsigned integer | number_unsigned | 0x1a
Unsigned integer | number_unsigned | 0x1b
Negative integer | number_integer | 0x20..0x37
Negative integer | number_integer | 0x38
Negative integer | number_integer | 0x39
Negative integer | number_integer | 0x3a
Negative integer | number_integer | 0x3b
Negative integer | number_integer | 0x40..0x57
UTF-8 string | string | 0x60..0x77
UTF-8 string | string | 0x78
UTF-8 string | string | 0x79
UTF-8 string | string | 0x7a
UTF-8 string | string | 0x7b
UTF-8 string | string | 0x7f
array | array | 0x80..0x97
array | array | 0x98
array | array | 0x99
array | array | 0x9a
array | array | 0x9b
array | array | 0x9f
map | object | 0xa0..0xb7
map | object | 0xb8
map | object | 0xb9
map | object | 0xba
map | object | 0xbb
map | object | 0xbf
False | `false` | 0xf4
True | `true` | 0xf5
Nill | `null` | 0xf6
Half-Precision Float | number_float | 0xf9
Single-Precision Float | number_float | 0xfa
Double-Precision Float | number_float | 0xfb
@warning The mapping is **incomplete** in the sense that not all CBOR
types can be converted to a JSON value. The following CBOR types
are not supported and will yield parse errors (parse_error.112):
- byte strings (0x40..0x5f)
- date/time (0xc0..0xc1)
- bignum (0xc2..0xc3)
- decimal fraction (0xc4)
- bigfloat (0xc5)
- tagged items (0xc6..0xd4, 0xd8..0xdb)
- expected conversions (0xd5..0xd7)
- simple values (0xe0..0xf3, 0xf8)
- undefined (0xf7)
@warning CBOR allows map keys of any type, whereas JSON only allows
strings as keys in object values. Therefore, CBOR maps with keys
other than UTF-8 strings are rejected (parse_error.113).
@note Any CBOR output created @ref to_cbor can be successfully parsed by
@ref from_cbor.
@param[in] v a byte vector in CBOR format @param[in] v a byte vector in CBOR format
@param[in] start_index the index to start reading from @a v (0 by default) @param[in] start_index the index to start reading from @a v (0 by default)
@return deserialized JSON value @return deserialized JSON value
@ -9021,6 +9129,7 @@ class basic_json
@throw parse_error.110 if the given vector ends prematurely @throw parse_error.110 if the given vector ends prematurely
@throw parse_error.112 if unsupported features from CBOR were @throw parse_error.112 if unsupported features from CBOR were
used in the given vector @a v or if the input is not valid CBOR used in the given vector @a v or if the input is not valid CBOR
@throw parse_error.113 if a string was expected as map key, but not found
@complexity Linear in the size of the byte vector @a v. @complexity Linear in the size of the byte vector @a v.
@ -11456,7 +11565,7 @@ class basic_json
reference_token.end(), reference_token.end(),
[](const char x) [](const char x)
{ {
return std::isdigit(x); return (x >= '0' and x <= '9');
}); });
// change value to array for numbers or "-" or to object // change value to array for numbers or "-" or to object

View file

@ -130,14 +130,14 @@ TEST_CASE("CBOR")
// check individual bytes // check individual bytes
CHECK(result[0] == 0x3b); CHECK(result[0] == 0x3b);
uint64_t restored = static_cast<uint64_t>((static_cast<uint64_t>(result[1]) << 070) + uint64_t restored = (static_cast<uint64_t>(result[1]) << 070) +
(static_cast<uint64_t>(result[2]) << 060) + (static_cast<uint64_t>(result[2]) << 060) +
(static_cast<uint64_t>(result[3]) << 050) + (static_cast<uint64_t>(result[3]) << 050) +
(static_cast<uint64_t>(result[4]) << 040) + (static_cast<uint64_t>(result[4]) << 040) +
(static_cast<uint64_t>(result[5]) << 030) + (static_cast<uint64_t>(result[5]) << 030) +
(static_cast<uint64_t>(result[6]) << 020) + (static_cast<uint64_t>(result[6]) << 020) +
(static_cast<uint64_t>(result[7]) << 010) + (static_cast<uint64_t>(result[7]) << 010) +
static_cast<uint64_t>(result[8])); static_cast<uint64_t>(result[8]);
CHECK(restored == positive); CHECK(restored == positive);
CHECK(-1 - static_cast<int64_t>(restored) == i); CHECK(-1 - static_cast<int64_t>(restored) == i);
@ -182,10 +182,10 @@ TEST_CASE("CBOR")
// check individual bytes // check individual bytes
CHECK(result[0] == 0x3a); CHECK(result[0] == 0x3a);
uint32_t restored = static_cast<uint32_t>((static_cast<uint32_t>(result[1]) << 030) + uint32_t restored = (static_cast<uint32_t>(result[1]) << 030) +
(static_cast<uint32_t>(result[2]) << 020) + (static_cast<uint32_t>(result[2]) << 020) +
(static_cast<uint32_t>(result[3]) << 010) + (static_cast<uint32_t>(result[3]) << 010) +
static_cast<uint32_t>(result[4])); static_cast<uint32_t>(result[4]);
CHECK(restored == positive); CHECK(restored == positive);
CHECK(-1ll - restored == i); CHECK(-1ll - restored == i);
@ -220,7 +220,7 @@ TEST_CASE("CBOR")
// check individual bytes // check individual bytes
CHECK(result[0] == 0x39); CHECK(result[0] == 0x39);
uint16_t restored = static_cast<uint8_t>(result[1]) * 256 + static_cast<uint8_t>(result[2]); uint16_t restored = static_cast<uint16_t>(static_cast<uint8_t>(result[1]) * 256 + static_cast<uint8_t>(result[2]));
CHECK(restored == positive); CHECK(restored == positive);
CHECK(-1 - restored == i); CHECK(-1 - restored == i);
@ -289,7 +289,7 @@ TEST_CASE("CBOR")
// create expected byte vector // create expected byte vector
std::vector<uint8_t> expected; std::vector<uint8_t> expected;
expected.push_back(0x20 - 1 - static_cast<uint8_t>(i)); expected.push_back(static_cast<uint8_t>(0x20 - 1 - static_cast<uint8_t>(i)));
// compare result + size // compare result + size
const auto result = json::to_cbor(j); const auto result = json::to_cbor(j);
@ -392,7 +392,7 @@ TEST_CASE("CBOR")
// check individual bytes // check individual bytes
CHECK(result[0] == 0x19); CHECK(result[0] == 0x19);
uint16_t restored = static_cast<uint8_t>(result[1]) * 256 + static_cast<uint8_t>(result[2]); uint16_t restored = static_cast<uint16_t>(static_cast<uint8_t>(result[1]) * 256 + static_cast<uint8_t>(result[2]));
CHECK(restored == i); CHECK(restored == i);
// roundtrip // roundtrip
@ -431,10 +431,10 @@ TEST_CASE("CBOR")
// check individual bytes // check individual bytes
CHECK(result[0] == 0x1a); CHECK(result[0] == 0x1a);
uint32_t restored = static_cast<uint32_t>((static_cast<uint32_t>(result[1]) << 030) + uint32_t restored = (static_cast<uint32_t>(result[1]) << 030) +
(static_cast<uint32_t>(result[2]) << 020) + (static_cast<uint32_t>(result[2]) << 020) +
(static_cast<uint32_t>(result[3]) << 010) + (static_cast<uint32_t>(result[3]) << 010) +
static_cast<uint32_t>(result[4])); static_cast<uint32_t>(result[4]);
CHECK(restored == i); CHECK(restored == i);
// roundtrip // roundtrip
@ -477,14 +477,14 @@ TEST_CASE("CBOR")
// check individual bytes // check individual bytes
CHECK(result[0] == 0x1b); CHECK(result[0] == 0x1b);
uint64_t restored = static_cast<uint64_t>((static_cast<uint64_t>(result[1]) << 070) + uint64_t restored = (static_cast<uint64_t>(result[1]) << 070) +
(static_cast<uint64_t>(result[2]) << 060) + (static_cast<uint64_t>(result[2]) << 060) +
(static_cast<uint64_t>(result[3]) << 050) + (static_cast<uint64_t>(result[3]) << 050) +
(static_cast<uint64_t>(result[4]) << 040) + (static_cast<uint64_t>(result[4]) << 040) +
(static_cast<uint64_t>(result[5]) << 030) + (static_cast<uint64_t>(result[5]) << 030) +
(static_cast<uint64_t>(result[6]) << 020) + (static_cast<uint64_t>(result[6]) << 020) +
(static_cast<uint64_t>(result[7]) << 010) + (static_cast<uint64_t>(result[7]) << 010) +
static_cast<uint64_t>(result[8])); static_cast<uint64_t>(result[8]);
CHECK(restored == i); CHECK(restored == i);
// roundtrip // roundtrip
@ -616,7 +616,7 @@ TEST_CASE("CBOR")
// check individual bytes // check individual bytes
CHECK(result[0] == 0x19); CHECK(result[0] == 0x19);
uint16_t restored = static_cast<uint8_t>(result[1]) * 256 + static_cast<uint8_t>(result[2]); uint16_t restored = static_cast<uint16_t>(static_cast<uint8_t>(result[1]) * 256 + static_cast<uint8_t>(result[2]));
CHECK(restored == i); CHECK(restored == i);
// roundtrip // roundtrip
@ -654,10 +654,10 @@ TEST_CASE("CBOR")
// check individual bytes // check individual bytes
CHECK(result[0] == 0x1a); CHECK(result[0] == 0x1a);
uint32_t restored = static_cast<uint32_t>((static_cast<uint32_t>(result[1]) << 030) + uint32_t restored = (static_cast<uint32_t>(result[1]) << 030) +
(static_cast<uint32_t>(result[2]) << 020) + (static_cast<uint32_t>(result[2]) << 020) +
(static_cast<uint32_t>(result[3]) << 010) + (static_cast<uint32_t>(result[3]) << 010) +
static_cast<uint32_t>(result[4])); static_cast<uint32_t>(result[4]);
CHECK(restored == i); CHECK(restored == i);
// roundtrip // roundtrip
@ -699,14 +699,14 @@ TEST_CASE("CBOR")
// check individual bytes // check individual bytes
CHECK(result[0] == 0x1b); CHECK(result[0] == 0x1b);
uint64_t restored = static_cast<uint64_t>((static_cast<uint64_t>(result[1]) << 070) + uint64_t restored = (static_cast<uint64_t>(result[1]) << 070) +
(static_cast<uint64_t>(result[2]) << 060) + (static_cast<uint64_t>(result[2]) << 060) +
(static_cast<uint64_t>(result[3]) << 050) + (static_cast<uint64_t>(result[3]) << 050) +
(static_cast<uint64_t>(result[4]) << 040) + (static_cast<uint64_t>(result[4]) << 040) +
(static_cast<uint64_t>(result[5]) << 030) + (static_cast<uint64_t>(result[5]) << 030) +
(static_cast<uint64_t>(result[6]) << 020) + (static_cast<uint64_t>(result[6]) << 020) +
(static_cast<uint64_t>(result[7]) << 010) + (static_cast<uint64_t>(result[7]) << 010) +
static_cast<uint64_t>(result[8])); static_cast<uint64_t>(result[8]);
CHECK(restored == i); CHECK(restored == i);
// roundtrip // roundtrip
@ -1538,6 +1538,83 @@ TEST_CASE("CBOR roundtrips", "[hide]")
} }
} }
TEST_CASE("all first bytes", "[!throws]")
{
// these bytes will fail immediately with exception parse_error.112
std::set<uint8_t> unsupported =
{
//// types not supported by this library
// byte strings
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
// byte strings
0x58, 0x59, 0x5a, 0x5b, 0x5f,
// date/time
0xc0, 0xc1,
// bignum
0xc2, 0xc3,
// decimal fracion
0xc4,
// bigfloat
0xc5,
// tagged item
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd,
0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd8,
0xd9, 0xda, 0xdb,
// expected conversion
0xd5, 0xd6, 0xd7,
// simple value
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xef, 0xf0,
0xf1, 0xf2, 0xf3,
0xf8,
// undefined
0xf7,
//// bytes not specified by CBOR
0x1c, 0x1d, 0x1e, 0x1f,
0x3c, 0x3d, 0x3e, 0x3f,
0x5c, 0x5d, 0x5e,
0x7c, 0x7d, 0x7e,
0x9c, 0x9d, 0x9e,
0xbc, 0xbd, 0xbe,
0xdc, 0xdd, 0xde, 0xdf,
0xee,
0xfc, 0xfe, 0xfd,
/// break cannot be the first byte
0xff
};
for (auto i = 0; i < 256; ++i)
{
const auto byte = static_cast<uint8_t>(i);
try
{
json::from_cbor({byte});
}
catch (const json::parse_error& e)
{
// check that parse_error.112 is only thrown if the
// first byte is in the unsupported set
CAPTURE(e.what());
if (std::find(unsupported.begin(), unsupported.end(), byte) != unsupported.end())
{
CHECK(e.id == 112);
}
else
{
CHECK(e.id != 112);
}
}
}
}
TEST_CASE("examples from RFC 7049 Appendix A") TEST_CASE("examples from RFC 7049 Appendix A")
{ {
SECTION("numbers") SECTION("numbers")

View file

@ -139,7 +139,7 @@ TEST_CASE("lexer class")
for (int c = 1; c < 128; ++c) for (int c = 1; c < 128; ++c)
{ {
// create string from the ASCII code // create string from the ASCII code
const auto s = std::string(1, c); const auto s = std::string(1, static_cast<char>(c));
// store scan() result // store scan() result
const auto res = json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(s.c_str()), const auto res = json::lexer(reinterpret_cast<const json::lexer::lexer_char_t*>(s.c_str()),
1).scan(); 1).scan();

View file

@ -494,7 +494,7 @@ TEST_CASE("parser class")
// invalid escapes // invalid escapes
for (int c = 1; c < 128; ++c) for (int c = 1; c < 128; ++c)
{ {
auto s = std::string("\"\\") + std::string(1, c) + "\""; auto s = std::string("\"\\") + std::string(1, static_cast<char>(c)) + "\"";
switch (c) switch (c)
{ {
@ -574,10 +574,10 @@ TEST_CASE("parser class")
std::string s = "\"\\u"; std::string s = "\"\\u";
// create a string with the iterated character at each position // create a string with the iterated character at each position
auto s1 = s + "000" + std::string(1, c) + "\""; auto s1 = s + "000" + std::string(1, static_cast<char>(c)) + "\"";
auto s2 = s + "00" + std::string(1, c) + "0\""; auto s2 = s + "00" + std::string(1, static_cast<char>(c)) + "0\"";
auto s3 = s + "0" + std::string(1, c) + "00\""; auto s3 = s + "0" + std::string(1, static_cast<char>(c)) + "00\"";
auto s4 = s + std::string(1, c) + "000\""; auto s4 = s + std::string(1, static_cast<char>(c)) + "000\"";
if (valid(c)) if (valid(c))
{ {

View file

@ -72,8 +72,8 @@ TEST_CASE("concepts")
// X::size_type must return an unsigned integer // X::size_type must return an unsigned integer
CHECK((std::is_unsigned<json::size_type>::value)); CHECK((std::is_unsigned<json::size_type>::value));
// X::size_type can represent any non-negative value of X::difference_type // X::size_type can represent any non-negative value of X::difference_type
CHECK(static_cast<size_t>(std::numeric_limits<json::difference_type>::max()) <= CHECK(static_cast<json::size_type>(std::numeric_limits<json::difference_type>::max()) <=
static_cast<size_t>(std::numeric_limits<json::size_type>::max())); std::numeric_limits<json::size_type>::max());
// the expression "X u" has the post-condition "u.empty()" // the expression "X u" has the post-condition "u.empty()"
{ {

View file

@ -48,7 +48,7 @@ TEST_CASE("element access 1")
CHECK(j.at(3) == json(nullptr)); CHECK(j.at(3) == json(nullptr));
CHECK(j.at(4) == json("string")); CHECK(j.at(4) == json("string"));
CHECK(j.at(5) == json(42.23)); CHECK(j.at(5) == json(42.23));
CHECK(j.at(6) == json(json::object())); CHECK(j.at(6) == json::object());
CHECK(j.at(7) == json({1, 2, 3})); CHECK(j.at(7) == json({1, 2, 3}));
CHECK(j_const.at(0) == json(1)); CHECK(j_const.at(0) == json(1));
@ -57,7 +57,7 @@ TEST_CASE("element access 1")
CHECK(j_const.at(3) == json(nullptr)); CHECK(j_const.at(3) == json(nullptr));
CHECK(j_const.at(4) == json("string")); CHECK(j_const.at(4) == json("string"));
CHECK(j_const.at(5) == json(42.23)); CHECK(j_const.at(5) == json(42.23));
CHECK(j_const.at(6) == json(json::object())); CHECK(j_const.at(6) == json::object());
CHECK(j_const.at(7) == json({1, 2, 3})); CHECK(j_const.at(7) == json({1, 2, 3}));
} }
@ -171,7 +171,7 @@ TEST_CASE("element access 1")
CHECK(j[3] == json(nullptr)); CHECK(j[3] == json(nullptr));
CHECK(j[4] == json("string")); CHECK(j[4] == json("string"));
CHECK(j[5] == json(42.23)); CHECK(j[5] == json(42.23));
CHECK(j[6] == json(json::object())); CHECK(j[6] == json::object());
CHECK(j[7] == json({1, 2, 3})); CHECK(j[7] == json({1, 2, 3}));
CHECK(j_const[0] == json(1)); CHECK(j_const[0] == json(1));
@ -180,7 +180,7 @@ TEST_CASE("element access 1")
CHECK(j_const[3] == json(nullptr)); CHECK(j_const[3] == json(nullptr));
CHECK(j_const[4] == json("string")); CHECK(j_const[4] == json("string"));
CHECK(j_const[5] == json(42.23)); CHECK(j_const[5] == json(42.23));
CHECK(j_const[6] == json(json::object())); CHECK(j_const[6] == json::object());
CHECK(j_const[7] == json({1, 2, 3})); CHECK(j_const[7] == json({1, 2, 3}));
} }

View file

@ -48,7 +48,7 @@ TEST_CASE("element access 2")
CHECK(j.at("null") == json(nullptr)); CHECK(j.at("null") == json(nullptr));
CHECK(j.at("string") == json("hello world")); CHECK(j.at("string") == json("hello world"));
CHECK(j.at("floating") == json(42.23)); CHECK(j.at("floating") == json(42.23));
CHECK(j.at("object") == json(json::object())); CHECK(j.at("object") == json::object());
CHECK(j.at("array") == json({1, 2, 3})); CHECK(j.at("array") == json({1, 2, 3}));
CHECK(j_const.at("integer") == json(1)); CHECK(j_const.at("integer") == json(1));
@ -57,7 +57,7 @@ TEST_CASE("element access 2")
CHECK(j_const.at("null") == json(nullptr)); CHECK(j_const.at("null") == json(nullptr));
CHECK(j_const.at("string") == json("hello world")); CHECK(j_const.at("string") == json("hello world"));
CHECK(j_const.at("floating") == json(42.23)); CHECK(j_const.at("floating") == json(42.23));
CHECK(j_const.at("object") == json(json::object())); CHECK(j_const.at("object") == json::object());
CHECK(j_const.at("array") == json({1, 2, 3})); CHECK(j_const.at("array") == json({1, 2, 3}));
} }
@ -161,7 +161,7 @@ TEST_CASE("element access 2")
CHECK(j.value("string", std::string("bar")) == "hello world"); CHECK(j.value("string", std::string("bar")) == "hello world");
CHECK(j.value("floating", 12.34) == Approx(42.23)); CHECK(j.value("floating", 12.34) == Approx(42.23));
CHECK(j.value("floating", 12) == 42); CHECK(j.value("floating", 12) == 42);
CHECK(j.value("object", json({{"foo", "bar"}})) == json(json::object())); CHECK(j.value("object", json({{"foo", "bar"}})) == json::object());
CHECK(j.value("array", json({10, 100})) == json({1, 2, 3})); CHECK(j.value("array", json({10, 100})) == json({1, 2, 3}));
CHECK(j_const.value("integer", 2) == 1); CHECK(j_const.value("integer", 2) == 1);
@ -173,7 +173,7 @@ TEST_CASE("element access 2")
CHECK(j_const.value("string", std::string("bar")) == "hello world"); CHECK(j_const.value("string", std::string("bar")) == "hello world");
CHECK(j_const.value("floating", 12.34) == Approx(42.23)); CHECK(j_const.value("floating", 12.34) == Approx(42.23));
CHECK(j_const.value("floating", 12) == 42); CHECK(j_const.value("floating", 12) == 42);
CHECK(j_const.value("object", json({{"foo", "bar"}})) == json(json::object())); CHECK(j_const.value("object", json({{"foo", "bar"}})) == json::object());
CHECK(j_const.value("array", json({10, 100})) == json({1, 2, 3})); CHECK(j_const.value("array", json({10, 100})) == json({1, 2, 3}));
} }
@ -298,7 +298,7 @@ TEST_CASE("element access 2")
CHECK(j.value("/string"_json_pointer, std::string("bar")) == "hello world"); CHECK(j.value("/string"_json_pointer, std::string("bar")) == "hello world");
CHECK(j.value("/floating"_json_pointer, 12.34) == Approx(42.23)); CHECK(j.value("/floating"_json_pointer, 12.34) == Approx(42.23));
CHECK(j.value("/floating"_json_pointer, 12) == 42); CHECK(j.value("/floating"_json_pointer, 12) == 42);
CHECK(j.value("/object"_json_pointer, json({{"foo", "bar"}})) == json(json::object())); CHECK(j.value("/object"_json_pointer, json({{"foo", "bar"}})) == json::object());
CHECK(j.value("/array"_json_pointer, json({10, 100})) == json({1, 2, 3})); CHECK(j.value("/array"_json_pointer, json({10, 100})) == json({1, 2, 3}));
CHECK(j_const.value("/integer"_json_pointer, 2) == 1); CHECK(j_const.value("/integer"_json_pointer, 2) == 1);
@ -310,7 +310,7 @@ TEST_CASE("element access 2")
CHECK(j_const.value("/string"_json_pointer, std::string("bar")) == "hello world"); CHECK(j_const.value("/string"_json_pointer, std::string("bar")) == "hello world");
CHECK(j_const.value("/floating"_json_pointer, 12.34) == Approx(42.23)); CHECK(j_const.value("/floating"_json_pointer, 12.34) == Approx(42.23));
CHECK(j_const.value("/floating"_json_pointer, 12) == 42); CHECK(j_const.value("/floating"_json_pointer, 12) == 42);
CHECK(j_const.value("/object"_json_pointer, json({{"foo", "bar"}})) == json(json::object())); CHECK(j_const.value("/object"_json_pointer, json({{"foo", "bar"}})) == json::object());
CHECK(j_const.value("/array"_json_pointer, json({10, 100})) == json({1, 2, 3})); CHECK(j_const.value("/array"_json_pointer, json({10, 100})) == json({1, 2, 3}));
} }
@ -435,7 +435,7 @@ TEST_CASE("element access 2")
CHECK(j["floating"] == json(42.23)); CHECK(j["floating"] == json(42.23));
CHECK(j[json::object_t::key_type("floating")] == j["floating"]); CHECK(j[json::object_t::key_type("floating")] == j["floating"]);
CHECK(j["object"] == json(json::object())); CHECK(j["object"] == json::object());
CHECK(j[json::object_t::key_type("object")] == j["object"]); CHECK(j[json::object_t::key_type("object")] == j["object"]);
CHECK(j["array"] == json({1, 2, 3})); CHECK(j["array"] == json({1, 2, 3}));
@ -456,7 +456,7 @@ TEST_CASE("element access 2")
CHECK(j_const["floating"] == json(42.23)); CHECK(j_const["floating"] == json(42.23));
CHECK(j_const[json::object_t::key_type("floating")] == j["floating"]); CHECK(j_const[json::object_t::key_type("floating")] == j["floating"]);
CHECK(j_const["object"] == json(json::object())); CHECK(j_const["object"] == json::object());
CHECK(j_const[json::object_t::key_type("object")] == j["object"]); CHECK(j_const[json::object_t::key_type("object")] == j["object"]);
CHECK(j_const["array"] == json({1, 2, 3})); CHECK(j_const["array"] == json({1, 2, 3}));

View file

@ -203,7 +203,7 @@ TEST_CASE("MessagePack")
// check individual bytes // check individual bytes
CHECK(result[0] == 0xcd); CHECK(result[0] == 0xcd);
uint16_t restored = static_cast<uint8_t>(result[1]) * 256 + static_cast<uint8_t>(result[2]); uint16_t restored = static_cast<uint16_t>(static_cast<uint8_t>(result[1]) * 256 + static_cast<uint8_t>(result[2]));
CHECK(restored == i); CHECK(restored == i);
// roundtrip // roundtrip
@ -242,10 +242,10 @@ TEST_CASE("MessagePack")
// check individual bytes // check individual bytes
CHECK(result[0] == 0xce); CHECK(result[0] == 0xce);
uint32_t restored = static_cast<uint32_t>((static_cast<uint32_t>(result[1]) << 030) + uint32_t restored = (static_cast<uint32_t>(result[1]) << 030) +
(static_cast<uint32_t>(result[2]) << 020) + (static_cast<uint32_t>(result[2]) << 020) +
(static_cast<uint32_t>(result[3]) << 010) + (static_cast<uint32_t>(result[3]) << 010) +
static_cast<uint32_t>(result[4])); static_cast<uint32_t>(result[4]);
CHECK(restored == i); CHECK(restored == i);
// roundtrip // roundtrip
@ -288,14 +288,14 @@ TEST_CASE("MessagePack")
// check individual bytes // check individual bytes
CHECK(result[0] == 0xcf); CHECK(result[0] == 0xcf);
uint64_t restored = static_cast<uint64_t>((static_cast<uint64_t>(result[1]) << 070) + uint64_t restored = (static_cast<uint64_t>(result[1]) << 070) +
(static_cast<uint64_t>(result[2]) << 060) + (static_cast<uint64_t>(result[2]) << 060) +
(static_cast<uint64_t>(result[3]) << 050) + (static_cast<uint64_t>(result[3]) << 050) +
(static_cast<uint64_t>(result[4]) << 040) + (static_cast<uint64_t>(result[4]) << 040) +
(static_cast<uint64_t>(result[5]) << 030) + (static_cast<uint64_t>(result[5]) << 030) +
(static_cast<uint64_t>(result[6]) << 020) + (static_cast<uint64_t>(result[6]) << 020) +
(static_cast<uint64_t>(result[7]) << 010) + (static_cast<uint64_t>(result[7]) << 010) +
static_cast<uint64_t>(result[8])); static_cast<uint64_t>(result[8]);
CHECK(restored == i); CHECK(restored == i);
// roundtrip // roundtrip
@ -415,10 +415,10 @@ TEST_CASE("MessagePack")
// check individual bytes // check individual bytes
CHECK(result[0] == 0xd2); CHECK(result[0] == 0xd2);
uint32_t restored = static_cast<uint32_t>((static_cast<uint32_t>(result[1]) << 030) + uint32_t restored = (static_cast<uint32_t>(result[1]) << 030) +
(static_cast<uint32_t>(result[2]) << 020) + (static_cast<uint32_t>(result[2]) << 020) +
(static_cast<uint32_t>(result[3]) << 010) + (static_cast<uint32_t>(result[3]) << 010) +
static_cast<uint32_t>(result[4])); static_cast<uint32_t>(result[4]);
CHECK(restored == i); CHECK(restored == i);
// roundtrip // roundtrip
@ -460,14 +460,14 @@ TEST_CASE("MessagePack")
// check individual bytes // check individual bytes
CHECK(result[0] == 0xd3); CHECK(result[0] == 0xd3);
int64_t restored = static_cast<int64_t>((static_cast<int64_t>(result[1]) << 070) + int64_t restored = (static_cast<int64_t>(result[1]) << 070) +
(static_cast<int64_t>(result[2]) << 060) + (static_cast<int64_t>(result[2]) << 060) +
(static_cast<int64_t>(result[3]) << 050) + (static_cast<int64_t>(result[3]) << 050) +
(static_cast<int64_t>(result[4]) << 040) + (static_cast<int64_t>(result[4]) << 040) +
(static_cast<int64_t>(result[5]) << 030) + (static_cast<int64_t>(result[5]) << 030) +
(static_cast<int64_t>(result[6]) << 020) + (static_cast<int64_t>(result[6]) << 020) +
(static_cast<int64_t>(result[7]) << 010) + (static_cast<int64_t>(result[7]) << 010) +
static_cast<int64_t>(result[8])); static_cast<int64_t>(result[8]);
CHECK(restored == i); CHECK(restored == i);
// roundtrip // roundtrip
@ -564,7 +564,7 @@ TEST_CASE("MessagePack")
// check individual bytes // check individual bytes
CHECK(result[0] == 0xcd); CHECK(result[0] == 0xcd);
uint16_t restored = static_cast<uint8_t>(result[1]) * 256 + static_cast<uint8_t>(result[2]); uint16_t restored = static_cast<uint16_t>(static_cast<uint8_t>(result[1]) * 256 + static_cast<uint8_t>(result[2]));
CHECK(restored == i); CHECK(restored == i);
// roundtrip // roundtrip
@ -602,10 +602,10 @@ TEST_CASE("MessagePack")
// check individual bytes // check individual bytes
CHECK(result[0] == 0xce); CHECK(result[0] == 0xce);
uint32_t restored = static_cast<uint32_t>((static_cast<uint32_t>(result[1]) << 030) + uint32_t restored = (static_cast<uint32_t>(result[1]) << 030) +
(static_cast<uint32_t>(result[2]) << 020) + (static_cast<uint32_t>(result[2]) << 020) +
(static_cast<uint32_t>(result[3]) << 010) + (static_cast<uint32_t>(result[3]) << 010) +
static_cast<uint32_t>(result[4])); static_cast<uint32_t>(result[4]);
CHECK(restored == i); CHECK(restored == i);
// roundtrip // roundtrip
@ -647,14 +647,14 @@ TEST_CASE("MessagePack")
// check individual bytes // check individual bytes
CHECK(result[0] == 0xcf); CHECK(result[0] == 0xcf);
uint64_t restored = static_cast<uint64_t>((static_cast<uint64_t>(result[1]) << 070) + uint64_t restored = (static_cast<uint64_t>(result[1]) << 070) +
(static_cast<uint64_t>(result[2]) << 060) + (static_cast<uint64_t>(result[2]) << 060) +
(static_cast<uint64_t>(result[3]) << 050) + (static_cast<uint64_t>(result[3]) << 050) +
(static_cast<uint64_t>(result[4]) << 040) + (static_cast<uint64_t>(result[4]) << 040) +
(static_cast<uint64_t>(result[5]) << 030) + (static_cast<uint64_t>(result[5]) << 030) +
(static_cast<uint64_t>(result[6]) << 020) + (static_cast<uint64_t>(result[6]) << 020) +
(static_cast<uint64_t>(result[7]) << 010) + (static_cast<uint64_t>(result[7]) << 010) +
static_cast<uint64_t>(result[8])); static_cast<uint64_t>(result[8]);
CHECK(restored == i); CHECK(restored == i);
// roundtrip // roundtrip

View file

@ -412,17 +412,17 @@ TEST_CASE("regression tests")
class CommaDecimalSeparator : public std::numpunct<char> class CommaDecimalSeparator : public std::numpunct<char>
{ {
protected: protected:
char do_decimal_point() const char do_decimal_point() const override
{ {
return ','; return ',';
} }
char do_thousands_sep() const char do_thousands_sep() const override
{ {
return '.'; return '.';
} }
std::string do_grouping() const std::string do_grouping() const override
{ {
return "\03"; return "\03";
} }
@ -755,7 +755,7 @@ TEST_CASE("regression tests")
}; };
CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error); CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error);
CHECK_THROWS_WITH(json::from_cbor(vec), CHECK_THROWS_WITH(json::from_cbor(vec),
"[json.exception.parse_error.110] parse error at 137: cannot read 1 bytes from vector"); "[json.exception.parse_error.113] parse error at 2: expected a CBOR string; last byte: 0x98");
// related test case: nonempty UTF-8 string (indefinite length) // related test case: nonempty UTF-8 string (indefinite length)
std::vector<uint8_t> vec1 {0x7f, 0x61, 0x61}; std::vector<uint8_t> vec1 {0x7f, 0x61, 0x61};
@ -808,7 +808,7 @@ TEST_CASE("regression tests")
}; };
CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error); CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error);
CHECK_THROWS_WITH(json::from_cbor(vec1), CHECK_THROWS_WITH(json::from_cbor(vec1),
"[json.exception.parse_error.110] parse error at 49: cannot read 4 bytes from vector"); "[json.exception.parse_error.113] parse error at 13: expected a CBOR string; last byte: 0xb4");
// related test case: double-precision // related test case: double-precision
std::vector<uint8_t> vec2 std::vector<uint8_t> vec2
@ -822,7 +822,7 @@ TEST_CASE("regression tests")
}; };
CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error); CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error);
CHECK_THROWS_WITH(json::from_cbor(vec2), CHECK_THROWS_WITH(json::from_cbor(vec2),
"[json.exception.parse_error.110] parse error at 49: cannot read 8 bytes from vector"); "[json.exception.parse_error.113] parse error at 13: expected a CBOR string; last byte: 0xb4");
} }
SECTION("issue #452 - Heap-buffer-overflow (OSS-Fuzz issue 585)") SECTION("issue #452 - Heap-buffer-overflow (OSS-Fuzz issue 585)")