Merge remote-tracking branch 'origin/develop' into claude/fix-issue-3989-db7e45

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

# Conflicts:
#	docs/mkdocs/docs/api/json_sax/parse_error.md
#	docs/mkdocs/docs/features/parsing/index.md
This commit is contained in:
Niels Lohmann committed 2026-10-02 11:38:09 +02:00
commit ab52c98f71
335 files changed
+6103 -1049

No files matched your search

+29 -14
View File
@@ -617,7 +617,7 @@ class binary_reader
@brief Parses a C-style string from the BSON input.
@param[in,out] result A reference to the string variable where the read
string is to be stored.
@return `true` if the \x00-byte indicating the end of the string was
@return `true` if the \\x00-byte indicating the end of the string was
encountered before the EOF; false` indicates an unexpected EOF.
*/
bool get_bson_cstr(string_t& result)
@@ -647,7 +647,7 @@ class binary_reader
@brief read a C-style string from contiguous input in one step
@param[in,out] result the string to append to
@return whether the string was read; if the input has no \x00-byte, nothing
@return whether the string was read; if the input has no \\x00-byte, nothing
is read, and @ref get_bson_cstr reports the end of the input
*/
bool get_bson_cstr_bulk(string_t& result, std::true_type /*bulk*/)
@@ -812,13 +812,13 @@ class binary_reader
case 0x10: // int32
{
std::int32_t value{};
return get_number<std::int32_t, true>(input_format_t::bson, value) && sax->number_integer(value);
return get_number<std::int32_t, true>(input_format_t::bson, value) && sax->number_integer(conditional_static_cast<number_integer_t>(value));
}
case 0x12: // int64
{
std::int64_t value{};
return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value);
return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(conditional_static_cast<number_integer_t>(value));
}
case 0x11: // uint64
@@ -856,7 +856,7 @@ class binary_reader
// too small for number_integer_t: pass the nearest floating-point number
return sax->number_float(static_cast<number_float_t>(-1) - static_cast<number_float_t>(number), "");
}
return sax->number_integer(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number));
return sax->number_integer(conditional_static_cast<number_integer_t>(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number)));
}
/*!
@@ -2269,25 +2269,25 @@ class binary_reader
case 0xD0: // int 8
{
std::int8_t number{};
return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
return get_number(input_format_t::msgpack, number) && sax->number_integer(conditional_static_cast<number_integer_t>(number));
}
case 0xD1: // int 16
{
std::int16_t number{};
return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
return get_number(input_format_t::msgpack, number) && sax->number_integer(conditional_static_cast<number_integer_t>(number));
}
case 0xD2: // int 32
{
std::int32_t number{};
return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
return get_number(input_format_t::msgpack, number) && sax->number_integer(conditional_static_cast<number_integer_t>(number));
}
case 0xD3: // int 64
{
std::int64_t number{};
return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
return get_number(input_format_t::msgpack, number) && sax->number_integer(conditional_static_cast<number_integer_t>(number));
}
case 0xDC: // array 16
@@ -3500,25 +3500,25 @@ class binary_reader
case 'i':
{
std::int8_t number{};
return get_number(input_format, number) && sax->number_integer(number);
return get_number(input_format, number) && sax->number_integer(conditional_static_cast<number_integer_t>(number));
}
case 'I':
{
std::int16_t number{};
return get_number(input_format, number) && sax->number_integer(number);
return get_number(input_format, number) && sax->number_integer(conditional_static_cast<number_integer_t>(number));
}
case 'l':
{
std::int32_t number{};
return get_number(input_format, number) && sax->number_integer(number);
return get_number(input_format, number) && sax->number_integer(conditional_static_cast<number_integer_t>(number));
}
case 'L':
{
std::int64_t number{};
return get_number(input_format, number) && sax->number_integer(number);
return get_number(input_format, number) && sax->number_integer(conditional_static_cast<number_integer_t>(number));
}
case 'u':
@@ -4171,7 +4171,7 @@ class binary_reader
// integer -1..-10
if (byte <= 0xC1)
{
return sax->number_integer(-1 - static_cast<number_integer_t>(byte - 0xB8));
return sax->number_integer(conditional_static_cast<number_integer_t>(-1 - static_cast<number_integer_t>(byte - 0xB8)));
}
// 0xC2..0xF7: a UTF-8 lead byte begins a string if a continuation
@@ -4301,6 +4301,11 @@ class binary_reader
if (0xC2 <= byte && byte <= 0xF7)
{
const auto second = get_bon8();
if (second == char_traits<char_type>::eof())
{
// the input ends inside a character or an integer
return unexpect_eof(input_format_t::bon8, "key");
}
unget_bon8(second);
if (is_bon8_continuation(second))
{
@@ -4517,6 +4522,12 @@ class binary_reader
// a lead byte ends the string if no continuation byte follows: it
// is then the first byte of an integer
const auto second = get_bon8();
if (second == char_traits<char_type>::eof())
{
// the input ends inside a character or an integer: either
// way, the message is incomplete
return unexpect_eof(input_format_t::bon8, "string");
}
if (!is_bon8_continuation(second))
{
unget_bon8(second);
@@ -4597,6 +4608,8 @@ class binary_reader
template<class T>
bool get_to(T& dest, const input_format_t format, const char* context)
{
// false positive: new_chars_read is read on the next lines
// @infer-ignore DEAD_STORE
auto new_chars_read = ia.get_elements(&dest);
chars_read += new_chars_read;
if (JSON_HEDLEY_UNLIKELY(new_chars_read < sizeof(T)))
@@ -4853,6 +4866,8 @@ class binary_reader
// resize() is required to make size() exactly old_size + wanted;
// that is the room get_elements() is allowed to write into
JSON_ASSERT(result.size() == old_size + wanted);
// false positive: bytes_read is read on the next lines
// @infer-ignore DEAD_STORE
const std::size_t bytes_read = ia.get_elements(&result[old_size], wanted);
chars_read += bytes_read;
if (JSON_HEDLEY_UNLIKELY(bytes_read < wanted))
@@ -744,6 +744,9 @@ struct container_input_adapter_factory< ContainerType,
static adapter_type create(ContainerType&& container)
{
// container is forwarded twice on purpose: the resulting begin/end
// iterator types must match adapter_type, computed the same way
// NOLINTNEXTLINE(bugprone-use-after-move)
return input_adapter(begin(std::forward<ContainerType>(container)), end(std::forward<ContainerType>(container)));
}
};
+2 -2
View File
@@ -222,9 +222,9 @@ class lexer : public lexer_base<BasicJsonType>
/////////////////////
/*!
@brief get codepoint from 4 hex characters following `\u`
@brief get codepoint from 4 hex characters following `\\u`
For input "\u c1 c2 c3 c4" the codepoint is:
For input "\\u c1 c2 c3 c4" the codepoint is:
(c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4
= (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0)
@@ -428,14 +428,14 @@ inline bool parse_float_eisel_lemire(const char* first, const char* last, double
}
std::uint64_t w = 0;
int digits = 0; // significant digits in w
unsigned int digits = 0; // significant digits in w
std::int64_t exponent = 0;
bool truncated = false;
bool in_fraction = false;
for (;;)
{
// eight digits at a time, as long as they fit into w
while (w != 0 && digits <= 19 - 8 && last - p >= 8)
while (w != 0 && digits <= 19u - 8u && last - p >= 8)
{
const std::uint64_t v = read_eight_bytes(p);
if (!is_eight_digits(v))
@@ -443,7 +443,7 @@ inline bool parse_float_eisel_lemire(const char* first, const char* last, double
break;
}
w = (w * 100000000u) + parse_eight_digits(v);
digits += 8;
digits += 8u;
exponent -= in_fraction ? 8 : 0;
p += 8;
}
@@ -459,7 +459,7 @@ inline bool parse_float_eisel_lemire(const char* first, const char* last, double
// leading zeros are not significant, but scale a fraction
exponent -= in_fraction ? 1 : 0;
}
else if (digits < 19)
else if (digits < 19u)
{
w = (w * 10u) + static_cast<std::uint64_t>(c - '0');
++digits;
+3 -2
View File
@@ -54,8 +54,9 @@ using parser_callback_t =
/*!
@brief syntax analysis
This class implements an iterative parser that keeps the open containers on
an explicit stack and reports what it reads as SAX events.
This class implements a parser for JSON text. Nested arrays and objects are tracked with an explicit
stack instead of recursion, so deeply nested input does not exhaust the call stack, and what is read
is reported as SAX events.
*/
template<typename BasicJsonType, typename InputAdapterType>
class parser