BSON: Support empty objects
This commit is contained in:
		
							parent
							
								
									f06c8fd8e3
								
							
						
					
					
						commit
						5f5836ce1c
					
				
					 4 changed files with 124 additions and 33 deletions
				
			
		| 
						 | 
				
			
			@ -127,25 +127,18 @@ class binary_reader
 | 
			
		|||
 | 
			
		||||
    bool parse_bson_internal()
 | 
			
		||||
    {
 | 
			
		||||
        int docLen = 0;
 | 
			
		||||
        int byte;
 | 
			
		||||
        for (int i = 0; i < 4; ++i)
 | 
			
		||||
        std::int32_t documentSize;
 | 
			
		||||
        get_number_little_endian(documentSize);
 | 
			
		||||
 | 
			
		||||
        if (not JSON_UNLIKELY(sax->start_object(documentSize - 5)))
 | 
			
		||||
        {
 | 
			
		||||
            byte = get();
 | 
			
		||||
            if (JSON_UNLIKELY(current == std::char_traits<char>::eof()))
 | 
			
		||||
            {
 | 
			
		||||
                if (i == 1)
 | 
			
		||||
                {
 | 
			
		||||
                    return sax->boolean(docLen != 0x00);
 | 
			
		||||
                }
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            docLen |= static_cast<std::int32_t>(byte) << 8 * i;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //sax->null();
 | 
			
		||||
        const auto result = sax->end_object();
 | 
			
		||||
 | 
			
		||||
        get();
 | 
			
		||||
        return true;
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
| 
						 | 
				
			
			@ -927,6 +920,35 @@ class binary_reader
 | 
			
		|||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename NumberType>
 | 
			
		||||
    bool get_number_little_endian(NumberType& result)
 | 
			
		||||
    {
 | 
			
		||||
        // step 1: read input into array with system's byte order
 | 
			
		||||
        std::array<uint8_t, sizeof(NumberType)> vec;
 | 
			
		||||
        for (std::size_t i = 0; i < sizeof(NumberType); ++i)
 | 
			
		||||
        {
 | 
			
		||||
            get();
 | 
			
		||||
            if (JSON_UNLIKELY(not unexpect_eof()))
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // reverse byte order prior to conversion if necessary
 | 
			
		||||
            if (!is_little_endian)
 | 
			
		||||
            {
 | 
			
		||||
                vec[sizeof(NumberType) - i - 1] = static_cast<uint8_t>(current);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                vec[i] = static_cast<uint8_t>(current); // LCOV_EXCL_LINE
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // step 2: convert array into number of type T and return
 | 
			
		||||
        std::memcpy(&result, vec.data(), sizeof(NumberType));
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief create a string by reading characters from the input
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -684,7 +684,8 @@ class binary_writer
 | 
			
		|||
    void write_bson_object(const BasicJsonType& j)
 | 
			
		||||
    {
 | 
			
		||||
        assert(j.type() == value_t::object);
 | 
			
		||||
 | 
			
		||||
        write_number_little_endian(5);
 | 
			
		||||
        oa->write_character(static_cast<CharType>(0x00));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6068,25 +6068,18 @@ class binary_reader
 | 
			
		|||
 | 
			
		||||
    bool parse_bson_internal()
 | 
			
		||||
    {
 | 
			
		||||
        int docLen = 0;
 | 
			
		||||
        int byte;
 | 
			
		||||
        for (int i = 0; i < 4; ++i)
 | 
			
		||||
        std::int32_t documentSize;
 | 
			
		||||
        get_number_little_endian(documentSize);
 | 
			
		||||
 | 
			
		||||
        if (not JSON_UNLIKELY(sax->start_object(documentSize - 5)))
 | 
			
		||||
        {
 | 
			
		||||
            byte = get();
 | 
			
		||||
            if (JSON_UNLIKELY(current == std::char_traits<char>::eof()))
 | 
			
		||||
            {
 | 
			
		||||
                if (i == 1)
 | 
			
		||||
                {
 | 
			
		||||
                    return sax->boolean(docLen != 0x00);
 | 
			
		||||
                }
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            docLen |= static_cast<std::int32_t>(byte) << 8 * i;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //sax->null();
 | 
			
		||||
        const auto result = sax->end_object();
 | 
			
		||||
 | 
			
		||||
        get();
 | 
			
		||||
        return true;
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
| 
						 | 
				
			
			@ -6868,6 +6861,35 @@ class binary_reader
 | 
			
		|||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename NumberType>
 | 
			
		||||
    bool get_number_little_endian(NumberType& result)
 | 
			
		||||
    {
 | 
			
		||||
        // step 1: read input into array with system's byte order
 | 
			
		||||
        std::array<uint8_t, sizeof(NumberType)> vec;
 | 
			
		||||
        for (std::size_t i = 0; i < sizeof(NumberType); ++i)
 | 
			
		||||
        {
 | 
			
		||||
            get();
 | 
			
		||||
            if (JSON_UNLIKELY(not unexpect_eof()))
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // reverse byte order prior to conversion if necessary
 | 
			
		||||
            if (!is_little_endian)
 | 
			
		||||
            {
 | 
			
		||||
                vec[sizeof(NumberType) - i - 1] = static_cast<uint8_t>(current);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                vec[i] = static_cast<uint8_t>(current); // LCOV_EXCL_LINE
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // step 2: convert array into number of type T and return
 | 
			
		||||
        std::memcpy(&result, vec.data(), sizeof(NumberType));
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
    @brief create a string by reading characters from the input
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -8354,7 +8376,8 @@ class binary_writer
 | 
			
		|||
    void write_bson_object(const BasicJsonType& j)
 | 
			
		||||
    {
 | 
			
		||||
        assert(j.type() == value_t::object);
 | 
			
		||||
 | 
			
		||||
        write_number_little_endian(5);
 | 
			
		||||
        oa->write_character(static_cast<CharType>(0x00));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,7 +36,7 @@ using nlohmann::json;
 | 
			
		|||
 | 
			
		||||
TEST_CASE("BSON")
 | 
			
		||||
{
 | 
			
		||||
    SECTION("individual values")
 | 
			
		||||
    SECTION("individual values not supported")
 | 
			
		||||
    {
 | 
			
		||||
        SECTION("discarded")
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -66,5 +66,50 @@ TEST_CASE("BSON")
 | 
			
		|||
                REQUIRE_THROWS_AS(json::to_bson(j), json::type_error);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SECTION("number")
 | 
			
		||||
        {
 | 
			
		||||
            json j = 42;
 | 
			
		||||
            REQUIRE_THROWS_AS(json::to_bson(j), json::type_error);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SECTION("float")
 | 
			
		||||
        {
 | 
			
		||||
            json j = 4.2;
 | 
			
		||||
            REQUIRE_THROWS_AS(json::to_bson(j), json::type_error);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SECTION("string")
 | 
			
		||||
        {
 | 
			
		||||
            json j = "not supported";
 | 
			
		||||
            REQUIRE_THROWS_AS(json::to_bson(j), json::type_error);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SECTION("array")
 | 
			
		||||
        {
 | 
			
		||||
            json j = std::vector<int> {1, 2, 3, 4, 5, 6, 7};
 | 
			
		||||
            REQUIRE_THROWS_AS(json::to_bson(j), json::type_error);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SECTION("objects")
 | 
			
		||||
    {
 | 
			
		||||
        SECTION("empty object")
 | 
			
		||||
        {
 | 
			
		||||
            json j = json::object();
 | 
			
		||||
            std::vector<uint8_t> expected =
 | 
			
		||||
            {
 | 
			
		||||
                0x05, 0x00, 0x00, 0x00, // size (little endian)
 | 
			
		||||
                // no entries
 | 
			
		||||
                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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue