diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 113dcb91..3fd6cc20 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -203,6 +203,14 @@ class binary_reader sax->boolean(static_cast(get())); } break; + case 0x0A: // null + { + string_t key; + get_bson_cstr(key); + sax->key(key); + sax->null(); + } + break; } } diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index a377d348..966d8c22 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -711,6 +711,16 @@ class binary_writer return /*id*/ 1ul + name.size() + 1ul + sizeof(std::int32_t) + j.m_value.string->size() + 1ul; } + std::size_t write_bson_null(const typename BasicJsonType::string_t& name, const BasicJsonType&) + { + oa->write_character(static_cast(0x0A)); // null + oa->write_characters( + reinterpret_cast(name.c_str()), + name.size() + 1u); + + return /*id*/ 1ul + name.size() + 1ul; + } + std::size_t write_bson_object_entry(const typename BasicJsonType::string_t& name, const BasicJsonType& j) { switch (j.type()) @@ -724,6 +734,8 @@ class binary_writer return write_bson_double(name, j); case value_t::string: return write_bson_string(name, j); + case value_t::null: + return write_bson_null(name, j); }; return 0ul; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index c549f907..faeaf214 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -6187,6 +6187,14 @@ class binary_reader sax->boolean(static_cast(get())); } break; + case 0x0A: // null + { + string_t key; + get_bson_cstr(key); + sax->key(key); + sax->null(); + } + break; } } @@ -8517,6 +8525,16 @@ class binary_writer return /*id*/ 1ul + name.size() + 1ul + sizeof(std::int32_t) + j.m_value.string->size() + 1ul; } + std::size_t write_bson_null(const typename BasicJsonType::string_t& name, const BasicJsonType&) + { + oa->write_character(static_cast(0x0A)); // null + oa->write_characters( + reinterpret_cast(name.c_str()), + name.size() + 1u); + + return /*id*/ 1ul + name.size() + 1ul; + } + std::size_t write_bson_object_entry(const typename BasicJsonType::string_t& name, const BasicJsonType& j) { switch (j.type()) @@ -8530,6 +8548,8 @@ class binary_writer return write_bson_double(name, j); case value_t::string: return write_bson_string(name, j); + case value_t::null: + return write_bson_null(name, j); }; return 0ul; diff --git a/test/src/unit-bson.cpp b/test/src/unit-bson.cpp index e3b4717f..e83e112a 100644 --- a/test/src/unit-bson.cpp +++ b/test/src/unit-bson.cpp @@ -208,6 +208,29 @@ TEST_CASE("BSON") CHECK(json::from_bson(result, true, false) == j); } + SECTION("non-empty object with null member") + { + json j = + { + { "entry", nullptr } + }; + + std::vector expected = + { + 0x0C, 0x00, 0x00, 0x00, // size (little endian) + 0x0A, /// entry: null + 'e', 'n', 't', 'r', 'y', '\x00', + 0x00 // end marker + }; + + const auto result = json::to_bson(j); + CHECK(result == expected); + + // roundtrip + CHECK(json::from_bson(result) == j); + CHECK(json::from_bson(result, true, false) == j); + } + } }