Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/mkdocs/docs/api/basic_json/object_t.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ To store objects in C++, a type is defined by the template parameters described

`StringType`
: the type of the keys or names (e.g., `std::string`). The comparison function `std::less<StringType>` is used to
order elements inside the container.
order elements inside the container. The `object_t::key_type` must be convertible to `string_t`.

`AllocatorType`
: the allocator to use for objects (e.g., `std::allocator`)
Expand Down
152 changes: 89 additions & 63 deletions include/nlohmann/detail/output/binary_writer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,16 +226,7 @@ class binary_writer

case value_t::string:
{
string_t storage;
const string_t& value = sanitize_utf8_for_write(*j.m_data.m_value.string, j, storage);

// step 1: write control byte and the string length
write_cbor_head(0x60, value.size());

// step 2: write the string
oa.write_characters(
reinterpret_cast<const CharType*>(value.data()),
value.size());
write_cbor_string(*j.m_data.m_value.string, j);
break;
}

Expand Down Expand Up @@ -299,24 +290,21 @@ class binary_writer

case value_t::object:
{
static_assert(
std::is_convertible <
typename BasicJsonType::object_t::key_type,
string_t >::value,
"object_t::key_type must be convertible to string_t");

// step 1: write control byte and the object size
write_cbor_head(0xA0, j.m_data.m_value.object->size());

// step 2: write each element
for (const auto& el : *j.m_data.m_value.object)
{
// el.first is checked here, against the object as
// diagnostics context, because write_cbor(el.first)
// converts it to a temporary basic_json that would be
// used as the context instead; for error_handler_t::keep
// and ::replace/::ignore the recursive write_cbor(el.first)
// call below handles the key like any other string, so no
// separate check is needed here for those
if (error_handler == error_handler_t::strict)
{
check_utf8(el.first, j);
}
write_cbor(el.first);
// el.first is written directly (not via a temporary
// basic_json), with the object as diagnostics context
write_cbor_string(el.first, j);
write_cbor(el.second);
}
break;
Expand Down Expand Up @@ -464,39 +452,7 @@ class binary_writer

case value_t::string:
{
string_t storage;
const string_t& value = sanitize_utf8_for_write(*j.m_data.m_value.string, j, storage);

// step 1: write control byte and the string length
const auto N = to_msgpack_length(value.size(), j);
if (N <= 31)
{
// fixstr
write_number(static_cast<std::uint8_t>(0xA0 | N));
}
else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{
// str 8
oa.write_character(to_char_type(0xD9));
write_number(static_cast<std::uint8_t>(N));
}
else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{
// str 16
oa.write_character(to_char_type(0xDA));
write_number(static_cast<std::uint16_t>(N));
}
else
{
// str 32
oa.write_character(to_char_type(0xDB));
write_number(static_cast<std::uint32_t>(N));
}

// step 2: write the string
oa.write_characters(
reinterpret_cast<const CharType*>(value.data()),
value.size());
write_msgpack_string(*j.m_data.m_value.string, j);
break;
}

Expand Down Expand Up @@ -620,6 +576,12 @@ class binary_writer

case value_t::object:
{
static_assert(
std::is_convertible <
typename BasicJsonType::object_t::key_type,
string_t >::value,
"object_t::key_type must be convertible to string_t");

// step 1: write control byte and the object size
const auto N = to_msgpack_length(j.m_data.m_value.object->size(), j);
if (N <= 15)
Expand All @@ -643,14 +605,9 @@ class binary_writer
// step 2: write each element
for (const auto& el : *j.m_data.m_value.object)
{
// as in write_cbor, el.first is checked here against the
// object as diagnostics context; the recursive call below
// handles keep/replace/ignore like any other string
if (error_handler == error_handler_t::strict)
{
check_utf8(el.first, j);
}
write_msgpack(el.first);
// as in write_cbor, el.first is written directly with the
// object as diagnostics context
write_msgpack_string(el.first, j);
write_msgpack(el.second);
}
break;
Expand Down Expand Up @@ -1542,6 +1499,75 @@ class binary_writer
}
}

/*!
@brief write a CBOR text string

@a value is checked or sanitized according to @ref error_handler, with
@a context (the string value itself, or the object a key belongs to) used
as diagnostics context; this avoids converting object keys to a temporary
basic_json just to write them
*/
void write_cbor_string(const string_t& value, const BasicJsonType& context)
{
string_t storage;
const string_t& sanitized = sanitize_utf8_for_write(value, context, storage);

// step 1: write control byte and the string length
write_cbor_head(0x60, sanitized.size());

// step 2: write the string
oa.write_characters(
reinterpret_cast<const CharType*>(sanitized.data()),
sanitized.size());
}

/////////////
// MsgPack //
/////////////

/*!
@brief write a MessagePack str

@a value is checked or sanitized according to @ref error_handler, with
@a context used as diagnostics context, as in @ref write_cbor_string
*/
void write_msgpack_string(const string_t& value, const BasicJsonType& context)
{
string_t storage;
const string_t& sanitized = sanitize_utf8_for_write(value, context, storage);

// step 1: write control byte and the string length
const auto N = to_msgpack_length(sanitized.size(), context);
if (N <= 31)
{
// fixstr
write_number(static_cast<std::uint8_t>(0xA0 | N));
}
else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{
// str 8
oa.write_character(to_char_type(0xD9));
write_number(static_cast<std::uint8_t>(N));
}
else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{
// str 16
oa.write_character(to_char_type(0xDA));
write_number(static_cast<std::uint16_t>(N));
}
else
{
// str 32
oa.write_character(to_char_type(0xDB));
write_number(static_cast<std::uint32_t>(N));
}

// step 2: write the string
oa.write_characters(
reinterpret_cast<const CharType*>(sanitized.data()),
sanitized.size());
}

////////////
// UBJSON //
////////////
Expand Down
Loading
Loading