mirror of
https://github.com/nlohmann/json.git
synced 2026-08-20 16:13:19 +00:00
Merge remote-tracking branch 'origin/develop' into claude/issue-5340-restore-unget
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
@@ -465,15 +465,6 @@ class binary_reader
|
||||
// CBOR //
|
||||
//////////
|
||||
|
||||
/*!
|
||||
@param[in] get_char whether a new character should be retrieved from the
|
||||
input (true) or whether the last read character should
|
||||
be considered instead (false)
|
||||
@param[in] tag_handler how CBOR tags should be treated
|
||||
|
||||
@return whether a valid CBOR value was passed to the SAX parser
|
||||
*/
|
||||
|
||||
template<typename NumberType>
|
||||
bool get_cbor_negative_integer()
|
||||
{
|
||||
@@ -492,6 +483,14 @@ class binary_reader
|
||||
return sax->number_integer(static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(number));
|
||||
}
|
||||
|
||||
/*!
|
||||
@param[in] get_char whether a new character should be retrieved from the
|
||||
input (true) or whether the last read character should
|
||||
be considered instead (false)
|
||||
@param[in] tag_handler how CBOR tags should be treated
|
||||
|
||||
@return whether a valid CBOR value was passed to the SAX parser
|
||||
*/
|
||||
bool parse_cbor_internal(const bool get_char,
|
||||
const cbor_tag_handler_t tag_handler)
|
||||
{
|
||||
@@ -774,7 +773,13 @@ class binary_reader
|
||||
case 0xBF: // map (indefinite length)
|
||||
return get_cbor_object(detail::unknown_size(), tag_handler);
|
||||
|
||||
case 0xC6: // tagged item
|
||||
case 0xC0: // tagged item
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -789,6 +794,9 @@ class binary_reader
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xD8: // tagged item (1 byte follows)
|
||||
case 0xD9: // tagged item (2 bytes follow)
|
||||
case 0xDA: // tagged item (4 bytes follow)
|
||||
@@ -1988,7 +1996,11 @@ class binary_reader
|
||||
{
|
||||
if (get_char)
|
||||
{
|
||||
get(); // TODO(niels): may we ignore N here?
|
||||
// no get_ignore_noop() here: the byte read next must be a string
|
||||
// length type specification, and a no-op ('N') is not valid in
|
||||
// that position. No-ops at positions where a value may appear are
|
||||
// already consumed by the callers via get_ignore_noop().
|
||||
get();
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
|
||||
|
||||
@@ -393,8 +393,12 @@ struct wide_string_input_helper<BaseInputAdapter, 4>
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown character
|
||||
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
|
||||
// A code point above U+10FFFF has no UTF-8 encoding. Passing the
|
||||
// unit through would narrow it to int, where 0xFFFFFFFF becomes
|
||||
// char_traits<char>::eof() and would end the input silently, so
|
||||
// emit a byte that is never valid UTF-8 and let the decoder
|
||||
// reject it.
|
||||
utf8_bytes[0] = 0xFF;
|
||||
utf8_bytes_filled = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,8 +370,10 @@ class json_sax_dom_parser
|
||||
|
||||
case value_t::string:
|
||||
{
|
||||
// include the length of the quotes, which is 2
|
||||
v.start_position = v.end_position - v.m_data.m_value.string->size() - 2;
|
||||
// escape sequences make the token longer than the value it
|
||||
// parses to, so the start position cannot be derived from
|
||||
// the value; use the offset the lexer recorded instead
|
||||
v.start_position = m_lexer_ref->get_token_start_position();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -769,8 +771,10 @@ class json_sax_dom_callback_parser
|
||||
|
||||
case value_t::string:
|
||||
{
|
||||
// include the length of the quotes, which is 2
|
||||
v.start_position = v.end_position - v.m_data.m_value.string->size() - 2;
|
||||
// escape sequences make the token longer than the value it
|
||||
// parses to, so the start position cannot be derived from
|
||||
// the value; use the offset the lexer recorded instead
|
||||
v.start_position = m_lexer_ref->get_token_start_position();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -1381,6 +1381,11 @@ scan_number_done:
|
||||
token_buffer.clear();
|
||||
decimal_point_position = std::string::npos;
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
// the first character of the token has already been read, hence the -1
|
||||
token_start_position = position.chars_read_total - 1;
|
||||
#endif
|
||||
|
||||
note_token_start(std::integral_constant<bool, lazy_token_string> {});
|
||||
}
|
||||
|
||||
@@ -1581,6 +1586,15 @@ scan_number_done:
|
||||
release_lookahead_impl(std::integral_constant<bool, can_release_lookahead> {});
|
||||
}
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
/// return the offset of the first character of the last read token; unlike
|
||||
/// the token's parsed value, this accounts for escape sequences
|
||||
constexpr std::size_t get_token_start_position() const noexcept
|
||||
{
|
||||
return token_start_position;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// seekable adapter: rebuild the last read token from the input on demand
|
||||
const std::vector<char_type>& collect_token_chars(std::vector<char_type>& out, std::true_type /*lazy*/) const
|
||||
{
|
||||
@@ -1781,6 +1795,12 @@ scan_number_done:
|
||||
/// the last read token on error for seekable adapters (see collect_token_chars)
|
||||
std::size_t token_string_start = 0;
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
/// start offset of the current token within the input, used to report
|
||||
/// diagnostic positions (see reset())
|
||||
std::size_t token_start_position = 0;
|
||||
#endif
|
||||
|
||||
/// buffer for variable-length tokens (numbers, strings)
|
||||
string_t token_buffer {};
|
||||
|
||||
|
||||
@@ -1670,7 +1670,23 @@ class binary_writer
|
||||
{
|
||||
return true;
|
||||
}
|
||||
len *= static_cast<std::size_t>(el.template get<std::uint64_t>());
|
||||
|
||||
// a dimension that does not fit into std::size_t, or a product that
|
||||
// overflows it, would wrap around and could match the size of
|
||||
// _ArrayData_ by accident; the resulting header announces an
|
||||
// element count that no reader can honor (the binary reader rejects
|
||||
// it with out_of_range.408), so encode as a plain object instead
|
||||
const auto dim = el.template get<std::uint64_t>();
|
||||
if (!value_in_range_of<std::size_t>(dim))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
const auto dim_size = static_cast<std::size_t>(dim);
|
||||
if (dim_size != 0 && len > (std::numeric_limits<std::size_t>::max)() / dim_size)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
len *= dim_size;
|
||||
}
|
||||
|
||||
key = "_ArrayData_";
|
||||
|
||||
@@ -3652,6 +3652,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
// note parentheses around operands are necessary; see
|
||||
// https://github.com/nlohmann/json/issues/1530
|
||||
// Mixed signed/unsigned integer comparisons check whether the signed value
|
||||
// is negative before casting. If it is, the comparison is performed with
|
||||
// the fixed values -1 and 1, which preserves the ordering relationship
|
||||
// because any negative signed value is smaller than any unsigned value.
|
||||
// Otherwise, the non-negative signed value is cast to unsigned before the
|
||||
// comparison to avoid wraparound.
|
||||
#define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result) \
|
||||
const auto lhs_type = lhs.type(); \
|
||||
const auto rhs_type = rhs.type(); \
|
||||
@@ -3710,12 +3716,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
} \
|
||||
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) \
|
||||
{ \
|
||||
return static_cast<number_integer_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_integer; \
|
||||
return (rhs.m_data.m_value.number_integer < 0) \
|
||||
? (number_integer_t(1) op number_integer_t(-1)) \
|
||||
: (lhs.m_data.m_value.number_unsigned op static_cast<number_unsigned_t>(rhs.m_data.m_value.number_integer)); \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) \
|
||||
{ \
|
||||
return lhs.m_data.m_value.number_integer op static_cast<number_integer_t>(rhs.m_data.m_value.number_unsigned); \
|
||||
} \
|
||||
return (lhs.m_data.m_value.number_integer < 0) \
|
||||
? (number_integer_t(-1) op number_integer_t(1)) \
|
||||
: (static_cast<number_unsigned_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_unsigned); \
|
||||
} \
|
||||
else if(compares_unordered(lhs, rhs))\
|
||||
{\
|
||||
return (unordered_result);\
|
||||
|
||||
Reference in New Issue
Block a user