From 7c19aa22108eef6ff01a16b7fa7b09ef9058b3b5 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 1 Aug 2021 22:00:57 +0200 Subject: [PATCH 01/14] :recycle: overwork byte_container_with_subtype --- .../nlohmann/byte_container_with_subtype.hpp | 16 +-- single_include/nlohmann/json.hpp | 16 +-- test/src/unit-byte_container_with_subtype.cpp | 97 +++++++++++++++++++ 3 files changed, 115 insertions(+), 14 deletions(-) create mode 100644 test/src/unit-byte_container_with_subtype.cpp diff --git a/include/nlohmann/byte_container_with_subtype.hpp b/include/nlohmann/byte_container_with_subtype.hpp index df68395a25..b9a1faf3e2 100644 --- a/include/nlohmann/byte_container_with_subtype.hpp +++ b/include/nlohmann/byte_container_with_subtype.hpp @@ -26,6 +26,8 @@ class byte_container_with_subtype : public BinaryType public: /// the type of the underlying container using container_type = BinaryType; + /// the type of the subtype + using subtype_type = std::uint8_t; byte_container_with_subtype() noexcept(noexcept(container_type())) : container_type() @@ -39,13 +41,13 @@ class byte_container_with_subtype : public BinaryType : container_type(std::move(b)) {} - byte_container_with_subtype(const container_type& b, std::uint8_t subtype_) noexcept(noexcept(container_type(b))) + byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b))) : container_type(b) , m_subtype(subtype_) , m_has_subtype(true) {} - byte_container_with_subtype(container_type&& b, std::uint8_t subtype_) noexcept(noexcept(container_type(std::move(b)))) + byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b)))) : container_type(std::move(b)) , m_subtype(subtype_) , m_has_subtype(true) @@ -80,7 +82,7 @@ class byte_container_with_subtype : public BinaryType @since version 3.8.0 */ - void set_subtype(std::uint8_t subtype_) noexcept + void set_subtype(subtype_type subtype_) noexcept { m_subtype = subtype_; m_has_subtype = true; @@ -90,7 +92,7 @@ class byte_container_with_subtype : public BinaryType @brief return the binary subtype Returns the numerical subtype of the value if it has a subtype. If it does - not have a subtype, this function will return size_t(-1) as a sentinel + not have a subtype, this function will return subtype_type(-1) as a sentinel value. @return the numerical subtype of the binary value @@ -107,9 +109,9 @@ class byte_container_with_subtype : public BinaryType @since version 3.8.0 */ - constexpr std::uint8_t subtype() const noexcept + constexpr subtype_type subtype() const noexcept { - return m_subtype; + return m_has_subtype ? m_subtype : subtype_type(-1); } /*! @@ -159,7 +161,7 @@ class byte_container_with_subtype : public BinaryType } private: - std::uint8_t m_subtype = 0; + subtype_type m_subtype = 0; bool m_has_subtype = false; }; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 28ce55292c..fc3d341594 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4982,6 +4982,8 @@ class byte_container_with_subtype : public BinaryType public: /// the type of the underlying container using container_type = BinaryType; + /// the type of the subtype + using subtype_type = std::uint8_t; byte_container_with_subtype() noexcept(noexcept(container_type())) : container_type() @@ -4995,13 +4997,13 @@ class byte_container_with_subtype : public BinaryType : container_type(std::move(b)) {} - byte_container_with_subtype(const container_type& b, std::uint8_t subtype_) noexcept(noexcept(container_type(b))) + byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b))) : container_type(b) , m_subtype(subtype_) , m_has_subtype(true) {} - byte_container_with_subtype(container_type&& b, std::uint8_t subtype_) noexcept(noexcept(container_type(std::move(b)))) + byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b)))) : container_type(std::move(b)) , m_subtype(subtype_) , m_has_subtype(true) @@ -5036,7 +5038,7 @@ class byte_container_with_subtype : public BinaryType @since version 3.8.0 */ - void set_subtype(std::uint8_t subtype_) noexcept + void set_subtype(subtype_type subtype_) noexcept { m_subtype = subtype_; m_has_subtype = true; @@ -5046,7 +5048,7 @@ class byte_container_with_subtype : public BinaryType @brief return the binary subtype Returns the numerical subtype of the value if it has a subtype. If it does - not have a subtype, this function will return size_t(-1) as a sentinel + not have a subtype, this function will return subtype_type(-1) as a sentinel value. @return the numerical subtype of the binary value @@ -5063,9 +5065,9 @@ class byte_container_with_subtype : public BinaryType @since version 3.8.0 */ - constexpr std::uint8_t subtype() const noexcept + constexpr subtype_type subtype() const noexcept { - return m_subtype; + return m_has_subtype ? m_subtype : subtype_type(-1); } /*! @@ -5115,7 +5117,7 @@ class byte_container_with_subtype : public BinaryType } private: - std::uint8_t m_subtype = 0; + subtype_type m_subtype = 0; bool m_has_subtype = false; }; diff --git a/test/src/unit-byte_container_with_subtype.cpp b/test/src/unit-byte_container_with_subtype.cpp new file mode 100644 index 0000000000..ba9c3c9e1d --- /dev/null +++ b/test/src/unit-byte_container_with_subtype.cpp @@ -0,0 +1,97 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ (test suite) +| | |__ | | | | | | version 3.9.1 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "doctest_compatibility.h" + +#include +using nlohmann::json; + +TEST_CASE("byte_container_with_subtype") +{ + using subtype_type = nlohmann::byte_container_with_subtype>::subtype_type; + + SECTION("empty container") + { + nlohmann::byte_container_with_subtype> container; + + CHECK(!container.has_subtype()); + CHECK(container.subtype() == subtype_type(-1)); + + container.clear_subtype(); + CHECK(!container.has_subtype()); + CHECK(container.subtype() == subtype_type(-1)); + + container.set_subtype(42); + CHECK(container.has_subtype()); + CHECK(container.subtype() == 42); + } + + SECTION("subtyped container") + { + nlohmann::byte_container_with_subtype> container({}, 42); + CHECK(container.has_subtype()); + CHECK(container.subtype() == 42); + + container.clear_subtype(); + CHECK(!container.has_subtype()); + CHECK(container.subtype() == subtype_type(-1)); + } + + SECTION("comparisons") + { + std::vector bytes = {{0xCA, 0xFE, 0xBA, 0xBE}}; + nlohmann::byte_container_with_subtype> container1; + nlohmann::byte_container_with_subtype> container2({}, 42); + nlohmann::byte_container_with_subtype> container3(bytes); + nlohmann::byte_container_with_subtype> container4(bytes, 42); + + CHECK(container1 == container1); + CHECK(container1 != container2); + CHECK(container1 != container3); + CHECK(container1 != container4); + CHECK(container2 != container1); + CHECK(container2 == container2); + CHECK(container2 != container3); + CHECK(container2 != container4); + CHECK(container3 != container1); + CHECK(container3 != container2); + CHECK(container3 == container3); + CHECK(container3 != container4); + CHECK(container4 != container1); + CHECK(container4 != container2); + CHECK(container4 != container3); + CHECK(container4 == container4); + + container3.clear(); + container4.clear(); + + CHECK(container1 == container3); + CHECK(container2 == container4); + } +} From 3eb1fb6be7dd4105f8f66c8d63dfc4f5e36bf147 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 6 Aug 2021 13:26:00 +0200 Subject: [PATCH 02/14] :recycle: change type of binary subtype --- include/nlohmann/byte_container_with_subtype.hpp | 2 +- single_include/nlohmann/json.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/byte_container_with_subtype.hpp b/include/nlohmann/byte_container_with_subtype.hpp index b9a1faf3e2..ffbacdc6d3 100644 --- a/include/nlohmann/byte_container_with_subtype.hpp +++ b/include/nlohmann/byte_container_with_subtype.hpp @@ -27,7 +27,7 @@ class byte_container_with_subtype : public BinaryType /// the type of the underlying container using container_type = BinaryType; /// the type of the subtype - using subtype_type = std::uint8_t; + using subtype_type = std::uint64_t; byte_container_with_subtype() noexcept(noexcept(container_type())) : container_type() diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 6efa460eef..3fcf708b1a 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4983,7 +4983,7 @@ class byte_container_with_subtype : public BinaryType /// the type of the underlying container using container_type = BinaryType; /// the type of the subtype - using subtype_type = std::uint8_t; + using subtype_type = std::uint64_t; byte_container_with_subtype() noexcept(noexcept(container_type())) : container_type() From 046df035fa5a6aced7342a1fe858af9ed4c09f16 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 6 Aug 2021 13:45:35 +0200 Subject: [PATCH 03/14] :recycle: change type of binary subtype --- include/nlohmann/detail/output/serializer.hpp | 3 ++- single_include/nlohmann/json.hpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index 9c2182c4a4..4409934597 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -674,6 +674,7 @@ class serializer @tparam NumberType either @a number_integer_t or @a number_unsigned_t */ template < typename NumberType, detail::enable_if_t < + std::is_integral::value || std::is_same::value || std::is_same::value || std::is_same::value, @@ -706,7 +707,7 @@ class serializer // use a pointer to fill the buffer auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg) - const bool is_negative = std::is_same::value && !(x >= 0); // see issue #755 + const bool is_negative = std::is_signed::value && !(x >= 0); // see issue #755 number_unsigned_t abs_value; unsigned int n_chars{}; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 3fcf708b1a..1f557450c6 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -16692,6 +16692,7 @@ class serializer @tparam NumberType either @a number_integer_t or @a number_unsigned_t */ template < typename NumberType, detail::enable_if_t < + std::is_integral::value || std::is_same::value || std::is_same::value || std::is_same::value, @@ -16724,7 +16725,7 @@ class serializer // use a pointer to fill the buffer auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg) - const bool is_negative = std::is_same::value && !(x >= 0); // see issue #755 + const bool is_negative = std::is_signed::value && !(x >= 0); // see issue #755 number_unsigned_t abs_value; unsigned int n_chars{}; From b7db1d68d9aeeabaa3dca6c9dcd43bd59cc8ae99 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 6 Aug 2021 14:36:38 +0200 Subject: [PATCH 04/14] :recycle: fix CBOR and BSON --- .../nlohmann/detail/output/binary_writer.hpp | 24 +++++++++++++-- include/nlohmann/json.hpp | 6 ++-- single_include/nlohmann/json.hpp | 30 +++++++++++++++---- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 8a172056b7..cbe6e5617b 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -282,8 +282,26 @@ class binary_writer { if (j.m_value.binary->has_subtype()) { - write_number(static_cast(0xd8)); - write_number(j.m_value.binary->subtype()); + if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xd8)); + write_number(static_cast(j.m_value.binary->subtype())); + } + else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xd9)); + write_number(static_cast(j.m_value.binary->subtype())); + } + else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xda)); + write_number(static_cast(j.m_value.binary->subtype())); + } + else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xdb)); + write_number(static_cast(j.m_value.binary->subtype())); + } } // step 1: write control byte and the binary array size @@ -1096,7 +1114,7 @@ class binary_writer write_bson_entry_header(name, 0x05); write_number(static_cast(value.size())); - write_number(value.has_subtype() ? value.subtype() : std::uint8_t(0x00)); + write_number(value.has_subtype() ? static_cast(value.subtype()) : std::uint8_t(0x00)); oa->write_characters(reinterpret_cast(value.data()), value.size()); } diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index cd81528111..43dc1d9d8f 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -1817,7 +1817,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 3.8.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary(const typename binary_t::container_type& init, std::uint8_t subtype) + static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype) { auto res = basic_json(); res.m_type = value_t::binary; @@ -1835,9 +1835,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return res; } - /// @copydoc binary(const typename binary_t::container_type&, std::uint8_t) + /// @copydoc binary(const typename binary_t::container_type&, typename binary_t::subtype_type) JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary(typename binary_t::container_type&& init, std::uint8_t subtype) + static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype) { auto res = basic_json(); res.m_type = value_t::binary; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 1f557450c6..1d69fb63f4 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -13585,8 +13585,26 @@ class binary_writer { if (j.m_value.binary->has_subtype()) { - write_number(static_cast(0xd8)); - write_number(j.m_value.binary->subtype()); + if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xd8)); + write_number(static_cast(j.m_value.binary->subtype())); + } + else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xd9)); + write_number(static_cast(j.m_value.binary->subtype())); + } + else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xda)); + write_number(static_cast(j.m_value.binary->subtype())); + } + else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xdb)); + write_number(static_cast(j.m_value.binary->subtype())); + } } // step 1: write control byte and the binary array size @@ -14399,7 +14417,7 @@ class binary_writer write_bson_entry_header(name, 0x05); write_number(static_cast(value.size())); - write_number(value.has_subtype() ? value.subtype() : std::uint8_t(0x00)); + write_number(value.has_subtype() ? static_cast(value.subtype()) : std::uint8_t(0x00)); oa->write_characters(reinterpret_cast(value.data()), value.size()); } @@ -18911,7 +18929,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 3.8.0 */ JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary(const typename binary_t::container_type& init, std::uint8_t subtype) + static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype) { auto res = basic_json(); res.m_type = value_t::binary; @@ -18929,9 +18947,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return res; } - /// @copydoc binary(const typename binary_t::container_type&, std::uint8_t) + /// @copydoc binary(const typename binary_t::container_type&, typename binary_t::subtype_type) JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json binary(typename binary_t::container_type&& init, std::uint8_t subtype) + static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype) { auto res = basic_json(); res.m_type = value_t::binary; From 51a98800223ac5007d532d61c4a8145b5e358d94 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 6 Aug 2021 15:31:11 +0200 Subject: [PATCH 05/14] :white_check_mark: add tests for CBOR --- test/src/unit-cbor.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index d3b81d8149..19cdf1879d 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -2486,7 +2486,14 @@ TEST_CASE("examples from RFC 7049 Appendix A") auto expected = utils::read_binary_file(TEST_DATA_DIRECTORY "/binary_data/cbor_binary.out"); CHECK(j == json::binary(expected)); + // 0xd8 CHECK(json::to_cbor(json::binary(std::vector {}, 0x42)) == std::vector {0xd8, 0x42, 0x40}); + // 0xd9 + CHECK(json::to_cbor(json::binary(std::vector {}, 1000)) == std::vector {0xd9, 0x03, 0xe8, 0x40}); + // 0xda + CHECK(json::to_cbor(json::binary(std::vector {}, 394216)) == std::vector {0xda, 0x00, 0x06, 0x03, 0xe8, 0x40}); + // 0xdb + CHECK(json::to_cbor(json::binary(std::vector {}, 8589934590)) == std::vector {0xdb, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xfe, 0x40}); } SECTION("arrays") From 89c98dfc20bebfaeafe779567709d19ce3b2fdd7 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 6 Aug 2021 16:41:01 +0200 Subject: [PATCH 06/14] :sparkles: add option to process binary subtypes in CBOR --- .../nlohmann/detail/input/binary_reader.hpp | 63 ++++++++++++++++--- single_include/nlohmann/json.hpp | 63 ++++++++++++++++--- test/src/unit-cbor.cpp | 8 +++ 3 files changed, 114 insertions(+), 20 deletions(-) diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 8f55e1959b..0212d24c6c 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -30,8 +30,9 @@ namespace detail /// how to treat CBOR tags enum class cbor_tag_handler_t { - error, ///< throw a parse_error exception in case of a tag - ignore ///< ignore tags + error, ///< throw a parse_error exception in case of a tag + ignore, ///< ignore tags + store ///< store tags as binary type }; /*! @@ -722,30 +723,31 @@ class binary_reader case cbor_tag_handler_t::ignore: { + // ignore binary subtype switch (current) { case 0xD8: { - std::uint8_t len{}; - get_number(input_format_t::cbor, len); + std::uint8_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); break; } case 0xD9: { - std::uint16_t len{}; - get_number(input_format_t::cbor, len); + std::uint16_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); break; } case 0xDA: { - std::uint32_t len{}; - get_number(input_format_t::cbor, len); + std::uint32_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); break; } case 0xDB: { - std::uint64_t len{}; - get_number(input_format_t::cbor, len); + std::uint64_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); break; } default: @@ -754,6 +756,47 @@ class binary_reader return parse_cbor_internal(true, tag_handler); } + case cbor_tag_handler_t::store: + { + binary_t b; + // use binary subtype and store in binary container + switch (current) + { + case 0xD8: + { + std::uint8_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xD9: + { + std::uint16_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xDA: + { + std::uint32_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xDB: + { + std::uint64_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + default: + break; + } + get(); + return get_cbor_binary(b) && sax->binary(b); + } + default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE return false; // LCOV_EXCL_LINE diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 1d69fb63f4..b7304f3464 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -8269,8 +8269,9 @@ namespace detail /// how to treat CBOR tags enum class cbor_tag_handler_t { - error, ///< throw a parse_error exception in case of a tag - ignore ///< ignore tags + error, ///< throw a parse_error exception in case of a tag + ignore, ///< ignore tags + store ///< store tags as binary type }; /*! @@ -8961,30 +8962,31 @@ class binary_reader case cbor_tag_handler_t::ignore: { + // ignore binary subtype switch (current) { case 0xD8: { - std::uint8_t len{}; - get_number(input_format_t::cbor, len); + std::uint8_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); break; } case 0xD9: { - std::uint16_t len{}; - get_number(input_format_t::cbor, len); + std::uint16_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); break; } case 0xDA: { - std::uint32_t len{}; - get_number(input_format_t::cbor, len); + std::uint32_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); break; } case 0xDB: { - std::uint64_t len{}; - get_number(input_format_t::cbor, len); + std::uint64_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); break; } default: @@ -8993,6 +8995,47 @@ class binary_reader return parse_cbor_internal(true, tag_handler); } + case cbor_tag_handler_t::store: + { + binary_t b; + // use binary subtype and store in binary container + switch (current) + { + case 0xD8: + { + std::uint8_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xD9: + { + std::uint16_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xDA: + { + std::uint32_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xDB: + { + std::uint64_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + default: + break; + } + get(); + return get_cbor_binary(b) && sax->binary(b); + } + default: // LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE return false; // LCOV_EXCL_LINE diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 19cdf1879d..1660cf9453 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -2488,12 +2488,20 @@ TEST_CASE("examples from RFC 7049 Appendix A") // 0xd8 CHECK(json::to_cbor(json::binary(std::vector {}, 0x42)) == std::vector {0xd8, 0x42, 0x40}); + CHECK(!json::from_cbor(json::to_cbor(json::binary(std::vector {}, 0x42)), true, true, json::cbor_tag_handler_t::ignore).get_binary().has_subtype()); + CHECK(json::from_cbor(json::to_cbor(json::binary(std::vector {}, 0x42)), true, true, json::cbor_tag_handler_t::store).get_binary().subtype() == 0x42); // 0xd9 CHECK(json::to_cbor(json::binary(std::vector {}, 1000)) == std::vector {0xd9, 0x03, 0xe8, 0x40}); + CHECK(!json::from_cbor(json::to_cbor(json::binary(std::vector {}, 1000)), true, true, json::cbor_tag_handler_t::ignore).get_binary().has_subtype()); + CHECK(json::from_cbor(json::to_cbor(json::binary(std::vector {}, 1000)), true, true, json::cbor_tag_handler_t::store).get_binary().subtype() == 1000); // 0xda CHECK(json::to_cbor(json::binary(std::vector {}, 394216)) == std::vector {0xda, 0x00, 0x06, 0x03, 0xe8, 0x40}); + CHECK(!json::from_cbor(json::to_cbor(json::binary(std::vector {}, 394216)), true, true, json::cbor_tag_handler_t::ignore).get_binary().has_subtype()); + CHECK(json::from_cbor(json::to_cbor(json::binary(std::vector {}, 394216)), true, true, json::cbor_tag_handler_t::store).get_binary().subtype() == 394216); // 0xdb CHECK(json::to_cbor(json::binary(std::vector {}, 8589934590)) == std::vector {0xdb, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xfe, 0x40}); + CHECK(!json::from_cbor(json::to_cbor(json::binary(std::vector {}, 8589934590)), true, true, json::cbor_tag_handler_t::ignore).get_binary().has_subtype()); + CHECK(json::from_cbor(json::to_cbor(json::binary(std::vector {}, 8589934590)), true, true, json::cbor_tag_handler_t::store).get_binary().subtype() == 8589934590); } SECTION("arrays") From b74474e3fd5571300954f30b8bdbe6f1ae9fc97e Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 7 Aug 2021 13:14:00 +0200 Subject: [PATCH 07/14] :green_heart: fix MSVC build --- .github/workflows/windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index fad51b632e..49f9bc2cfd 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -43,7 +43,7 @@ jobs: run: cmake -S . -B build -G "Visual Studio 15 2017" -A ${{ matrix.architecture }} -DJSON_BuildTests=On if: matrix.build_type == 'Release' && matrix.architecture != 'x64' - name: cmake - run: cmake -S . -B build -G "Visual Studio 15 2017" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DJSON_FastTests=ON + run: cmake -S . -B build -G "Visual Studio 15 2017" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DJSON_FastTests=ON -DCMAKE_EXE_LINKER_FLAGS="/STACK:4000000 if: matrix.build_type == 'Debug' - name: build run: cmake --build build --config ${{ matrix.build_type }} --parallel 10 @@ -75,7 +75,7 @@ jobs: run: cmake -S . -B build -G "Visual Studio 16 2019" -A ${{ matrix.architecture }} -DJSON_BuildTests=On if: matrix.build_type == 'Release' - name: cmake - run: cmake -S . -B build -G "Visual Studio 16 2019" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DJSON_FastTests=ON + run: cmake -S . -B build -G "Visual Studio 16 2019" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DJSON_FastTests=ON -DCMAKE_EXE_LINKER_FLAGS="/STACK:4000000 if: matrix.build_type == 'Debug' - name: build run: cmake --build build --config ${{ matrix.build_type }} --parallel 10 From 176e9bf0ab418d8edd97d4132706ee2559f1863e Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 7 Aug 2021 13:14:08 +0200 Subject: [PATCH 08/14] :white_check_mark: add tests for CBOR --- include/nlohmann/detail/input/binary_reader.hpp | 2 +- test/src/unit-cbor.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 0212d24c6c..aaa08897db 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -791,7 +791,7 @@ class binary_reader break; } default: - break; + return parse_cbor_internal(true, tag_handler); } get(); return get_cbor_binary(b) && sax->binary(b); diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 1660cf9453..9ab0a0db8c 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -2572,6 +2572,9 @@ TEST_CASE("Tagged values") // check that parsing succeeds and gets original value in ignore mode auto j_tagged = json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::ignore); CHECK(j_tagged == j); + + auto j_tagged_stored = json::from_cbor(v_tagged, true, true, json::cbor_tag_handler_t::store); + CHECK(j_tagged_stored == j); } } From c5928501b05a57d448af992189d78af3e4535a7d Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 7 Aug 2021 13:19:25 +0200 Subject: [PATCH 09/14] :green_heart: fix MSVC build --- .github/workflows/windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 49f9bc2cfd..a17a87f0d7 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -43,7 +43,7 @@ jobs: run: cmake -S . -B build -G "Visual Studio 15 2017" -A ${{ matrix.architecture }} -DJSON_BuildTests=On if: matrix.build_type == 'Release' && matrix.architecture != 'x64' - name: cmake - run: cmake -S . -B build -G "Visual Studio 15 2017" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DJSON_FastTests=ON -DCMAKE_EXE_LINKER_FLAGS="/STACK:4000000 + run: cmake -S . -B build -G "Visual Studio 15 2017" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DJSON_FastTests=ON -DCMAKE_EXE_LINKER_FLAGS="/STACK:4000000" if: matrix.build_type == 'Debug' - name: build run: cmake --build build --config ${{ matrix.build_type }} --parallel 10 @@ -75,7 +75,7 @@ jobs: run: cmake -S . -B build -G "Visual Studio 16 2019" -A ${{ matrix.architecture }} -DJSON_BuildTests=On if: matrix.build_type == 'Release' - name: cmake - run: cmake -S . -B build -G "Visual Studio 16 2019" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DJSON_FastTests=ON -DCMAKE_EXE_LINKER_FLAGS="/STACK:4000000 + run: cmake -S . -B build -G "Visual Studio 16 2019" -A ${{ matrix.architecture }} -DJSON_BuildTests=On -DJSON_FastTests=ON -DCMAKE_EXE_LINKER_FLAGS="/STACK:4000000" if: matrix.build_type == 'Debug' - name: build run: cmake --build build --config ${{ matrix.build_type }} --parallel 10 From 346c9c1a19c27b07eaf62f0a94b3f47a6113533a Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 7 Aug 2021 13:37:17 +0200 Subject: [PATCH 10/14] :green_heart: fix MSVC build --- test/src/unit-cbor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 9ab0a0db8c..e35d781220 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -2560,6 +2560,8 @@ TEST_CASE("Tagged values") 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4 }) { + CAPTURE(b); + // add tag to value auto v_tagged = v; v_tagged.insert(v_tagged.begin(), b); From a4c3cf779812f875c18d1a56a8e840dabe06644a Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 7 Aug 2021 13:40:01 +0200 Subject: [PATCH 11/14] :green_heart: fix MSVC build --- single_include/nlohmann/json.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index b7304f3464..5ec21b9156 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -9030,7 +9030,7 @@ class binary_reader break; } default: - break; + return parse_cbor_internal(true, tag_handler); } get(); return get_cbor_binary(b) && sax->binary(b); From db7ccafbda58f72e2a87daf49163bc8f88de8db6 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 7 Aug 2021 13:55:25 +0200 Subject: [PATCH 12/14] :green_heart: fix MSVC build --- .github/workflows/windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index a17a87f0d7..e47d0e94f0 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -88,7 +88,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: cmake - run: cmake -S . -B build -G "Visual Studio 16 2019" -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/permissive- /std:c++latest /utf-8 /W4" + run: cmake -S . -B build -G "Visual Studio 16 2019" -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/permissive- /std:c++latest /utf-8 /W4" -DCMAKE_EXE_LINKER_FLAGS="/STACK:4000000" - name: build run: cmake --build build --config Release --parallel 10 - name: test From 523f7c2c9d89f06ff47db9066e4a2af5a49f5a8b Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 8 Aug 2021 13:24:17 +0200 Subject: [PATCH 13/14] :bulb: update documentation --- doc/mkdocs/docs/api/basic_json/binary_t.md | 2 +- .../docs/api/basic_json/cbor_tag_handler_t.md | 8 ++- .../docs/features/binary_formats/cbor.md | 4 +- .../docs/features/binary_formats/index.md | 2 +- doc/mkdocs/docs/features/binary_values.md | 9 +-- .../nlohmann/byte_container_with_subtype.hpp | 7 ++- include/nlohmann/detail/input/parser.hpp | 2 +- include/nlohmann/detail/output/serializer.hpp | 2 +- include/nlohmann/json.hpp | 48 ++++++++------- single_include/nlohmann/json.hpp | 59 ++++++++++--------- 10 files changed, 80 insertions(+), 63 deletions(-) diff --git a/doc/mkdocs/docs/api/basic_json/binary_t.md b/doc/mkdocs/docs/api/basic_json/binary_t.md index 2d6cd574e3..0dd859dccd 100644 --- a/doc/mkdocs/docs/api/basic_json/binary_t.md +++ b/doc/mkdocs/docs/api/basic_json/binary_t.md @@ -64,4 +64,4 @@ type `#!cpp binary_t*` must be dereferenced. ## Version history -- Added in version 3.8.0. +- Added in version 3.8.0. Changed type of subtype to `std::uint64_t` in version 3.9.2. diff --git a/doc/mkdocs/docs/api/basic_json/cbor_tag_handler_t.md b/doc/mkdocs/docs/api/basic_json/cbor_tag_handler_t.md index ea417de55a..9281157187 100644 --- a/doc/mkdocs/docs/api/basic_json/cbor_tag_handler_t.md +++ b/doc/mkdocs/docs/api/basic_json/cbor_tag_handler_t.md @@ -4,7 +4,8 @@ enum class cbor_tag_handler_t { error, - ignore + ignore, + store }; ``` @@ -16,6 +17,9 @@ error ignore : ignore tags +store +: store tagged values as binary container with subtype (for bytes 0xd8..0xdb) + ## Version history -- Added in version 3.9.0. +- Added in version 3.9.0. Added value `store` in 3.9.2. diff --git a/doc/mkdocs/docs/features/binary_formats/cbor.md b/doc/mkdocs/docs/features/binary_formats/cbor.md index daa29be875..a7a8fc0026 100644 --- a/doc/mkdocs/docs/features/binary_formats/cbor.md +++ b/doc/mkdocs/docs/features/binary_formats/cbor.md @@ -55,6 +55,8 @@ binary | *size*: 256..65535 | byte string (2 by binary | *size*: 65536..4294967295 | byte string (4 bytes follow) | 0x5A binary | *size*: 4294967296..18446744073709551615 | byte string (8 bytes follow) | 0x5B +Binary values with subtype are mapped to tagged values (0xD8..0xDB) depending on the subtype, followed by a byte string, +see "binary" cells in the table above. !!! success "Complete mapping" @@ -162,7 +164,7 @@ Double-Precision Float | number_float | 0xFB !!! warning "Tagged items" - Tagged items will throw a parse error by default. However, they can be ignored by passing `cbor_tag_handler_t::ignore` to function `from_cbor`. + Tagged items will throw a parse error by default. They can be ignored by passing `cbor_tag_handler_t::ignore` to function `from_cbor`. They can be stored by passing `cbor_tag_handler_t::store` to function `from_cbor`. ??? example diff --git a/doc/mkdocs/docs/features/binary_formats/index.md b/doc/mkdocs/docs/features/binary_formats/index.md index 55f963c2d2..279009d118 100644 --- a/doc/mkdocs/docs/features/binary_formats/index.md +++ b/doc/mkdocs/docs/features/binary_formats/index.md @@ -25,7 +25,7 @@ to efficiently encode JSON values to byte vectors and to decode such vectors. | Format | Binary values | Binary subtypes | | ----------- | ------------- | --------------- | | BSON | supported | supported | -| CBOR | supported | not supported | +| CBOR | supported | supported | | MessagePack | supported | supported | | UBJSON | not supported | not supported | diff --git a/doc/mkdocs/docs/features/binary_values.md b/doc/mkdocs/docs/features/binary_values.md index 4716aac7eb..66e7216881 100644 --- a/doc/mkdocs/docs/features/binary_values.md +++ b/doc/mkdocs/docs/features/binary_values.md @@ -9,10 +9,10 @@ JSON itself does not have a binary value. As such, binary values are an extensio ```plantuml class json::binary_t { -- setters -- - +void set_subtype(std::uint8_t subtype) + +void set_subtype(std::uint64_t subtype) +void clear_subtype() -- getters -- - +std::uint8_t subtype() const + +std::uint64_t subtype() const +bool has_subtype() const } @@ -68,7 +68,7 @@ j.get_binary().has_subtype(); // returns true j.get_binary().size(); // returns 4 ``` -For convencience, binary JSON values can be constructed via `json::binary`: +For convenience, binary JSON values can be constructed via `json::binary`: ```cpp auto j2 = json::binary({0xCA, 0xFE, 0xBA, 0xBE}, 23); @@ -76,6 +76,7 @@ auto j3 = json::binary({0xCA, 0xFE, 0xBA, 0xBE}); j2 == j; // returns true j3.get_binary().has_subtype(); // returns false +j3.get_binary().subtype(); // returns std::uint64_t(-1) as j3 has no subtype ``` @@ -184,7 +185,7 @@ JSON does not have a binary type, and this library does not introduce a new type 0xCA 0xFE 0xBA 0xBE // content ``` - Note that the subtype is serialized as tag. However, parsing tagged values yield a parse error unless `json::cbor_tag_handler_t::ignore` is passed to `json::from_cbor`. + Note that the subtype is serialized as tag. However, parsing tagged values yield a parse error unless `json::cbor_tag_handler_t::ignore` or `json::cbor_tag_handler_t::store` is passed to `json::from_cbor`. ```json { diff --git a/include/nlohmann/byte_container_with_subtype.hpp b/include/nlohmann/byte_container_with_subtype.hpp index ffbacdc6d3..0c117bff5f 100644 --- a/include/nlohmann/byte_container_with_subtype.hpp +++ b/include/nlohmann/byte_container_with_subtype.hpp @@ -1,6 +1,6 @@ #pragma once -#include // uint8_t +#include // uint8_t, uint64_t #include // tie #include // move @@ -18,7 +18,7 @@ order to override the binary type. @tparam BinaryType container to store bytes (`std::vector` by default) -@since version 3.8.0 +@since version 3.8.0; changed type of subtypes to std::uint64_t in 3.9.2. */ template class byte_container_with_subtype : public BinaryType @@ -107,7 +107,8 @@ class byte_container_with_subtype : public BinaryType @sa see @ref has_subtype() -- returns whether or not the binary value has a subtype - @since version 3.8.0 + @since version 3.8.0; fixed return value to properly return + subtype_type(-1) as documented in version 3.9.2 */ constexpr subtype_type subtype() const noexcept { diff --git a/include/nlohmann/detail/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp index 90f2327656..a1096c7337 100644 --- a/include/nlohmann/detail/input/parser.hpp +++ b/include/nlohmann/detail/input/parser.hpp @@ -23,7 +23,7 @@ namespace detail // parser // //////////// -enum class parse_event_t : uint8_t +enum class parse_event_t : std::uint8_t { /// the parser read `{` and started to process a JSON object object_start, diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index 4409934597..b9f53477a9 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -389,7 +389,7 @@ class serializer for (std::size_t i = 0; i < s.size(); ++i) { - const auto byte = static_cast(s[i]); + const auto byte = static_cast(s[i]); switch (decode(state, codepoint, byte)) { diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 43dc1d9d8f..4ac2e75317 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -902,8 +902,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec #### Notes on subtypes - CBOR - - Binary values are represented as byte strings. No subtypes are - supported and will be ignored when CBOR is written. + - Binary values are represented as byte strings. Subtypes are serialized + as tagged values. - MessagePack - If a subtype is given and the binary array contains exactly 1, 2, 4, 8, or 16 elements, the fixext family (fixext1, fixext2, fixext4, fixext8) @@ -1497,7 +1497,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @ref number_float_t, and all convertible number types such as `int`, `size_t`, `int64_t`, `float` or `double` can be used. - **boolean**: @ref boolean_t / `bool` can be used. - - **binary**: @ref binary_t / `std::vector` may be used, + - **binary**: @ref binary_t / `std::vector` may be used, unfortunately because string literals cannot be distinguished from binary character arrays by the C++ type system, all types compatible with `const char*` will be directed to the string constructor instead. This is both @@ -7187,6 +7187,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec binary | *size*: 65536..4294967295 | byte string (4 bytes follow) | 0x5A binary | *size*: 4294967296..18446744073709551615 | byte string (8 bytes follow) | 0x5B + Binary values with subtype are mapped to tagged values (0xD8..0xDB) + depending on the subtype, followed by a byte string, see "binary" cells + in the table above. + @note The mapping is **complete** in the sense that any JSON value type can be converted to a CBOR value. @@ -7227,16 +7231,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 2.0.9; compact representation of floating-point numbers since version 3.8.0 */ - static std::vector to_cbor(const basic_json& j) + static std::vector to_cbor(const basic_json& j) { - std::vector result; + std::vector result; to_cbor(j, result); return result; } - static void to_cbor(const basic_json& j, detail::output_adapter o) + static void to_cbor(const basic_json& j, detail::output_adapter o) { - binary_writer(o).write_cbor(j); + binary_writer(o).write_cbor(j); } static void to_cbor(const basic_json& j, detail::output_adapter o) @@ -7322,16 +7326,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 2.0.9 */ - static std::vector to_msgpack(const basic_json& j) + static std::vector to_msgpack(const basic_json& j) { - std::vector result; + std::vector result; to_msgpack(j, result); return result; } - static void to_msgpack(const basic_json& j, detail::output_adapter o) + static void to_msgpack(const basic_json& j, detail::output_adapter o) { - binary_writer(o).write_msgpack(j); + binary_writer(o).write_msgpack(j); } static void to_msgpack(const basic_json& j, detail::output_adapter o) @@ -7425,19 +7429,19 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 3.1.0 */ - static std::vector to_ubjson(const basic_json& j, - const bool use_size = false, - const bool use_type = false) + static std::vector to_ubjson(const basic_json& j, + const bool use_size = false, + const bool use_type = false) { - std::vector result; + std::vector result; to_ubjson(j, result, use_size, use_type); return result; } - static void to_ubjson(const basic_json& j, detail::output_adapter o, + static void to_ubjson(const basic_json& j, detail::output_adapter o, const bool use_size = false, const bool use_type = false) { - binary_writer(o).write_ubjson(j, use_size, use_type); + binary_writer(o).write_ubjson(j, use_size, use_type); } static void to_ubjson(const basic_json& j, detail::output_adapter o, @@ -7503,9 +7507,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @sa see @ref to_cbor(const basic_json&) for the related CBOR format @sa see @ref to_msgpack(const basic_json&) for the related MessagePack format */ - static std::vector to_bson(const basic_json& j) + static std::vector to_bson(const basic_json& j) { - std::vector result; + std::vector result; to_bson(j, result); return result; } @@ -7518,13 +7522,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @pre The input `j` shall be an object: `j.is_object() == true` @sa see @ref to_bson(const basic_json&) */ - static void to_bson(const basic_json& j, detail::output_adapter o) + static void to_bson(const basic_json& j, detail::output_adapter o) { - binary_writer(o).write_bson(j); + binary_writer(o).write_bson(j); } /*! - @copydoc to_bson(const basic_json&, detail::output_adapter) + @copydoc to_bson(const basic_json&, detail::output_adapter) */ static void to_bson(const basic_json& j, detail::output_adapter o) { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 5ec21b9156..1e323e0c5a 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4956,7 +4956,7 @@ struct adl_serializer // #include -#include // uint8_t +#include // uint8_t, uint64_t #include // tie #include // move @@ -4974,7 +4974,7 @@ order to override the binary type. @tparam BinaryType container to store bytes (`std::vector` by default) -@since version 3.8.0 +@since version 3.8.0; changed type of subtypes to std::uint64_t in 3.9.2. */ template class byte_container_with_subtype : public BinaryType @@ -5063,7 +5063,8 @@ class byte_container_with_subtype : public BinaryType @sa see @ref has_subtype() -- returns whether or not the binary value has a subtype - @since version 3.8.0 + @since version 3.8.0; fixed return value to properly return + subtype_type(-1) as documented in version 3.9.2 */ constexpr subtype_type subtype() const noexcept { @@ -10783,7 +10784,7 @@ namespace detail // parser // //////////// -enum class parse_event_t : uint8_t +enum class parse_event_t : std::uint8_t { /// the parser read `{` and started to process a JSON object object_start, @@ -16468,7 +16469,7 @@ class serializer for (std::size_t i = 0; i < s.size(); ++i) { - const auto byte = static_cast(s[i]); + const auto byte = static_cast(s[i]); switch (decode(state, codepoint, byte)) { @@ -18057,8 +18058,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec #### Notes on subtypes - CBOR - - Binary values are represented as byte strings. No subtypes are - supported and will be ignored when CBOR is written. + - Binary values are represented as byte strings. Subtypes are serialized + as tagged values. - MessagePack - If a subtype is given and the binary array contains exactly 1, 2, 4, 8, or 16 elements, the fixext family (fixext1, fixext2, fixext4, fixext8) @@ -18652,7 +18653,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @ref number_float_t, and all convertible number types such as `int`, `size_t`, `int64_t`, `float` or `double` can be used. - **boolean**: @ref boolean_t / `bool` can be used. - - **binary**: @ref binary_t / `std::vector` may be used, + - **binary**: @ref binary_t / `std::vector` may be used, unfortunately because string literals cannot be distinguished from binary character arrays by the C++ type system, all types compatible with `const char*` will be directed to the string constructor instead. This is both @@ -24342,6 +24343,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec binary | *size*: 65536..4294967295 | byte string (4 bytes follow) | 0x5A binary | *size*: 4294967296..18446744073709551615 | byte string (8 bytes follow) | 0x5B + Binary values with subtype are mapped to tagged values (0xD8..0xDB) + depending on the subtype, followed by a byte string, see "binary" cells + in the table above. + @note The mapping is **complete** in the sense that any JSON value type can be converted to a CBOR value. @@ -24382,16 +24387,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 2.0.9; compact representation of floating-point numbers since version 3.8.0 */ - static std::vector to_cbor(const basic_json& j) + static std::vector to_cbor(const basic_json& j) { - std::vector result; + std::vector result; to_cbor(j, result); return result; } - static void to_cbor(const basic_json& j, detail::output_adapter o) + static void to_cbor(const basic_json& j, detail::output_adapter o) { - binary_writer(o).write_cbor(j); + binary_writer(o).write_cbor(j); } static void to_cbor(const basic_json& j, detail::output_adapter o) @@ -24477,16 +24482,16 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 2.0.9 */ - static std::vector to_msgpack(const basic_json& j) + static std::vector to_msgpack(const basic_json& j) { - std::vector result; + std::vector result; to_msgpack(j, result); return result; } - static void to_msgpack(const basic_json& j, detail::output_adapter o) + static void to_msgpack(const basic_json& j, detail::output_adapter o) { - binary_writer(o).write_msgpack(j); + binary_writer(o).write_msgpack(j); } static void to_msgpack(const basic_json& j, detail::output_adapter o) @@ -24580,19 +24585,19 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @since version 3.1.0 */ - static std::vector to_ubjson(const basic_json& j, - const bool use_size = false, - const bool use_type = false) + static std::vector to_ubjson(const basic_json& j, + const bool use_size = false, + const bool use_type = false) { - std::vector result; + std::vector result; to_ubjson(j, result, use_size, use_type); return result; } - static void to_ubjson(const basic_json& j, detail::output_adapter o, + static void to_ubjson(const basic_json& j, detail::output_adapter o, const bool use_size = false, const bool use_type = false) { - binary_writer(o).write_ubjson(j, use_size, use_type); + binary_writer(o).write_ubjson(j, use_size, use_type); } static void to_ubjson(const basic_json& j, detail::output_adapter o, @@ -24658,9 +24663,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @sa see @ref to_cbor(const basic_json&) for the related CBOR format @sa see @ref to_msgpack(const basic_json&) for the related MessagePack format */ - static std::vector to_bson(const basic_json& j) + static std::vector to_bson(const basic_json& j) { - std::vector result; + std::vector result; to_bson(j, result); return result; } @@ -24673,13 +24678,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec @pre The input `j` shall be an object: `j.is_object() == true` @sa see @ref to_bson(const basic_json&) */ - static void to_bson(const basic_json& j, detail::output_adapter o) + static void to_bson(const basic_json& j, detail::output_adapter o) { - binary_writer(o).write_bson(j); + binary_writer(o).write_bson(j); } /*! - @copydoc to_bson(const basic_json&, detail::output_adapter) + @copydoc to_bson(const basic_json&, detail::output_adapter) */ static void to_bson(const basic_json& j, detail::output_adapter o) { From 1aceeff3fc09313afd666ef50021b4faeeaad2c0 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 14 Aug 2021 13:40:52 +0200 Subject: [PATCH 14/14] :rotating_light: fix C4244 warning --- include/nlohmann/detail/hash.hpp | 2 +- single_include/nlohmann/json.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/detail/hash.hpp b/include/nlohmann/detail/hash.hpp index 70c5daf338..ac07c2e8f0 100644 --- a/include/nlohmann/detail/hash.hpp +++ b/include/nlohmann/detail/hash.hpp @@ -103,7 +103,7 @@ std::size_t hash(const BasicJsonType& j) auto seed = combine(type, j.get_binary().size()); const auto h = std::hash {}(j.get_binary().has_subtype()); seed = combine(seed, h); - seed = combine(seed, j.get_binary().subtype()); + seed = combine(seed, static_cast(j.get_binary().subtype())); for (const auto byte : j.get_binary()) { seed = combine(seed, std::hash {}(byte)); diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 5f810e291e..16afb8a6a7 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -5266,7 +5266,7 @@ std::size_t hash(const BasicJsonType& j) auto seed = combine(type, j.get_binary().size()); const auto h = std::hash {}(j.get_binary().has_subtype()); seed = combine(seed, h); - seed = combine(seed, j.get_binary().subtype()); + seed = combine(seed, static_cast(j.get_binary().subtype())); for (const auto byte : j.get_binary()) { seed = combine(seed, std::hash {}(byte));