Merge branch 'develop' of https://github.com/nlohmann/json into feature/bson
Conflicts: include/nlohmann/detail/input/binary_reader.hpp single_include/nlohmann/json.hpp src/unit-bson.cpp
This commit is contained in:
commit
2a63869159
110 changed files with 2497 additions and 1418 deletions
|
@ -104,7 +104,8 @@ class binary_reader
|
|||
|
||||
if (JSON_UNLIKELY(current != std::char_traits<char>::eof()))
|
||||
{
|
||||
return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read, "expected end of input"));
|
||||
return sax->parse_error(chars_read, get_token_string(),
|
||||
parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +140,7 @@ class binary_reader
|
|||
while (true)
|
||||
{
|
||||
get();
|
||||
if (JSON_UNLIKELY(not unexpect_eof()))
|
||||
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::bson, "cstring")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -165,7 +166,7 @@ class binary_reader
|
|||
template <typename NumberType>
|
||||
bool get_bson_string(const NumberType len, string_t& result)
|
||||
{
|
||||
return get_string(len - static_cast<NumberType>(1), result)
|
||||
return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result)
|
||||
&& get() != std::char_traits<char>::eof();
|
||||
}
|
||||
|
||||
|
@ -195,14 +196,14 @@ class binary_reader
|
|||
case 0x01: // double
|
||||
{
|
||||
double number;
|
||||
return get_number<double, true>(number)
|
||||
return get_number<double, true>(input_format_t::bson, number)
|
||||
&& sax->number_float(static_cast<number_float_t>(number), "");
|
||||
}
|
||||
case 0x02: // string
|
||||
{
|
||||
std::int32_t len;
|
||||
string_t value;
|
||||
return get_number<std::int32_t, true>(len)
|
||||
return get_number<std::int32_t, true>(input_format_t::bson, len)
|
||||
&& get_bson_string(len, value)
|
||||
&& sax->string(value);
|
||||
}
|
||||
|
@ -213,13 +214,13 @@ class binary_reader
|
|||
case 0x10: // int32
|
||||
{
|
||||
std::int32_t value;
|
||||
return get_number<std::int32_t, true>(value)
|
||||
return get_number<std::int32_t, true>(input_format_t::bson, value)
|
||||
&& sax->number_integer(static_cast<std::int32_t>(value));
|
||||
}
|
||||
case 0x12: // int64
|
||||
{
|
||||
std::int64_t value;
|
||||
return get_number<std::int64_t, true>(value)
|
||||
return get_number<std::int64_t, true>(input_format_t::bson, value)
|
||||
&& sax->number_integer(static_cast<std::int64_t>(value));
|
||||
}
|
||||
case 0x0A: // null
|
||||
|
@ -256,7 +257,7 @@ class binary_reader
|
|||
{
|
||||
while (auto element_type = get())
|
||||
{
|
||||
if (JSON_UNLIKELY(not unexpect_eof()))
|
||||
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::bson, "element list")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -288,7 +289,7 @@ class binary_reader
|
|||
bool parse_bson_array()
|
||||
{
|
||||
std::int32_t documentSize;
|
||||
get_number<std::int32_t, true>(documentSize);
|
||||
get_number<std::int32_t, true>(input_format_t::bson, documentSize);
|
||||
|
||||
if (JSON_UNLIKELY(not sax->start_array(-1)))
|
||||
{
|
||||
|
@ -310,7 +311,7 @@ class binary_reader
|
|||
bool parse_bson_internal()
|
||||
{
|
||||
std::int32_t documentSize;
|
||||
get_number<std::int32_t, true>(documentSize);
|
||||
get_number<std::int32_t, true>(input_format_t::bson, documentSize);
|
||||
|
||||
if (JSON_UNLIKELY(not sax->start_object(-1)))
|
||||
{
|
||||
|
@ -338,7 +339,7 @@ class binary_reader
|
|||
{
|
||||
// EOF
|
||||
case std::char_traits<char>::eof():
|
||||
return unexpect_eof();
|
||||
return unexpect_eof(input_format_t::cbor, "value");
|
||||
|
||||
// Integer 0x00..0x17 (0..23)
|
||||
case 0x00:
|
||||
|
@ -370,25 +371,25 @@ class binary_reader
|
|||
case 0x18: // Unsigned integer (one-byte uint8_t follows)
|
||||
{
|
||||
uint8_t number;
|
||||
return get_number(number) and sax->number_unsigned(number);
|
||||
return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
|
||||
}
|
||||
|
||||
case 0x19: // Unsigned integer (two-byte uint16_t follows)
|
||||
{
|
||||
uint16_t number;
|
||||
return get_number(number) and sax->number_unsigned(number);
|
||||
return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
|
||||
}
|
||||
|
||||
case 0x1A: // Unsigned integer (four-byte uint32_t follows)
|
||||
{
|
||||
uint32_t number;
|
||||
return get_number(number) and sax->number_unsigned(number);
|
||||
return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
|
||||
}
|
||||
|
||||
case 0x1B: // Unsigned integer (eight-byte uint64_t follows)
|
||||
{
|
||||
uint64_t number;
|
||||
return get_number(number) and sax->number_unsigned(number);
|
||||
return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
|
||||
}
|
||||
|
||||
// Negative integer -1-0x00..-1-0x17 (-1..-24)
|
||||
|
@ -421,25 +422,25 @@ class binary_reader
|
|||
case 0x38: // Negative integer (one-byte uint8_t follows)
|
||||
{
|
||||
uint8_t number;
|
||||
return get_number(number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
|
||||
return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
|
||||
}
|
||||
|
||||
case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
|
||||
{
|
||||
uint16_t number;
|
||||
return get_number(number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
|
||||
return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
|
||||
}
|
||||
|
||||
case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
|
||||
{
|
||||
uint32_t number;
|
||||
return get_number(number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
|
||||
return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
|
||||
}
|
||||
|
||||
case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
|
||||
{
|
||||
uint64_t number;
|
||||
return get_number(number) and sax->number_integer(static_cast<number_integer_t>(-1)
|
||||
return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1)
|
||||
- static_cast<number_integer_t>(number));
|
||||
}
|
||||
|
||||
|
@ -508,25 +509,25 @@ class binary_reader
|
|||
case 0x98: // array (one-byte uint8_t for n follows)
|
||||
{
|
||||
uint8_t len;
|
||||
return get_number(len) and get_cbor_array(static_cast<std::size_t>(len));
|
||||
return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
|
||||
}
|
||||
|
||||
case 0x99: // array (two-byte uint16_t for n follow)
|
||||
{
|
||||
uint16_t len;
|
||||
return get_number(len) and get_cbor_array(static_cast<std::size_t>(len));
|
||||
return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
|
||||
}
|
||||
|
||||
case 0x9A: // array (four-byte uint32_t for n follow)
|
||||
{
|
||||
uint32_t len;
|
||||
return get_number(len) and get_cbor_array(static_cast<std::size_t>(len));
|
||||
return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
|
||||
}
|
||||
|
||||
case 0x9B: // array (eight-byte uint64_t for n follow)
|
||||
{
|
||||
uint64_t len;
|
||||
return get_number(len) and get_cbor_array(static_cast<std::size_t>(len));
|
||||
return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
|
||||
}
|
||||
|
||||
case 0x9F: // array (indefinite length)
|
||||
|
@ -562,25 +563,25 @@ class binary_reader
|
|||
case 0xB8: // map (one-byte uint8_t for n follows)
|
||||
{
|
||||
uint8_t len;
|
||||
return get_number(len) and get_cbor_object(static_cast<std::size_t>(len));
|
||||
return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
|
||||
}
|
||||
|
||||
case 0xB9: // map (two-byte uint16_t for n follow)
|
||||
{
|
||||
uint16_t len;
|
||||
return get_number(len) and get_cbor_object(static_cast<std::size_t>(len));
|
||||
return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
|
||||
}
|
||||
|
||||
case 0xBA: // map (four-byte uint32_t for n follow)
|
||||
{
|
||||
uint32_t len;
|
||||
return get_number(len) and get_cbor_object(static_cast<std::size_t>(len));
|
||||
return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
|
||||
}
|
||||
|
||||
case 0xBB: // map (eight-byte uint64_t for n follow)
|
||||
{
|
||||
uint64_t len;
|
||||
return get_number(len) and get_cbor_object(static_cast<std::size_t>(len));
|
||||
return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
|
||||
}
|
||||
|
||||
case 0xBF: // map (indefinite length)
|
||||
|
@ -597,17 +598,20 @@ class binary_reader
|
|||
|
||||
case 0xF9: // Half-Precision Float (two-byte IEEE 754)
|
||||
{
|
||||
const int byte1 = get();
|
||||
if (JSON_UNLIKELY(not unexpect_eof()))
|
||||
const int byte1_raw = get();
|
||||
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, "number")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const int byte2 = get();
|
||||
if (JSON_UNLIKELY(not unexpect_eof()))
|
||||
const int byte2_raw = get();
|
||||
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, "number")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto byte1 = static_cast<unsigned char>(byte1_raw);
|
||||
const auto byte2 = static_cast<unsigned char>(byte2_raw);
|
||||
|
||||
// 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
|
||||
|
@ -643,19 +647,19 @@ class binary_reader
|
|||
case 0xFA: // Single-Precision Float (four-byte IEEE 754)
|
||||
{
|
||||
float number;
|
||||
return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
|
||||
return get_number(input_format_t::cbor, number) and sax->number_float(static_cast<number_float_t>(number), "");
|
||||
}
|
||||
|
||||
case 0xFB: // Double-Precision Float (eight-byte IEEE 754)
|
||||
{
|
||||
double number;
|
||||
return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
|
||||
return get_number(input_format_t::cbor, number) and sax->number_float(static_cast<number_float_t>(number), "");
|
||||
}
|
||||
|
||||
default: // anything else (0xFF is handled inside the other types)
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + last_token));
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -669,7 +673,7 @@ class binary_reader
|
|||
{
|
||||
// EOF
|
||||
case std::char_traits<char>::eof():
|
||||
return unexpect_eof();
|
||||
return unexpect_eof(input_format_t::msgpack, "value");
|
||||
|
||||
// positive fixint
|
||||
case 0x00:
|
||||
|
@ -890,61 +894,61 @@ class binary_reader
|
|||
case 0xCA: // float 32
|
||||
{
|
||||
float number;
|
||||
return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
|
||||
return get_number(input_format_t::msgpack, number) and sax->number_float(static_cast<number_float_t>(number), "");
|
||||
}
|
||||
|
||||
case 0xCB: // float 64
|
||||
{
|
||||
double number;
|
||||
return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
|
||||
return get_number(input_format_t::msgpack, number) and sax->number_float(static_cast<number_float_t>(number), "");
|
||||
}
|
||||
|
||||
case 0xCC: // uint 8
|
||||
{
|
||||
uint8_t number;
|
||||
return get_number(number) and sax->number_unsigned(number);
|
||||
return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
|
||||
}
|
||||
|
||||
case 0xCD: // uint 16
|
||||
{
|
||||
uint16_t number;
|
||||
return get_number(number) and sax->number_unsigned(number);
|
||||
return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
|
||||
}
|
||||
|
||||
case 0xCE: // uint 32
|
||||
{
|
||||
uint32_t number;
|
||||
return get_number(number) and sax->number_unsigned(number);
|
||||
return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
|
||||
}
|
||||
|
||||
case 0xCF: // uint 64
|
||||
{
|
||||
uint64_t number;
|
||||
return get_number(number) and sax->number_unsigned(number);
|
||||
return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
|
||||
}
|
||||
|
||||
case 0xD0: // int 8
|
||||
{
|
||||
int8_t number;
|
||||
return get_number(number) and sax->number_integer(number);
|
||||
return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
|
||||
}
|
||||
|
||||
case 0xD1: // int 16
|
||||
{
|
||||
int16_t number;
|
||||
return get_number(number) and sax->number_integer(number);
|
||||
return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
|
||||
}
|
||||
|
||||
case 0xD2: // int 32
|
||||
{
|
||||
int32_t number;
|
||||
return get_number(number) and sax->number_integer(number);
|
||||
return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
|
||||
}
|
||||
|
||||
case 0xD3: // int 64
|
||||
{
|
||||
int64_t number;
|
||||
return get_number(number) and sax->number_integer(number);
|
||||
return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
|
||||
}
|
||||
|
||||
case 0xD9: // str 8
|
||||
|
@ -958,25 +962,25 @@ class binary_reader
|
|||
case 0xDC: // array 16
|
||||
{
|
||||
uint16_t len;
|
||||
return get_number(len) and get_msgpack_array(static_cast<std::size_t>(len));
|
||||
return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len));
|
||||
}
|
||||
|
||||
case 0xDD: // array 32
|
||||
{
|
||||
uint32_t len;
|
||||
return get_number(len) and get_msgpack_array(static_cast<std::size_t>(len));
|
||||
return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len));
|
||||
}
|
||||
|
||||
case 0xDE: // map 16
|
||||
{
|
||||
uint16_t len;
|
||||
return get_number(len) and get_msgpack_object(static_cast<std::size_t>(len));
|
||||
return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len));
|
||||
}
|
||||
|
||||
case 0xDF: // map 32
|
||||
{
|
||||
uint32_t len;
|
||||
return get_number(len) and get_msgpack_object(static_cast<std::size_t>(len));
|
||||
return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len));
|
||||
}
|
||||
|
||||
// negative fixint
|
||||
|
@ -1017,7 +1021,7 @@ class binary_reader
|
|||
default: // anything else
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "error reading MessagePack; last byte: 0x" + last_token));
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, "invalid byte: 0x" + last_token, "value")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1067,6 +1071,7 @@ class binary_reader
|
|||
@brief read a number from the input
|
||||
|
||||
@tparam NumberType the type of the number
|
||||
@param[in] format the current format (for diagnostics)
|
||||
@param[out] result number of type @a NumberType
|
||||
|
||||
@return whether conversion completed
|
||||
|
@ -1076,14 +1081,14 @@ class binary_reader
|
|||
(big endian) and therefore need reordering on little endian systems.
|
||||
*/
|
||||
template<typename NumberType, bool InputIsLittleEndian = false>
|
||||
bool get_number(NumberType& result)
|
||||
bool get_number(const input_format_t format, NumberType& result)
|
||||
{
|
||||
// step 1: read input into array with system's byte order
|
||||
std::array<uint8_t, sizeof(NumberType)> vec;
|
||||
for (std::size_t i = 0; i < sizeof(NumberType); ++i)
|
||||
{
|
||||
get();
|
||||
if (JSON_UNLIKELY(not unexpect_eof()))
|
||||
if (JSON_UNLIKELY(not unexpect_eof(format, "number")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1109,8 +1114,9 @@ class binary_reader
|
|||
@brief create a string by reading characters from the input
|
||||
|
||||
@tparam NumberType the type of the number
|
||||
@param[in] format the current format (for diagnostics)
|
||||
@param[in] len number of characters to read
|
||||
@param[out] string created by reading @a len bytes
|
||||
@param[out] result string created by reading @a len bytes
|
||||
|
||||
@return whether string creation completed
|
||||
|
||||
|
@ -1119,13 +1125,13 @@ class binary_reader
|
|||
the input before we run out of string memory.
|
||||
*/
|
||||
template<typename NumberType>
|
||||
bool get_string(const NumberType len, string_t& result)
|
||||
bool get_string(const input_format_t format, const NumberType len, string_t& result)
|
||||
{
|
||||
bool success = true;
|
||||
std::generate_n(std::back_inserter(result), len, [this, &success]()
|
||||
std::generate_n(std::back_inserter(result), len, [this, &success, &format]()
|
||||
{
|
||||
get();
|
||||
if (JSON_UNLIKELY(not unexpect_eof()))
|
||||
if (JSON_UNLIKELY(not unexpect_eof(format, "string")))
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
|
@ -1147,7 +1153,7 @@ class binary_reader
|
|||
*/
|
||||
bool get_cbor_string(string_t& result)
|
||||
{
|
||||
if (JSON_UNLIKELY(not unexpect_eof()))
|
||||
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, "string")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1180,31 +1186,31 @@ class binary_reader
|
|||
case 0x76:
|
||||
case 0x77:
|
||||
{
|
||||
return get_string(current & 0x1F, result);
|
||||
return get_string(input_format_t::cbor, current & 0x1F, result);
|
||||
}
|
||||
|
||||
case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
|
||||
{
|
||||
uint8_t len;
|
||||
return get_number(len) and get_string(len, result);
|
||||
return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
|
||||
}
|
||||
|
||||
case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
|
||||
{
|
||||
uint16_t len;
|
||||
return get_number(len) and get_string(len, result);
|
||||
return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
|
||||
}
|
||||
|
||||
case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
|
||||
{
|
||||
uint32_t len;
|
||||
return get_number(len) and get_string(len, result);
|
||||
return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
|
||||
}
|
||||
|
||||
case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
|
||||
{
|
||||
uint64_t len;
|
||||
return get_number(len) and get_string(len, result);
|
||||
return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
|
||||
}
|
||||
|
||||
case 0x7F: // UTF-8 string (indefinite length)
|
||||
|
@ -1224,7 +1230,7 @@ class binary_reader
|
|||
default:
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + last_token));
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x" + last_token, "string")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1242,6 +1248,7 @@ class binary_reader
|
|||
}
|
||||
|
||||
if (len != std::size_t(-1))
|
||||
{
|
||||
for (std::size_t i = 0; i < len; ++i)
|
||||
{
|
||||
if (JSON_UNLIKELY(not parse_cbor_internal()))
|
||||
|
@ -1249,6 +1256,7 @@ class binary_reader
|
|||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (get() != 0xFF)
|
||||
|
@ -1325,7 +1333,7 @@ class binary_reader
|
|||
*/
|
||||
bool get_msgpack_string(string_t& result)
|
||||
{
|
||||
if (JSON_UNLIKELY(not unexpect_eof()))
|
||||
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::msgpack, "string")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1366,31 +1374,31 @@ class binary_reader
|
|||
case 0xBE:
|
||||
case 0xBF:
|
||||
{
|
||||
return get_string(current & 0x1F, result);
|
||||
return get_string(input_format_t::msgpack, current & 0x1F, result);
|
||||
}
|
||||
|
||||
case 0xD9: // str 8
|
||||
{
|
||||
uint8_t len;
|
||||
return get_number(len) and get_string(len, result);
|
||||
return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);
|
||||
}
|
||||
|
||||
case 0xDA: // str 16
|
||||
{
|
||||
uint16_t len;
|
||||
return get_number(len) and get_string(len, result);
|
||||
return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);
|
||||
}
|
||||
|
||||
case 0xDB: // str 32
|
||||
{
|
||||
uint32_t len;
|
||||
return get_number(len) and get_string(len, result);
|
||||
return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "expected a MessagePack string; last byte: 0x" + last_token));
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, "expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x" + last_token, "string")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1468,7 +1476,7 @@ class binary_reader
|
|||
get(); // TODO: may we ignore N here?
|
||||
}
|
||||
|
||||
if (JSON_UNLIKELY(not unexpect_eof()))
|
||||
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1478,36 +1486,36 @@ class binary_reader
|
|||
case 'U':
|
||||
{
|
||||
uint8_t len;
|
||||
return get_number(len) and get_string(len, result);
|
||||
return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
|
||||
}
|
||||
|
||||
case 'i':
|
||||
{
|
||||
int8_t len;
|
||||
return get_number(len) and get_string(len, result);
|
||||
return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
|
||||
}
|
||||
|
||||
case 'I':
|
||||
{
|
||||
int16_t len;
|
||||
return get_number(len) and get_string(len, result);
|
||||
return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
|
||||
}
|
||||
|
||||
case 'l':
|
||||
{
|
||||
int32_t len;
|
||||
return get_number(len) and get_string(len, result);
|
||||
return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
|
||||
}
|
||||
|
||||
case 'L':
|
||||
{
|
||||
int64_t len;
|
||||
return get_number(len) and get_string(len, result);
|
||||
return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
|
||||
}
|
||||
|
||||
default:
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "expected a UBJSON string; last byte: 0x" + last_token));
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1522,7 +1530,7 @@ class binary_reader
|
|||
case 'U':
|
||||
{
|
||||
uint8_t number;
|
||||
if (JSON_UNLIKELY(not get_number(number)))
|
||||
if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1533,7 +1541,7 @@ class binary_reader
|
|||
case 'i':
|
||||
{
|
||||
int8_t number;
|
||||
if (JSON_UNLIKELY(not get_number(number)))
|
||||
if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1544,7 +1552,7 @@ class binary_reader
|
|||
case 'I':
|
||||
{
|
||||
int16_t number;
|
||||
if (JSON_UNLIKELY(not get_number(number)))
|
||||
if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1555,7 +1563,7 @@ class binary_reader
|
|||
case 'l':
|
||||
{
|
||||
int32_t number;
|
||||
if (JSON_UNLIKELY(not get_number(number)))
|
||||
if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1566,7 +1574,7 @@ class binary_reader
|
|||
case 'L':
|
||||
{
|
||||
int64_t number;
|
||||
if (JSON_UNLIKELY(not get_number(number)))
|
||||
if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1577,7 +1585,7 @@ class binary_reader
|
|||
default:
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "byte after '#' must denote a number type; last byte: 0x" + last_token));
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1602,7 +1610,7 @@ class binary_reader
|
|||
if (current == '$')
|
||||
{
|
||||
result.second = get(); // must not ignore 'N', because 'N' maybe the type
|
||||
if (JSON_UNLIKELY(not unexpect_eof()))
|
||||
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "type")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1610,12 +1618,12 @@ class binary_reader
|
|||
get_ignore_noop();
|
||||
if (JSON_UNLIKELY(current != '#'))
|
||||
{
|
||||
if (JSON_UNLIKELY(not unexpect_eof()))
|
||||
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "expected '#' after UBJSON type information; last byte: 0x" + last_token));
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "expected '#' after type information; last byte: 0x" + last_token, "size")));
|
||||
}
|
||||
|
||||
return get_ubjson_size_value(result.first);
|
||||
|
@ -1636,7 +1644,7 @@ class binary_reader
|
|||
switch (prefix)
|
||||
{
|
||||
case std::char_traits<char>::eof(): // EOF
|
||||
return unexpect_eof();
|
||||
return unexpect_eof(input_format_t::ubjson, "value");
|
||||
|
||||
case 'T': // true
|
||||
return sax->boolean(true);
|
||||
|
@ -1649,56 +1657,56 @@ class binary_reader
|
|||
case 'U':
|
||||
{
|
||||
uint8_t number;
|
||||
return get_number(number) and sax->number_unsigned(number);
|
||||
return get_number(input_format_t::ubjson, number) and sax->number_unsigned(number);
|
||||
}
|
||||
|
||||
case 'i':
|
||||
{
|
||||
int8_t number;
|
||||
return get_number(number) and sax->number_integer(number);
|
||||
return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
|
||||
}
|
||||
|
||||
case 'I':
|
||||
{
|
||||
int16_t number;
|
||||
return get_number(number) and sax->number_integer(number);
|
||||
return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
|
||||
}
|
||||
|
||||
case 'l':
|
||||
{
|
||||
int32_t number;
|
||||
return get_number(number) and sax->number_integer(number);
|
||||
return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
|
||||
}
|
||||
|
||||
case 'L':
|
||||
{
|
||||
int64_t number;
|
||||
return get_number(number) and sax->number_integer(number);
|
||||
return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
|
||||
}
|
||||
|
||||
case 'd':
|
||||
{
|
||||
float number;
|
||||
return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
|
||||
return get_number(input_format_t::ubjson, number) and sax->number_float(static_cast<number_float_t>(number), "");
|
||||
}
|
||||
|
||||
case 'D':
|
||||
{
|
||||
double number;
|
||||
return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
|
||||
return get_number(input_format_t::ubjson, number) and sax->number_float(static_cast<number_float_t>(number), "");
|
||||
}
|
||||
|
||||
case 'C': // char
|
||||
{
|
||||
get();
|
||||
if (JSON_UNLIKELY(not unexpect_eof()))
|
||||
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "char")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (JSON_UNLIKELY(current > 127))
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token));
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char")));
|
||||
}
|
||||
string_t s(1, static_cast<char>(current));
|
||||
return sax->string(s);
|
||||
|
@ -1719,7 +1727,7 @@ class binary_reader
|
|||
default: // anything else
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "error reading UBJSON; last byte: 0x" + last_token));
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "invalid byte: 0x" + last_token, "value")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1862,13 +1870,16 @@ class binary_reader
|
|||
}
|
||||
|
||||
/*!
|
||||
@param[in] format the current format (for diagnostics)
|
||||
@param[in] context further context information (for diagnostics)
|
||||
@return whether the last read character is not EOF
|
||||
*/
|
||||
bool unexpect_eof() const
|
||||
bool unexpect_eof(const input_format_t format, const char* context) const
|
||||
{
|
||||
if (JSON_UNLIKELY(current == std::char_traits<char>::eof()))
|
||||
{
|
||||
return sax->parse_error(chars_read, "<end of file>", parse_error::create(110, chars_read, "unexpected end of input"));
|
||||
return sax->parse_error(chars_read, "<end of file>",
|
||||
parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1884,6 +1895,45 @@ class binary_reader
|
|||
}
|
||||
|
||||
private:
|
||||
/*!
|
||||
@param[in] format the current format
|
||||
@param[in] detail a detailed error message
|
||||
@param[in] context further contect information
|
||||
@return a message string to use in the parse_error exceptions
|
||||
*/
|
||||
std::string exception_message(const input_format_t format,
|
||||
const std::string& detail,
|
||||
const std::string& context) const
|
||||
{
|
||||
std::string error_msg = "syntax error while parsing ";
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case input_format_t::cbor:
|
||||
error_msg += "CBOR";
|
||||
break;
|
||||
|
||||
case input_format_t::msgpack:
|
||||
error_msg += "MessagePack";
|
||||
break;
|
||||
|
||||
case input_format_t::ubjson:
|
||||
error_msg += "UBJSON";
|
||||
break;
|
||||
|
||||
case input_format_t::bson:
|
||||
error_msg += "BSON";
|
||||
break;
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
assert(false);
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return error_msg + " " + context + ": " + detail;
|
||||
}
|
||||
|
||||
/// input adapter
|
||||
input_adapter_t ia = nullptr;
|
||||
|
||||
|
@ -1899,5 +1949,5 @@ class binary_reader
|
|||
/// the SAX parser
|
||||
json_sax_t* sax = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
|
|
@ -71,6 +71,8 @@ class input_stream_adapter : public input_adapter_protocol
|
|||
// delete because of pointer members
|
||||
input_stream_adapter(const input_stream_adapter&) = delete;
|
||||
input_stream_adapter& operator=(input_stream_adapter&) = delete;
|
||||
input_stream_adapter(input_stream_adapter&&) = delete;
|
||||
input_stream_adapter& operator=(input_stream_adapter&&) = delete;
|
||||
|
||||
// std::istream/std::streambuf use std::char_traits<char>::to_int_type, to
|
||||
// ensure that std::char_traits<char>::eof() and the character 0xFF do not
|
||||
|
@ -97,6 +99,9 @@ class input_buffer_adapter : public input_adapter_protocol
|
|||
// delete because of pointer members
|
||||
input_buffer_adapter(const input_buffer_adapter&) = delete;
|
||||
input_buffer_adapter& operator=(input_buffer_adapter&) = delete;
|
||||
input_buffer_adapter(input_buffer_adapter&&) = delete;
|
||||
input_buffer_adapter& operator=(input_buffer_adapter&&) = delete;
|
||||
~input_buffer_adapter() override = default;
|
||||
|
||||
std::char_traits<char>::int_type get_character() noexcept override
|
||||
{
|
||||
|
@ -115,38 +120,11 @@ class input_buffer_adapter : public input_adapter_protocol
|
|||
const char* const limit;
|
||||
};
|
||||
|
||||
template<typename WideStringType>
|
||||
class wide_string_input_adapter : public input_adapter_protocol
|
||||
template<typename WideStringType, size_t T>
|
||||
struct wide_string_input_helper
|
||||
{
|
||||
public:
|
||||
explicit wide_string_input_adapter(const WideStringType& w) : str(w) {}
|
||||
|
||||
std::char_traits<char>::int_type get_character() noexcept override
|
||||
{
|
||||
// check if buffer needs to be filled
|
||||
if (utf8_bytes_index == utf8_bytes_filled)
|
||||
{
|
||||
if (sizeof(typename WideStringType::value_type) == 2)
|
||||
{
|
||||
fill_buffer_utf16();
|
||||
}
|
||||
else
|
||||
{
|
||||
fill_buffer_utf32();
|
||||
}
|
||||
|
||||
assert(utf8_bytes_filled > 0);
|
||||
assert(utf8_bytes_index == 0);
|
||||
}
|
||||
|
||||
// use buffer
|
||||
assert(utf8_bytes_filled > 0);
|
||||
assert(utf8_bytes_index < utf8_bytes_filled);
|
||||
return utf8_bytes[utf8_bytes_index++];
|
||||
}
|
||||
|
||||
private:
|
||||
void fill_buffer_utf16()
|
||||
// UTF-32
|
||||
static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled)
|
||||
{
|
||||
utf8_bytes_index = 0;
|
||||
|
||||
|
@ -158,7 +136,62 @@ class wide_string_input_adapter : public input_adapter_protocol
|
|||
else
|
||||
{
|
||||
// get the current character
|
||||
const int wc = static_cast<int>(str[current_wchar++]);
|
||||
const auto wc = static_cast<int>(str[current_wchar++]);
|
||||
|
||||
// UTF-32 to UTF-8 encoding
|
||||
if (wc < 0x80)
|
||||
{
|
||||
utf8_bytes[0] = wc;
|
||||
utf8_bytes_filled = 1;
|
||||
}
|
||||
else if (wc <= 0x7FF)
|
||||
{
|
||||
utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F);
|
||||
utf8_bytes[1] = 0x80 | (wc & 0x3F);
|
||||
utf8_bytes_filled = 2;
|
||||
}
|
||||
else if (wc <= 0xFFFF)
|
||||
{
|
||||
utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F);
|
||||
utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);
|
||||
utf8_bytes[2] = 0x80 | (wc & 0x3F);
|
||||
utf8_bytes_filled = 3;
|
||||
}
|
||||
else if (wc <= 0x10FFFF)
|
||||
{
|
||||
utf8_bytes[0] = 0xF0 | ((wc >> 18) & 0x07);
|
||||
utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F);
|
||||
utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F);
|
||||
utf8_bytes[3] = 0x80 | (wc & 0x3F);
|
||||
utf8_bytes_filled = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown character
|
||||
utf8_bytes[0] = wc;
|
||||
utf8_bytes_filled = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename WideStringType>
|
||||
struct wide_string_input_helper<WideStringType, 2>
|
||||
{
|
||||
// UTF-16
|
||||
static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled)
|
||||
{
|
||||
utf8_bytes_index = 0;
|
||||
|
||||
if (current_wchar == str.size())
|
||||
{
|
||||
utf8_bytes[0] = std::char_traits<char>::eof();
|
||||
utf8_bytes_filled = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get the current character
|
||||
const auto wc = static_cast<int>(str[current_wchar++]);
|
||||
|
||||
// UTF-16 to UTF-8 encoding
|
||||
if (wc < 0x80)
|
||||
|
@ -183,7 +216,7 @@ class wide_string_input_adapter : public input_adapter_protocol
|
|||
{
|
||||
if (current_wchar < str.size())
|
||||
{
|
||||
const int wc2 = static_cast<int>(str[current_wchar++]);
|
||||
const auto wc2 = static_cast<int>(str[current_wchar++]);
|
||||
const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF));
|
||||
utf8_bytes[0] = 0xf0 | (charcode >> 18);
|
||||
utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F);
|
||||
|
@ -201,58 +234,38 @@ class wide_string_input_adapter : public input_adapter_protocol
|
|||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void fill_buffer_utf32()
|
||||
template<typename WideStringType>
|
||||
class wide_string_input_adapter : public input_adapter_protocol
|
||||
{
|
||||
public:
|
||||
explicit wide_string_input_adapter(const WideStringType& w) : str(w) {}
|
||||
|
||||
std::char_traits<char>::int_type get_character() noexcept override
|
||||
{
|
||||
utf8_bytes_index = 0;
|
||||
|
||||
if (current_wchar == str.size())
|
||||
// check if buffer needs to be filled
|
||||
if (utf8_bytes_index == utf8_bytes_filled)
|
||||
{
|
||||
utf8_bytes[0] = std::char_traits<char>::eof();
|
||||
utf8_bytes_filled = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// get the current character
|
||||
const int wc = static_cast<int>(str[current_wchar++]);
|
||||
fill_buffer<sizeof(typename WideStringType::value_type)>();
|
||||
|
||||
// UTF-32 to UTF-8 encoding
|
||||
if (wc < 0x80)
|
||||
{
|
||||
utf8_bytes[0] = wc;
|
||||
utf8_bytes_filled = 1;
|
||||
}
|
||||
else if (wc <= 0x7FF)
|
||||
{
|
||||
utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F);
|
||||
utf8_bytes[1] = 0x80 | (wc & 0x3F);
|
||||
utf8_bytes_filled = 2;
|
||||
}
|
||||
else if (wc <= 0xFFFF)
|
||||
{
|
||||
utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F);
|
||||
utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);
|
||||
utf8_bytes[2] = 0x80 | (wc & 0x3F);
|
||||
utf8_bytes_filled = 3;
|
||||
}
|
||||
else if (wc <= 0x10FFFF)
|
||||
{
|
||||
utf8_bytes[0] = 0xF0 | ((wc >> 18 ) & 0x07);
|
||||
utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F);
|
||||
utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F);
|
||||
utf8_bytes[3] = 0x80 | (wc & 0x3F);
|
||||
utf8_bytes_filled = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown character
|
||||
utf8_bytes[0] = wc;
|
||||
utf8_bytes_filled = 1;
|
||||
}
|
||||
assert(utf8_bytes_filled > 0);
|
||||
assert(utf8_bytes_index == 0);
|
||||
}
|
||||
|
||||
// use buffer
|
||||
assert(utf8_bytes_filled > 0);
|
||||
assert(utf8_bytes_index < utf8_bytes_filled);
|
||||
return utf8_bytes[utf8_bytes_index++];
|
||||
}
|
||||
|
||||
private:
|
||||
template<size_t T>
|
||||
void fill_buffer()
|
||||
{
|
||||
wide_string_input_helper<WideStringType, T>::fill_buffer(str, current_wchar, utf8_bytes, utf8_bytes_index, utf8_bytes_filled);
|
||||
}
|
||||
|
||||
/// the wstring to process
|
||||
const WideStringType& str;
|
||||
|
||||
|
@ -373,5 +386,5 @@ class input_adapter
|
|||
/// the actual adapter
|
||||
input_adapter_t ia = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
|
|
@ -113,7 +113,7 @@ struct json_sax
|
|||
@brief a parse error occurred
|
||||
@param[in] position the position in the input where the error occurs
|
||||
@param[in] last_token the last read token
|
||||
@param[in] error_msg a detailed error message
|
||||
@param[in] ex an exception object describing the error
|
||||
@return whether parsing should proceed (must return false)
|
||||
*/
|
||||
virtual bool parse_error(std::size_t position,
|
||||
|
@ -181,7 +181,7 @@ class json_sax_dom_parser
|
|||
return true;
|
||||
}
|
||||
|
||||
bool number_float(number_float_t val, const string_t&)
|
||||
bool number_float(number_float_t val, const string_t& /*unused*/)
|
||||
{
|
||||
handle_value(val);
|
||||
return true;
|
||||
|
@ -238,7 +238,7 @@ class json_sax_dom_parser
|
|||
return true;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t, const std::string&,
|
||||
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
|
||||
const detail::exception& ex)
|
||||
{
|
||||
errored = true;
|
||||
|
@ -286,20 +286,19 @@ class json_sax_dom_parser
|
|||
root = BasicJsonType(std::forward<Value>(v));
|
||||
return &root;
|
||||
}
|
||||
|
||||
assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
|
||||
|
||||
if (ref_stack.back()->is_array())
|
||||
{
|
||||
ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
|
||||
return &(ref_stack.back()->m_value.array->back());
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
|
||||
if (ref_stack.back()->is_array())
|
||||
{
|
||||
ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
|
||||
return &(ref_stack.back()->m_value.array->back());
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(object_element);
|
||||
*object_element = BasicJsonType(std::forward<Value>(v));
|
||||
return object_element;
|
||||
}
|
||||
assert(object_element);
|
||||
*object_element = BasicJsonType(std::forward<Value>(v));
|
||||
return object_element;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -358,7 +357,7 @@ class json_sax_dom_callback_parser
|
|||
return true;
|
||||
}
|
||||
|
||||
bool number_float(number_float_t val, const string_t&)
|
||||
bool number_float(number_float_t val, const string_t& /*unused*/)
|
||||
{
|
||||
handle_value(val);
|
||||
return true;
|
||||
|
@ -496,7 +495,7 @@ class json_sax_dom_callback_parser
|
|||
return true;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t, const std::string&,
|
||||
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
|
||||
const detail::exception& ex)
|
||||
{
|
||||
errored = true;
|
||||
|
@ -574,37 +573,37 @@ class json_sax_dom_callback_parser
|
|||
root = std::move(value);
|
||||
return {true, &root};
|
||||
}
|
||||
|
||||
// skip this value if we already decided to skip the parent
|
||||
// (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
|
||||
if (not ref_stack.back())
|
||||
{
|
||||
return {false, nullptr};
|
||||
}
|
||||
|
||||
// we now only expect arrays and objects
|
||||
assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
|
||||
|
||||
if (ref_stack.back()->is_array())
|
||||
{
|
||||
ref_stack.back()->m_value.array->push_back(std::move(value));
|
||||
return {true, &(ref_stack.back()->m_value.array->back())};
|
||||
}
|
||||
else
|
||||
{
|
||||
// skip this value if we already decided to skip the parent
|
||||
// (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
|
||||
if (not ref_stack.back())
|
||||
// check if we should store an element for the current key
|
||||
assert(not key_keep_stack.empty());
|
||||
const bool store_element = key_keep_stack.back();
|
||||
key_keep_stack.pop_back();
|
||||
|
||||
if (not store_element)
|
||||
{
|
||||
return {false, nullptr};
|
||||
}
|
||||
|
||||
assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
|
||||
if (ref_stack.back()->is_array())
|
||||
{
|
||||
ref_stack.back()->m_value.array->push_back(std::move(value));
|
||||
return {true, &(ref_stack.back()->m_value.array->back())};
|
||||
}
|
||||
else
|
||||
{
|
||||
// check if we should store an element for the current key
|
||||
assert(not key_keep_stack.empty());
|
||||
const bool store_element = key_keep_stack.back();
|
||||
key_keep_stack.pop_back();
|
||||
|
||||
if (not store_element)
|
||||
{
|
||||
return {false, nullptr};
|
||||
}
|
||||
|
||||
assert(object_element);
|
||||
*object_element = std::move(value);
|
||||
return {true, object_element};
|
||||
}
|
||||
assert(object_element);
|
||||
*object_element = std::move(value);
|
||||
return {true, object_element};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -642,37 +641,37 @@ class json_sax_acceptor
|
|||
return true;
|
||||
}
|
||||
|
||||
bool boolean(bool)
|
||||
bool boolean(bool /*unused*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_integer(number_integer_t)
|
||||
bool number_integer(number_integer_t /*unused*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_unsigned(number_unsigned_t)
|
||||
bool number_unsigned(number_unsigned_t /*unused*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_float(number_float_t, const string_t&)
|
||||
bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool string(string_t&)
|
||||
bool string(string_t& /*unused*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t = std::size_t(-1))
|
||||
bool start_object(std::size_t /*unused*/ = std::size_t(-1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool key(string_t&)
|
||||
bool key(string_t& /*unused*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -682,7 +681,7 @@ class json_sax_acceptor
|
|||
return true;
|
||||
}
|
||||
|
||||
bool start_array(std::size_t = std::size_t(-1))
|
||||
bool start_array(std::size_t /*unused*/ = std::size_t(-1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -692,11 +691,11 @@ class json_sax_acceptor
|
|||
return true;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t, const std::string&, const detail::exception&)
|
||||
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
}
|
||||
} // namespace nlohmann
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
#include <nlohmann/detail/input/input_adapters.hpp>
|
||||
#include <nlohmann/detail/input/position_t.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
|
@ -104,7 +105,10 @@ class lexer
|
|||
|
||||
// delete because of pointer members
|
||||
lexer(const lexer&) = delete;
|
||||
lexer(lexer&&) = delete;
|
||||
lexer& operator=(lexer&) = delete;
|
||||
lexer& operator=(lexer&&) = delete;
|
||||
~lexer() = default;
|
||||
|
||||
private:
|
||||
/////////////////////
|
||||
|
@ -393,39 +397,194 @@ class lexer
|
|||
|
||||
// invalid control characters
|
||||
case 0x00:
|
||||
{
|
||||
error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x01:
|
||||
{
|
||||
error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x02:
|
||||
{
|
||||
error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x03:
|
||||
{
|
||||
error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x04:
|
||||
{
|
||||
error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x05:
|
||||
{
|
||||
error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x06:
|
||||
{
|
||||
error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x07:
|
||||
{
|
||||
error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x08:
|
||||
{
|
||||
error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x09:
|
||||
{
|
||||
error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x0A:
|
||||
{
|
||||
error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x0B:
|
||||
{
|
||||
error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x0C:
|
||||
{
|
||||
error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x0D:
|
||||
{
|
||||
error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x0E:
|
||||
{
|
||||
error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x0F:
|
||||
{
|
||||
error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x10:
|
||||
{
|
||||
error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x11:
|
||||
{
|
||||
error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x12:
|
||||
{
|
||||
error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x13:
|
||||
{
|
||||
error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x14:
|
||||
{
|
||||
error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x15:
|
||||
{
|
||||
error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x16:
|
||||
{
|
||||
error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x17:
|
||||
{
|
||||
error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x18:
|
||||
{
|
||||
error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x19:
|
||||
{
|
||||
error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x1A:
|
||||
{
|
||||
error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x1B:
|
||||
{
|
||||
error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x1C:
|
||||
{
|
||||
error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x1D:
|
||||
{
|
||||
error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x1E:
|
||||
{
|
||||
error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
case 0x1F:
|
||||
{
|
||||
error_message = "invalid string: control character must be escaped";
|
||||
error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F";
|
||||
return token_type::parse_error;
|
||||
}
|
||||
|
||||
|
@ -709,7 +868,7 @@ class lexer
|
|||
locale's decimal point is used instead of `.` to work with the
|
||||
locale-dependent converters.
|
||||
*/
|
||||
token_type scan_number()
|
||||
token_type scan_number() // lgtm [cpp/use-of-goto]
|
||||
{
|
||||
// reset token_buffer to store the number's bytes
|
||||
reset();
|
||||
|
@ -1082,7 +1241,9 @@ scan_number_done:
|
|||
*/
|
||||
std::char_traits<char>::int_type get()
|
||||
{
|
||||
++chars_read;
|
||||
++position.chars_read_total;
|
||||
++position.chars_read_current_line;
|
||||
|
||||
if (next_unget)
|
||||
{
|
||||
// just reset the next_unget variable and work with current
|
||||
|
@ -1097,6 +1258,13 @@ scan_number_done:
|
|||
{
|
||||
token_string.push_back(std::char_traits<char>::to_char_type(current));
|
||||
}
|
||||
|
||||
if (current == '\n')
|
||||
{
|
||||
++position.lines_read;
|
||||
++position.chars_read_current_line = 0;
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
|
@ -1104,14 +1272,29 @@ scan_number_done:
|
|||
@brief unget current character (read it again on next get)
|
||||
|
||||
We implement unget by setting variable next_unget to true. The input is not
|
||||
changed - we just simulate ungetting by modifying chars_read and
|
||||
token_string. The next call to get() will behave as if the unget character
|
||||
is read again.
|
||||
changed - we just simulate ungetting by modifying chars_read_total,
|
||||
chars_read_current_line, and token_string. The next call to get() will
|
||||
behave as if the unget character is read again.
|
||||
*/
|
||||
void unget()
|
||||
{
|
||||
next_unget = true;
|
||||
--chars_read;
|
||||
|
||||
--position.chars_read_total;
|
||||
|
||||
// in case we "unget" a newline, we have to also decrement the lines_read
|
||||
if (position.chars_read_current_line == 0)
|
||||
{
|
||||
if (position.lines_read > 0)
|
||||
{
|
||||
--position.lines_read;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
--position.chars_read_current_line;
|
||||
}
|
||||
|
||||
if (JSON_LIKELY(current != std::char_traits<char>::eof()))
|
||||
{
|
||||
assert(token_string.size() != 0);
|
||||
|
@ -1159,9 +1342,9 @@ scan_number_done:
|
|||
/////////////////////
|
||||
|
||||
/// return position of last read token
|
||||
constexpr std::size_t get_position() const noexcept
|
||||
constexpr position_t get_position() const noexcept
|
||||
{
|
||||
return chars_read;
|
||||
return position;
|
||||
}
|
||||
|
||||
/// return the last read token (for errors only). Will never contain EOF
|
||||
|
@ -1208,30 +1391,20 @@ scan_number_done:
|
|||
{
|
||||
if (get() == 0xEF)
|
||||
{
|
||||
if (get() == 0xBB and get() == 0xBF)
|
||||
{
|
||||
// we completely parsed the BOM
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// after reading 0xEF, an unexpected character followed
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// the first character is not the beginning of the BOM; unget it to
|
||||
// process is later
|
||||
unget();
|
||||
return true;
|
||||
// check if we completely parse the BOM
|
||||
return get() == 0xBB and get() == 0xBF;
|
||||
}
|
||||
|
||||
// the first character is not the beginning of the BOM; unget it to
|
||||
// process is later
|
||||
unget();
|
||||
return true;
|
||||
}
|
||||
|
||||
token_type scan()
|
||||
{
|
||||
// initially, skip the BOM
|
||||
if (chars_read == 0 and not skip_bom())
|
||||
if (position.chars_read_total == 0 and not skip_bom())
|
||||
{
|
||||
error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given";
|
||||
return token_type::parse_error;
|
||||
|
@ -1309,8 +1482,8 @@ scan_number_done:
|
|||
/// whether the next get() call should just return current
|
||||
bool next_unget = false;
|
||||
|
||||
/// the number of characters read
|
||||
std::size_t chars_read = 0;
|
||||
/// the start position of the current token
|
||||
position_t position;
|
||||
|
||||
/// raw input token string (for error messages)
|
||||
std::vector<char> token_string {};
|
||||
|
@ -1329,5 +1502,5 @@ scan_number_done:
|
|||
/// the decimal point
|
||||
const char decimal_point_char = '.';
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
|
|
@ -91,7 +91,8 @@ class parser
|
|||
{
|
||||
sdp.parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input)));
|
||||
parse_error::create(101, m_lexer.get_position(),
|
||||
exception_message(token_type::end_of_input, "value")));
|
||||
}
|
||||
|
||||
// in case of an error, return discarded value
|
||||
|
@ -119,7 +120,8 @@ class parser
|
|||
{
|
||||
sdp.parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input)));
|
||||
parse_error::create(101, m_lexer.get_position(),
|
||||
exception_message(token_type::end_of_input, "value")));
|
||||
}
|
||||
|
||||
// in case of an error, return discarded value
|
||||
|
@ -154,7 +156,8 @@ class parser
|
|||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input)));
|
||||
parse_error::create(101, m_lexer.get_position(),
|
||||
exception_message(token_type::end_of_input, "value")));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -199,14 +202,12 @@ class parser
|
|||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
|
||||
parse_error::create(101, m_lexer.get_position(),
|
||||
exception_message(token_type::value_string, "object key")));
|
||||
}
|
||||
else
|
||||
if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
|
||||
{
|
||||
if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// parse separator (:)
|
||||
|
@ -214,7 +215,8 @@ class parser
|
|||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
|
||||
parse_error::create(101, m_lexer.get_position(),
|
||||
exception_message(token_type::name_separator, "object separator")));
|
||||
}
|
||||
|
||||
// remember we are now inside an object
|
||||
|
@ -328,14 +330,16 @@ class parser
|
|||
// using "uninitialized" to avoid "expected" message
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized)));
|
||||
parse_error::create(101, m_lexer.get_position(),
|
||||
exception_message(token_type::uninitialized, "value")));
|
||||
}
|
||||
|
||||
default: // the last token was unexpected
|
||||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value)));
|
||||
parse_error::create(101, m_lexer.get_position(),
|
||||
exception_message(token_type::literal_or_value, "value")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -383,7 +387,8 @@ class parser
|
|||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array)));
|
||||
parse_error::create(101, m_lexer.get_position(),
|
||||
exception_message(token_type::end_array, "array")));
|
||||
}
|
||||
}
|
||||
else // object
|
||||
|
@ -396,7 +401,8 @@ class parser
|
|||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
|
||||
parse_error::create(101, m_lexer.get_position(),
|
||||
exception_message(token_type::value_string, "object key")));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -411,7 +417,8 @@ class parser
|
|||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
|
||||
parse_error::create(101, m_lexer.get_position(),
|
||||
exception_message(token_type::name_separator, "object separator")));
|
||||
}
|
||||
|
||||
// parse values
|
||||
|
@ -440,7 +447,8 @@ class parser
|
|||
{
|
||||
return sax->parse_error(m_lexer.get_position(),
|
||||
m_lexer.get_token_string(),
|
||||
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object)));
|
||||
parse_error::create(101, m_lexer.get_position(),
|
||||
exception_message(token_type::end_object, "object")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -453,9 +461,17 @@ class parser
|
|||
return (last_token = m_lexer.scan());
|
||||
}
|
||||
|
||||
std::string exception_message(const token_type expected)
|
||||
std::string exception_message(const token_type expected, const std::string& context)
|
||||
{
|
||||
std::string error_msg = "syntax error - ";
|
||||
std::string error_msg = "syntax error ";
|
||||
|
||||
if (not context.empty())
|
||||
{
|
||||
error_msg += "while parsing " + context + " ";
|
||||
}
|
||||
|
||||
error_msg += "- ";
|
||||
|
||||
if (last_token == token_type::parse_error)
|
||||
{
|
||||
error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" +
|
||||
|
@ -484,5 +500,5 @@ class parser
|
|||
/// whether to throw exceptions in case of errors
|
||||
const bool allow_exceptions = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
|
27
include/nlohmann/detail/input/position_t.hpp
Normal file
27
include/nlohmann/detail/input/position_t.hpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef> // size_t
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/// struct to capture the start position of the current token
|
||||
struct position_t
|
||||
{
|
||||
/// the total number of characters read
|
||||
std::size_t chars_read_total = 0;
|
||||
/// the number of characters read in the current line
|
||||
std::size_t chars_read_current_line = 0;
|
||||
/// the number of lines read
|
||||
std::size_t lines_read = 0;
|
||||
|
||||
/// conversion to size_t to preserve SAX interface
|
||||
constexpr operator size_t() const
|
||||
{
|
||||
return chars_read_total;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue