diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index d3c09bc9..0feb6dd4 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -41,9 +41,6 @@ class binary_reader using json_sax_t = json_sax; public: - /// the supported binary input formats - enum class binary_format_t { cbor, msgpack, ubjson }; - /*! @brief create a binary reader @@ -61,30 +58,35 @@ class binary_reader @return */ - bool sax_parse(const binary_format_t format, json_sax_t* sax_, const bool strict) + bool sax_parse(const input_format_t format, + json_sax_t* sax_, + const bool strict = true) { sax = sax_; bool result; switch (format) { - case binary_format_t::cbor: + case input_format_t::cbor: result = parse_cbor_internal(); break; - case binary_format_t::msgpack: + case input_format_t::msgpack: result = parse_msgpack_internal(); break; - case binary_format_t::ubjson: + case input_format_t::ubjson: result = parse_ubjson_internal(); break; + + default: + assert(false); // LCOV_EXCL_LINE } // strict mode: next byte must be EOF if (result and strict) { - if (format == binary_format_t::ubjson) + if (format == input_format_t::ubjson) { get_ignore_noop(); } diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index ef66948d..92987e97 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -20,6 +20,9 @@ namespace nlohmann { namespace detail { +/// the supported input formats +enum class input_format_t { json, cbor, msgpack, ubjson }; + //////////////////// // input adapters // //////////////////// diff --git a/include/nlohmann/detail/input/json_sax.hpp b/include/nlohmann/detail/input/json_sax.hpp index 5763e652..98479eb9 100644 --- a/include/nlohmann/detail/input/json_sax.hpp +++ b/include/nlohmann/detail/input/json_sax.hpp @@ -105,21 +105,12 @@ struct json_sax */ virtual bool end_array() = 0; - /*! - @brief a binary value was read - @param[in] val byte vector - @return whether parsing should proceed - @note examples are CBOR type 2 strings, MessagePack bin, and maybe UBJSON - array - */ - virtual bool binary(const std::vector& val) = 0; - /*! @brief a parse error occurred @param[in] position the position in the input where the error occurs @param[in] last_token the last read token @param[in] error_msg a detailed error message - @return whether parsing should proceed + @return whether parsing should proceed (must return false) */ virtual bool parse_error(std::size_t position, const std::string& last_token, @@ -225,11 +216,6 @@ class json_sax_dom_parser : public json_sax return true; } - bool binary(const std::vector&) override - { - return true; - } - bool parse_error(std::size_t, const std::string&, const detail::exception& ex) override { @@ -430,11 +416,6 @@ class json_sax_dom_callback_parser : public json_sax return true; } - bool binary(const std::vector&) override - { - return true; - } - bool parse_error(std::size_t, const std::string&, const detail::exception& ex) override { @@ -580,11 +561,6 @@ class json_sax_acceptor : public json_sax return true; } - bool binary(const std::vector&) override - { - return true; - } - bool parse_error(std::size_t, const std::string&, const detail::exception&) override { return false; diff --git a/include/nlohmann/detail/input/lexer.hpp b/include/nlohmann/detail/input/lexer.hpp index 98cc1b69..20c1b3fe 100644 --- a/include/nlohmann/detail/input/lexer.hpp +++ b/include/nlohmann/detail/input/lexer.hpp @@ -99,7 +99,7 @@ class lexer } } - explicit lexer(detail::input_adapter_t adapter) + explicit lexer(detail::input_adapter_t&& adapter) : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} // delete because of pointer members diff --git a/include/nlohmann/detail/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp index 5d389dc6..a38101c9 100644 --- a/include/nlohmann/detail/input/parser.hpp +++ b/include/nlohmann/detail/input/parser.hpp @@ -60,10 +60,10 @@ class parser std::function; /// a parser reading from an input adapter - explicit parser(detail::input_adapter_t adapter, + explicit parser(detail::input_adapter_t&& adapter, const parser_callback_t cb = nullptr, const bool allow_exceptions_ = true) - : callback(cb), m_lexer(adapter), allow_exceptions(allow_exceptions_) + : callback(cb), m_lexer(std::move(adapter)), allow_exceptions(allow_exceptions_) { // read first token get_token(); @@ -160,19 +160,22 @@ class parser bool accept(const bool strict = true) { json_sax_acceptor sax_acceptor; - - if (not sax_parse_internal(&sax_acceptor)) - { - return false; - } - - // strict => last token must be EOF - return not strict or (get_token() == token_type::end_of_input); + return sax_parse(&sax_acceptor, strict); } - bool sax_parse(json_sax_t* sax) + bool sax_parse(json_sax_t* sax, const bool strict = true) { - return sax_parse_internal(sax); + const bool result = sax_parse_internal(sax); + + // strict mode: next byte must be EOF + if (result and strict and (get_token() != token_type::end_of_input)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input))); + } + + return result; } private: diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index ff2f7f34..66d0fb37 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -209,6 +209,8 @@ class basic_json /// helper type for initializer lists of basic_json values using initializer_list_t = std::initializer_list>; + using input_format_t = detail::input_format_t; + //////////////// // exceptions // //////////////// @@ -5996,7 +5998,7 @@ class basic_json @since version 2.0.3 (contiguous containers) */ - static basic_json parse(detail::input_adapter i, + static basic_json parse(detail::input_adapter&& i, const parser_callback_t cb = nullptr, const bool allow_exceptions = true) { @@ -6005,36 +6007,23 @@ class basic_json return result; } - /*! - @copydoc basic_json parse(detail::input_adapter, const parser_callback_t) - */ - static basic_json parse(detail::input_adapter& i, - const parser_callback_t cb = nullptr, - const bool allow_exceptions = true) - { - basic_json result; - parser(i, cb, allow_exceptions).parse(true, result); - return result; - } - - static bool accept(detail::input_adapter i) + static bool accept(detail::input_adapter&& i) { return parser(i).accept(true); } - static bool accept(detail::input_adapter& i) + static bool sax_parse(detail::input_adapter&& i, json_sax_t* sax, + input_format_t format = input_format_t::json, + const bool strict = true) { - return parser(i).accept(true); - } - - static bool sax_parse(detail::input_adapter i, json_sax_t* sax) - { - return parser(i).sax_parse(sax); - } - - static bool sax_parse(detail::input_adapter& i, json_sax_t* sax) - { - return parser(i).sax_parse(sax); + assert(sax); + switch (format) + { + case input_format_t::json: + return parser(std::move(i)).sax_parse(sax, strict); + default: + return binary_reader(std::move(i)).sax_parse(format, sax, strict); + } } /*! @@ -6639,13 +6628,13 @@ class basic_json @a strict parameter since 3.0.0; added @allow_exceptions parameter since 3.2.0 */ - static basic_json from_cbor(detail::input_adapter i, + static basic_json from_cbor(detail::input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::input_adapter(i)).sax_parse(binary_reader::binary_format_t::cbor, &sdp, strict); + const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::cbor, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -6660,7 +6649,7 @@ class basic_json { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).sax_parse(binary_reader::binary_format_t::cbor, &sdp, strict); + const bool res = binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).sax_parse(input_format_t::cbor, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -6742,13 +6731,13 @@ class basic_json @a strict parameter since 3.0.0; added @allow_exceptions parameter since 3.2.0 */ - static basic_json from_msgpack(detail::input_adapter i, + static basic_json from_msgpack(detail::input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::input_adapter(i)).sax_parse(binary_reader::binary_format_t::msgpack, &sdp, strict); + const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::msgpack, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -6763,7 +6752,7 @@ class basic_json { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).sax_parse(binary_reader::binary_format_t::msgpack, &sdp, strict); + const bool res = binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).sax_parse(input_format_t::msgpack, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -6824,13 +6813,13 @@ class basic_json @since version 3.1.0; added @allow_exceptions parameter since 3.2.0 */ - static basic_json from_ubjson(detail::input_adapter i, + static basic_json from_ubjson(detail::input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::input_adapter(i)).sax_parse(binary_reader::binary_format_t::ubjson, &sdp, strict); + const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::ubjson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -6845,7 +6834,7 @@ class basic_json { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).sax_parse(binary_reader::binary_format_t::ubjson, &sdp, strict); + const bool res = binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).sax_parse(input_format_t::ubjson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 67af8de1..55e1e01b 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -1593,6 +1593,9 @@ namespace nlohmann { namespace detail { +/// the supported input formats +enum class input_format_t { json, cbor, msgpack, ubjson }; + //////////////////// // input adapters // //////////////////// @@ -1938,7 +1941,7 @@ class lexer } } - explicit lexer(detail::input_adapter_t adapter) + explicit lexer(detail::input_adapter_t&& adapter) : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} // delete because of pointer members @@ -3242,21 +3245,12 @@ struct json_sax */ virtual bool end_array() = 0; - /*! - @brief a binary value was read - @param[in] val byte vector - @return whether parsing should proceed - @note examples are CBOR type 2 strings, MessagePack bin, and maybe UBJSON - array - */ - virtual bool binary(const std::vector& val) = 0; - /*! @brief a parse error occurred @param[in] position the position in the input where the error occurs @param[in] last_token the last read token @param[in] error_msg a detailed error message - @return whether parsing should proceed + @return whether parsing should proceed (must return false) */ virtual bool parse_error(std::size_t position, const std::string& last_token, @@ -3362,11 +3356,6 @@ class json_sax_dom_parser : public json_sax return true; } - bool binary(const std::vector&) override - { - return true; - } - bool parse_error(std::size_t, const std::string&, const detail::exception& ex) override { @@ -3567,11 +3556,6 @@ class json_sax_dom_callback_parser : public json_sax return true; } - bool binary(const std::vector&) override - { - return true; - } - bool parse_error(std::size_t, const std::string&, const detail::exception& ex) override { @@ -3717,11 +3701,6 @@ class json_sax_acceptor : public json_sax return true; } - bool binary(const std::vector&) override - { - return true; - } - bool parse_error(std::size_t, const std::string&, const detail::exception&) override { return false; @@ -3783,10 +3762,10 @@ class parser std::function; /// a parser reading from an input adapter - explicit parser(detail::input_adapter_t adapter, + explicit parser(detail::input_adapter_t&& adapter, const parser_callback_t cb = nullptr, const bool allow_exceptions_ = true) - : callback(cb), m_lexer(adapter), allow_exceptions(allow_exceptions_) + : callback(cb), m_lexer(std::move(adapter)), allow_exceptions(allow_exceptions_) { // read first token get_token(); @@ -3883,19 +3862,22 @@ class parser bool accept(const bool strict = true) { json_sax_acceptor sax_acceptor; - - if (not sax_parse_internal(&sax_acceptor)) - { - return false; - } - - // strict => last token must be EOF - return not strict or (get_token() == token_type::end_of_input); + return sax_parse(&sax_acceptor, strict); } - bool sax_parse(json_sax_t* sax) + bool sax_parse(json_sax_t* sax, const bool strict = true) { - return sax_parse_internal(sax); + const bool result = sax_parse_internal(sax); + + // strict mode: next byte must be EOF + if (result and strict and (get_token() != token_type::end_of_input)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input))); + } + + return result; } private: @@ -5699,9 +5681,6 @@ class binary_reader using json_sax_t = json_sax; public: - /// the supported binary input formats - enum class binary_format_t { cbor, msgpack, ubjson }; - /*! @brief create a binary reader @@ -5719,30 +5698,35 @@ class binary_reader @return */ - bool sax_parse(const binary_format_t format, json_sax_t* sax_, const bool strict) + bool sax_parse(const input_format_t format, + json_sax_t* sax_, + const bool strict = true) { sax = sax_; bool result; switch (format) { - case binary_format_t::cbor: + case input_format_t::cbor: result = parse_cbor_internal(); break; - case binary_format_t::msgpack: + case input_format_t::msgpack: result = parse_msgpack_internal(); break; - case binary_format_t::ubjson: + case input_format_t::ubjson: result = parse_ubjson_internal(); break; + + default: + assert(false); // LCOV_EXCL_LINE } // strict mode: next byte must be EOF if (result and strict) { - if (format == binary_format_t::ubjson) + if (format == input_format_t::ubjson) { get_ignore_noop(); } @@ -10958,6 +10942,8 @@ class basic_json /// helper type for initializer lists of basic_json values using initializer_list_t = std::initializer_list>; + using input_format_t = detail::input_format_t; + //////////////// // exceptions // //////////////// @@ -16745,7 +16731,7 @@ class basic_json @since version 2.0.3 (contiguous containers) */ - static basic_json parse(detail::input_adapter i, + static basic_json parse(detail::input_adapter&& i, const parser_callback_t cb = nullptr, const bool allow_exceptions = true) { @@ -16754,36 +16740,23 @@ class basic_json return result; } - /*! - @copydoc basic_json parse(detail::input_adapter, const parser_callback_t) - */ - static basic_json parse(detail::input_adapter& i, - const parser_callback_t cb = nullptr, - const bool allow_exceptions = true) - { - basic_json result; - parser(i, cb, allow_exceptions).parse(true, result); - return result; - } - - static bool accept(detail::input_adapter i) + static bool accept(detail::input_adapter&& i) { return parser(i).accept(true); } - static bool accept(detail::input_adapter& i) + static bool sax_parse(detail::input_adapter&& i, json_sax_t* sax, + input_format_t format = input_format_t::json, + const bool strict = true) { - return parser(i).accept(true); - } - - static bool sax_parse(detail::input_adapter i, json_sax_t* sax) - { - return parser(i).sax_parse(sax); - } - - static bool sax_parse(detail::input_adapter& i, json_sax_t* sax) - { - return parser(i).sax_parse(sax); + assert(sax); + switch (format) + { + case input_format_t::json: + return parser(std::move(i)).sax_parse(sax, strict); + default: + return binary_reader(std::move(i)).sax_parse(format, sax, strict); + } } /*! @@ -17388,13 +17361,13 @@ class basic_json @a strict parameter since 3.0.0; added @allow_exceptions parameter since 3.2.0 */ - static basic_json from_cbor(detail::input_adapter i, + static basic_json from_cbor(detail::input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::input_adapter(i)).sax_parse(binary_reader::binary_format_t::cbor, &sdp, strict); + const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::cbor, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -17409,7 +17382,7 @@ class basic_json { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).sax_parse(binary_reader::binary_format_t::cbor, &sdp, strict); + const bool res = binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).sax_parse(input_format_t::cbor, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -17491,13 +17464,13 @@ class basic_json @a strict parameter since 3.0.0; added @allow_exceptions parameter since 3.2.0 */ - static basic_json from_msgpack(detail::input_adapter i, + static basic_json from_msgpack(detail::input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::input_adapter(i)).sax_parse(binary_reader::binary_format_t::msgpack, &sdp, strict); + const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::msgpack, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -17512,7 +17485,7 @@ class basic_json { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).sax_parse(binary_reader::binary_format_t::msgpack, &sdp, strict); + const bool res = binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).sax_parse(input_format_t::msgpack, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -17573,13 +17546,13 @@ class basic_json @since version 3.1.0; added @allow_exceptions parameter since 3.2.0 */ - static basic_json from_ubjson(detail::input_adapter i, + static basic_json from_ubjson(detail::input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::input_adapter(i)).sax_parse(binary_reader::binary_format_t::ubjson, &sdp, strict); + const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::ubjson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -17594,7 +17567,7 @@ class basic_json { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).sax_parse(binary_reader::binary_format_t::ubjson, &sdp, strict); + const bool res = binary_reader(detail::input_adapter(std::forward(a1), std::forward(a2))).sax_parse(input_format_t::ubjson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index ba07026a..cd8fb0db 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -33,6 +33,76 @@ using nlohmann::json; #include +class SaxCountdown : public nlohmann::json::json_sax_t +{ + public: + explicit SaxCountdown(const int count) : events_left(count) + {} + + bool null() override + { + return events_left-- > 0; + } + + bool boolean(bool) override + { + return events_left-- > 0; + } + + bool number_integer(json::number_integer_t) override + { + return events_left-- > 0; + } + + bool number_unsigned(json::number_unsigned_t) override + { + return events_left-- > 0; + } + + bool number_float(json::number_float_t, const std::string&) override + { + return events_left-- > 0; + } + + bool string(std::string&&) override + { + return events_left-- > 0; + } + + bool start_object(std::size_t) override + { + return events_left-- > 0; + } + + bool key(std::string&&) override + { + return events_left-- > 0; + } + + bool end_object() override + { + return events_left-- > 0; + } + + bool start_array(std::size_t) override + { + return events_left-- > 0; + } + + bool end_array() override + { + return events_left-- > 0; + } + + bool parse_error(std::size_t, const std::string&, const json::exception&) override + { + return false; + } + + private: + int events_left = 0; +}; + TEST_CASE("CBOR") { SECTION("individual values") @@ -1467,6 +1537,30 @@ TEST_CASE("CBOR") } } } + + SECTION("SAX aborts") + { + SECTION("start_array(len)") + { + std::vector v = {0x83, 0x01, 0x02, 0x03}; + SaxCountdown scp(0); + CHECK(not json::sax_parse(v, &scp, json::input_format_t::cbor)); + } + + SECTION("start_object(len)") + { + std::vector v = {0xA1, 0x63, 0x66, 0x6F, 0x6F, 0xF4}; + SaxCountdown scp(0); + CHECK(not json::sax_parse(v, &scp, json::input_format_t::cbor)); + } + + SECTION("key()") + { + std::vector v = {0xA1, 0x63, 0x66, 0x6F, 0x6F, 0xF4}; + SaxCountdown scp(1); + CHECK(not json::sax_parse(v, &scp, json::input_format_t::cbor)); + } + } } // use this testcase outside [hide] to run it with Valgrind diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index c425207a..1e100568 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -117,12 +117,6 @@ class SaxEventLogger : public nlohmann::json::json_sax_t return true; } - bool binary(const std::vector&) override - { - events.push_back("binary()"); - return true; - } - bool parse_error(std::size_t position, const std::string&, const json::exception&) override { errored = true; @@ -195,11 +189,6 @@ class SaxCountdown : public nlohmann::json::json_sax_t return events_left-- > 0; } - bool binary(const std::vector&) override - { - return events_left-- > 0; - } - bool parse_error(std::size_t, const std::string&, const json::exception&) override { return false; @@ -248,7 +237,7 @@ bool accept_helper(const std::string& s) // 4. parse with SAX (compare with relaxed accept result) SaxEventLogger el; - CHECK_NOTHROW(json::sax_parse(s, &el)); + CHECK_NOTHROW(json::sax_parse(s, &el, json::input_format_t::json, false)); CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept(false) == not el.errored); // 5. parse with simple callback diff --git a/test/src/unit-deserialization.cpp b/test/src/unit-deserialization.cpp index 4243e839..5aa3a8b6 100644 --- a/test/src/unit-deserialization.cpp +++ b/test/src/unit-deserialization.cpp @@ -116,12 +116,6 @@ struct SaxEventLogger : public nlohmann::json::json_sax_t return true; } - bool binary(const std::vector&) override - { - events.push_back("binary()"); - return true; - } - bool parse_error(std::size_t position, const std::string&, const json::exception&) override { events.push_back("parse_error(" + std::to_string(position) + ")"); diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp index e1c209d9..6974c530 100644 --- a/test/src/unit-msgpack.cpp +++ b/test/src/unit-msgpack.cpp @@ -33,6 +33,76 @@ using nlohmann::json; #include +class SaxCountdown : public nlohmann::json::json_sax_t +{ + public: + explicit SaxCountdown(const int count) : events_left(count) + {} + + bool null() override + { + return events_left-- > 0; + } + + bool boolean(bool) override + { + return events_left-- > 0; + } + + bool number_integer(json::number_integer_t) override + { + return events_left-- > 0; + } + + bool number_unsigned(json::number_unsigned_t) override + { + return events_left-- > 0; + } + + bool number_float(json::number_float_t, const std::string&) override + { + return events_left-- > 0; + } + + bool string(std::string&&) override + { + return events_left-- > 0; + } + + bool start_object(std::size_t) override + { + return events_left-- > 0; + } + + bool key(std::string&&) override + { + return events_left-- > 0; + } + + bool end_object() override + { + return events_left-- > 0; + } + + bool start_array(std::size_t) override + { + return events_left-- > 0; + } + + bool end_array() override + { + return events_left-- > 0; + } + + bool parse_error(std::size_t, const std::string&, const json::exception&) override + { + return false; + } + + private: + int events_left = 0; +}; + TEST_CASE("MessagePack") { SECTION("individual values") @@ -1200,6 +1270,30 @@ TEST_CASE("MessagePack") } } } + + SECTION("SAX aborts") + { + SECTION("start_array(len)") + { + std::vector v = {0x93, 0x01, 0x02, 0x03}; + SaxCountdown scp(0); + CHECK(not json::sax_parse(v, &scp, json::input_format_t::msgpack)); + } + + SECTION("start_object(len)") + { + std::vector v = {0x81, 0xa3, 0x66, 0x6F, 0x6F, 0xc2}; + SaxCountdown scp(0); + CHECK(not json::sax_parse(v, &scp, json::input_format_t::msgpack)); + } + + SECTION("key()") + { + std::vector v = {0x81, 0xa3, 0x66, 0x6F, 0x6F, 0xc2}; + SaxCountdown scp(1); + CHECK(not json::sax_parse(v, &scp, json::input_format_t::msgpack)); + } + } } diff --git a/test/src/unit-ubjson.cpp b/test/src/unit-ubjson.cpp index 11774268..7f92d969 100644 --- a/test/src/unit-ubjson.cpp +++ b/test/src/unit-ubjson.cpp @@ -33,6 +33,76 @@ using nlohmann::json; #include +class SaxCountdown : public nlohmann::json::json_sax_t +{ + public: + explicit SaxCountdown(const int count) : events_left(count) + {} + + bool null() override + { + return events_left-- > 0; + } + + bool boolean(bool) override + { + return events_left-- > 0; + } + + bool number_integer(json::number_integer_t) override + { + return events_left-- > 0; + } + + bool number_unsigned(json::number_unsigned_t) override + { + return events_left-- > 0; + } + + bool number_float(json::number_float_t, const std::string&) override + { + return events_left-- > 0; + } + + bool string(std::string&&) override + { + return events_left-- > 0; + } + + bool start_object(std::size_t) override + { + return events_left-- > 0; + } + + bool key(std::string&&) override + { + return events_left-- > 0; + } + + bool end_object() override + { + return events_left-- > 0; + } + + bool start_array(std::size_t) override + { + return events_left-- > 0; + } + + bool end_array() override + { + return events_left-- > 0; + } + + bool parse_error(std::size_t, const std::string&, const json::exception&) override + { + return false; + } + + private: + int events_left = 0; +}; + TEST_CASE("UBJSON") { SECTION("individual values") @@ -1241,6 +1311,51 @@ TEST_CASE("UBJSON") } } + SECTION("SAX aborts") + { + SECTION("start_array()") + { + std::vector v = {'[', 'T', 'F', ']'}; + SaxCountdown scp(0); + CHECK(not json::sax_parse(v, &scp, json::input_format_t::ubjson)); + } + + SECTION("start_object()") + { + std::vector v = {'{', 'i', 3, 'f', 'o', 'o', 'F', '}'}; + SaxCountdown scp(0); + CHECK(not json::sax_parse(v, &scp, json::input_format_t::ubjson)); + } + + SECTION("key() in object") + { + std::vector v = {'{', 'i', 3, 'f', 'o', 'o', 'F', '}'}; + SaxCountdown scp(1); + CHECK(not json::sax_parse(v, &scp, json::input_format_t::ubjson)); + } + + SECTION("start_array(len)") + { + std::vector v = {'[', '#', 'i', '2', 'T', 'F'}; + SaxCountdown scp(0); + CHECK(not json::sax_parse(v, &scp, json::input_format_t::ubjson)); + } + + SECTION("start_object(len)") + { + std::vector v = {'{', '#', 'i', '1', 3, 'f', 'o', 'o', 'F'}; + SaxCountdown scp(0); + CHECK(not json::sax_parse(v, &scp, json::input_format_t::ubjson)); + } + + SECTION("key() in object with length") + { + std::vector v = {'{', 'i', 3, 'f', 'o', 'o', 'F', '}'}; + SaxCountdown scp(1); + CHECK(not json::sax_parse(v, &scp, json::input_format_t::ubjson)); + } + } + SECTION("parsing values") { SECTION("strings")