From 6c447de0768cb9cf235c886525e1aaa411a34e3d Mon Sep 17 00:00:00 2001 From: Julian Becker Date: Sat, 15 Sep 2018 11:33:24 +0200 Subject: [PATCH] BSON: Support objects with string members --- .../nlohmann/detail/input/binary_reader.hpp | 25 ++++++++--- .../nlohmann/detail/output/binary_writer.hpp | 19 +++++++- single_include/nlohmann/json.hpp | 44 ++++++++++++++++--- test/src/unit-bson.cpp | 26 +++++++++++ 4 files changed, 100 insertions(+), 14 deletions(-) diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index dc9015b8..113dcb91 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -139,7 +139,7 @@ class binary_reader /*! @return whether array creation completed */ - bool get_bson_str(string_t& result) + bool get_bson_cstr(string_t& result) { bool success = true; generate_until(std::back_inserter(result), [](char c) @@ -148,7 +148,7 @@ class binary_reader }, [this, &success] { get(); - if (JSON_UNLIKELY(unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof())) { success = false; } @@ -172,20 +172,33 @@ class binary_reader { switch (entry_type) { - case 0x01: + case 0x01: // double { string_t key; - get_bson_str(key); + get_bson_cstr(key); sax->key(key); double number; get_number_little_endian(number); sax->number_float(static_cast(number), ""); } break; - case 0x08: + case 0x02: // string { string_t key; - get_bson_str(key); + get_bson_cstr(key); + sax->key(key); + std::int32_t len; + string_t value; + get_number_little_endian(len); + get_string(len - 1ul, value); + get(); + sax->string(value); + } + break; + case 0x08: // boolean + { + string_t key; + get_bson_cstr(key); sax->key(key); sax->boolean(static_cast(get())); } diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 283c2cf2..a377d348 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -688,7 +688,7 @@ class binary_writer std::size_t write_bson_double(const typename BasicJsonType::string_t& name, const BasicJsonType& j) { - oa->write_character(static_cast(0x01)); // boolean + oa->write_character(static_cast(0x01)); // double oa->write_characters( reinterpret_cast(name.c_str()), name.size() + 1u); @@ -696,6 +696,21 @@ class binary_writer return /*id*/ 1ul + name.size() + 1u + /*double value*/ 8u; } + std::size_t write_bson_string(const typename BasicJsonType::string_t& name, const BasicJsonType& j) + { + oa->write_character(static_cast(0x02)); // string (UTF-8) + oa->write_characters( + reinterpret_cast(name.c_str()), + name.size() + 1u); + + write_number_little_endian(static_cast(j.m_value.string->size() + 1ul)); + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size() + 1); + + return /*id*/ 1ul + name.size() + 1ul + sizeof(std::int32_t) + j.m_value.string->size() + 1ul; + } + std::size_t write_bson_object_entry(const typename BasicJsonType::string_t& name, const BasicJsonType& j) { switch (j.type()) @@ -707,6 +722,8 @@ class binary_writer return write_bson_boolean(name, j); case value_t::number_float: return write_bson_double(name, j); + case value_t::string: + return write_bson_string(name, j); }; return 0ul; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 3da42389..c549f907 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -6123,7 +6123,7 @@ class binary_reader /*! @return whether array creation completed */ - bool get_bson_str(string_t& result) + bool get_bson_cstr(string_t& result) { bool success = true; generate_until(std::back_inserter(result), [](char c) @@ -6132,7 +6132,7 @@ class binary_reader }, [this, &success] { get(); - if (JSON_UNLIKELY(unexpect_eof())) + if (JSON_UNLIKELY(not unexpect_eof())) { success = false; } @@ -6156,20 +6156,33 @@ class binary_reader { switch (entry_type) { - case 0x01: + case 0x01: // double { string_t key; - get_bson_str(key); + get_bson_cstr(key); sax->key(key); double number; get_number_little_endian(number); sax->number_float(static_cast(number), ""); } break; - case 0x08: + case 0x02: // string { string_t key; - get_bson_str(key); + get_bson_cstr(key); + sax->key(key); + std::int32_t len; + string_t value; + get_number_little_endian(len); + get_string(len - 1ul, value); + get(); + sax->string(value); + } + break; + case 0x08: // boolean + { + string_t key; + get_bson_cstr(key); sax->key(key); sax->boolean(static_cast(get())); } @@ -8481,7 +8494,7 @@ class binary_writer std::size_t write_bson_double(const typename BasicJsonType::string_t& name, const BasicJsonType& j) { - oa->write_character(static_cast(0x01)); // boolean + oa->write_character(static_cast(0x01)); // double oa->write_characters( reinterpret_cast(name.c_str()), name.size() + 1u); @@ -8489,6 +8502,21 @@ class binary_writer return /*id*/ 1ul + name.size() + 1u + /*double value*/ 8u; } + std::size_t write_bson_string(const typename BasicJsonType::string_t& name, const BasicJsonType& j) + { + oa->write_character(static_cast(0x02)); // string (UTF-8) + oa->write_characters( + reinterpret_cast(name.c_str()), + name.size() + 1u); + + write_number_little_endian(static_cast(j.m_value.string->size() + 1ul)); + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size() + 1); + + return /*id*/ 1ul + name.size() + 1ul + sizeof(std::int32_t) + j.m_value.string->size() + 1ul; + } + std::size_t write_bson_object_entry(const typename BasicJsonType::string_t& name, const BasicJsonType& j) { switch (j.type()) @@ -8500,6 +8528,8 @@ class binary_writer return write_bson_boolean(name, j); case value_t::number_float: return write_bson_double(name, j); + case value_t::string: + return write_bson_string(name, j); }; return 0ul; diff --git a/test/src/unit-bson.cpp b/test/src/unit-bson.cpp index 97746807..e3b4717f 100644 --- a/test/src/unit-bson.cpp +++ b/test/src/unit-bson.cpp @@ -183,5 +183,31 @@ TEST_CASE("BSON") CHECK(json::from_bson(result) == j); CHECK(json::from_bson(result, true, false) == j); } + + SECTION("non-empty object with string") + { + json j = + { + { "entry", "bsonstr" } + }; + + std::vector expected = + { + 0x18, 0x00, 0x00, 0x00, // size (little endian) + 0x02, /// entry: string (UTF-8) + 'e', 'n', 't', 'r', 'y', '\x00', + 0x08, 0x00, 0x00, 0x00, 'b', 's', 'o', 'n', 's', 't', 'r', '\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); + } + + } }