From f0c6ab4d3ba93fedb6bf3fb9704d318967aab7f5 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 8 May 2020 14:21:11 +0200 Subject: [PATCH] :bug: fix bug in SAX callback parser --- include/nlohmann/detail/input/json_sax.hpp | 34 ++------------------ include/nlohmann/json.hpp | 2 +- single_include/nlohmann/json.hpp | 36 ++-------------------- test/src/unit-cbor.cpp | 23 ++++++++++++++ test/src/unit-pointer_access.cpp | 29 +++++++++++++++++ 5 files changed, 58 insertions(+), 66 deletions(-) diff --git a/include/nlohmann/detail/input/json_sax.hpp b/include/nlohmann/detail/input/json_sax.hpp index 47c859df0..c54b80df7 100644 --- a/include/nlohmann/detail/input/json_sax.hpp +++ b/include/nlohmann/detail/input/json_sax.hpp @@ -214,7 +214,7 @@ class json_sax_dom_parser bool binary(binary_t& val) { - handle_binary(val); + handle_value(BasicJsonType::binary_array(std::move(val))); return true; } @@ -327,36 +327,6 @@ class json_sax_dom_parser return object_element; } - /*! - @invariant If the ref stack is empty, then the passed value will be the new - root. - @invariant If the ref stack contains a value, then it is an array or an - object to which we can add elements - */ - template - JSON_HEDLEY_RETURNS_NON_NULL - BasicJsonType* handle_binary(BinaryValue&& v) - { - if (ref_stack.empty()) - { - root = BasicJsonType::binary_array(std::forward(v)); - return &root; - } - - assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); - - if (ref_stack.back()->is_array()) - { - ref_stack.back()->m_value.array->emplace_back(BasicJsonType::binary_array(std::forward(v))); - return &(ref_stack.back()->m_value.array->back()); - } - - assert(ref_stack.back()->is_object()); - assert(object_element); - *object_element = BasicJsonType::binary_array(std::forward(v)); - return object_element; - } - /// the parsed JSON value BasicJsonType& root; /// stack to model hierarchy of values @@ -434,7 +404,7 @@ class json_sax_dom_callback_parser bool binary(binary_t& val) { - handle_value(val); + handle_value(BasicJsonType::binary_array(val)); return true; } diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 792263e23..480f0e20b 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -2794,7 +2794,7 @@ class basic_json /// get a pointer to the value (binary) binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept { - return is_binary() ? m_value.binary : nullptr; + return is_binary() ? reinterpret_cast(m_value.binary) : nullptr; } /// get a pointer to the value (binary) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 93f6e7c9e..fc8c90267 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4881,7 +4881,7 @@ class json_sax_dom_parser bool binary(binary_t& val) { - handle_binary(val); + handle_value(BasicJsonType::binary_array(std::move(val))); return true; } @@ -4994,36 +4994,6 @@ class json_sax_dom_parser return object_element; } - /*! - @invariant If the ref stack is empty, then the passed value will be the new - root. - @invariant If the ref stack contains a value, then it is an array or an - object to which we can add elements - */ - template - JSON_HEDLEY_RETURNS_NON_NULL - BasicJsonType* handle_binary(BinaryValue&& v) - { - if (ref_stack.empty()) - { - root = BasicJsonType::binary_array(std::forward(v)); - return &root; - } - - assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); - - if (ref_stack.back()->is_array()) - { - ref_stack.back()->m_value.array->emplace_back(BasicJsonType::binary_array(std::forward(v))); - return &(ref_stack.back()->m_value.array->back()); - } - - assert(ref_stack.back()->is_object()); - assert(object_element); - *object_element = BasicJsonType::binary_array(std::forward(v)); - return object_element; - } - /// the parsed JSON value BasicJsonType& root; /// stack to model hierarchy of values @@ -5101,7 +5071,7 @@ class json_sax_dom_callback_parser bool binary(binary_t& val) { - handle_value(val); + handle_value(BasicJsonType::binary_array(val)); return true; } @@ -18280,7 +18250,7 @@ class basic_json /// get a pointer to the value (binary) binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept { - return is_binary() ? m_value.binary : nullptr; + return is_binary() ? reinterpret_cast(m_value.binary) : nullptr; } /// get a pointer to the value (binary) diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 4f0954da5..403e03024 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -1442,6 +1442,29 @@ TEST_CASE("CBOR") std::vector input = {0xA1, 0x63, 0x66, 0x6F, 0x6F, 0x40}; CHECK_NOTHROW(json::from_cbor(input)); } + + SECTION("SAX callback with binary") + { + // object mapping "foo" to byte string + std::vector input = {0xA1, 0x63, 0x66, 0x6F, 0x6F, 0x41, 0x00}; + + // callback to set binary_seen to true if a binary value was seen + bool binary_seen = false; + auto callback = [&binary_seen](int /*depth*/, json::parse_event_t /*event*/, json & parsed) + { + if (parsed.is_binary()) + { + binary_seen = true; + } + return true; + }; + + json j; + auto cbp = nlohmann::detail::json_sax_dom_callback_parser(j, callback, true); + CHECK(json::sax_parse(input, &cbp, json::input_format_t::cbor)); + CHECK(j.at("foo").is_binary()); + CHECK(binary_seen); + } } } diff --git a/test/src/unit-pointer_access.cpp b/test/src/unit-pointer_access.cpp index 95fdb7805..f61cfee99 100644 --- a/test/src/unit-pointer_access.cpp +++ b/test/src/unit-pointer_access.cpp @@ -442,4 +442,33 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() == nullptr); } + + SECTION("pointer access to const binary_t") + { + using test_type = const json::binary_t; + const json value = json::binary_array({}); + + // check if pointers are returned correctly + test_type* p1 = value.get_ptr(); + CHECK(p1 == value.get_ptr()); + //CHECK(*p1 == value.get()); + + const test_type* p2 = value.get_ptr(); + CHECK(p2 == value.get_ptr()); + //CHECK(*p2 == value.get()); + + const test_type* const p3 = value.get_ptr(); + CHECK(p3 == value.get_ptr()); + //CHECK(*p3 == value.get()); + + // check if null pointers are returned correctly + CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() != nullptr); + } }