mirror of
https://github.com/nlohmann/json.git
synced 2026-06-19 02:44:20 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3249b180cc | |||
| 61f0d683e0 | |||
| b3effb609c |
@@ -170,24 +170,7 @@ class binary_reader
|
||||
bool parse_bson_internal()
|
||||
{
|
||||
std::int32_t document_size{};
|
||||
if (JSON_HEDLEY_UNLIKELY((!get_number<std::int32_t, true>(input_format_t::bson, document_size))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(document_size < 5))
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||
exception_message(input_format_t::bson,
|
||||
concat("BSON document size must be at least 5, is ", std::to_string(document_size)),
|
||||
"document size"), nullptr));
|
||||
}
|
||||
|
||||
// The document begins at the size field and ends document_size bytes later
|
||||
// (including the size field itself and the trailing 0x00 terminator).
|
||||
const std::size_t document_start = chars_read - sizeof(std::int32_t);
|
||||
const std::size_t expected_end = document_start + static_cast<std::size_t>(document_size);
|
||||
get_number<std::int32_t, true>(input_format_t::bson, document_size);
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size())))
|
||||
{
|
||||
@@ -199,15 +182,6 @@ class binary_reader
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(chars_read != expected_end))
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||
exception_message(input_format_t::bson,
|
||||
"BSON document terminator did not land at declared document size",
|
||||
"document"), nullptr));
|
||||
}
|
||||
|
||||
return sax->end_object();
|
||||
}
|
||||
|
||||
@@ -257,21 +231,7 @@ class binary_reader
|
||||
exception_message(input_format_t::bson, concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr));
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_string(input_format_t::bson, len - static_cast<NumberType>(1), result)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(get() != 0x00))
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||
exception_message(input_format_t::bson,
|
||||
"BSON string is not null-terminated",
|
||||
"string"), nullptr));
|
||||
}
|
||||
|
||||
return true;
|
||||
return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != char_traits<char_type>::eof();
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -438,24 +398,7 @@ class binary_reader
|
||||
bool parse_bson_array()
|
||||
{
|
||||
std::int32_t document_size{};
|
||||
if (JSON_HEDLEY_UNLIKELY((!get_number<std::int32_t, true>(input_format_t::bson, document_size))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(document_size < 5))
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||
exception_message(input_format_t::bson,
|
||||
concat("BSON document size must be at least 5, is ", std::to_string(document_size)),
|
||||
"document size"), nullptr));
|
||||
}
|
||||
|
||||
// The document begins at the size field and ends document_size bytes later
|
||||
// (including the size field itself and the trailing 0x00 terminator).
|
||||
const std::size_t document_start = chars_read - sizeof(std::int32_t);
|
||||
const std::size_t expected_end = document_start + static_cast<std::size_t>(document_size);
|
||||
get_number<std::int32_t, true>(input_format_t::bson, document_size);
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size())))
|
||||
{
|
||||
@@ -467,15 +410,6 @@ class binary_reader
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(chars_read != expected_end))
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||
exception_message(input_format_t::bson,
|
||||
"BSON array terminator did not land at declared array size",
|
||||
"array"), nullptr));
|
||||
}
|
||||
|
||||
return sax->end_array();
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +128,8 @@ class serializer
|
||||
const auto new_indent = current_indent + indent_step;
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
|
||||
{
|
||||
indent_string.resize(indent_string.size() * 2, ' ');
|
||||
indent_string.resize((std::max)(indent_string.size() * 2, static_cast<std::size_t>(new_indent)), indent_char);
|
||||
JSON_ASSERT(indent_string.size() >= new_indent);
|
||||
}
|
||||
|
||||
// first n-1 elements
|
||||
@@ -201,7 +202,8 @@ class serializer
|
||||
const auto new_indent = current_indent + indent_step;
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
|
||||
{
|
||||
indent_string.resize(indent_string.size() * 2, ' ');
|
||||
indent_string.resize((std::max)(indent_string.size() * 2, static_cast<std::size_t>(new_indent)), indent_char);
|
||||
JSON_ASSERT(indent_string.size() >= new_indent);
|
||||
}
|
||||
|
||||
// first n-1 elements
|
||||
@@ -262,7 +264,8 @@ class serializer
|
||||
const auto new_indent = current_indent + indent_step;
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
|
||||
{
|
||||
indent_string.resize(indent_string.size() * 2, ' ');
|
||||
indent_string.resize((std::max)(indent_string.size() * 2, static_cast<std::size_t>(new_indent)), indent_char);
|
||||
JSON_ASSERT(indent_string.size() >= new_indent);
|
||||
}
|
||||
|
||||
o->write_characters(indent_string.c_str(), new_indent);
|
||||
|
||||
@@ -10312,24 +10312,7 @@ class binary_reader
|
||||
bool parse_bson_internal()
|
||||
{
|
||||
std::int32_t document_size{};
|
||||
if (JSON_HEDLEY_UNLIKELY((!get_number<std::int32_t, true>(input_format_t::bson, document_size))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(document_size < 5))
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||
exception_message(input_format_t::bson,
|
||||
concat("BSON document size must be at least 5, is ", std::to_string(document_size)),
|
||||
"document size"), nullptr));
|
||||
}
|
||||
|
||||
// The document begins at the size field and ends document_size bytes later
|
||||
// (including the size field itself and the trailing 0x00 terminator).
|
||||
const std::size_t document_start = chars_read - sizeof(std::int32_t);
|
||||
const std::size_t expected_end = document_start + static_cast<std::size_t>(document_size);
|
||||
get_number<std::int32_t, true>(input_format_t::bson, document_size);
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size())))
|
||||
{
|
||||
@@ -10341,15 +10324,6 @@ class binary_reader
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(chars_read != expected_end))
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||
exception_message(input_format_t::bson,
|
||||
"BSON document terminator did not land at declared document size",
|
||||
"document"), nullptr));
|
||||
}
|
||||
|
||||
return sax->end_object();
|
||||
}
|
||||
|
||||
@@ -10399,21 +10373,7 @@ class binary_reader
|
||||
exception_message(input_format_t::bson, concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr));
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!get_string(input_format_t::bson, len - static_cast<NumberType>(1), result)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(get() != 0x00))
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||
exception_message(input_format_t::bson,
|
||||
"BSON string is not null-terminated",
|
||||
"string"), nullptr));
|
||||
}
|
||||
|
||||
return true;
|
||||
return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != char_traits<char_type>::eof();
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -10580,24 +10540,7 @@ class binary_reader
|
||||
bool parse_bson_array()
|
||||
{
|
||||
std::int32_t document_size{};
|
||||
if (JSON_HEDLEY_UNLIKELY((!get_number<std::int32_t, true>(input_format_t::bson, document_size))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(document_size < 5))
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||
exception_message(input_format_t::bson,
|
||||
concat("BSON document size must be at least 5, is ", std::to_string(document_size)),
|
||||
"document size"), nullptr));
|
||||
}
|
||||
|
||||
// The document begins at the size field and ends document_size bytes later
|
||||
// (including the size field itself and the trailing 0x00 terminator).
|
||||
const std::size_t document_start = chars_read - sizeof(std::int32_t);
|
||||
const std::size_t expected_end = document_start + static_cast<std::size_t>(document_size);
|
||||
get_number<std::int32_t, true>(input_format_t::bson, document_size);
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size())))
|
||||
{
|
||||
@@ -10609,15 +10552,6 @@ class binary_reader
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(chars_read != expected_end))
|
||||
{
|
||||
auto last_token = get_token_string();
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||
exception_message(input_format_t::bson,
|
||||
"BSON array terminator did not land at declared array size",
|
||||
"array"), nullptr));
|
||||
}
|
||||
|
||||
return sax->end_array();
|
||||
}
|
||||
|
||||
@@ -19368,7 +19302,8 @@ class serializer
|
||||
const auto new_indent = current_indent + indent_step;
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
|
||||
{
|
||||
indent_string.resize(indent_string.size() * 2, ' ');
|
||||
indent_string.resize((std::max)(indent_string.size() * 2, static_cast<std::size_t>(new_indent)), indent_char);
|
||||
JSON_ASSERT(indent_string.size() >= new_indent);
|
||||
}
|
||||
|
||||
// first n-1 elements
|
||||
@@ -19441,7 +19376,8 @@ class serializer
|
||||
const auto new_indent = current_indent + indent_step;
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
|
||||
{
|
||||
indent_string.resize(indent_string.size() * 2, ' ');
|
||||
indent_string.resize((std::max)(indent_string.size() * 2, static_cast<std::size_t>(new_indent)), indent_char);
|
||||
JSON_ASSERT(indent_string.size() >= new_indent);
|
||||
}
|
||||
|
||||
// first n-1 elements
|
||||
@@ -19502,7 +19438,8 @@ class serializer
|
||||
const auto new_indent = current_indent + indent_step;
|
||||
if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
|
||||
{
|
||||
indent_string.resize(indent_string.size() * 2, ' ');
|
||||
indent_string.resize((std::max)(indent_string.size() * 2, static_cast<std::size_t>(new_indent)), indent_char);
|
||||
JSON_ASSERT(indent_string.size() >= new_indent);
|
||||
}
|
||||
|
||||
o->write_characters(indent_string.c_str(), new_indent);
|
||||
|
||||
@@ -1294,76 +1294,3 @@ TEST_CASE("BSON roundtrips" * doctest::skip())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Invalid document size handling")
|
||||
{
|
||||
SECTION("document size must be at least 5")
|
||||
{
|
||||
std::vector<std::uint8_t> const v = {0x04, 0x00, 0x00, 0x00, 0x00};
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 4: syntax error while parsing BSON document size: BSON document size must be at least 5, is 4", json::parse_error&);
|
||||
CHECK(json::from_bson(v, true, false).is_discarded());
|
||||
}
|
||||
|
||||
SECTION("declared document size must match consumed bytes (extra trailing element)")
|
||||
{
|
||||
// Declares 5-byte empty document but appends an int32 element after the declared end.
|
||||
std::vector<std::uint8_t> const v =
|
||||
{
|
||||
0x05, 0x00, 0x00, 0x00,
|
||||
0x10, 'a', 'd', 'm', 'i', 'n', 0x00,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
0x00
|
||||
};
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 16: syntax error while parsing BSON document: BSON document terminator did not land at declared document size", json::parse_error&);
|
||||
CHECK(json::from_bson(v, true, false).is_discarded());
|
||||
}
|
||||
|
||||
SECTION("declared document size must match consumed bytes (premature terminator)")
|
||||
{
|
||||
// Declares 32-byte document but only contains the size field followed by an immediate terminator.
|
||||
std::vector<std::uint8_t> const v =
|
||||
{
|
||||
0x20, 0x00, 0x00, 0x00,
|
||||
0x00
|
||||
};
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 5: syntax error while parsing BSON document: BSON document terminator did not land at declared document size", json::parse_error&);
|
||||
CHECK(json::from_bson(v, true, false).is_discarded());
|
||||
}
|
||||
|
||||
SECTION("array declared size must match consumed bytes")
|
||||
{
|
||||
// Outer object contains an array "a" that declares 5 bytes (empty) but
|
||||
// actually contains an int32 element before its terminator.
|
||||
std::vector<std::uint8_t> const v =
|
||||
{
|
||||
0x14, 0x00, 0x00, 0x00, // object size = 20
|
||||
0x04, 'a', 0x00, // key "a", array type
|
||||
0x05, 0x00, 0x00, 0x00, // array declared size = 5 (empty)
|
||||
0x10, '0', 0x00, 0x01, 0x00, 0x00, 0x00, // extra int32 element "0" = 1
|
||||
0x00, // array terminator
|
||||
0x00 // object terminator
|
||||
};
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 19: syntax error while parsing BSON array: BSON array terminator did not land at declared array size", json::parse_error&);
|
||||
CHECK(json::from_bson(v, true, false).is_discarded());
|
||||
}
|
||||
|
||||
SECTION("BSON string must end with 0x00")
|
||||
{
|
||||
// Length-prefixed string whose terminator byte is 'X' (0x58), not 0x00.
|
||||
std::vector<std::uint8_t> const v =
|
||||
{
|
||||
0x0F, 0x00, 0x00, 0x00,
|
||||
0x02, 's', 0x00,
|
||||
0x02, 0x00, 0x00, 0x00,
|
||||
'A', 'X',
|
||||
0x00
|
||||
};
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 13: syntax error while parsing BSON string: BSON string is not null-terminated", json::parse_error&);
|
||||
CHECK(json::from_bson(v, true, false).is_discarded());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,6 +245,41 @@ TEST_CASE("object inspection")
|
||||
CHECK(binary.dump(1024).size() == 2086);
|
||||
}
|
||||
|
||||
SECTION("indentation and resize")
|
||||
{
|
||||
SECTION("array")
|
||||
{
|
||||
const auto j_array = json::parse("[[[[[[]]]]]]");
|
||||
// check right size after indentation triggering a resize
|
||||
CHECK(j_array.dump(1024).size() == 25622);
|
||||
// check if right indentation symbol is used
|
||||
CHECK(j_array.dump(1024, '\t')[4096] == '\t');
|
||||
// check resize is large enough
|
||||
CHECK(j_array.dump(10000).size() == 250022);
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
const auto j_object = json::parse(R"({"":{"":{"":{"":{"":{}}}}}})");
|
||||
// check right size after indentation triggering a resize
|
||||
CHECK(j_object.dump(1024).size() == 25642);
|
||||
// check if right indentation symbol is used
|
||||
CHECK(j_object.dump(1024, '\t')[4096] == '\t');
|
||||
// check resize is large enough
|
||||
CHECK(j_object.dump(10000).size() == 250042);
|
||||
}
|
||||
|
||||
SECTION("binary")
|
||||
{
|
||||
const auto j_binary = json::binary({1, 2, 3}, 128);
|
||||
// check right size after indentation triggering a resize
|
||||
CHECK(j_binary.dump(1024).size() == 2086);
|
||||
CHECK(j_binary.dump(1024, '\t')[1024] == '\t');
|
||||
// check resize is large enough
|
||||
CHECK(j_binary.dump(10000).size() == 20038);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("dump and floating-point numbers")
|
||||
{
|
||||
auto s = json(42.23).dump();
|
||||
|
||||
@@ -311,16 +311,14 @@ TEST_CASE("dump for basic_json with long double number_float_t")
|
||||
SECTION("round-trip dump/parse")
|
||||
{
|
||||
constexpr std::array<long double, 13> values =
|
||||
{
|
||||
{
|
||||
0.0L, -0.0L, 1.0L, -1.0L,
|
||||
0.5L, -0.5L, 1.5L, -2.25L,
|
||||
1.23e45L, 1.23e-45L,
|
||||
(std::numeric_limits<long double>::min)(),
|
||||
std::numeric_limits<long double>::lowest(),
|
||||
(std::numeric_limits<long double>::max)()
|
||||
}
|
||||
};
|
||||
{{
|
||||
0.0L, -0.0L, 1.0L, -1.0L,
|
||||
0.5L, -0.5L, 1.5L, -2.25L,
|
||||
1.23e45L, 1.23e-45L,
|
||||
(std::numeric_limits<long double>::min)(),
|
||||
std::numeric_limits<long double>::lowest(),
|
||||
(std::numeric_limits<long double>::max)()
|
||||
}};
|
||||
|
||||
for (long double v : values)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user