🔨 a lot of restructuring

- removed uncached input stream adapter; it was too slow anyway - implemented a class binary_read which parses CBOR based on input adapters - in the CBOR parser, numbers are created via memcpy to avoid undefined behavior
parent 3a5cf9bd
......@@ -47,7 +47,8 @@ doctest:
# -Wno-keyword-macro: unit-tests use "#define private public"
# -Wno-deprecated-declarations: the library deprecated some functions
# -Wno-weak-vtables: exception class is defined inline, but has virtual method
# -Wno-range-loop-analysis: iterator_wrapper tests tests "for(const auto i...)"
# -Wno-range-loop-analysis: iterator_wrapper tests "for(const auto i...)"
# -Wno-float-equal: not all comparisons in the tests can be replaced by Approx
pedantic_clang:
$(MAKE) json_unit CXXFLAGS="\
-std=c++11 \
......@@ -58,7 +59,8 @@ pedantic_clang:
-Wno-keyword-macro \
-Wno-deprecated-declarations \
-Wno-weak-vtables \
-Wno-range-loop-analysis"
-Wno-range-loop-analysis \
-Wno-float-equal"
# calling GCC with most warnings
pedantic_gcc:
......
......@@ -38,7 +38,7 @@ SOFTWARE.
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
#include <cstdint> // int64_t, uint64_t
#include <cstdlib> // abort, strtod, strtof, strtold, strtoul, strtoll, strtoull
#include <cstring> // strlen
#include <cstring> // memcpy, strlen
#include <forward_list> // forward_list
#include <functional> // function, hash, less
#include <initializer_list> // initializer_list
......@@ -9228,12 +9228,12 @@ class basic_json
@since version 2.0.9, parameter @a start_index since 2.1.1
*/
static basic_json from_cbor(const std::vector<uint8_t>& v,
const size_t start_index = 0)
{
size_t i = start_index;
return from_cbor_internal(v, i);
}
//static basic_json from_cbor(const std::vector<uint8_t>& v,
// const size_t start_index = 0)
//{
// size_t i = start_index;
// return from_cbor_internal(v, i);
//}
/// @}
......@@ -10281,211 +10281,734 @@ class basic_json
private:
//////////////////////
// lexer and parser //
//////////////////////
////////////////////
// input adapters //
////////////////////
/*!
@brief lexical analysis
/// abstract input adapter interface
class input_adapter
{
public:
virtual int get_character() = 0;
virtual std::string read(size_t offset, size_t length) = 0;
virtual ~input_adapter() {}
};
This class organizes the lexical analysis during JSON deserialization.
*/
class lexer
/// input adapter for cached stream input
class cached_input_stream_adapter : public input_adapter
{
public:
cached_input_stream_adapter(std::istream& i, const size_t buffer_size)
: is(i), start_position(is.tellg()),
buffer(buffer_size, std::char_traits<char>::eof())
{
// immediately abort if stream is erroneous
if (JSON_UNLIKELY(i.fail()))
{
JSON_THROW(parse_error::create(111, 0, "bad input stream"));
}
// initial fill; unfilled buffer characters remain EOF
is.read(buffer.data(), static_cast<std::streamsize>(buffer.size()));
// skip byte-order mark
assert(buffer.size() >= 3);
if (buffer[0] == '\xEF' and buffer[1] == '\xBB' and buffer[2] == '\xBF')
{
buffer_pos += 3;
processed_chars += 3;
}
}
~cached_input_stream_adapter() override
{
// clear stream flags
is.clear();
// set stream after last processed char
is.seekg(start_position + static_cast<std::streamoff>(processed_chars - 1));
}
int get_character() override
{
// check if refilling is necessary
if (JSON_UNLIKELY(buffer_pos == buffer.size()))
{
// refill
is.read(reinterpret_cast<char*>(buffer.data()), static_cast<std::streamsize>(buffer.size()));
// set unfilled characters to EOF
std::fill_n(buffer.begin() + static_cast<int>(is.gcount()),
buffer.size() - static_cast<size_t>(is.gcount()),
std::char_traits<char>::eof());
// the buffer is ready
buffer_pos = 0;
}
++processed_chars;
const int res = buffer[buffer_pos++];
return (res == std::char_traits<char>::eof()) ? res : res & 0xFF;
}
std::string read(size_t offset, size_t length) override
{
// create buffer
std::string result(length, '\0');
// save stream position
auto current_pos = is.tellg();
// save stream flags
auto flags = is.rdstate();
// clear stream flags
is.clear();
// set stream position
is.seekg(static_cast<std::streamoff>(offset));
// read bytes
is.read(&result[0], static_cast<std::streamsize>(length));
// reset stream position
is.seekg(current_pos);
// reset stream flags
is.setstate(flags);
return result;
}
private:
/// the associated input stream
std::istream& is;
/// chars returned via get_character()
size_t processed_chars = 0;
/// chars processed in the current buffer
size_t buffer_pos = 0;
/// position of the stream when we started
const std::streampos start_position;
/// abstract input adapter interface
class input_adapter
/// internal buffer
std::vector<char> buffer;
};
/// input adapter for buffer input
class input_buffer_adapter : public input_adapter
{
public:
input_buffer_adapter(const char* b, size_t l)
: input_adapter(), cursor(b), limit(b + l), start(b)
{}
// delete because of pointer members
input_buffer_adapter(const input_buffer_adapter&) = delete;
input_buffer_adapter& operator=(input_buffer_adapter&) = delete;
int get_character() override
{
public:
virtual int get_character() = 0;
virtual std::string read(size_t offset, size_t length) = 0;
virtual ~input_adapter() {}
};
if (JSON_LIKELY(cursor < limit))
{
return *(cursor++) & 0xFF;
}
else
{
return std::char_traits<char>::eof();
}
}
/// input adapter for cached stream input
class cached_input_stream_adapter : public input_adapter
std::string read(size_t offset, size_t length) override
{
public:
cached_input_stream_adapter(std::istream& i, const size_t buffer_size)
: is(i), start_position(is.tellg()),
buffer(buffer_size, std::char_traits<char>::eof())
// avoid reading too many characters
const size_t max_length = static_cast<size_t>(limit - start);
return std::string(start + offset, std::min({length, max_length}));
}
private:
/// pointer to the current character
const char* cursor;
/// pointer past the last character
const char* limit;
/// pointer to the first character
const char* start;
};
////////////////////
// binary formats //
////////////////////
private:
class binary_reader
{
public:
explicit binary_reader(std::istream& i)
: ia(new cached_input_stream_adapter(i, 16384))
{}
binary_reader(const char* buff, const size_t len)
: ia(new input_buffer_adapter(buff, len))
{}
~binary_reader()
{
delete ia;
}
// switch off unwanted functions (due to pointer members)
binary_reader(const binary_reader&) = delete;
binary_reader operator=(const binary_reader&) = delete;
/*!
@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
*/
basic_json parse_cbor(const bool get_char = true)
{
switch (get_char ? get() : current)
{
// immediately abort if stream is erroneous
if (JSON_UNLIKELY(i.fail()))
// EOF
case std::char_traits<char>::eof():
{
JSON_THROW(parse_error::create(111, 0, "bad input stream"));
JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input"));
}
// initial fill; unfilled buffer characters remain EOF
is.read(buffer.data(), static_cast<std::streamsize>(buffer.size()));
// 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<number_unsigned_t>(current);
}
// skip byte-order mark
assert(buffer.size() >= 3);
if (buffer[0] == '\xEF' and buffer[1] == '\xBB' and buffer[2] == '\xBF')
case 0x18: // Unsigned integer (one-byte uint8_t follows)
{
buffer_pos += 3;
processed_chars += 3;
return get_number<uint8_t>();
}
}
~cached_input_stream_adapter() override
{
// clear stream flags
is.clear();
// set stream after last processed char
is.seekg(start_position + static_cast<std::streamoff>(processed_chars - 1));
}
case 0x19: // Unsigned integer (two-byte uint16_t follows)
{
return get_number<uint16_t>();
}
int get_character() override
{
// check if refilling is necessary
if (JSON_UNLIKELY(buffer_pos == buffer.size()))
case 0x1a: // Unsigned integer (four-byte uint32_t follows)
{
return get_number<uint32_t>();
}
case 0x1b: // Unsigned integer (eight-byte uint64_t follows)
{
return get_number<uint64_t>();
}
// 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<int8_t>(0x20 - 1 - current);
}
case 0x38: // Negative integer (one-byte uint8_t follows)
{
// must be uint8_t !
return static_cast<number_integer_t>(-1) - get_number<uint8_t>();
}
case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
{
return static_cast<number_integer_t>(-1) - get_number<uint16_t>();
}
case 0x3a: // Negative integer -1-n (four-byte uint32_t follows)
{
return static_cast<number_integer_t>(-1) - get_number<uint32_t>();
}
case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows)
{
return static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(get_number<uint64_t>());
}
// 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:
{
// refill
is.read(reinterpret_cast<char*>(buffer.data()), static_cast<std::streamsize>(buffer.size()));
// set unfilled characters to EOF
std::fill_n(buffer.begin() + static_cast<int>(is.gcount()),
buffer.size() - static_cast<size_t>(is.gcount()),
std::char_traits<char>::eof());
// the buffer is ready
buffer_pos = 0;
basic_json result = value_t::array;
const auto len = static_cast<size_t>(current - 0x80);
for (size_t i = 0; i < len; ++i)
{
result.push_back(parse_cbor());
}
return result;
}
++processed_chars;
return buffer[buffer_pos++];
}
case 0x98: // array (one-byte uint8_t for n follows)
{
basic_json result = value_t::array;
const auto len = static_cast<size_t>(get_number<uint8_t>());
for (size_t i = 0; i < len; ++i)
{
result.push_back(parse_cbor());
}
return result;
}
std::string read(size_t offset, size_t length) override
{
// create buffer
std::string result(length, '\0');
case 0x99: // array (two-byte uint16_t for n follow)
{
basic_json result = value_t::array;
const auto len = static_cast<size_t>(get_number<uint16_t>());
for (size_t i = 0; i < len; ++i)
{
result.push_back(parse_cbor());
}
return result;
}
// save stream position
auto current_pos = is.tellg();
// save stream flags
auto flags = is.rdstate();
case 0x9a: // array (four-byte uint32_t for n follow)
{
basic_json result = value_t::array;
const auto len = static_cast<size_t>(get_number<uint32_t>());
for (size_t i = 0; i < len; ++i)
{
result.push_back(parse_cbor());
}
return result;
}
// clear stream flags
is.clear();
// set stream position
is.seekg(static_cast<std::streamoff>(offset));
// read bytes
is.read(&result[0], static_cast<std::streamsize>(length));
case 0x9b: // array (eight-byte uint64_t for n follow)
{
basic_json result = value_t::array;
const auto len = static_cast<size_t>(get_number<uint64_t>());
for (size_t i = 0; i < len; ++i)
{
result.push_back(parse_cbor());
}
return result;
}
// reset stream position
is.seekg(current_pos);
// reset stream flags
is.setstate(flags);
case 0x9f: // array (indefinite length)
{
basic_json result = value_t::array;
while (get() != 0xff)
{
result.push_back(parse_cbor(false));
}
return result;
}
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:
{
basic_json result = value_t::object;
const auto len = static_cast<size_t>(current - 0xa0);
for (size_t i = 0; i < len; ++i)
{
get();
result[get_cbor_string()] = parse_cbor();
}
return result;
}
private:
/// the associated input stream
std::istream& is;
case 0xb8: // map (one-byte uint8_t for n follows)
{
basic_json result = value_t::object;
const auto len = static_cast<size_t>(get_number<uint8_t>());
for (size_t i = 0; i < len; ++i)
{
get();
result[get_cbor_string()] = parse_cbor();
}
return result;
}
/// chars returned via get_character()
size_t processed_chars = 0;
/// chars processed in the current buffer
size_t buffer_pos = 0;
case 0xb9: // map (two-byte uint16_t for n follow)
{
basic_json result = value_t::object;
const auto len = static_cast<size_t>(get_number<uint16_t>());
for (size_t i = 0; i < len; ++i)
{
get();
result[get_cbor_string()] = parse_cbor();
}
return result;
}
/// position of the stream when we started
const std::streampos start_position;
case 0xba: // map (four-byte uint32_t for n follow)
{
basic_json result = value_t::object;
const auto len = static_cast<size_t>(get_number<uint32_t>());
for (size_t i = 0; i < len; ++i)
{
get();
result[get_cbor_string()] = parse_cbor();
}
return result;
}
/// internal buffer
std::vector<char> buffer;
};
case 0xbb: // map (eight-byte uint64_t for n follow)
{
basic_json result = value_t::object;
const auto len = static_cast<size_t>(get_number<uint64_t>());
for (size_t i = 0; i < len; ++i)
{
get();
result[get_cbor_string()] = parse_cbor();
}
return result;
}
/// input adapter for uncached stream input
class input_stream_adapter : public input_adapter
{
public:
input_stream_adapter(std::istream& i)
: is(i)
{
// immediately abort if stream is erroneous
if (i.fail())
case 0xbf: // map (indefinite length)
{
JSON_THROW(parse_error::create(111, 0, "bad input stream"));
basic_json result = value_t::object;
while (get() != 0xff)
{
result[get_cbor_string()] = parse_cbor();
}
return result;
}
}
int get_character() override
{
return is.get();
}
case 0xf4: // false
{
return false;
}
std::string read(size_t offset, size_t length) override
{
// create buffer
std::string result(length, '\0');
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<double>::infinity()
: std::numeric_limits<double>::quiet_NaN();
}
return (half & 0x8000) != 0 ? -val : val;
}
// save stream position
auto current_pos = is.tellg();
// save stream flags
auto flags = is.rdstate();
case 0xfa: // Single-Precision Float (four-byte IEEE 754)
{
return get_number<float>();
}
// clear stream flags
is.clear();
// set stream position
is.seekg(offset);
// read bytes
is.read(&result[0], length);
case 0xfb: // Double-Precision Float (eight-byte IEEE 754)
{
return get_number<double>();
}
// reset stream position
is.seekg(current_pos);
// reset stream flags
is.setstate(flags);
default: // anything else (0xFF is handled inside the other types)
{
std::stringstream ss;
ss << std::hex << current;
JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str()));
}
}
}
return result;
private:
int get()
{
++chars_read;
return (current = ia->get_character());
}
// todo: check if this breaks with endianess
template<typename T>
T get_number()
{
std::array<uint8_t, sizeof(T)> vec;
for (size_t i = 0; i < sizeof(T); ++i)
{
get();
check_eof();
vec[sizeof(T) - i - 1] = static_cast<uint8_t>(current);
}
private:
/// the associated input stream
std::istream& is;
};
T result;
std::memcpy(&result, vec.data(), sizeof(T));
return result;
}
/// input adapter for buffer input
class input_buffer_adapter : public input_adapter
std::string get_string(const size_t len)
{
public:
input_buffer_adapter(const char* b, size_t l)
: input_adapter(), cursor(b), limit(b + l), start(b)
{}
std::string result;
for (size_t i = 0; i < len; ++i)
{
get();
check_eof();
result.append(1, static_cast<char>(current));
}
return result;
}
// delete because of pointer members
input_buffer_adapter(const input_buffer_adapter&) = delete;
input_buffer_adapter& operator=(input_buffer_adapter&) = delete;
std::string get_cbor_string()
{
check_eof();
int get_character() override
switch (current)
{
if (JSON_LIKELY(cursor < limit))
// 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:
{
return *cursor++;
const auto len = static_cast<size_t>(current - 0x60);
return get_string(len);
}
else
case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
{
const auto len = static_cast<size_t>(get_number<uint8_t>());
return get_string(len);
}
case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
{
return std::char_traits<char>::eof();
const auto len = static_cast<size_t>(get_number<uint16_t>());
return get_string(len);
}
case 0x7a: // UTF-8 string (four-byte uint32_t for n follow)
{
const auto len = static_cast<size_t>(get_number<uint32_t>());
return get_string(len);
}
case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow)
{
const auto len = static_cast<size_t>(get_number<uint64_t>());
return get_string(len);
}
case 0x7f: // UTF-8 string (indefinite length)
{
std::string result;
while (get() != 0xff)
{
check_eof();
result.append(1, static_cast<char>(current));
}
return result;
}
default:
{
std::stringstream ss;
ss << std::hex << current;
JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str()));
}
}
}
std::string read(size_t offset, size_t length) override
void check_eof()
{
if (JSON_UNLIKELY(current == std::char_traits<char>::eof()))
{
// avoid reading too many characters
const size_t max_length = static_cast<size_t>(limit - start);
return std::string(start + offset, std::min({length, max_length}));
JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input"));
}
}
private:
/// pointer to the current character
const char* cursor;
/// pointer past the last character
const char* limit;
/// pointer to the first character
const char* start;
};
private:
/// input adapter
input_adapter* ia = nullptr;
/// the current character
int current = std::char_traits<char>::eof();
/// the number of characters read
size_t chars_read = 0;
};
public:
static basic_json from_cbor(const std::vector<uint8_t>& v,
const size_t start_index = 0)
{
binary_reader br(reinterpret_cast<const char*>(v.data() + start_index), v.size() - start_index);
return br.parse_cbor();
}
//////////////////////
// lexer and parser //
//////////////////////
private:
/*!
@brief lexical analysis
This class organizes the lexical analysis during JSON deserialization.
*/
class lexer
{
public:
/// token types for the parser
enum class token_type
......@@ -11009,178 +11532,178 @@ class basic_json
}
// invalid control characters
case '\x00':
case '\x01':
case '\x02':
case '\x03':
case '\x04':
case '\x05':
case '\x06':
case '\x07':
case '\x08':
case '\x09':
case '\x0a':
case '\x0b':
case '\x0c':
case '\x0d':
case '\x0e':
case '\x0f':
case '\x10':
case '\x11':
case '\x12':
case '\x13':
case '\x14':
case '\x15':
case '\x16':
case '\x17':
case '\x18':
case '\x19':
case '\x1a':
case '\x1b':
case '\x1c':
case '\x1d':
case '\x1e':
case '\x1f':
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:
{
error_message = "invalid string: control characters (U+0000 through U+001f) must be escaped";
return token_type::parse_error;
}
// U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))
case '\x20':
case '\x21':
case '\x23':
case '\x24':
case '\x25':
case '\x26':
case '\x27':
case '\x28':
case '\x29':
case '\x2a':
case '\x2b':
case '\x2c':
case '\x2d':
case '\x2e':
case '\x2f':
case '\x30':
case '\x31':
case '\x32':
case '\x33':
case '\x34':
case '\x35':
case '\x36':
case '\x37':
case '\x38':
case '\x39':
case '\x3a':
case '\x3b':
case '\x3c':
case '\x3d':
case '\x3e':
case '\x3f':
case '\x40':
case '\x41':
case '\x42':
case '\x43':
case '\x44':
case '\x45':
case '\x46':
case '\x47':
case '\x48':
case '\x49':
case '\x4a':
case '\x4b':
case '\x4c':
case '\x4d':
case '\x4e':
case '\x4f':
case '\x50':
case '\x51':
case '\x52':
case '\x53':
case '\x54':
case '\x55':
case '\x56':
case '\x57':
case '\x58':
case '\x59':
case '\x5a':
case '\x5b':
case '\x5d':
case '\x5e':
case '\x5f':
case '\x60':
case '\x61':
case '\x62':
case '\x63':
case '\x64':
case '\x65':
case '\x66':
case '\x67':
case '\x68':
case '\x69':
case '\x6a':
case '\x6b':
case '\x6c':
case '\x6d':
case '\x6e':
case '\x6f':
case '\x70':
case '\x71':
case '\x72':
case '\x73':
case '\x74':
case '\x75':
case '\x76':
case '\x77':
case '\x78':
case '\x79':
case '\x7a':
case '\x7b':
case '\x7c':
case '\x7d':
case '\x7e':
case '\x7f':
case 0x20:
case 0x21:
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 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:
{
add(current);
break;
}
// U+0080..U+07FF: bytes C2..DF 80..BF
case '\xc2':
case '\xc3':
case '\xc4':
case '\xc5':
case '\xc6':
case '\xc7':
case '\xc8':
case '\xc9':
case '\xca':
case '\xcb':
case '\xcc':
case '\xcd':
case '\xce':
case '\xcf':
case '\xd0':
case '\xd1':
case '\xd2':
case '\xd3':
case '\xd4':
case '\xd5':
case '\xd6':
case '\xd7':
case '\xd8':
case '\xd9':
case '\xda':
case '\xdb':
case '\xdc':
case '\xdd':
case '\xde':
case '\xdf':
case 0xc2:
case 0xc3:
case 0xc4:
case 0xc5:
case 0xc6:
case 0xc7:
case 0xc8:
case 0xc9:
case 0xca:
case 0xcb:
case 0xcc:
case 0xcd:
case 0xce:
case 0xcf:
case 0xd0:
case 0xd1:
case 0xd2:
case 0xd3:
case 0xd4:
case 0xd5:
case 0xd6:
case 0xd7:
case 0xd8:
case 0xd9:
case 0xda:
case 0xdb:
case 0xdc:
case 0xdd:
case 0xde:
case 0xdf:
{
add(current);
get();
if (JSON_LIKELY('\x80' <= current and current <= '\xbf'))
if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
{
add(current);
continue;
......@@ -11191,15 +11714,15 @@ class basic_json
}
// U+0800..U+0FFF: bytes E0 A0..BF 80..BF
case '\xe0':
case 0xe0:
{
add(current);
get();
if (JSON_LIKELY('\xa0' <= current and current <= '\xbf'))
if (JSON_LIKELY(0xa0 <= current and current <= 0xbf))
{
add(current);
get();
if (JSON_LIKELY('\x80' <= current and current <= '\xbf'))
if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
{
add(current);
continue;
......@@ -11212,28 +11735,28 @@ class basic_json
// U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF
// U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF
case '\xe1':
case '\xe2':
case '\xe3':
case '\xe4':
case '\xe5':
case '\xe6':
case '\xe7':
case '\xe8':
case '\xe9':
case '\xea':
case '\xeb':
case '\xec':
case '\xee':
case '\xef':
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 0xee:
case 0xef:
{
add(current);
get();
if (JSON_LIKELY('\x80' <= current and current <= '\xbf'))
if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
{
add(current);
get();
if (JSON_LIKELY('\x80' <= current and current <= '\xbf'))
if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
{
add(current);
continue;
......@@ -11245,15 +11768,15 @@ class basic_json
}
// U+D000..U+D7FF: bytes ED 80..9F 80..BF
case '\xed':
case 0xed:
{
add(current);
get();
if (JSON_LIKELY('\x80' <= current and current <= '\x9f'))
if (JSON_LIKELY(0x80 <= current and current <= 0x9f))
{
add(current);
get();
if (JSON_LIKELY('\x80' <= current and current <= '\xbf'))
if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
{
add(current);
continue;
......@@ -11265,19 +11788,19 @@ class basic_json
}
// U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
case '\xf0':
case 0xf0:
{
add(current);
get();
if (JSON_LIKELY('\x90' <= current and current <= '\xbf'))
if (JSON_LIKELY(0x90 <= current and current <= 0xbf))
{
add(current);
get();
if (JSON_LIKELY('\x80' <= current and current <= '\xbf'))
if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
{
add(current);
get();
if (JSON_LIKELY('\x80' <= current and current <= '\xbf'))
if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
{
add(current);
continue;
......@@ -11290,21 +11813,21 @@ class basic_json
}
// U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
case '\xf1':
case '\xf2':
case '\xf3':
case 0xf1:
case 0xf2:
case 0xf3:
{
add(current);
get();
if (JSON_LIKELY('\x80' <= current and current <= '\xbf'))
if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
{
add(current);
get();
if (JSON_LIKELY('\x80' <= current and current <= '\xbf'))
if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
{
add(current);
get();
if (JSON_LIKELY('\x80' <= current and current <= '\xbf'))
if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
{
add(current);
continue;
......@@ -11317,19 +11840,19 @@ class basic_json
}
// U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
case '\xf4':
case 0xf4:
{
add(current);
get();
if (JSON_LIKELY('\x80' <= current and current <= '\x8f'))
if (JSON_LIKELY(0x80 <= current and current <= 0x8f))
{
add(current);
get();
if (JSON_LIKELY('\x80' <= current and current <= '\xbf'))
if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
{
add(current);
get();
if (JSON_LIKELY('\x80' <= current and current <= '\xbf'))
if (JSON_LIKELY(0x80 <= current and current <= 0xbf))
{
add(current);
continue;
......
......@@ -1166,35 +1166,35 @@ TEST_CASE("CBOR")
CHECK_THROWS_AS(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})), json::parse_error);
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x18})),
"[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector");
"[json.exception.parse_error.110] parse error at 2: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x19})),
"[json.exception.parse_error.110] parse error at 2: cannot read 2 bytes from vector");
"[json.exception.parse_error.110] parse error at 2: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x19, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 2 bytes from vector");
"[json.exception.parse_error.110] parse error at 3: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1a})),
"[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector");
"[json.exception.parse_error.110] parse error at 2: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1a, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector");
"[json.exception.parse_error.110] parse error at 3: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1a, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector");
"[json.exception.parse_error.110] parse error at 4: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1a, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector");
"[json.exception.parse_error.110] parse error at 5: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1b})),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
"[json.exception.parse_error.110] parse error at 2: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
"[json.exception.parse_error.110] parse error at 3: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
"[json.exception.parse_error.110] parse error at 4: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
"[json.exception.parse_error.110] parse error at 5: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
"[json.exception.parse_error.110] parse error at 6: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
"[json.exception.parse_error.110] parse error at 7: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
"[json.exception.parse_error.110] parse error at 8: unexpected end of input");
CHECK_THROWS_WITH(json::from_cbor(std::vector<uint8_t>({0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
"[json.exception.parse_error.110] parse error at 9: unexpected end of input");
}
SECTION("unsupported bytes")
......@@ -1756,7 +1756,7 @@ TEST_CASE("examples from RFC 7049 Appendix A")
CHECK(json::parse("\"\\ud800\\udd51\"") == json::from_cbor(std::vector<uint8_t>({0x64, 0xf0, 0x90, 0x85, 0x91})));
// indefinite length strings
CHECK(json::parse("\"streaming\"") == json::from_cbor(std::vector<uint8_t>({0x7f, 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x67, 0xff})));
CHECK(json::parse("\"streaming\"") == json::from_cbor(std::vector<uint8_t>({0x7f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0xff})));
}
SECTION("arrays")
......
......@@ -629,7 +629,7 @@ TEST_CASE("regression tests")
std::vector<uint8_t> vec {0x65, 0xf5, 0x0a, 0x48, 0x21};
CHECK_THROWS_AS(json::from_cbor(vec), json::parse_error);
CHECK_THROWS_WITH(json::from_cbor(vec),
"[json.exception.parse_error.110] parse error at 2: cannot read 5 bytes from vector");
"[json.exception.parse_error.110] parse error at 6: unexpected end of input");
}
SECTION("issue #407 - Heap-buffer-overflow (OSS-Fuzz issue 343)")
......@@ -650,19 +650,19 @@ TEST_CASE("regression tests")
std::vector<uint8_t> vec3 {0xf9, 0x8f};
CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error);
CHECK_THROWS_WITH(json::from_cbor(vec3),
"[json.exception.parse_error.110] parse error at 2: cannot read 2 bytes from vector");
"[json.exception.parse_error.110] parse error at 3: unexpected end of input");
// related test case: incomplete Single-Precision Float (CBOR)
std::vector<uint8_t> vec4 {0xfa, 0x8f, 0x0a};
CHECK_THROWS_AS(json::from_cbor(vec4), json::parse_error);
CHECK_THROWS_WITH(json::from_cbor(vec4),
"[json.exception.parse_error.110] parse error at 2: cannot read 4 bytes from vector");
"[json.exception.parse_error.110] parse error at 4: unexpected end of input");
// related test case: incomplete Double-Precision Float (CBOR)
std::vector<uint8_t> vec5 {0xfb, 0x8f, 0x0a};
CHECK_THROWS_AS(json::from_cbor(vec5), json::parse_error);
CHECK_THROWS_WITH(json::from_cbor(vec5),
"[json.exception.parse_error.110] parse error at 2: cannot read 8 bytes from vector");
"[json.exception.parse_error.110] parse error at 4: unexpected end of input");
}
SECTION("issue #408 - Heap-buffer-overflow (OSS-Fuzz issue 344)")
......@@ -705,7 +705,7 @@ TEST_CASE("regression tests")
std::vector<uint8_t> vec2;
CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error);
CHECK_THROWS_WITH(json::from_cbor(vec2),
"[json.exception.parse_error.110] parse error at 1: cannot read 1 bytes from vector");
"[json.exception.parse_error.110] parse error at 1: unexpected end of input");
CHECK_THROWS_AS(json::from_msgpack(vec2), json::parse_error);
CHECK_THROWS_WITH(json::from_msgpack(vec2),
"[json.exception.parse_error.110] parse error at 1: cannot read 1 bytes from vector");
......@@ -717,19 +717,19 @@ TEST_CASE("regression tests")
std::vector<uint8_t> vec1 {0x7f};
CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error);
CHECK_THROWS_WITH(json::from_cbor(vec1),
"[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector");
"[json.exception.parse_error.110] parse error at 2: unexpected end of input");
// related test case: empty array (indefinite length)
std::vector<uint8_t> vec2 {0x9f};
CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error);
CHECK_THROWS_WITH(json::from_cbor(vec2),
"[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector");
"[json.exception.parse_error.110] parse error at 2: unexpected end of input");
// related test case: empty map (indefinite length)
std::vector<uint8_t> vec3 {0xbf};
CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error);
CHECK_THROWS_WITH(json::from_cbor(vec3),
"[json.exception.parse_error.110] parse error at 2: cannot read 1 bytes from vector");
"[json.exception.parse_error.110] parse error at 2: unexpected end of input");
}
SECTION("issue #412 - Heap-buffer-overflow (OSS-Fuzz issue 367)")
......@@ -763,19 +763,19 @@ TEST_CASE("regression tests")
std::vector<uint8_t> vec1 {0x7f, 0x61, 0x61};
CHECK_THROWS_AS(json::from_cbor(vec1), json::parse_error);
CHECK_THROWS_WITH(json::from_cbor(vec1),
"[json.exception.parse_error.110] parse error at 4: cannot read 1 bytes from vector");
"[json.exception.parse_error.110] parse error at 4: unexpected end of input");
// related test case: nonempty array (indefinite length)
std::vector<uint8_t> vec2 {0x9f, 0x01};
CHECK_THROWS_AS(json::from_cbor(vec2), json::parse_error);
CHECK_THROWS_WITH(json::from_cbor(vec2),
"[json.exception.parse_error.110] parse error at 3: cannot read 1 bytes from vector");
"[json.exception.parse_error.110] parse error at 3: unexpected end of input");
// related test case: nonempty map (indefinite length)
std::vector<uint8_t> vec3 {0xbf, 0x61, 0x61, 0x01};
CHECK_THROWS_AS(json::from_cbor(vec3), json::parse_error);
CHECK_THROWS_WITH(json::from_cbor(vec3),
"[json.exception.parse_error.110] parse error at 5: cannot read 1 bytes from vector");
"[json.exception.parse_error.110] parse error at 5: unexpected end of input");
}
SECTION("issue #414 - compare with literal 0)")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment