1.4: BSON writers share one write-pass UTF-8 sanitizer (#5891)
write_bson_entry_header and write_bson_string re-derived the error-handler policy differently. Both now use sanitize_utf8_for_bson_write, which treats strict like keep (the size pass already validated) and sanitizes replace/ignore into the bytes the size pass measured. No context plumbing is needed. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
1 file changed
+31
-8
@@ -1550,14 +1550,15 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
oa.write_character(to_char_type(element_type));
|
oa.write_character(to_char_type(element_type));
|
||||||
|
|
||||||
if (error_handler == error_handler_t::keep || error_handler == error_handler_t::strict || is_valid_utf8(name))
|
if (JSON_HEDLEY_LIKELY(error_handler == error_handler_t::keep || error_handler == error_handler_t::strict))
|
||||||
{
|
{
|
||||||
oa.write_characters(reinterpret_cast<const CharType*>(name.data()), name.size());
|
oa.write_characters(reinterpret_cast<const CharType*>(name.data()), name.size());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const string_t sanitized = sanitize_utf8(name, error_handler);
|
string_t storage;
|
||||||
oa.write_characters(reinterpret_cast<const CharType*>(sanitized.data()), sanitized.size());
|
const string_t& written = sanitize_utf8_for_bson_write(name, storage);
|
||||||
|
oa.write_characters(reinterpret_cast<const CharType*>(written.data()), written.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// the terminating null byte is written explicitly rather than taken
|
// the terminating null byte is written explicitly rather than taken
|
||||||
@@ -1633,11 +1634,8 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
write_bson_entry_header(name, 0x02);
|
write_bson_entry_header(name, 0x02);
|
||||||
|
|
||||||
const bool sanitize = error_handler != error_handler_t::keep
|
string_t storage;
|
||||||
&& error_handler != error_handler_t::strict
|
const string_t& written = sanitize_utf8_for_bson_write(value, storage);
|
||||||
&& !is_valid_utf8(value);
|
|
||||||
const string_t sanitized = sanitize ? sanitize_utf8(value, error_handler) : string_t{};
|
|
||||||
const string_t& written = sanitize ? sanitized : value;
|
|
||||||
|
|
||||||
write_number<std::int32_t>(to_bson_length(written.size() + 1ul), true);
|
write_number<std::int32_t>(to_bson_length(written.size() + 1ul), true);
|
||||||
oa.write_characters(
|
oa.write_characters(
|
||||||
@@ -4902,6 +4900,31 @@ class binary_writer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief the write-pass counterpart of @ref sanitize_utf8_for_write for BSON
|
||||||
|
|
||||||
|
The size pass (@ref calc_bson_entry_header_size, @ref
|
||||||
|
calc_bson_string_size) has already validated @a s, and thrown for @ref
|
||||||
|
error_handler_t::strict if it was ill-formed. Here, @ref
|
||||||
|
error_handler_t::strict therefore behaves like @ref error_handler_t::keep,
|
||||||
|
and @ref error_handler_t::replace / @ref error_handler_t::ignore produce
|
||||||
|
exactly the bytes the size pass measured. Hence no context is needed.
|
||||||
|
|
||||||
|
@param[in] s the string (value or object key) to write
|
||||||
|
@param[out] storage backing storage for a sanitized copy
|
||||||
|
|
||||||
|
@return a reference to @a s, or to @a storage once it holds a sanitized copy
|
||||||
|
*/
|
||||||
|
const string_t& sanitize_utf8_for_bson_write(const string_t& s, string_t& storage) const
|
||||||
|
{
|
||||||
|
if (error_handler == error_handler_t::keep || error_handler == error_handler_t::strict || is_valid_utf8(s))
|
||||||
|
{
|
||||||
|
return s; // NOLINT(bugprone-return-const-ref-from-parameter): callers pass lvalues that outlive the call
|
||||||
|
}
|
||||||
|
storage = sanitize_utf8(s, error_handler);
|
||||||
|
return storage;
|
||||||
|
}
|
||||||
|
|
||||||
/// deleted: anything but a string_t would bind a temporary that dies before the returned reference is used
|
/// deleted: anything but a string_t would bind a temporary that dies before the returned reference is used
|
||||||
template < typename T, enable_if_t < !std::is_same<T, string_t>::value, int > = 0 >
|
template < typename T, enable_if_t < !std::is_same<T, string_t>::value, int > = 0 >
|
||||||
const string_t& sanitize_utf8_for_write(const T& /*s*/, const BasicJsonType& /*context*/, string_t& /*storage*/) const = delete; // NOLINT(hicpp-use-equals-delete,modernize-use-equals-delete): a private helper's guard, not part of the interface
|
const string_t& sanitize_utf8_for_write(const T& /*s*/, const BasicJsonType& /*context*/, string_t& /*storage*/) const = delete; // NOLINT(hicpp-use-equals-delete,modernize-use-equals-delete): a private helper's guard, not part of the interface
|
||||||
|
|||||||
Reference in new issue
Block a user