diff options
Diffstat (limited to 'include/jsoncons_ext/cbor')
| -rw-r--r-- | include/jsoncons_ext/cbor/cbor.hpp | 26 | ||||
| -rw-r--r-- | include/jsoncons_ext/cbor/cbor_cursor.hpp | 351 | ||||
| -rw-r--r-- | include/jsoncons_ext/cbor/cbor_cursor2.hpp | 265 | ||||
| -rw-r--r-- | include/jsoncons_ext/cbor/cbor_detail.hpp | 93 | ||||
| -rw-r--r-- | include/jsoncons_ext/cbor/cbor_encoder.hpp | 1766 | ||||
| -rw-r--r-- | include/jsoncons_ext/cbor/cbor_error.hpp | 105 | ||||
| -rw-r--r-- | include/jsoncons_ext/cbor/cbor_options.hpp | 113 | ||||
| -rw-r--r-- | include/jsoncons_ext/cbor/cbor_parser.hpp | 1942 | ||||
| -rw-r--r-- | include/jsoncons_ext/cbor/cbor_reader.hpp | 116 | ||||
| -rw-r--r-- | include/jsoncons_ext/cbor/decode_cbor.hpp | 203 | ||||
| -rw-r--r-- | include/jsoncons_ext/cbor/encode_cbor.hpp | 151 | 
11 files changed, 5131 insertions, 0 deletions
| diff --git a/include/jsoncons_ext/cbor/cbor.hpp b/include/jsoncons_ext/cbor/cbor.hpp new file mode 100644 index 0000000..3f7329f --- /dev/null +++ b/include/jsoncons_ext/cbor/cbor.hpp @@ -0,0 +1,26 @@ +// Copyright 2017 Daniel Parkerstd +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + + +#ifndef JSONCONS_CBOR_CBOR_HPP +#define JSONCONS_CBOR_CBOR_HPP + +#include <string> +#include <vector> +#include <memory> +#include <type_traits> // std::enable_if +#include <istream> // std::basic_istream +#include <jsoncons/json.hpp> +#include <jsoncons/json_filter.hpp> +#include <jsoncons/config/jsoncons_config.hpp> +#include <jsoncons_ext/cbor/cbor_reader.hpp> +#include <jsoncons_ext/cbor/cbor_cursor.hpp> +#include <jsoncons_ext/cbor/cbor_encoder.hpp> +#include <jsoncons_ext/cbor/encode_cbor.hpp> +#include <jsoncons_ext/cbor/decode_cbor.hpp> + +#endif + diff --git a/include/jsoncons_ext/cbor/cbor_cursor.hpp b/include/jsoncons_ext/cbor/cbor_cursor.hpp new file mode 100644 index 0000000..af0d1a8 --- /dev/null +++ b/include/jsoncons_ext/cbor/cbor_cursor.hpp @@ -0,0 +1,351 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_CBOR_CURSOR_HPP +#define JSONCONS_CBOR_CBOR_CURSOR_HPP + +#include <memory> // std::allocator +#include <string> +#include <vector> +#include <stdexcept> +#include <system_error> +#include <ios> +#include <istream> // std::basic_istream +#include <jsoncons/byte_string.hpp> +#include <jsoncons/config/jsoncons_config.hpp> +#include <jsoncons/json_visitor.hpp> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/staj_cursor.hpp> +#include <jsoncons/source.hpp> +#include <jsoncons_ext/cbor/cbor_parser.hpp> + +namespace jsoncons {  +namespace cbor { + +template<class Source=jsoncons::binary_stream_source,class Allocator=std::allocator<char>> +class basic_cbor_cursor : public basic_staj_cursor<char>, private virtual ser_context +{ +public: +    using source_type = Source; +    using char_type = char; +    using allocator_type = Allocator; +private: +    basic_cbor_parser<Source,Allocator> parser_; +    basic_staj_visitor<char_type> cursor_visitor_; +    basic_json_visitor2_to_visitor_adaptor<char_type,Allocator> cursor_handler_adaptor_; +    bool eof_; + +    // Noncopyable and nonmoveable +    basic_cbor_cursor(const basic_cbor_cursor&) = delete; +    basic_cbor_cursor& operator=(const basic_cbor_cursor&) = delete; + +public: +    using string_view_type = string_view; + +    template <class Sourceable> +    basic_cbor_cursor(Sourceable&& source, +                      const cbor_decode_options& options = cbor_decode_options(), +                      const Allocator& alloc = Allocator()) +        : parser_(std::forward<Sourceable>(source), options, alloc),  +          cursor_visitor_(accept_all),  +          cursor_handler_adaptor_(cursor_visitor_, alloc), +          eof_(false) +    { +        if (!done()) +        { +            next(); +        } +    } + +    // Constructors that set parse error codes + +    template <class Sourceable> +    basic_cbor_cursor(Sourceable&& source,  +                      std::error_code& ec) +        : basic_cbor_cursor(std::allocator_arg, Allocator(), +                            std::forward<Sourceable>(source),  +                            cbor_decode_options(),  +                            ec) +    { +    } + +    template <class Sourceable> +    basic_cbor_cursor(Sourceable&& source,  +                      const cbor_decode_options& options, +                      std::error_code& ec) +        : basic_cbor_cursor(std::allocator_arg, Allocator(), +                            std::forward<Sourceable>(source),  +                            options,  +                            ec) +    { +    } + +    template <class Sourceable> +    basic_cbor_cursor(std::allocator_arg_t, const Allocator& alloc,  +                      Sourceable&& source, +                      const cbor_decode_options& options, +                      std::error_code& ec) +       : parser_(std::forward<Sourceable>(source), options, alloc),  +         cursor_visitor_(accept_all), +         cursor_handler_adaptor_(cursor_visitor_, alloc), +         eof_(false) +    { +        if (!done()) +        { +            next(ec); +        } +    } + +    void reset() +    { +        parser_.reset(); +        cursor_visitor_.reset(); +        cursor_handler_adaptor_.reset(); +        eof_ = false; +        if (!done()) +        { +            next(); +        } +    } + +    template <class Sourceable> +    void reset(Sourceable&& source) +    { +        parser_.reset(std::forward<Sourceable>(source)); +        cursor_visitor_.reset(); +        cursor_handler_adaptor_.reset(); +        eof_ = false; +        if (!done()) +        { +            next(); +        } +    } + +    void reset(std::error_code& ec) +    { +        parser_.reset(); +        cursor_visitor_.reset(); +        cursor_handler_adaptor_.reset(); +        eof_ = false; +        if (!done()) +        { +            next(ec); +        } +    } + +    template <class Sourceable> +    void reset(Sourceable&& source, std::error_code& ec) +    { +        parser_.reset(std::forward<Sourceable>(source)); +        cursor_visitor_.reset(); +        cursor_handler_adaptor_.reset(); +        eof_ = false; +        if (!done()) +        { +            next(ec); +        } +    } + +    bool done() const override +    { +        return parser_.done(); +    } + +    bool is_typed_array() const +    { +        return cursor_visitor_.is_typed_array(); +    } + +    const staj_event& current() const override +    { +        return cursor_visitor_.event(); +    } + +    void read_to(basic_json_visitor<char_type>& visitor) override +    { +        std::error_code ec; +        read_to(visitor, ec); +        if (ec) +        { +            JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); +        } +    } + +    void read_to(basic_json_visitor<char_type>& visitor, +                 std::error_code& ec) override +    { +        if (cursor_visitor_.dump(visitor, *this, ec)) +        { +            read_next(visitor, ec); +        } +    } + +    void next() override +    { +        std::error_code ec; +        next(ec); +        if (ec) +        { +            JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); +        } +    } + +    void next(std::error_code& ec) override +    { +        read_next(ec); +    } + +    const ser_context& context() const override +    { +        return *this; +    } + +    bool eof() const +    { +        return eof_; +    } + +    std::size_t line() const override +    { +        return parser_.line(); +    } + +    std::size_t column() const override +    { +        return parser_.column(); +    } + +    friend +    staj_filter_view operator|(basic_cbor_cursor& cursor,  +                               std::function<bool(const staj_event&, const ser_context&)> pred) +    { +        return staj_filter_view(cursor, pred); +    } + +#if !defined(JSONCONS_NO_DEPRECATED) + +    template <class Sourceable> +    JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter") +    basic_cbor_cursor(Sourceable&& source, +                      std::function<bool(const staj_event&, const ser_context&)> filter, +                      const cbor_decode_options& options = cbor_decode_options(), +                      const Allocator& alloc = Allocator()) +       : parser_(std::forward<Sourceable>(source), options, alloc),  +         cursor_visitor_(filter),  +         cursor_handler_adaptor_(cursor_visitor_, alloc), +         eof_(false) +    { +        if (!done()) +        { +            next(); +        } +    } + +    template <class Sourceable> +    JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter") +    basic_cbor_cursor(Sourceable&& source, +                      std::function<bool(const staj_event&, const ser_context&)> filter, +                      std::error_code& ec) +        : basic_cbor_cursor(std::allocator_arg, Allocator(), +                            std::forward<Sourceable>(source), filter, ec) +    { +    } + +    template <class Sourceable> +    JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter") +    basic_cbor_cursor(std::allocator_arg_t, const Allocator& alloc,  +                      Sourceable&& source, +                      std::function<bool(const staj_event&, const ser_context&)> filter, +                      std::error_code& ec) +       : parser_(std::forward<Sourceable>(source), alloc),  +         cursor_visitor_(filter), +         cursor_handler_adaptor_(cursor_visitor_, alloc), +         eof_(false) +    { +        if (!done()) +        { +            next(ec); +        } +    } + +    JSONCONS_DEPRECATED_MSG("Instead, use read_to(basic_json_visitor<char_type>&)") +    void read(basic_json_visitor<char_type>& visitor) +    { +        read_to(visitor); +    } + +    JSONCONS_DEPRECATED_MSG("Instead, use read_to(basic_json_visitor<char_type>&, std::error_code&)") +    void read(basic_json_visitor<char_type>& visitor, +                 std::error_code& ec)  +    { +        read_to(visitor, ec); +    } +#endif +private: +    static bool accept_all(const staj_event&, const ser_context&)  +    { +        return true; +    } + +    void read_next(std::error_code& ec) +    { +        if (cursor_visitor_.in_available()) +        { +            cursor_visitor_.send_available(ec); +        } +        else +        { +            parser_.restart(); +            while (!parser_.stopped()) +            { +                parser_.parse(cursor_handler_adaptor_, ec); +                if (ec) return; +            } +        } +    } + +    void read_next(basic_json_visitor<char_type>& visitor, std::error_code& ec) +    { +        { +            struct resource_wrapper +            { +                basic_json_visitor2_to_visitor_adaptor<char_type,Allocator>& adaptor; +                basic_json_visitor<char_type>& original; + +                resource_wrapper(basic_json_visitor2_to_visitor_adaptor<char_type,Allocator>& adaptor, +                                 basic_json_visitor<char_type>& visitor) +                    : adaptor(adaptor), original(adaptor.destination()) +                { +                    adaptor.destination(visitor); +                } + +                ~resource_wrapper() +                { +                    adaptor.destination(original); +                } +            } wrapper(cursor_handler_adaptor_, visitor); + +            parser_.restart(); +            while (!parser_.stopped()) +            { +                parser_.parse(cursor_handler_adaptor_, ec); +                if (ec) +                { +                    return; +                } +            } +        } +    } +}; + +using cbor_stream_cursor = basic_cbor_cursor<jsoncons::binary_stream_source>; +using cbor_bytes_cursor = basic_cbor_cursor<jsoncons::bytes_source>; + +} // namespace cbor +} // namespace jsoncons + +#endif + diff --git a/include/jsoncons_ext/cbor/cbor_cursor2.hpp b/include/jsoncons_ext/cbor/cbor_cursor2.hpp new file mode 100644 index 0000000..eee7445 --- /dev/null +++ b/include/jsoncons_ext/cbor/cbor_cursor2.hpp @@ -0,0 +1,265 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_CBOR_CURSOR2_HPP +#define JSONCONS_CBOR_CBOR_CURSOR2_HPP + +#include <memory> // std::allocator +#include <string> +#include <vector> +#include <stdexcept> +#include <system_error> +#include <ios> +#include <istream> // std::basic_istream +#include <jsoncons/byte_string.hpp> +#include <jsoncons/config/jsoncons_config.hpp> +#include <jsoncons/json_visitor2.hpp> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/staj2_cursor.hpp> +#include <jsoncons/source.hpp> +#include <jsoncons_ext/cbor/cbor_parser.hpp> + +namespace jsoncons {  +namespace cbor { + +    template<class Source=jsoncons::binary_stream_source,class Allocator=std::allocator<char>> +    class basic_cbor_cursor2 : public basic_staj2_cursor<char>, private virtual ser_context +    { +    public: +        using source_type = Source; +        using char_type = char; +        using allocator_type = Allocator; +    private: +        basic_cbor_parser<Source,Allocator> parser_; +        basic_staj2_visitor<char_type> cursor_visitor_; +        bool eof_; + +        // Noncopyable and nonmoveable +        basic_cbor_cursor2(const basic_cbor_cursor2&) = delete; +        basic_cbor_cursor2& operator=(const basic_cbor_cursor2&) = delete; + +    public: +        using string_view_type = string_view; + +        template <class Sourceable> +        basic_cbor_cursor2(Sourceable&& source, +                          const cbor_decode_options& options = cbor_decode_options(), +                          const Allocator& alloc = Allocator()) +            : parser_(std::forward<Sourceable>(source), options, alloc),  +              cursor_visitor_(accept_all),  +              eof_(false) +        { +            if (!done()) +            { +                next(); +            } +        } + +        // Constructors that set parse error codes + +        template <class Sourceable> +        basic_cbor_cursor2(Sourceable&& source,  +                          std::error_code& ec) +            : basic_cbor_cursor2(std::allocator_arg, Allocator(), +                                std::forward<Sourceable>(source),  +                                cbor_decode_options(),  +                                ec) +        { +        } + +        template <class Sourceable> +        basic_cbor_cursor2(Sourceable&& source,  +                          const cbor_decode_options& options, +                          std::error_code& ec) +            : basic_cbor_cursor2(std::allocator_arg, Allocator(), +                                std::forward<Sourceable>(source),  +                                options,  +                                ec) +        { +        } + +        template <class Sourceable> +        basic_cbor_cursor2(std::allocator_arg_t, const Allocator& alloc,  +                          Sourceable&& source, +                          const cbor_decode_options& options, +                          std::error_code& ec) +           : parser_(std::forward<Sourceable>(source), options, alloc),  +             cursor_visitor_(accept_all), +             eof_(false) +        { +            if (!done()) +            { +                next(ec); +            } +        } + +        void reset() +        { +            parser_.reset(); +            cursor_visitor_.reset(); +            eof_ = false; +            if (!done()) +            { +                next(); +            } +        } + +        template <class Sourceable> +        void reset(Sourceable&& source) +        { +            parser_.reset(std::forward<Sourceable>(source)); +            cursor_visitor_.reset(); +            eof_ = false; +            if (!done()) +            { +                next(); +            } +        } + +        void reset(std::error_code& ec) +        { +            parser_.reset(); +            cursor_visitor_.reset(); +            eof_ = false; +            if (!done()) +            { +                next(ec); +            } +        } + +        template <class Sourceable> +        void reset(Sourceable&& source, std::error_code& ec) +        { +            parser_.reset(std::forward<Sourceable>(source)); +            cursor_visitor_.reset(); +            eof_ = false; +            if (!done()) +            { +                next(ec); +            } +        } + +        bool done() const override +        { +            return parser_.done(); +        } + +        bool is_typed_array() const +        { +            return cursor_visitor_.is_typed_array(); +        } + +        const staj2_event& current() const override +        { +            return cursor_visitor_.event(); +        } + +        void read_to(basic_json_visitor2<char_type>& visitor) override +        { +            std::error_code ec; +            read_to(visitor, ec); +            if (ec) +            { +                JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); +            } +        } + +        void read_to(basic_json_visitor2<char_type>& visitor, +                     std::error_code& ec) override +        { +            if (cursor_visitor_.dump(visitor, *this, ec)) +            { +                read_next(visitor, ec); +            } +        } + +        void next() override +        { +            std::error_code ec; +            next(ec); +            if (ec) +            { +                JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); +            } +        } + +        void next(std::error_code& ec) override +        { +            read_next(ec); +        } + +        const ser_context& context() const override +        { +            return *this; +        } + +        bool eof() const +        { +            return eof_; +        } + +        std::size_t line() const override +        { +            return parser_.line(); +        } + +        std::size_t column() const override +        { +            return parser_.column(); +        } + +        friend +        staj2_filter_view operator|(basic_cbor_cursor2& cursor,  +                                   std::function<bool(const staj2_event&, const ser_context&)> pred) +        { +            return staj2_filter_view(cursor, pred); +        } + +    private: +        static bool accept_all(const staj2_event&, const ser_context&)  +        { +            return true; +        } + +        void read_next(std::error_code& ec) +        { +            if (cursor_visitor_.in_available()) +            { +                cursor_visitor_.send_available(ec); +            } +            else +            { +                parser_.restart(); +                while (!parser_.stopped()) +                { +                    parser_.parse(cursor_visitor_, ec); +                    if (ec) return; +                } +            } +        } + +        void read_next(basic_json_visitor2<char_type>& visitor, std::error_code& ec) +        { +            parser_.restart(); +            while (!parser_.stopped()) +            { +                parser_.parse(visitor, ec); +                if (ec) +                { +                    return; +                } +            } +        } +    }; + +    using cbor_stream_cursor2 = basic_cbor_cursor2<jsoncons::binary_stream_source>; +    using cbor_bytes_cursor2 = basic_cbor_cursor2<jsoncons::bytes_source>; + +} // namespace cbor +} // namespace jsoncons + +#endif + diff --git a/include/jsoncons_ext/cbor/cbor_detail.hpp b/include/jsoncons_ext/cbor/cbor_detail.hpp new file mode 100644 index 0000000..9acfc3c --- /dev/null +++ b/include/jsoncons_ext/cbor/cbor_detail.hpp @@ -0,0 +1,93 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_CBOR_DETAIL_HPP +#define JSONCONS_CBOR_CBOR_DETAIL_HPP + +#include <string> +#include <vector> +#include <memory> +#include <iterator> // std::forward_iterator_tag +#include <limits> // std::numeric_limits +#include <utility> // std::move +#include <jsoncons/json.hpp> +#include <jsoncons/json_visitor.hpp> +#include <jsoncons/config/jsoncons_config.hpp> + +// 0x00..0x17 (0..23) +#define JSONCONS_CBOR_0x00_0x17 \ +    0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x09:case 0x0a:case 0x0b:case 0x0c:case 0x0d:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16:case 0x17 + +#define JSONCONS_CBOR_ARRAY_TAGS \ +    0x40:case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46:case 0x47:case 0x48:case 0x49:case 0x4a:case 0x4b:case 0x4c:case 0x4d:case 0x4e:case 0x4f:case 0x50:case 0x51:case 0x52:case 0x53:case 0x54:case 0x55:case 0x56:case 0x57     + +namespace jsoncons { namespace cbor { namespace detail { + +//const uint8_t cbor_array_tags_010_mask = 0b11100000; +//const uint8_t cbor_array_tags_f_mask = 0b00010000; +//const uint8_t cbor_array_tags_s_mask = 0b00001000; +//const uint8_t cbor_array_tags_e_mask = 0b00000100; +//const uint8_t cbor_array_tags_ll_mask = 0b00000011; + +const uint8_t cbor_array_tags_010_mask = 0xE0; +const uint8_t cbor_array_tags_f_mask = 0x10; +const uint8_t cbor_array_tags_s_mask = 0x08; +const uint8_t cbor_array_tags_e_mask = 0x04; +const uint8_t cbor_array_tags_ll_mask = 0x03; + +const uint8_t cbor_array_tags_010_shift = 5; +const uint8_t cbor_array_tags_f_shift = 4; +const uint8_t cbor_array_tags_s_shift = 3; +const uint8_t cbor_array_tags_e_shift = 2; +const uint8_t cbor_array_tags_ll_shift = 0; + +enum class cbor_major_type : uint8_t +{ +    unsigned_integer = 0x00, +    negative_integer = 0x01, +    byte_string = 0x02, +    text_string = 0x03, +    array = 0x04, +    map = 0x05,    +    semantic_tag = 0x06, +    simple = 0x7 +}; + +namespace additional_info +{ +    const uint8_t indefinite_length = 0x1f; +} + +inline +size_t min_length_for_stringref(uint64_t index) +{ +    std::size_t n; +    if (index <= 23) +    { +        n = 3; +    } +    else if (index <= 255) +    { +        n = 4; +    } +    else if (index <= 65535) +    { +        n = 5; +    } +    else if (index <= 4294967295) +    { +        n = 7; +    } +    else  +    { +        n = 11; +    } +    return n; +} + +}}} + +#endif diff --git a/include/jsoncons_ext/cbor/cbor_encoder.hpp b/include/jsoncons_ext/cbor/cbor_encoder.hpp new file mode 100644 index 0000000..f4699ee --- /dev/null +++ b/include/jsoncons_ext/cbor/cbor_encoder.hpp @@ -0,0 +1,1766 @@ +// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_CBOR_ENCODER_HPP +#define JSONCONS_CBOR_CBOR_ENCODER_HPP + +#include <string> +#include <vector> +#include <limits> // std::numeric_limits +#include <memory> +#include <utility> // std::move +#include <jsoncons/json_exception.hpp> // jsoncons::ser_error +#include <jsoncons/json_visitor.hpp> +#include <jsoncons/config/jsoncons_config.hpp> +#include <jsoncons/sink.hpp> +#include <jsoncons/detail/parse_number.hpp> +#include <jsoncons_ext/cbor/cbor_error.hpp> +#include <jsoncons_ext/cbor/cbor_options.hpp> + +namespace jsoncons { namespace cbor { + +enum class cbor_container_type {object, indefinite_length_object, array, indefinite_length_array}; + +template<class Sink=jsoncons::binary_stream_sink,class Allocator=std::allocator<char>> +class basic_cbor_encoder final : public basic_json_visitor<char> +{ +    using super_type = basic_json_visitor<char>; + +    enum class decimal_parse_state { start, integer, exp1, exp2, fraction1 }; +    enum class hexfloat_parse_state { start, expect_0, expect_x, integer, exp1, exp2, fraction1 }; + +    static constexpr int64_t nanos_in_second = 1000000000; +    static constexpr int64_t millis_in_second = 1000; + +public: +    using allocator_type = Allocator; +    using sink_type = Sink; +    using typename super_type::char_type; +    using typename super_type::string_view_type; + +private: +    using char_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<char_type>; +    using byte_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<uint8_t>;                   + +    using string_type = std::basic_string<char_type,std::char_traits<char_type>,char_allocator_type>; +    using byte_string_type = basic_byte_string<byte_allocator_type>; + +    struct stack_item +    { +        cbor_container_type type_; +        std::size_t length_; +        std::size_t count_; + +        stack_item(cbor_container_type type, std::size_t length = 0) noexcept +           : type_(type), length_(length), count_(0) +        { +        } + +        std::size_t length() const +        { +            return length_; +        } + +        std::size_t count() const +        { +            return count_; +        } + +        bool is_object() const +        { +            return type_ == cbor_container_type::object || type_ == cbor_container_type::indefinite_length_object; +        } + +        bool is_indefinite_length() const +        { +            return type_ == cbor_container_type::indefinite_length_array || type_ == cbor_container_type::indefinite_length_object; +        } + +    }; + +    typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<std::pair<const string_type,size_t>> string_size_allocator_type; +    typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<std::pair<const byte_string_type,size_t>> byte_string_size_allocator_type; +    typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<stack_item> stack_item_allocator_type; + +    Sink sink_; +    const cbor_encode_options options_; +    allocator_type alloc_; + +    std::vector<stack_item,stack_item_allocator_type> stack_; +    std::map<string_type,size_t,std::less<string_type>,string_size_allocator_type> stringref_map_; +    std::map<byte_string_type,size_t,std::less<byte_string_type>,byte_string_size_allocator_type> bytestringref_map_; +    std::size_t next_stringref_ = 0; +    int nesting_depth_; + +    // Noncopyable and nonmoveable +    basic_cbor_encoder(const basic_cbor_encoder&) = delete; +    basic_cbor_encoder& operator=(const basic_cbor_encoder&) = delete; +public: +    explicit basic_cbor_encoder(Sink&& sink,  +                                const Allocator& alloc = Allocator()) +       : basic_cbor_encoder(std::forward<Sink>(sink), cbor_encode_options(), alloc) +    { +    } +    basic_cbor_encoder(Sink&& sink,  +                       const cbor_encode_options& options,  +                       const Allocator& alloc = Allocator()) +       : sink_(std::forward<Sink>(sink)),  +         options_(options),  +         alloc_(alloc), +         stack_(alloc), +#if !defined(JSONCONS_NO_MAP_CONS_TAKES_ALLOCATOR)  +         stringref_map_(alloc), +         bytestringref_map_(alloc), +#endif  +         nesting_depth_(0)         +    { +        if (options.pack_strings()) +        { +            write_tag(256); +        } +    } + +    ~basic_cbor_encoder() noexcept +    { +        JSONCONS_TRY +        { +            sink_.flush(); +        } +        JSONCONS_CATCH(...) +        { +        } +    } + +    void reset() +    { +        stack_.clear(); +        stringref_map_.clear(); +        bytestringref_map_.clear(); +        next_stringref_ = 0; +        nesting_depth_ = 0; +    } + +    void reset(Sink&& sink) +    { +        sink_ = std::move(sink); +        reset(); +    } + +private: +    // Implementing methods + +    void visit_flush() override +    { +        sink_.flush(); +    } + +    bool visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) override +    { +        if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) +        { +            ec = cbor_errc::max_nesting_depth_exceeded; +            return false; +        }  +        stack_.emplace_back(cbor_container_type::indefinite_length_object); +         +        sink_.push_back(0xbf); +        return true; +    } + +    bool visit_begin_object(std::size_t length, semantic_tag, const ser_context&, std::error_code& ec) override +    { +        if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) +        { +            ec = cbor_errc::max_nesting_depth_exceeded; +            return false; +        }  +        stack_.emplace_back(cbor_container_type::object, length); + +        if (length <= 0x17) +        { +            binary::native_to_big(static_cast<uint8_t>(0xa0 + length),  +                                  std::back_inserter(sink_)); +        }  +        else if (length <= 0xff) +        { +            binary::native_to_big(static_cast<uint8_t>(0xb8),  +                                  std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint8_t>(length),  +                                  std::back_inserter(sink_)); +        }  +        else if (length <= 0xffff) +        { +            binary::native_to_big(static_cast<uint8_t>(0xb9),  +                                  std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint16_t>(length),  +                                  std::back_inserter(sink_)); +        }  +        else if (length <= 0xffffffff) +        { +            binary::native_to_big(static_cast<uint8_t>(0xba),  +                                  std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint32_t>(length),  +                                  std::back_inserter(sink_)); +        }  +        else if (length <= 0xffffffffffffffff) +        { +            binary::native_to_big(static_cast<uint8_t>(0xbb),  +                                  std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint64_t>(length),  +                                  std::back_inserter(sink_)); +        } + +        return true; +    } + +    bool visit_end_object(const ser_context&, std::error_code& ec) override +    { +        JSONCONS_ASSERT(!stack_.empty()); +        --nesting_depth_; + +        if (stack_.back().is_indefinite_length()) +        { +            sink_.push_back(0xff); +        } +        else +        { +            if (stack_.back().count() < stack_.back().length()) +            { +                ec = cbor_errc::too_few_items; +                return false; +            } +            if (stack_.back().count() > stack_.back().length()) +            { +                ec = cbor_errc::too_many_items; +                return false; +            } +        } + +        stack_.pop_back(); +        end_value(); + +        return true; +    } + +    bool visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) override +    { +        if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) +        { +            ec = cbor_errc::max_nesting_depth_exceeded; +            return false; +        }  +        stack_.emplace_back(cbor_container_type::indefinite_length_array); +        sink_.push_back(0x9f); +        return true; +    } + +    bool visit_begin_array(std::size_t length, semantic_tag, const ser_context&, std::error_code& ec) override +    { +        if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) +        { +            ec = cbor_errc::max_nesting_depth_exceeded; +            return false; +        }  +        stack_.emplace_back(cbor_container_type::array, length); +        if (length <= 0x17) +        { +            binary::native_to_big(static_cast<uint8_t>(0x80 + length),  +                                  std::back_inserter(sink_)); +        }  +        else if (length <= 0xff) +        { +            binary::native_to_big(static_cast<uint8_t>(0x98),  +                                  std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint8_t>(length),  +                                  std::back_inserter(sink_)); +        }  +        else if (length <= 0xffff) +        { +            binary::native_to_big(static_cast<uint8_t>(0x99),  +                                  std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint16_t>(length),  +                                  std::back_inserter(sink_)); +        }  +        else if (length <= 0xffffffff) +        { +            binary::native_to_big(static_cast<uint8_t>(0x9a),  +                                  std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint32_t>(length),  +                                  std::back_inserter(sink_)); +        }  +        else if (length <= 0xffffffffffffffff) +        { +            binary::native_to_big(static_cast<uint8_t>(0x9b),  +                                  std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint64_t>(length),  +                                  std::back_inserter(sink_)); +        } +        return true; +    } + +    bool visit_end_array(const ser_context&, std::error_code& ec) override +    { +        JSONCONS_ASSERT(!stack_.empty()); +        --nesting_depth_; + +        if (stack_.back().is_indefinite_length()) +        { +            sink_.push_back(0xff); +        } +        else +        { +            if (stack_.back().count() < stack_.back().length()) +            { +                ec = cbor_errc::too_few_items; +                return false; +            } +            if (stack_.back().count() > stack_.back().length()) +            { +                ec = cbor_errc::too_many_items; +                return false; +            } +        } + +        stack_.pop_back(); +        end_value(); + +        return true; +    } + +    bool visit_key(const string_view_type& name, const ser_context&, std::error_code&) override +    { +        write_string(name); +        return true; +    } + +    bool visit_null(semantic_tag tag, const ser_context&, std::error_code&) override +    { +        if (tag == semantic_tag::undefined) +        { +            sink_.push_back(0xf7); +        } +        else +        { +            sink_.push_back(0xf6); +        } + +        end_value(); +        return true; +    } + +    void write_string(const string_view& sv) +    { +        auto sink = unicode_traits::validate(sv.data(), sv.size()); +        if (sink.ec != unicode_traits::conv_errc()) +        { +            JSONCONS_THROW(ser_error(cbor_errc::invalid_utf8_text_string)); +        } + +        if (options_.pack_strings() && sv.size() >= jsoncons::cbor::detail::min_length_for_stringref(next_stringref_)) +        { +            string_type s(sv.data(), sv.size(), alloc_); +            auto it = stringref_map_.find(s); +            if (it == stringref_map_.end()) +            { +                stringref_map_.emplace(std::make_pair(std::move(s), next_stringref_++)); +                write_utf8_string(sv); +            } +            else +            { +                write_tag(25); +                write_uint64_value(it->second); +            } +        } +        else +        { +            write_utf8_string(sv); +        } +    } + +    void write_utf8_string(const string_view& sv) +    { +        const size_t length = sv.size(); + +        if (length <= 0x17) +        { +            // fixstr stores a byte array whose length is upto 31 bytes +            binary::native_to_big(static_cast<uint8_t>(0x60 + length),  +                                            std::back_inserter(sink_)); +        } +        else if (length <= 0xff) +        { +            binary::native_to_big(static_cast<uint8_t>(0x78),  +                                            std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint8_t>(length),  +                                            std::back_inserter(sink_)); +        } +        else if (length <= 0xffff) +        { +            binary::native_to_big(static_cast<uint8_t>(0x79),  +                                            std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint16_t>(length),  +                                            std::back_inserter(sink_)); +        } +        else if (length <= 0xffffffff) +        { +            binary::native_to_big(static_cast<uint8_t>(0x7a),  +                                            std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint32_t>(length),  +                                            std::back_inserter(sink_)); +        } +        else if (length <= 0xffffffffffffffff) +        { +            binary::native_to_big(static_cast<uint8_t>(0x7b),  +                                            std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint64_t>(length),  +                                            std::back_inserter(sink_)); +        } + +        for (auto c : sv) +        { +            sink_.push_back(c); +        } +    } + +    void write_bignum(bigint& n) +    { +        bool is_neg = n < 0; +        if (is_neg) +        { +            n = - n -1; +        } + +        int signum; +        std::vector<uint8_t> data; +        n.write_bytes_be(signum, data); +        std::size_t length = data.size(); + +        if (is_neg) +        { +            write_tag(3); +        } +        else +        { +            write_tag(2); +        } + +        if (length <= 0x17) +        { +            // fixstr stores a byte array whose length is upto 31 bytes +            binary::native_to_big(static_cast<uint8_t>(0x40 + length),  +                                  std::back_inserter(sink_)); +        } +        else if (length <= 0xff) +        { +            binary::native_to_big(static_cast<uint8_t>(0x58),  +                                  std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint8_t>(length),  +                                  std::back_inserter(sink_)); +        } +        else if (length <= 0xffff) +        { +            binary::native_to_big(static_cast<uint8_t>(0x59),  +                                  std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint16_t>(length),  +                                  std::back_inserter(sink_)); +        } +        else if (length <= 0xffffffff) +        { +            binary::native_to_big(static_cast<uint8_t>(0x5a),  +                                  std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint32_t>(length),  +                                  std::back_inserter(sink_)); +        } +        else if (length <= 0xffffffffffffffff) +        { +            binary::native_to_big(static_cast<uint8_t>(0x5b),  +                                  std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint64_t>(length),  +                                  std::back_inserter(sink_)); +        } + +        for (auto c : data) +        { +            sink_.push_back(c); +        } +    } + +    bool write_decimal_value(const string_view_type& sv, const ser_context& context, std::error_code& ec) +    { +        bool more = true; + +        decimal_parse_state state = decimal_parse_state::start; +        std::basic_string<char> s; +        std::basic_string<char> exponent; +        int64_t scale = 0; +        for (auto c : sv) +        { +            switch (state) +            { +                case decimal_parse_state::start: +                { +                    switch (c) +                    { +                        case '-': +                            s.push_back(c); +                            state = decimal_parse_state::integer; +                            break; +                        case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': +                            s.push_back(c); +                            state = decimal_parse_state::integer; +                            break; +                        default: +                        { +                            ec = cbor_errc::invalid_decimal_fraction; +                            return false; +                        } +                    } +                    break; +                } +                case decimal_parse_state::integer: +                { +                    switch (c) +                    { +                        case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': +                            s.push_back(c); +                            break; +                        case 'e': case 'E': +                            state = decimal_parse_state::exp1; +                            break; +                        case '.': +                            state = decimal_parse_state::fraction1; +                            break; +                        default: +                        { +                            ec = cbor_errc::invalid_decimal_fraction; +                            return false; +                        } +                    } +                    break; +                } +                case decimal_parse_state::exp1: +                { +                    switch (c) +                    { +                        case '+': +                            state = decimal_parse_state::exp2; +                            break; +                        case '-': +                            exponent.push_back(c); +                            state = decimal_parse_state::exp2; +                            break; +                        case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': +                            exponent.push_back(c); +                            state = decimal_parse_state::exp2; +                            break; +                        default: +                        { +                            ec = cbor_errc::invalid_decimal_fraction; +                            return false; +                        } +                    } +                    break; +                } +                case decimal_parse_state::exp2: +                { +                    switch (c) +                    { +                        case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': +                            exponent.push_back(c); +                            break; +                        default: +                        { +                            ec = cbor_errc::invalid_decimal_fraction; +                            return false; +                        } +                    } +                    break; +                } +                case decimal_parse_state::fraction1: +                { +                    switch (c) +                    { +                        case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': +                            s.push_back(c); +                            --scale; +                            break; +                        default: +                        { +                            ec = cbor_errc::invalid_decimal_fraction; +                            return false; +                        } +                    } +                    break; +                } +            } +        } + +        write_tag(4); +        more = visit_begin_array((std::size_t)2, semantic_tag::none, context, ec); +        if (!more) {return more;} +        if (exponent.length() > 0) +        { +            int64_t val; +            auto r = jsoncons::detail::to_integer(exponent.data(), exponent.length(), val); +            if (!r) +            { +                ec = r.error_code(); +                return false; +            } +            scale += val; +        } +        more = visit_int64(scale, semantic_tag::none, context, ec); +        if (!more) {return more;} + +        int64_t val{ 0 }; +        auto r = jsoncons::detail::to_integer(s.data(),s.length(), val); +        if (r) +        { +            more = visit_int64(val, semantic_tag::none, context, ec); +            if (!more) {return more;} +        } +        else if (r.error_code() == jsoncons::detail::to_integer_errc::overflow) +        { +            bigint n = bigint::from_string(s.data(), s.length()); +            write_bignum(n); +            end_value(); +        } +        else +        { +            ec = r.error_code(); +            return false; +        } +        more = visit_end_array(context, ec); + +        return more; +    } + +    bool write_hexfloat_value(const string_view_type& sv, const ser_context& context, std::error_code& ec) +    { +        bool more = true; + +        hexfloat_parse_state state = hexfloat_parse_state::start; +        std::basic_string<char> s; +        std::basic_string<char> exponent; +        int64_t scale = 0; + +        for (auto c : sv) +        { +            switch (state) +            { +                case hexfloat_parse_state::start: +                { +                    switch (c) +                    { +                        case '-': +                            s.push_back(c); +                            state = hexfloat_parse_state::expect_0; +                            break; +                        case '0': +                            state = hexfloat_parse_state::expect_x; +                            break; +                        default: +                        { +                            ec = cbor_errc::invalid_bigfloat; +                            return false; +                        } +                    } +                    break; +                } +                case hexfloat_parse_state::expect_0: +                { +                    switch (c) +                    { +                        case '0': +                            state = hexfloat_parse_state::expect_x; +                            break; +                        default: +                        { +                            ec = cbor_errc::invalid_bigfloat; +                            return false; +                        } +                    } +                    break; +                } +                case hexfloat_parse_state::expect_x: +                { +                    switch (c) +                    { +                        case 'x': +                        case 'X': +                            state = hexfloat_parse_state::integer; +                            break; +                        default: +                        { +                            ec = cbor_errc::invalid_bigfloat; +                            return false; +                        } +                    } +                    break; +                } +                case hexfloat_parse_state::integer: +                { +                    switch (c) +                    { +                        case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': +                            s.push_back(c); +                            break; +                        case 'p': case 'P': +                            state = hexfloat_parse_state::exp1; +                            break; +                        case '.': +                            state = hexfloat_parse_state::fraction1; +                            break; +                        default: +                        { +                            ec = cbor_errc::invalid_bigfloat; +                            return false; +                        } +                    } +                    break; +                } +                case hexfloat_parse_state::exp1: +                { +                    switch (c) +                    { +                        case '+': +                            state = hexfloat_parse_state::exp2; +                            break; +                        case '-': +                            exponent.push_back(c); +                            state = hexfloat_parse_state::exp2; +                            break; +                        case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': +                            exponent.push_back(c); +                            state = hexfloat_parse_state::exp2; +                            break; +                        default: +                        { +                            ec = cbor_errc::invalid_bigfloat; +                            return false; +                        } +                    } +                    break; +                } +                case hexfloat_parse_state::exp2: +                { +                    switch (c) +                    { +                        case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': +                            exponent.push_back(c); +                            break; +                        default: +                        { +                            ec = cbor_errc::invalid_bigfloat; +                            return false; +                        } +                    } +                    break; +                } +                case hexfloat_parse_state::fraction1: +                { +                    switch (c) +                    { +                        case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': +                            s.push_back(c); +                            scale -= 4; +                            break; +                        default: +                        { +                            ec = cbor_errc::invalid_bigfloat; +                            return false; +                        } +                    } +                    break; +                } +            } +        } + +        write_tag(5); +        more = visit_begin_array((std::size_t)2, semantic_tag::none, context, ec); +        if (!more) return more; + +        if (exponent.length() > 0) +        { +            int64_t val{ 0 }; +            auto r = jsoncons::detail::base16_to_integer(exponent.data(), exponent.length(), val); +            if (!r) +            { +                ec = r.error_code(); +                return false; +            } +            scale += val; +        } +        more = visit_int64(scale, semantic_tag::none, context, ec); +        if (!more) return more; + +        int64_t val{ 0 }; +        auto r = jsoncons::detail::base16_to_integer(s.data(),s.length(), val); +        if (r) +        { +            more = visit_int64(val, semantic_tag::none, context, ec); +            if (!more) return more; +        } +        else if (r.error_code() == jsoncons::detail::to_integer_errc::overflow) +        { +            bigint n = bigint::from_string_radix(s.data(), s.length(), 16); +            write_bignum(n); +            end_value(); +        } +        else +        { +            JSONCONS_THROW(json_runtime_error<std::invalid_argument>(r.error_code().message())); +        } +        return visit_end_array(context, ec); +    } + +    bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context& context, std::error_code& ec) override +    { +        switch (tag) +        { +            case semantic_tag::bigint: +            { +                bigint n = bigint::from_string(sv.data(), sv.length()); +                write_bignum(n); +                end_value(); +                break; +            } +            case semantic_tag::bigdec: +            { +                return write_decimal_value(sv, context, ec); +            } +            case semantic_tag::bigfloat: +            { +                return write_hexfloat_value(sv, context, ec); +            } +            case semantic_tag::datetime: +            { +                write_tag(0); + +                write_string(sv); +                end_value(); +                break; +            } +            case semantic_tag::uri: +            { +                write_tag(32); +                write_string(sv); +                end_value(); +                break; +            } +            case semantic_tag::base64url: +            { +                write_tag(33); +                write_string(sv); +                end_value(); +                break; +            } +            case semantic_tag::base64: +            { +                write_tag(34); +                write_string(sv); +                end_value(); +                break; +            } +            default: +            { +                write_string(sv); +                end_value(); +                break; +            } +        } +        return true; +    } + +    bool visit_byte_string(const byte_string_view& b,  +                           semantic_tag tag,  +                           const ser_context&, +                           std::error_code&) override +    { +        byte_string_chars_format encoding_hint; +        switch (tag) +        { +            case semantic_tag::base16: +                encoding_hint = byte_string_chars_format::base16; +                break; +            case semantic_tag::base64: +                encoding_hint = byte_string_chars_format::base64; +                break; +            case semantic_tag::base64url: +                encoding_hint = byte_string_chars_format::base64url; +                break; +            default: +                encoding_hint = byte_string_chars_format::none; +                break; +        } +        switch (encoding_hint) +        { +            case byte_string_chars_format::base64url: +                write_tag(21); +                break; +            case byte_string_chars_format::base64: +                write_tag(22); +                break; +            case byte_string_chars_format::base16: +                write_tag(23); +                break; +            default: +                break; +        } +        if (options_.pack_strings() && b.size() >= jsoncons::cbor::detail::min_length_for_stringref(next_stringref_)) +        { +            byte_string_type bs(b.data(), b.size(), alloc_); +            auto it = bytestringref_map_.find(bs); +            if (it == bytestringref_map_.end()) +            { +                bytestringref_map_.emplace(std::make_pair(bs, next_stringref_++)); +                write_byte_string_value(bs); +            } +            else +            { +                write_tag(25); +                write_uint64_value(it->second); +            } +        } +        else +        { +            write_byte_string_value(b); +        } + +        end_value(); +        return true; +    } + +    bool visit_byte_string(const byte_string_view& b,  +                           uint64_t ext_tag,  +                           const ser_context&, +                           std::error_code&) override +    { +        if (options_.pack_strings() && b.size() >= jsoncons::cbor::detail::min_length_for_stringref(next_stringref_)) +        { +            byte_string_type bs(b.data(), b.size(), alloc_); +            auto it = bytestringref_map_.find(bs); +            if (it == bytestringref_map_.end()) +            { +                bytestringref_map_.emplace(std::make_pair(bs, next_stringref_++)); +                write_tag(ext_tag); +                write_byte_string_value(bs); +            } +            else +            { +                write_tag(25); +                write_uint64_value(it->second); +            } +        } +        else +        { +            write_tag(ext_tag); +            write_byte_string_value(b); +        } + +        end_value(); +        return true; +    } + +    void write_byte_string_value(const byte_string_view& b)  +    { +        if (b.size() <= 0x17) +        { +            // fixstr stores a byte array whose length is upto 31 bytes +            binary::native_to_big(static_cast<uint8_t>(0x40 + b.size()),  +                                            std::back_inserter(sink_)); +        } +        else if (b.size() <= 0xff) +        { +            binary::native_to_big(static_cast<uint8_t>(0x58),  +                                            std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint8_t>(b.size()),  +                                            std::back_inserter(sink_)); +        } +        else if (b.size() <= 0xffff) +        { +            binary::native_to_big(static_cast<uint8_t>(0x59),  +                                            std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint16_t>(b.size()),  +                                            std::back_inserter(sink_)); +        } +        else if (b.size() <= 0xffffffff) +        { +            binary::native_to_big(static_cast<uint8_t>(0x5a),  +                                            std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint32_t>(b.size()),  +                                            std::back_inserter(sink_)); +        } +        else // if (b.size() <= 0xffffffffffffffff) +        { +            binary::native_to_big(static_cast<uint8_t>(0x5b),  +                                            std::back_inserter(sink_)); +            binary::native_to_big(static_cast<uint64_t>(b.size()),  +                                            std::back_inserter(sink_)); +        } + +        for (auto c : b) +        { +            sink_.push_back(c); +        } +    } + +    bool visit_double(double val,  +                      semantic_tag tag, +                      const ser_context&, +                      std::error_code&) override +    { +        switch (tag) +        { +            case semantic_tag::epoch_second: +                write_tag(1); +                break; +            case semantic_tag::epoch_milli: +                write_tag(1); +                if (val != 0) +                { +                    val /= millis_in_second; +                } +                break; +            case semantic_tag::epoch_nano: +                write_tag(1); +                if (val != 0) +                { +                    val /= nanos_in_second; +                } +                break; +            default: +                break; +        } + +        float valf = (float)val; +        if ((double)valf == val) +        { +            binary::native_to_big(static_cast<uint8_t>(0xfa),  +                                  std::back_inserter(sink_)); +            binary::native_to_big(valf, std::back_inserter(sink_)); +        } +        else +        { +            binary::native_to_big(static_cast<uint8_t>(0xfb),  +                                  std::back_inserter(sink_)); +            binary::native_to_big(val, std::back_inserter(sink_)); +        } + +        // write double + +        end_value(); +        return true; +    } + +    bool visit_int64(int64_t value,  +                        semantic_tag tag,  +                        const ser_context& context, +                        std::error_code& ec) override +    { +        switch (tag) +        { +            case semantic_tag::epoch_milli: +            case semantic_tag::epoch_nano: +                return visit_double(static_cast<double>(value), tag, context, ec); +            case semantic_tag::epoch_second: +                write_tag(1); +                break; +            default: +                break; +        } +        if (value >= 0) +        { +            if (value <= 0x17) +            { +                binary::native_to_big(static_cast<uint8_t>(value),  +                                  std::back_inserter(sink_)); +            }  +            else if (value <= (std::numeric_limits<uint8_t>::max)()) +            { +                binary::native_to_big(static_cast<uint8_t>(0x18),  +                                  std::back_inserter(sink_)); +                binary::native_to_big(static_cast<uint8_t>(value),  +                                  std::back_inserter(sink_)); +            }  +            else if (value <= (std::numeric_limits<uint16_t>::max)()) +            { +                binary::native_to_big(static_cast<uint8_t>(0x19),  +                                  std::back_inserter(sink_)); +                binary::native_to_big(static_cast<uint16_t>(value),  +                                  std::back_inserter(sink_)); +            }  +            else if (value <= (std::numeric_limits<uint32_t>::max)()) +            { +                binary::native_to_big(static_cast<uint8_t>(0x1a),  +                                  std::back_inserter(sink_)); +                binary::native_to_big(static_cast<uint32_t>(value),  +                                  std::back_inserter(sink_)); +            }  +            else if (value <= (std::numeric_limits<int64_t>::max)()) +            { +                binary::native_to_big(static_cast<uint8_t>(0x1b),  +                                  std::back_inserter(sink_)); +                binary::native_to_big(static_cast<int64_t>(value),  +                                  std::back_inserter(sink_)); +            } +        } else +        { +            const auto posnum = -1 - value; +            if (value >= -24) +            { +                binary::native_to_big(static_cast<uint8_t>(0x20 + posnum),  +                                  std::back_inserter(sink_)); +            }  +            else if (posnum <= (std::numeric_limits<uint8_t>::max)()) +            { +                binary::native_to_big(static_cast<uint8_t>(0x38),  +                                  std::back_inserter(sink_)); +                binary::native_to_big(static_cast<uint8_t>(posnum),  +                                  std::back_inserter(sink_)); +            }  +            else if (posnum <= (std::numeric_limits<uint16_t>::max)()) +            { +                binary::native_to_big(static_cast<uint8_t>(0x39),  +                                  std::back_inserter(sink_)); +                binary::native_to_big(static_cast<uint16_t>(posnum),  +                                  std::back_inserter(sink_)); +            }  +            else if (posnum <= (std::numeric_limits<uint32_t>::max)()) +            { +                binary::native_to_big(static_cast<uint8_t>(0x3a),  +                                  std::back_inserter(sink_)); +                binary::native_to_big(static_cast<uint32_t>(posnum),  +                                  std::back_inserter(sink_)); +            }  +            else if (posnum <= (std::numeric_limits<int64_t>::max)()) +            { +                binary::native_to_big(static_cast<uint8_t>(0x3b),  +                                  std::back_inserter(sink_)); +                binary::native_to_big(static_cast<int64_t>(posnum),  +                                  std::back_inserter(sink_)); +            } +        } +        end_value(); +        return true; +    } + +    bool visit_uint64(uint64_t value,  +                      semantic_tag tag,  +                      const ser_context& context, +                      std::error_code& ec) override +    { +        switch (tag) +        { +            case semantic_tag::epoch_milli: +            case semantic_tag::epoch_nano: +                return visit_double(static_cast<double>(value), tag, context, ec); +            case semantic_tag::epoch_second: +                write_tag(1); +                break; +            default: +                break; +        } + +        write_uint64_value(value); +        end_value(); +        return true; +    } + +    void write_tag(uint64_t value) +    { +        if (value <= 0x17) +        { +            sink_.push_back(0xc0 | static_cast<uint8_t>(value));  +        }  +        else if (value <=(std::numeric_limits<uint8_t>::max)()) +        { +            sink_.push_back(0xd8); +            sink_.push_back(static_cast<uint8_t>(value)); +        }  +        else if (value <=(std::numeric_limits<uint16_t>::max)()) +        { +            sink_.push_back(0xd9); +            binary::native_to_big(static_cast<uint16_t>(value),  +                                            std::back_inserter(sink_)); +        } +        else if (value <=(std::numeric_limits<uint32_t>::max)()) +        { +            sink_.push_back(0xda); +            binary::native_to_big(static_cast<uint32_t>(value),  +                                            std::back_inserter(sink_)); +        } +        else  +        { +            sink_.push_back(0xdb); +            binary::native_to_big(static_cast<uint64_t>(value),  +                                            std::back_inserter(sink_)); +        } +    } + +    void write_uint64_value(uint64_t value)  +    { +        if (value <= 0x17) +        { +            sink_.push_back(static_cast<uint8_t>(value)); +        }  +        else if (value <=(std::numeric_limits<uint8_t>::max)()) +        { +            sink_.push_back(static_cast<uint8_t>(0x18)); +            sink_.push_back(static_cast<uint8_t>(value)); +        }  +        else if (value <=(std::numeric_limits<uint16_t>::max)()) +        { +            sink_.push_back(static_cast<uint8_t>(0x19)); +            binary::native_to_big(static_cast<uint16_t>(value),  +                                            std::back_inserter(sink_)); +        }  +        else if (value <=(std::numeric_limits<uint32_t>::max)()) +        { +            sink_.push_back(static_cast<uint8_t>(0x1a)); +            binary::native_to_big(static_cast<uint32_t>(value),  +                                            std::back_inserter(sink_)); +        }  +        else if (value <=(std::numeric_limits<uint64_t>::max)()) +        { +            sink_.push_back(static_cast<uint8_t>(0x1b)); +            binary::native_to_big(static_cast<uint64_t>(value),  +                                            std::back_inserter(sink_)); +        } +    } + +    bool visit_bool(bool value, semantic_tag, const ser_context&, std::error_code&) override +    { +        if (value) +        { +            sink_.push_back(0xf5); +        } +        else +        { +            sink_.push_back(0xf4); +        } + +        end_value(); +        return true; +    } + +    bool visit_typed_array(const jsoncons::span<const uint8_t>& v,  +                        semantic_tag tag, +                        const ser_context& context,  +                        std::error_code& ec) override +    { +        if (options_.use_typed_arrays()) +        { +            switch (tag) +            { +                case semantic_tag::clamped: +                    write_tag(0x44); +                    break; +                default: +                    write_tag(0x40); +                    break; +            } +            write_byte_string_value(byte_string_view(v)); +            return true; +        } +        else +        { +            bool more = this->begin_array(v.size(), semantic_tag::none, context, ec); +            for (auto p = v.begin(); more && p != v.end(); ++p) +            { +                more = this->uint64_value(*p, tag, context, ec); +            } +            if (more) +            { +                more = this->end_array(context, ec); +            } +            return more; +        } +    } + +    bool visit_typed_array(const jsoncons::span<const uint16_t>& data,   +                        semantic_tag tag, +                        const ser_context& context,  +                        std::error_code& ec) override +    { +        if (options_.use_typed_arrays()) +        { +            write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),  +                                  uint16_t(),  +                                  tag); +            std::vector<uint8_t> v(data.size()*sizeof(uint16_t)); +            std::memcpy(v.data(),data.data(),data.size()*sizeof(uint16_t)); +            write_byte_string_value(byte_string_view(v)); +            return true; +        } +        else +        { +            bool more = this->begin_array(data.size(), semantic_tag::none, context, ec); +            for (auto p = data.begin(); more && p != data.end(); ++p) +            { +                more = this->uint64_value(*p, tag, context, ec); +            } +            if (more) +            { +                more = this->end_array(context, ec); +            } +            return more; +        } +    } + +    bool visit_typed_array(const jsoncons::span<const uint32_t>& data,   +                        semantic_tag tag, +                        const ser_context& context,  +                        std::error_code& ec) override +    { +        if (options_.use_typed_arrays()) +        { +            write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),  +                                  uint32_t(),  +                                  tag); +            std::vector<uint8_t> v(data.size()*sizeof(uint32_t)); +            std::memcpy(v.data(), data.data(), data.size()*sizeof(uint32_t)); +            write_byte_string_value(byte_string_view(v)); +            return true; +        } +        else +        { +            bool more = this->begin_array(data.size(), semantic_tag::none, context, ec); +            for (auto p = data.begin(); more && p != data.end(); ++p) +            { +                more = this->uint64_value(*p, semantic_tag::none, context, ec); +            } +            if (more) +            { +                more = this->end_array(context, ec); +            } +            return more; +        } +    } + +    bool visit_typed_array(const jsoncons::span<const uint64_t>& data,   +                        semantic_tag tag, +                        const ser_context& context,  +                        std::error_code& ec) override +    { +        if (options_.use_typed_arrays()) +        { +            write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),  +                                  uint64_t(),  +                                  tag); +            std::vector<uint8_t> v(data.size()*sizeof(uint64_t)); +            std::memcpy(v.data(), data.data(), data.size()*sizeof(uint64_t)); +            write_byte_string_value(byte_string_view(v)); +            return true; +        } +        else +        { +            bool more = this->begin_array(data.size(), semantic_tag::none, context, ec); +            for (auto p = data.begin(); more && p != data.end(); ++p) +            { +                more = this->uint64_value(*p,semantic_tag::none,context, ec); +            } +            if (more) +            { +                more = this->end_array(context, ec); +            } +            return more; +        } +    } + +    bool visit_typed_array(const jsoncons::span<const int8_t>& data,   +                        semantic_tag, +                        const ser_context& context,  +                        std::error_code& ec) override +    { +        if (options_.use_typed_arrays()) +        { +            write_tag(0x48); +            std::vector<uint8_t> v(data.size()*sizeof(int8_t)); +            std::memcpy(v.data(), data.data(), data.size()*sizeof(int8_t)); +            write_byte_string_value(byte_string_view(v)); +            return true; +        } +        else +        { +            bool more = this->begin_array(data.size(), semantic_tag::none,context, ec); +            for (auto p = data.begin(); more && p != data.end(); ++p) +            { +                more = this->int64_value(*p,semantic_tag::none,context, ec); +            } +            if (more) +            { +                more = this->end_array(context, ec); +            } +            return more; +        } +    } + +    bool visit_typed_array(const jsoncons::span<const int16_t>& data,   +                        semantic_tag tag, +                        const ser_context& context,  +                        std::error_code& ec) override +    { +        if (options_.use_typed_arrays()) +        { +            write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),  +                                  int16_t(),  +                                  tag); +            std::vector<uint8_t> v(data.size()*sizeof(int16_t)); +            std::memcpy(v.data(), data.data(), data.size()*sizeof(int16_t)); +            write_byte_string_value(byte_string_view(v)); +            return true; +        } +        else +        { +            bool more = this->begin_array(data.size(), semantic_tag::none,context, ec); +            for (auto p = data.begin(); more && p != data.end(); ++p) +            { +                more = this->int64_value(*p,semantic_tag::none,context, ec); +            } +            if (more) +            { +                more = this->end_array(context, ec); +            } +            return more; +        } +    } + +    bool visit_typed_array(const jsoncons::span<const int32_t>& data,   +                        semantic_tag tag, +                        const ser_context& context,  +                        std::error_code& ec) override +    { +        if (options_.use_typed_arrays()) +        { +            write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),  +                                  int32_t(),  +                                  tag); +            std::vector<uint8_t> v(data.size()*sizeof(int32_t)); +            std::memcpy(v.data(), data.data(), data.size()*sizeof(int32_t)); +            write_byte_string_value(byte_string_view(v)); +            return true; +        } +        else +        { +            bool more = this->begin_array(data.size(), semantic_tag::none,context, ec); +            for (auto p = data.begin(); more && p != data.end(); ++p) +            { +                more = this->int64_value(*p,semantic_tag::none,context, ec); +            } +            if (more) +            { +                more = this->end_array(context, ec); +            } +            return more; +        } +    } + +    bool visit_typed_array(const jsoncons::span<const int64_t>& data,   +                        semantic_tag tag, +                        const ser_context& context,  +                        std::error_code& ec) override +    { +        if (options_.use_typed_arrays()) +        { +            write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),  +                                  int64_t(),  +                                  tag); +            std::vector<uint8_t> v(data.size()*sizeof(int64_t)); +            std::memcpy(v.data(), data.data(), data.size()*sizeof(int64_t)); +            write_byte_string_value(byte_string_view(v)); +            return true; +        } +        else +        { +            bool more = this->begin_array(data.size(), semantic_tag::none,context, ec); +            for (auto p = data.begin(); more && p != data.end(); ++p) +            { +                more = this->int64_value(*p,semantic_tag::none,context, ec); +            } +            if (more) +            { +                more = this->end_array(context, ec); +            } +            return more; +        } +    } + +    bool visit_typed_array(half_arg_t, const jsoncons::span<const uint16_t>& data,   +                        semantic_tag tag, +                        const ser_context& context,  +                        std::error_code& ec) override +    { +        if (options_.use_typed_arrays()) +        { +            write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),  +                                  half_arg,  +                                  tag); +            std::vector<uint8_t> v(data.size()*sizeof(uint16_t)); +            std::memcpy(v.data(),data.data(),data.size()*sizeof(uint16_t)); +            write_byte_string_value(byte_string_view(v)); +            return true; +        } +        else +        { +            bool more = this->begin_array(data.size(), semantic_tag::none, context, ec); +            for (auto p = data.begin(); more && p != data.end(); ++p) +            { +                more = this->half_value(*p, tag, context, ec); +            } +            if (more) +            { +                more = this->end_array(context, ec); +            } +            return more; +        } +    } + +    bool visit_typed_array(const jsoncons::span<const float>& data,   +                        semantic_tag tag, +                        const ser_context& context,  +                        std::error_code& ec) override +    { +        if (options_.use_typed_arrays()) +        { +            write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),  +                                  float(),  +                                  tag); +            std::vector<uint8_t> v(data.size()*sizeof(float)); +            std::memcpy(v.data(), data.data(), data.size()*sizeof(float)); +            write_byte_string_value(byte_string_view(v)); +            return true; +        } +        else +        { +            bool more = this->begin_array(data.size(), semantic_tag::none,context, ec); +            for (auto p = data.begin(); more && p != data.end(); ++p) +            { +                more = this->double_value(*p,semantic_tag::none,context, ec); +            } +            if (more) +            { +                more = this->end_array(context, ec); +            } +            return more; +        } +    } + +    bool visit_typed_array(const jsoncons::span<const double>& data,   +                        semantic_tag tag, +                        const ser_context& context,  +                        std::error_code& ec) override +    { +        if (options_.use_typed_arrays()) +        { +            write_typed_array_tag(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>(),  +                                  double(),  +                                  tag); +            std::vector<uint8_t> v(data.size()*sizeof(double)); +            std::memcpy(v.data(), data.data(), data.size()*sizeof(double)); +            write_byte_string_value(byte_string_view(v)); +            return true; +        } +        else +        { +            bool more = this->begin_array(data.size(), semantic_tag::none,context, ec); +            for (auto p = data.begin(); more && p != data.end(); ++p) +            { +                more = this->double_value(*p,semantic_tag::none,context, ec); +            } +            if (more) +            { +                more = this->end_array(context, ec); +            } +            return more; +        } +    } +/* +    bool visit_typed_array(const jsoncons::span<const float128_type>&,  +                        semantic_tag, +                        const ser_context&,  +                        std::error_code&) override +    { +        return true; +    } +*/ +    bool visit_begin_multi_dim(const jsoncons::span<const size_t>& shape, +                            semantic_tag tag, +                            const ser_context& context,  +                            std::error_code& ec) override +    { +        switch (tag) +        { +            case semantic_tag::multi_dim_column_major: +                write_tag(1040); +                break; +            default: +                write_tag(40); +                break; +        } +        bool more = visit_begin_array(2, semantic_tag::none, context, ec); +        if (more) +            more = visit_begin_array(shape.size(), semantic_tag::none, context, ec); +        for (auto it = shape.begin(); more && it != shape.end(); ++it) +        { +            more = visit_uint64(*it, semantic_tag::none, context, ec); +        } +        if (more) +        { +            more = visit_end_array(context, ec); +        } +        return more; +    } + +    bool visit_end_multi_dim(const ser_context& context, +                          std::error_code& ec) override +    { +        bool more = visit_end_array(context, ec); +        return more; +    } + +    void write_typed_array_tag(std::true_type,  +                               uint16_t, +                               semantic_tag) +    { +        write_tag(0x41); // big endian +    } +    void write_typed_array_tag(std::false_type, +                               uint16_t, +                               semantic_tag) +    { +        write_tag(0x45); +    } + +    void write_typed_array_tag(std::true_type,  +                               uint32_t, +                               semantic_tag) +    { +        write_tag(0x42); // big endian +    } +    void write_typed_array_tag(std::false_type, +                               uint32_t, +                               semantic_tag) +    { +        write_tag(0x46);  // little endian +    } + +    void write_typed_array_tag(std::true_type,  +                               uint64_t, +                               semantic_tag) +    { +        write_tag(0x43); // big endian +    } +    void write_typed_array_tag(std::false_type, +                               uint64_t, +                               semantic_tag) +    { +        write_tag(0x47);  // little endian +    } + +    void write_typed_array_tag(std::true_type,  +                               int16_t, +                               semantic_tag) +    { +        write_tag(0x49); // big endian +    } +    void write_typed_array_tag(std::false_type, +                               int16_t, +                               semantic_tag) +    { +        write_tag(0x4d);  // little endian +    } + +    void write_typed_array_tag(std::true_type,  +                               int32_t, +                               semantic_tag) +    { +        write_tag(0x4a); // big endian +    } +    void write_typed_array_tag(std::false_type, +                               int32_t, +                               semantic_tag) +    { +        write_tag(0x4e);  // little endian +    } + +    void write_typed_array_tag(std::true_type,  +                               int64_t, +                               semantic_tag) +    { +        write_tag(0x4b); // big endian +    } +    void write_typed_array_tag(std::false_type, +                               int64_t, +                               semantic_tag) +    { +        write_tag(0x4f);  // little endian +    } + +    void write_typed_array_tag(std::true_type,  +                               half_arg_t, +                               semantic_tag) +    { +        write_tag(0x50); +    } +    void write_typed_array_tag(std::false_type, +                               half_arg_t, +                               semantic_tag) +    { +        write_tag(0x54); +    } +                         +    void write_typed_array_tag(std::true_type,  +                               float, +                               semantic_tag) +    { +        write_tag(0x51); // big endian +    } +    void write_typed_array_tag(std::false_type, +                               float, +                               semantic_tag) +    { +        write_tag(0x55);  // little endian +    } + +    void write_typed_array_tag(std::true_type,  +                               double, +                               semantic_tag) +    { +        write_tag(0x52); // big endian +    } +    void write_typed_array_tag(std::false_type, +                               double, +                               semantic_tag) +    { +        write_tag(0x56);  // little endian +    } + +    void end_value() +    { +        if (!stack_.empty()) +        { +            ++stack_.back().count_; +        } +    } +}; + +using cbor_stream_encoder = basic_cbor_encoder<jsoncons::binary_stream_sink>; +using cbor_bytes_encoder = basic_cbor_encoder<jsoncons::bytes_sink<std::vector<uint8_t>>>; + +#if !defined(JSONCONS_NO_DEPRECATED) +JSONCONS_DEPRECATED_MSG("Instead, use cbor_bytes_encoder") typedef cbor_bytes_encoder cbor_bytes_serializer; + +template<class Sink=jsoncons::binary_stream_sink> +using basic_cbor_serializer = basic_cbor_encoder<Sink>;  + +JSONCONS_DEPRECATED_MSG("Instead, use cbor_stream_encoder") typedef cbor_stream_encoder cbor_encoder; +JSONCONS_DEPRECATED_MSG("Instead, use cbor_stream_encoder") typedef cbor_stream_encoder cbor_serializer; +JSONCONS_DEPRECATED_MSG("Instead, use cbor_bytes_encoder") typedef cbor_bytes_encoder cbor_buffer_serializer; +#endif + +}} +#endif diff --git a/include/jsoncons_ext/cbor/cbor_error.hpp b/include/jsoncons_ext/cbor/cbor_error.hpp new file mode 100644 index 0000000..a7a6626 --- /dev/null +++ b/include/jsoncons_ext/cbor/cbor_error.hpp @@ -0,0 +1,105 @@ +/// Copyright 2018 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_CBOR_ERROR_HPP +#define JSONCONS_CBOR_CBOR_ERROR_HPP + +#include <system_error> +#include <jsoncons/config/jsoncons_config.hpp> +#include <jsoncons/json_exception.hpp> // jsoncons::ser_error + +namespace jsoncons { namespace cbor { + +enum class cbor_errc +{ +    success = 0, +    unexpected_eof, +    source_error, +    invalid_decimal_fraction, +    invalid_bigfloat, +    invalid_utf8_text_string, +    too_many_items, +    too_few_items, +    number_too_large, +    stringref_too_large, +    max_nesting_depth_exceeded, +    unknown_type, +    illegal_chunked_string +}; + +class cbor_error_category_impl +   : public std::error_category +{ +public: +    const char* name() const noexcept override +    { +        return "jsoncons/cbor"; +    } +    std::string message(int ev) const override +    { +        switch (static_cast<cbor_errc>(ev)) +        { +            case cbor_errc::unexpected_eof: +                return "Unexpected end of file"; +            case cbor_errc::source_error: +                return "Source error"; +            case cbor_errc::invalid_decimal_fraction: +                return "Invalid decimal fraction"; +            case cbor_errc::invalid_bigfloat: +                return "Invalid bigfloat"; +            case cbor_errc::invalid_utf8_text_string: +                return "Illegal UTF-8 encoding in text string"; +            case cbor_errc::too_many_items: +                return "Too many items were added to a CBOR map or array of known length"; +            case cbor_errc::too_few_items: +                return "Too few items were added to a CBOR map or array of known length"; +            case cbor_errc::number_too_large: +                return "Number exceeds implementation limits"; +            case cbor_errc::stringref_too_large: +                return "stringref exceeds stringref map size"; +            case cbor_errc::max_nesting_depth_exceeded: +                return "Data item nesting exceeds limit in options"; +            case cbor_errc::unknown_type: +                return "An unknown type was found in the stream"; +            case cbor_errc::illegal_chunked_string: +                return "An illegal type was found while parsing an indefinite length string"; +            default: +                return "Unknown CBOR parser error"; +        } +    } +}; + +inline +const std::error_category& cbor_error_category() +{ +  static cbor_error_category_impl instance; +  return instance; +} + +inline  +std::error_code make_error_code(cbor_errc e) +{ +    return std::error_code(static_cast<int>(e),cbor_error_category()); +} + + +#if !defined(JSONCONS_NO_DEPRECATED) + +JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error cbor_error; +JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error cbor_decode_error; +JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error cbor_reader_errc; +#endif + +}} + +namespace std { +    template<> +    struct is_error_code_enum<jsoncons::cbor::cbor_errc> : public true_type +    { +    }; +} + +#endif diff --git a/include/jsoncons_ext/cbor/cbor_options.hpp b/include/jsoncons_ext/cbor/cbor_options.hpp new file mode 100644 index 0000000..1de4a4e --- /dev/null +++ b/include/jsoncons_ext/cbor/cbor_options.hpp @@ -0,0 +1,113 @@ +// Copyright 2019 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_CBOR_OPTIONS_HPP +#define JSONCONS_CBOR_CBOR_OPTIONS_HPP + +#include <string> +#include <limits> // std::numeric_limits +#include <cwchar> +#include <jsoncons/json_exception.hpp> +#include <jsoncons_ext/cbor/cbor_detail.hpp> + +namespace jsoncons { namespace cbor { + +class cbor_options; + +class cbor_options_common +{ +    friend class cbor_options; + +    int max_nesting_depth_; +protected: +    virtual ~cbor_options_common() = default; + +    cbor_options_common() +        : max_nesting_depth_(1024) +    { +    } + +    cbor_options_common(const cbor_options_common&) = default; +    cbor_options_common& operator=(const cbor_options_common&) = default; +    cbor_options_common(cbor_options_common&&) = default; +    cbor_options_common& operator=(cbor_options_common&&) = default; +public: +    int max_nesting_depth() const  +    { +        return max_nesting_depth_; +    } +}; + +class cbor_decode_options : public virtual cbor_options_common +{ +    friend class cbor_options; +public: +    cbor_decode_options() +    { +    } +}; + +class cbor_encode_options : public virtual cbor_options_common +{ +    friend class cbor_options; + +    bool use_stringref_; +    bool use_typed_arrays_; +public: +    cbor_encode_options() +        : use_stringref_(false), +          use_typed_arrays_(false) +    { +    } + +    bool pack_strings() const  +    { +        return use_stringref_; +    } + +    bool use_typed_arrays() const  +    { +        return use_typed_arrays_; +    } +}; + +class cbor_options final : public cbor_decode_options, public cbor_encode_options +{ +public: +    using cbor_options_common::max_nesting_depth; +    using cbor_encode_options::pack_strings; +    using cbor_encode_options::use_typed_arrays; + +    cbor_options& max_nesting_depth(int value) +    { +        this->max_nesting_depth_ = value; +        return *this; +    } + +    cbor_options& pack_strings(bool value) +    { +        this->use_stringref_ = value; +        return *this; +    } + +    cbor_options& use_typed_arrays(bool value) +    { +        this->use_typed_arrays_ = value; +        return *this; +    } + +#if !defined(JSONCONS_NO_DEPRECATED) +    JSONCONS_DEPRECATED_MSG("Instead, use use_typed_arrays(bool)") +    cbor_options& enable_typed_arrays(bool value) +    { +        this->use_typed_arrays_ = value; +        return *this; +    } +#endif +}; + +}} +#endif diff --git a/include/jsoncons_ext/cbor/cbor_parser.hpp b/include/jsoncons_ext/cbor/cbor_parser.hpp new file mode 100644 index 0000000..f3d03bb --- /dev/null +++ b/include/jsoncons_ext/cbor/cbor_parser.hpp @@ -0,0 +1,1942 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_CBOR_PARSER_HPP +#define JSONCONS_CBOR_CBOR_PARSER_HPP + +#include <string> +#include <vector> +#include <memory> +#include <utility> // std::move +#include <bitset> // std::bitset +#include <jsoncons/json.hpp> +#include <jsoncons/source.hpp> +#include <jsoncons/json_visitor.hpp> +#include <jsoncons/config/jsoncons_config.hpp> +#include <jsoncons_ext/cbor/cbor_error.hpp> +#include <jsoncons_ext/cbor/cbor_detail.hpp> +#include <jsoncons_ext/cbor/cbor_options.hpp> +#include <jsoncons/json_visitor2.hpp> + +namespace jsoncons { namespace cbor { + +enum class parse_mode {root,accept,array,indefinite_array,map_key,map_value,indefinite_map_key,indefinite_map_value,multi_dim}; + +struct mapped_string +{ +    jsoncons::cbor::detail::cbor_major_type type; +    std::string s; +    std::vector<uint8_t> bytes; + +    mapped_string(const std::string& s) +        : type(jsoncons::cbor::detail::cbor_major_type::text_string), s(s) +    { +    } + +    mapped_string(std::string&& s) +        : type(jsoncons::cbor::detail::cbor_major_type::text_string), s(std::move(s)) +    { +    } + +    mapped_string(const std::vector<uint8_t>& bytes) +        : type(jsoncons::cbor::detail::cbor_major_type::byte_string), bytes(bytes) +    { +    } + +    mapped_string(std::vector<uint8_t>&& bytes) +        : type(jsoncons::cbor::detail::cbor_major_type::byte_string), bytes(std::move(bytes)) +    { +    } + +    mapped_string(const mapped_string&) = default; + +    mapped_string(mapped_string&&) = default; + +    mapped_string& operator=(const mapped_string&) = default; + +    mapped_string& operator=(mapped_string&&) = default; +}; + +struct parse_state  +{ +    parse_mode mode;  +    std::size_t length; +    std::size_t index; +    bool pop_stringref_map_stack; + +    parse_state(parse_mode mode, std::size_t length, bool pop_stringref_map_stack = false) noexcept +        : mode(mode), length(length), index(0), pop_stringref_map_stack(pop_stringref_map_stack) +    { +    } + +    parse_state(const parse_state&) = default; +    parse_state(parse_state&&) = default; +}; + +template <class Source,class Allocator=std::allocator<char>> +class basic_cbor_parser : public ser_context +{ +    using char_type = char; +    using char_traits_type = std::char_traits<char>; +    using allocator_type = Allocator; +    using char_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<char_type>; +    using byte_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<uint8_t>;                   +    using tag_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<uint64_t>;                  +    using parse_state_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<parse_state>;                          +    using stringref_map = std::vector<mapped_string>; +    using stringref_map_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<stringref_map>;                            + +    using string_type = std::basic_string<char_type,char_traits_type,char_allocator_type>; + +    enum {stringref_tag, // 25 +          stringref_namespace_tag, // 256 +          item_tag, +          num_of_tags}; + +    std::bitset<num_of_tags> other_tags_; + +    allocator_type alloc_; +    Source source_; +    cbor_decode_options options_; + +    bool more_; +    bool done_; +    string_type text_buffer_; +    std::vector<uint8_t,byte_allocator_type> bytes_buffer_; +    uint64_t item_tag_; +    std::vector<parse_state,parse_state_allocator_type> state_stack_; +    std::vector<uint8_t,byte_allocator_type> typed_array_; +    std::vector<std::size_t> shape_; +    std::size_t index_; // TODO: Never used! +    std::vector<stringref_map,stringref_map_allocator_type> stringref_map_stack_; +    int nesting_depth_; + +    struct read_byte_string_from_buffer +    { +        byte_string_view bytes; + +        read_byte_string_from_buffer(const byte_string_view& b) +            : bytes(b) +        { +        } +        template <class Container> +        void operator()(Container& c, std::error_code&) +        { +            c.clear(); +            c.reserve(bytes.size()); +            for (auto b : bytes) +            { +                c.push_back(b); +            } +        } +    }; + +    struct read_byte_string_from_source +    { +        basic_cbor_parser<Source,Allocator>* source; + +        read_byte_string_from_source(basic_cbor_parser<Source,Allocator>* source) +            : source(source) +        { +        } +        template <class Container> +        void operator()(Container& c, std::error_code& ec) +        { +            source->read_byte_string(c,ec); +        } +    }; + +public: +    template <class Sourceable> +    basic_cbor_parser(Sourceable&& source, +                      const cbor_decode_options& options = cbor_decode_options(), +                      const Allocator alloc = Allocator()) +       : alloc_(alloc), +         source_(std::forward<Sourceable>(source)), +         options_(options), +         more_(true),  +         done_(false), +         text_buffer_(alloc), +         bytes_buffer_(alloc), +         item_tag_(0), +         state_stack_(alloc), +         typed_array_(alloc), +         index_(0), +         stringref_map_stack_(alloc), +         nesting_depth_(0) +    { +        state_stack_.emplace_back(parse_mode::root,0); +    } + +    void restart() +    { +        more_ = true; +    } + +    void reset() +    { +        more_ = true; +        done_ = false; +        text_buffer_.clear(); +        bytes_buffer_.clear(); +        item_tag_ = 0; +        state_stack_.clear(); +        state_stack_.emplace_back(parse_mode::root,0); +        typed_array_.clear(); +        stringref_map_stack_.clear(); +        nesting_depth_ = 0; +    } + +    template <class Sourceable> +    void reset(Sourceable&& source) +    { +        source_ = std::forward<Sourceable>(source); +        reset(); +    } + +    bool done() const +    { +        return done_; +    } + +    bool stopped() const +    { +        return !more_; +    } + +    std::size_t line() const override +    { +        return 0; +    } + +    std::size_t column() const override +    { +        return source_.position(); +    } + +    void parse(json_visitor2& visitor, std::error_code& ec) +    { +        while (!done_ && more_) +        { +            switch (state_stack_.back().mode) +            { +                case parse_mode::multi_dim: +                { +                    if (state_stack_.back().index == 0) +                    { +                        ++state_stack_.back().index; +                        read_item(visitor, ec); +                    } +                    else +                    { +                        produce_end_multi_dim(visitor, ec); +                    } +                    break; +                } +                case parse_mode::array: +                { +                    if (state_stack_.back().index < state_stack_.back().length) +                    { +                        ++state_stack_.back().index; +                        read_item(visitor, ec); +                    } +                    else +                    { +                        end_array(visitor, ec); +                    } +                    break; +                } +                case parse_mode::indefinite_array: +                { +                    auto c = source_.peek(); +                    if (c.eof) +                    { +                        ec = cbor_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } +                    if (c.value == 0xff) +                    { +                        source_.ignore(1); +                        end_array(visitor, ec); +                    } +                    else +                    { +                        read_item(visitor, ec); +                    } +                    break; +                } +                case parse_mode::map_key: +                { +                    if (state_stack_.back().index < state_stack_.back().length) +                    { +                        ++state_stack_.back().index; +                        state_stack_.back().mode = parse_mode::map_value; +                        read_item(visitor, ec); +                    } +                    else +                    { +                        end_object(visitor, ec); +                    } +                    break; +                } +                case parse_mode::map_value: +                { +                    state_stack_.back().mode = parse_mode::map_key; +                    read_item(visitor, ec); +                    break; +                } +                case parse_mode::indefinite_map_key: +                { +                    auto c = source_.peek(); +                    if (c.eof) +                    { +                        ec = cbor_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } +                    if (c.value == 0xff) +                    { +                        source_.ignore(1); +                        end_object(visitor, ec); +                    } +                    else +                    { +                        state_stack_.back().mode = parse_mode::indefinite_map_value; +                        read_item(visitor, ec); +                    } +                    break; +                } +                case parse_mode::indefinite_map_value: +                { +                    state_stack_.back().mode = parse_mode::indefinite_map_key; +                    read_item(visitor, ec); +                    break; +                } +                case parse_mode::root: +                { +                    state_stack_.back().mode = parse_mode::accept; +                    read_item(visitor, ec); +                    break; +                } +                case parse_mode::accept: +                { +                    JSONCONS_ASSERT(state_stack_.size() == 1); +                    state_stack_.clear(); +                    more_ = false; +                    done_ = true; +                    visitor.flush(); +                    break; +                } +            } +        } +    } +private: +    void read_item(json_visitor2& visitor, std::error_code& ec) +    { +        read_tags(ec); +        if (!more_) +        { +            return; +        } +        auto c = source_.peek(); +        if (c.eof) +        { +            ec = cbor_errc::unexpected_eof; +            more_ = false; +            return; +        } +        jsoncons::cbor::detail::cbor_major_type major_type = get_major_type(c.value); +        uint8_t info = get_additional_information_value(c.value); + +        switch (major_type) +        { +            case jsoncons::cbor::detail::cbor_major_type::unsigned_integer: +            { +                uint64_t val = get_uint64_value(ec); +                if (ec) +                { +                    return; +                } +                if (!stringref_map_stack_.empty() && other_tags_[stringref_tag]) +                { +                    other_tags_[stringref_tag] = false; +                    if (val >= stringref_map_stack_.back().size()) +                    { +                        ec = cbor_errc::stringref_too_large; +                        more_ = false; +                        return; +                    } +                    stringref_map::size_type index = (stringref_map::size_type)val; +                    if (index != val) +                    { +                        ec = cbor_errc::number_too_large; +                        more_ = false; +                        return; +                    } +                    auto& str = stringref_map_stack_.back().at(index); +                    switch (str.type) +                    { +                        case jsoncons::cbor::detail::cbor_major_type::text_string: +                        { +                            handle_string(visitor, jsoncons::basic_string_view<char>(str.s.data(),str.s.length()),ec); +                            if (ec) +                            { +                                return; +                            } +                            break; +                        } +                        case jsoncons::cbor::detail::cbor_major_type::byte_string: +                        { +                            read_byte_string_from_buffer read(byte_string_view(str.bytes)); +                            write_byte_string(read, visitor, ec); +                            if (ec) +                            { +                                return; +                            } +                            break; +                        } +                        default: +                            JSONCONS_UNREACHABLE(); +                            break; +                    } +                } +                else +                { +                    semantic_tag tag = semantic_tag::none; +                    if (other_tags_[item_tag]) +                    { +                        if (item_tag_ == 1) +                        { +                            tag = semantic_tag::epoch_second; +                        } +                        other_tags_[item_tag] = false; +                    } +                    more_ = visitor.uint64_value(val, tag, *this, ec); +                } +                break; +            } +            case jsoncons::cbor::detail::cbor_major_type::negative_integer: +            { +                int64_t val = get_int64_value(ec); +                if (ec) +                { +                    return; +                } +                semantic_tag tag = semantic_tag::none; +                if (other_tags_[item_tag]) +                { +                    if (item_tag_ == 1) +                    { +                        tag = semantic_tag::epoch_second; +                    } +                    other_tags_[item_tag] = false; +                } +                more_ = visitor.int64_value(val, tag, *this, ec); +                break; +            } +            case jsoncons::cbor::detail::cbor_major_type::byte_string: +            { +                read_byte_string_from_source read(this); +                write_byte_string(read, visitor, ec); +                if (ec) +                { +                    return; +                } +                break; +            } +            case jsoncons::cbor::detail::cbor_major_type::text_string: +            { +                text_buffer_.clear(); +                read_text_string(text_buffer_, ec); +                if (ec) +                { +                    return; +                } +                auto result = unicode_traits::validate(text_buffer_.data(),text_buffer_.size()); +                if (result.ec != unicode_traits::conv_errc()) +                { +                    ec = cbor_errc::invalid_utf8_text_string; +                    more_ = false; +                    return; +                } +                handle_string(visitor, jsoncons::basic_string_view<char>(text_buffer_.data(),text_buffer_.length()),ec); +                if (ec) +                { +                    return; +                } +                break; +            } +            case jsoncons::cbor::detail::cbor_major_type::semantic_tag: +            { +                JSONCONS_UNREACHABLE(); +                break; +            } +            case jsoncons::cbor::detail::cbor_major_type::simple: +            { +                switch (info) +                { +                    case 0x14: +                        more_ = visitor.bool_value(false, semantic_tag::none, *this, ec); +                        source_.ignore(1); +                        break; +                    case 0x15: +                        more_ = visitor.bool_value(true, semantic_tag::none, *this, ec); +                        source_.ignore(1); +                        break; +                    case 0x16: +                        more_ = visitor.null_value(semantic_tag::none, *this, ec); +                        source_.ignore(1); +                        break; +                    case 0x17: +                        more_ = visitor.null_value(semantic_tag::undefined, *this, ec); +                        source_.ignore(1); +                        break; +                    case 0x19: // Half-Precision Float (two-byte IEEE 754) +                    { +                        uint64_t val = get_uint64_value(ec); +                        if (ec) +                        { +                            return; +                        } +                        more_ = visitor.half_value(static_cast<uint16_t>(val), semantic_tag::none, *this, ec); +                        break; +                    } +                    case 0x1a: // Single-Precision Float (four-byte IEEE 754) +                    case 0x1b: // Double-Precision Float (eight-byte IEEE 754) +                    { +                        double val = get_double(ec); +                        if (ec) +                        { +                            return; +                        } +                        semantic_tag tag = semantic_tag::none; +                        if (other_tags_[item_tag]) +                        { +                            if (item_tag_ == 1) +                            { +                                tag = semantic_tag::epoch_second; +                            } +                            other_tags_[item_tag] = false; +                        } +                        more_ = visitor.double_value(val, tag, *this, ec); +                        break; +                    } +                    default: +                    { +                        ec = cbor_errc::unknown_type; +                        more_ = false; +                        return; +                    } +                } +                break; +            } +            case jsoncons::cbor::detail::cbor_major_type::array: +            { +                if (other_tags_[item_tag]) +                { +                    switch (item_tag_) +                    { +                        case 0x04: +                            text_buffer_.clear(); +                            read_decimal_fraction(text_buffer_, ec); +                            if (ec) +                            { +                                return; +                            } +                            more_ = visitor.string_value(text_buffer_, semantic_tag::bigdec, *this, ec); +                            break; +                        case 0x05: +                            text_buffer_.clear(); +                            read_bigfloat(text_buffer_, ec); +                            if (ec) +                            { +                                return; +                            } +                            more_ = visitor.string_value(text_buffer_, semantic_tag::bigfloat, *this, ec); +                            break; +                        case 40: // row major storage +                            produce_begin_multi_dim(visitor, semantic_tag::multi_dim_row_major, ec); +                            break; +                        case 1040: // column major storage +                            produce_begin_multi_dim(visitor, semantic_tag::multi_dim_column_major, ec); +                            break; +                        default: +                            begin_array(visitor, info, ec); +                            break; +                    } +                    other_tags_[item_tag] = false; +                } +                else +                { +                    begin_array(visitor, info, ec); +                } +                break; +            } +            case jsoncons::cbor::detail::cbor_major_type::map: +            { +                begin_object(visitor, info, ec); +                break; +            } +            default: +                break; +        } +        other_tags_[item_tag] = false; +    } + +    void begin_array(json_visitor2& visitor, uint8_t info, std::error_code& ec) +    { +        if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) +        { +            ec = cbor_errc::max_nesting_depth_exceeded; +            more_ = false; +            return; +        }  +        semantic_tag tag = semantic_tag::none; +        bool pop_stringref_map_stack = false; +        if (other_tags_[stringref_namespace_tag]) +        { +            stringref_map_stack_.emplace_back(alloc_); +            other_tags_[stringref_namespace_tag] = false; +            pop_stringref_map_stack = true; +        } +        switch (info) +        { +            case jsoncons::cbor::detail::additional_info::indefinite_length: +            { +                state_stack_.emplace_back(parse_mode::indefinite_array,0,pop_stringref_map_stack); +                more_ = visitor.begin_array(tag, *this, ec); +                source_.ignore(1); +                break; +            } +            default: // definite length +            { +                std::size_t len = get_size(ec); +                if (!more_) +                { +                    return; +                } +                state_stack_.emplace_back(parse_mode::array,len,pop_stringref_map_stack); +                more_ = visitor.begin_array(len, tag, *this, ec); +                break; +            } +        } +    } + +    void end_array(json_visitor2& visitor, std::error_code& ec) +    { +        --nesting_depth_; + +        more_ = visitor.end_array(*this, ec); +        if (state_stack_.back().pop_stringref_map_stack) +        { +            stringref_map_stack_.pop_back(); +        } +        state_stack_.pop_back(); +    } + +    void begin_object(json_visitor2& visitor, uint8_t info, std::error_code& ec) +    { +        if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) +        { +            ec = cbor_errc::max_nesting_depth_exceeded; +            more_ = false; +            return; +        }  +        bool pop_stringref_map_stack = false; +        if (other_tags_[stringref_namespace_tag]) +        { +            stringref_map_stack_.emplace_back(alloc_); +            other_tags_[stringref_namespace_tag] = false; +            pop_stringref_map_stack = true; +        } +        switch (info) +        { +            case jsoncons::cbor::detail::additional_info::indefinite_length:  +            { +                state_stack_.emplace_back(parse_mode::indefinite_map_key,0,pop_stringref_map_stack); +                more_ = visitor.begin_object(semantic_tag::none, *this, ec); +                source_.ignore(1); +                break; +            } +            default: // definite_length +            { +                std::size_t len = get_size(ec); +                if (!more_) +                { +                    return; +                } +                state_stack_.emplace_back(parse_mode::map_key,len,pop_stringref_map_stack); +                more_ = visitor.begin_object(len, semantic_tag::none, *this, ec); +                break; +            } +        } +    } + +    void end_object(json_visitor2& visitor, std::error_code& ec) +    { +        --nesting_depth_; +        more_ = visitor.end_object(*this, ec); +        if (state_stack_.back().pop_stringref_map_stack) +        { +            stringref_map_stack_.pop_back(); +        } +        state_stack_.pop_back(); +    } + +    void read_text_string(string_type& s, std::error_code& ec) +    { +        auto c = source_.peek(); +        if (c.eof) +        { +            ec = cbor_errc::unexpected_eof; +            more_ = false; +            return; +        } +        jsoncons::cbor::detail::cbor_major_type major_type = get_major_type(c.value); +        uint8_t info = get_additional_information_value(c.value); + +        JSONCONS_ASSERT(major_type == jsoncons::cbor::detail::cbor_major_type::text_string); +        auto func = [&s](Source& source, std::size_t length, std::error_code& ec) -> bool +        { +            if (source_reader<Source>::read(source, s, length) != length) +            { +                ec = cbor_errc::unexpected_eof; +                return false; +            } +            return true; +        }; +        iterate_string_chunks(func, major_type, ec); +        if (!stringref_map_stack_.empty() &&  +            info != jsoncons::cbor::detail::additional_info::indefinite_length && +            s.length() >= jsoncons::cbor::detail::min_length_for_stringref(stringref_map_stack_.back().size())) +        { +            stringref_map_stack_.back().emplace_back(s); +        } +    } + +    std::size_t get_size(std::error_code& ec) +    { +        uint64_t u = get_uint64_value(ec); +        if (!more_) +        { +            return 0; +        } +        std::size_t len = static_cast<std::size_t>(u); +        if (len != u) +        { +            ec = cbor_errc::number_too_large; +            more_ = false; +        } +        return len; +    } + +    bool read_byte_string(std::vector<uint8_t,byte_allocator_type>& v, std::error_code& ec) +    { +        bool more = true; +        v.clear(); +        auto c = source_.peek(); +        if (c.eof) +        { +            ec = cbor_errc::unexpected_eof; +            more = false; +            return more; +        } +        jsoncons::cbor::detail::cbor_major_type major_type = get_major_type(c.value); +        uint8_t info = get_additional_information_value(c.value); + +        JSONCONS_ASSERT(major_type == jsoncons::cbor::detail::cbor_major_type::byte_string); + +        switch(info) +        { +            case jsoncons::cbor::detail::additional_info::indefinite_length: +            { +                auto func = [&v,&more](Source& source, std::size_t length, std::error_code& ec) -> bool +                { +                    if (source_reader<Source>::read(source, v, length) != length) +                    { +                        ec = cbor_errc::unexpected_eof; +                        more = false; +                        return more; +                    } +                    return true; +                }; +                iterate_string_chunks(func, major_type, ec); +                break; +            } +            default: +            { +                std::size_t length = get_size(ec); +                if (ec) +                { +                    more = false; +                    return more; +                } +                if (source_reader<Source>::read(source_, v, length) != length) +                { +                    ec = cbor_errc::unexpected_eof; +                    more = false; +                    return more; +                } +                if (!stringref_map_stack_.empty() && +                    v.size() >= jsoncons::cbor::detail::min_length_for_stringref(stringref_map_stack_.back().size())) +                { +                    stringref_map_stack_.back().emplace_back(v); +                } +                break; +            } +        } +        return more; +    } + +    template <class Function> +    void iterate_string_chunks(Function& func, jsoncons::cbor::detail::cbor_major_type type, std::error_code& ec) +    { +        int nesting_level = 0; + +        bool done = false; +        while (!done) +        { +            auto c = source_.peek(); +            if (c.eof) +            { +                ec = cbor_errc::unexpected_eof; +                more_ = false; +                return; +            } +            if (nesting_level > 0 && c.value == 0xff) +            { +                --nesting_level; +                if (nesting_level == 0) +                { +                    done = true; +                } +                source_.ignore(1); +                continue; +            } + +            jsoncons::cbor::detail::cbor_major_type major_type = get_major_type(c.value); +            if (major_type != type) +            { +                ec = cbor_errc::illegal_chunked_string; +                more_ = false; +                return; +            } +            uint8_t info = get_additional_information_value(c.value); + +            switch (info) +            { +                case jsoncons::cbor::detail::additional_info::indefinite_length: +                { +                    ++nesting_level; +                    source_.ignore(1); +                    break; +                } +                default: // definite length +                { +                    std::size_t length = get_size(ec); +                    if (!more_) +                    { +                        return; +                    } +                    more_ = func(source_, length, ec); +                    if (!more_) +                    { +                        return; +                    } +                    if (nesting_level == 0) +                    { +                        done = true; +                    } +                    break; +                } +            } +        }  +    } + +    uint64_t get_uint64_value(std::error_code& ec) +    { +        uint64_t val = 0; + +        uint8_t initial_b; +        if (source_.read(&initial_b, 1) == 0) +        { +            ec = cbor_errc::unexpected_eof; +            more_ = false; +            return 0; +        } +        uint8_t info = get_additional_information_value(initial_b); +        switch (info) +        { +            case JSONCONS_CBOR_0x00_0x17: // Integer 0x00..0x17 (0..23) +            { +                val = info; +                break; +            } + +            case 0x18: // Unsigned integer (one-byte uint8_t follows) +            { +                uint8_t b; +                if (source_.read(&b, 1) == 0) +                { +                    ec = cbor_errc::unexpected_eof; +                    more_ = false; +                    return val; +                } +                val = b; +                break; +            } + +            case 0x19: // Unsigned integer (two-byte uint16_t follows) +            { +                uint8_t buf[sizeof(uint16_t)]; +                source_.read(buf, sizeof(uint16_t)); +                val = binary::big_to_native<uint16_t>(buf, sizeof(buf)); +                break; +            } + +            case 0x1a: // Unsigned integer (four-byte uint32_t follows) +            { +                uint8_t buf[sizeof(uint32_t)]; +                source_.read(buf, sizeof(uint32_t)); +                val = binary::big_to_native<uint32_t>(buf, sizeof(buf)); +                break; +            } + +            case 0x1b: // Unsigned integer (eight-byte uint64_t follows) +            { +                uint8_t buf[sizeof(uint64_t)]; +                source_.read(buf, sizeof(uint64_t)); +                val = binary::big_to_native<uint64_t>(buf, sizeof(buf)); +                break; +            } +            default: +                break; +        } +        return val; +    } + +    int64_t get_int64_value(std::error_code& ec) +    { +        int64_t val = 0; + +        auto ch = source_.peek(); +        if (ch.eof) +        { +            ec = cbor_errc::unexpected_eof; +            more_ = false; +            return val; +        } + +        jsoncons::cbor::detail::cbor_major_type major_type = get_major_type(ch.value); +        uint8_t info = get_additional_information_value(ch.value); +        switch (major_type) +        { +            case jsoncons::cbor::detail::cbor_major_type::negative_integer: +                source_.ignore(1); +                switch (info) +                { +                    case JSONCONS_CBOR_0x00_0x17: // 0x00..0x17 (0..23) +                    { +                        val = static_cast<int8_t>(- 1 - info); +                        break; +                    } +                    case 0x18: // Negative integer (one-byte uint8_t follows) +                        { +                            uint8_t b; +                            if (source_.read(&b, 1) == 0) +                            { +                                ec = cbor_errc::unexpected_eof; +                                more_ = false; +                                return val; +                            } +                            val = static_cast<int64_t>(-1) - static_cast<int64_t>(b); +                            break; +                        } + +                    case 0x19: // Negative integer -1-n (two-byte uint16_t follows) +                        { +                            uint8_t buf[sizeof(uint16_t)]; +                            if (source_.read(buf, sizeof(uint16_t)) != sizeof(uint16_t)) +                            { +                                ec = cbor_errc::unexpected_eof; +                                more_ = false; +                                return val; +                            } +                            auto x = binary::big_to_native<uint16_t>(buf, sizeof(buf)); +                            val = static_cast<int64_t>(-1)- x; +                            break; +                        } + +                    case 0x1a: // Negative integer -1-n (four-byte uint32_t follows) +                        { +                            uint8_t buf[sizeof(uint32_t)]; +                            if (source_.read(buf, sizeof(uint32_t)) != sizeof(uint32_t)) +                            { +                                ec = cbor_errc::unexpected_eof; +                                more_ = false; +                                return val; +                            } +                            auto x = binary::big_to_native<uint32_t>(buf, sizeof(buf)); +                            val = static_cast<int64_t>(-1)- x; +                            break; +                        } + +                    case 0x1b: // Negative integer -1-n (eight-byte uint64_t follows) +                        { +                            uint8_t buf[sizeof(uint64_t)]; +                            if (source_.read(buf, sizeof(uint64_t)) != sizeof(uint64_t)) +                            { +                                ec = cbor_errc::unexpected_eof; +                                more_ = false; +                                return val; +                            } +                            auto x = binary::big_to_native<uint64_t>(buf, sizeof(buf)); +                            val = static_cast<int64_t>(-1)- static_cast<int64_t>(x); +                            break; +                        } +                } +                break; + +                case jsoncons::cbor::detail::cbor_major_type::unsigned_integer: +                { +                    uint64_t x = get_uint64_value(ec); +                    if (ec) +                    { +                        return 0; +                    } +                    if (x <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)())) +                    { +                        val = x; +                    } +                    else +                    { +                        // error; +                    } +                     +                    break; +                } +                break; +            default: +                break; +        } + +        return val; +    } + +    double get_double(std::error_code& ec) +    { +        double val = 0; + +        uint8_t b; +        if (source_.read(&b, 1) == 0) +        { +            ec = cbor_errc::unexpected_eof; +            more_ = false; +            return 0; +        } +        uint8_t info = get_additional_information_value(b); +        switch (info) +        { +        case 0x1a: // Single-Precision Float (four-byte IEEE 754) +            { +                uint8_t buf[sizeof(float)]; +                if (source_.read(buf, sizeof(float)) !=sizeof(float))  +                { +                    ec = cbor_errc::unexpected_eof; +                    more_ = false; +                    return 0; +                } +                val = binary::big_to_native<float>(buf, sizeof(buf)); +                break; +            } + +        case 0x1b: //  Double-Precision Float (eight-byte IEEE 754) +            { +                uint8_t buf[sizeof(double)]; +                if (source_.read(buf, sizeof(double)) != sizeof(double)) +                { +                    ec = cbor_errc::unexpected_eof; +                    more_ = false; +                    return 0; +                } +                val = binary::big_to_native<double>(buf, sizeof(buf)); +                break; +            } +            default: +                break; +        } +         +        return val; +    } + +    void read_decimal_fraction(string_type& result, std::error_code& ec) +    { +        std::size_t size = get_size(ec); +        if (!more_) +        { +            return; +        } +        if (size != 2) +        { +            ec = cbor_errc::invalid_decimal_fraction; +            more_ = false; +            return; +        } + +        auto c = source_.peek(); +        if (c.eof) +        { +            ec = cbor_errc::unexpected_eof; +            more_ = false; +            return; +        } +        int64_t exponent = 0; +        switch (get_major_type(c.value)) +        { +            case jsoncons::cbor::detail::cbor_major_type::unsigned_integer: +            { +                exponent = get_uint64_value(ec); +                if (ec) +                { +                    return; +                } +                break; +            } +            case jsoncons::cbor::detail::cbor_major_type::negative_integer: +            { +                exponent = get_int64_value(ec); +                if (ec) +                { +                    return; +                } +                break; +            } +            default: +            { +                ec = cbor_errc::invalid_decimal_fraction; +                more_ = false; +                return; +            } +        } + +        string_type s; + +        c = source_.peek(); +        if (c.eof) +        { +            ec = cbor_errc::unexpected_eof; +            more_ = false; +            return; +        } + +        switch (get_major_type(c.value)) +        { +            case jsoncons::cbor::detail::cbor_major_type::unsigned_integer: +            { +                uint64_t val = get_uint64_value(ec); +                if (ec) +                { +                    return; +                } +                jsoncons::detail::from_integer(val, s); +                break; +            } +            case jsoncons::cbor::detail::cbor_major_type::negative_integer: +            { +                int64_t val = get_int64_value(ec); +                if (ec) +                { +                    return; +                } +                jsoncons::detail::from_integer(val, s); +                break; +            } +            case jsoncons::cbor::detail::cbor_major_type::semantic_tag: +            { +                uint8_t b; +                if (source_.read(&b, 1) == 0) +                { +                    ec = cbor_errc::unexpected_eof; +                    more_ = false; +                    return; +                } +                uint8_t tag = get_additional_information_value(b); +                c = source_.peek(); +                if (c.eof) +                { +                    ec = cbor_errc::unexpected_eof; +                    more_ = false; +                    return; +                } + +                if (get_major_type(c.value) == jsoncons::cbor::detail::cbor_major_type::byte_string) +                { +                    bytes_buffer_.clear(); +                    read_byte_string(bytes_buffer_, ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    if (tag == 2) +                    { +                        bigint n = bigint::from_bytes_be(1, bytes_buffer_.data(), bytes_buffer_.size()); +                        n.write_string(s); +                    } +                    else if (tag == 3) +                    { +                        bigint n = bigint::from_bytes_be(1, bytes_buffer_.data(), bytes_buffer_.size()); +                        n = -1 - n; +                        n.write_string(s); +                    } +                } +                break; +            } +            default: +            { +                ec = cbor_errc::invalid_decimal_fraction; +                more_ = false; +                return; +            } +        } + +        if (s.size() >= static_cast<std::size_t>((std::numeric_limits<int32_t>::max)()) ||  +            exponent >= (std::numeric_limits<int32_t>::max)() ||  +            exponent <= (std::numeric_limits<int32_t>::min)()) +        { +            ec = cbor_errc::invalid_decimal_fraction; +            more_ = false; +            return; +        } +        else if (s.size() > 0) +        { +            if (s[0] == '-') +            { +                result.push_back('-'); +                jsoncons::detail::prettify_string(s.c_str()+1, s.size()-1, (int)exponent, -4, 17, result); +            } +            else +            { +                jsoncons::detail::prettify_string(s.c_str(), s.size(), (int)exponent, -4, 17, result); +            } +        } +        else +        { +            ec = cbor_errc::invalid_decimal_fraction; +            more_ = false; +            return; +        } +    } + +    void read_bigfloat(string_type& s, std::error_code& ec) +    { +        std::size_t size = get_size(ec); +        if (!more_) +        { +            return; +        } +        if (size != 2) +        { +            ec = cbor_errc::invalid_bigfloat; +            more_ = false; +            return; +        } + +        auto c = source_.peek(); +        if (c.eof) +        { +            ec = cbor_errc::unexpected_eof; +            more_ = false; +            return; +        } +        int64_t exponent = 0; +        switch (get_major_type(c.value)) +        { +            case jsoncons::cbor::detail::cbor_major_type::unsigned_integer: +            { +                exponent = get_uint64_value(ec); +                if (ec) +                { +                    return; +                } +                break; +            } +            case jsoncons::cbor::detail::cbor_major_type::negative_integer: +            { +                exponent = get_int64_value(ec); +                if (ec) +                { +                    return; +                } +                break; +            } +            default: +            { +                ec = cbor_errc::invalid_bigfloat; +                more_ = false; +                return; +            } +        } + +        c = source_.peek(); +        if (c.eof) +        { +            ec = cbor_errc::unexpected_eof; +            more_ = false; +            return; +        } +        switch (get_major_type(c.value)) +        { +            case jsoncons::cbor::detail::cbor_major_type::unsigned_integer: +            { +                uint64_t val = get_uint64_value(ec); +                if (ec) +                { +                    return; +                } +                s.push_back('0'); +                s.push_back('x'); +                jsoncons::detail::integer_to_string_hex(val, s); +                break; +            } +            case jsoncons::cbor::detail::cbor_major_type::negative_integer: +            { +                int64_t val = get_int64_value(ec); +                if (ec) +                { +                    return; +                } +                s.push_back('-'); +                s.push_back('0'); +                s.push_back('x'); +                jsoncons::detail::integer_to_string_hex(static_cast<uint64_t>(-val), s); +                break; +            } +            case jsoncons::cbor::detail::cbor_major_type::semantic_tag: +            { +                uint8_t b; +                if (source_.read(&b, 1) == 0) +                { +                    ec = cbor_errc::unexpected_eof; +                    more_ = false; +                    return; +                } +                uint8_t tag = get_additional_information_value(b); + +                c = source_.peek(); +                if (c.eof) +                { +                    ec = cbor_errc::unexpected_eof; +                    more_ = false; +                    return; +                } + +                if (get_major_type(c.value) == jsoncons::cbor::detail::cbor_major_type::byte_string) +                { +                    bytes_buffer_.clear();  +                    more_ = read_byte_string(bytes_buffer_, ec); +                    if (!more_) +                    { +                        return; +                    } +                    if (tag == 2) +                    { +                        s.push_back('0'); +                        s.push_back('x'); +                        bigint n = bigint::from_bytes_be(1, bytes_buffer_.data(), bytes_buffer_.size()); +                        n.write_string_hex(s); +                    } +                    else if (tag == 3) +                    { +                        s.push_back('-'); +                        s.push_back('0'); +                        bigint n = bigint::from_bytes_be(1, bytes_buffer_.data(), bytes_buffer_.size()); +                        n = -1 - n; +                        n.write_string_hex(s); +                        s[2] = 'x'; // overwrite minus +                    } +                } +                break; +            } +            default: +            { +                ec = cbor_errc::invalid_bigfloat; +                more_ = false; +                return; +            } +        } + +        s.push_back('p'); +        if (exponent >=0) +        { +            jsoncons::detail::integer_to_string_hex(static_cast<uint64_t>(exponent), s); +        } +        else +        { +            s.push_back('-'); +            jsoncons::detail::integer_to_string_hex(static_cast<uint64_t>(-exponent), s); +        } +    } + +    static jsoncons::cbor::detail::cbor_major_type get_major_type(uint8_t type) +    { +        static constexpr uint8_t major_type_shift = 0x05; +        uint8_t value = type >> major_type_shift; +        return static_cast<jsoncons::cbor::detail::cbor_major_type>(value); +    } + +    static uint8_t get_additional_information_value(uint8_t type) +    { +        static constexpr uint8_t additional_information_mask = (1U << 5) - 1; +        uint8_t value = type & additional_information_mask; +        return value; +    } + +    void read_tags(std::error_code& ec) +    { +        auto c = source_.peek(); +        if (c.eof) +        { +            ec = cbor_errc::unexpected_eof; +            more_ = false; +            return; +        } +        jsoncons::cbor::detail::cbor_major_type major_type = get_major_type(c.value); + +        while (major_type == jsoncons::cbor::detail::cbor_major_type::semantic_tag) +        { +            uint64_t val = get_uint64_value(ec); +            if (!more_) +            { +                return; +            } +            switch(val) +            { +                case 25: // stringref +                    other_tags_[stringref_tag] = true; +                    break; +                case 256: // stringref-namespace +                    other_tags_[stringref_namespace_tag] = true; +                    break; +                default: +                    other_tags_[item_tag] = true; +                    item_tag_ = val; +                    break; +            } +            c = source_.peek(); +            if (c.eof) +            { +                ec = cbor_errc::unexpected_eof; +                more_ = false; +                return; +            } +            major_type = get_major_type(c.value); +        } +    } + +    void handle_string(json_visitor2& visitor, const jsoncons::basic_string_view<char>& v, std::error_code& ec) +    { +        semantic_tag tag = semantic_tag::none; +        if (other_tags_[item_tag]) +        { +            switch (item_tag_) +            { +                case 0: +                    tag = semantic_tag::datetime; +                    break; +                case 32: +                    tag = semantic_tag::uri; +                    break; +                case 33: +                    tag = semantic_tag::base64url; +                    break; +                case 34: +                    tag = semantic_tag::base64; +                    break; +                default: +                    break; +            } +            other_tags_[item_tag] = false; +        } +        more_ = visitor.string_value(v, tag, *this, ec); +    } + +    static jsoncons::endian get_typed_array_endianness(const uint8_t tag) +    { +        return ((tag & detail::cbor_array_tags_e_mask) >> detail::cbor_array_tags_e_shift) == 0 ? jsoncons::endian::big : jsoncons::endian::little;  +    } + +    static std::size_t get_typed_array_bytes_per_element(const uint8_t tag) +    { +        const uint8_t f = (tag & detail::cbor_array_tags_f_mask) >> detail::cbor_array_tags_f_shift;  +        const uint8_t ll = (tag & detail::cbor_array_tags_ll_mask) >> detail::cbor_array_tags_ll_shift;  + +        return std::size_t(1) << (f + ll);  +    } + +    template <typename Read> +    void write_byte_string(Read read, json_visitor2& visitor, std::error_code& ec) +    { +        if (other_tags_[item_tag]) +        { +            switch (item_tag_) +            { +                case 0x2: +                { +                    bytes_buffer_.clear(); +                    read(bytes_buffer_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    bigint n = bigint::from_bytes_be(1, bytes_buffer_.data(), bytes_buffer_.size()); +                    text_buffer_.clear(); +                    n.write_string(text_buffer_); +                    more_ = visitor.string_value(text_buffer_, semantic_tag::bigint, *this, ec); +                    break; +                } +                case 0x3: +                { +                    bytes_buffer_.clear(); +                    read(bytes_buffer_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    bigint n = bigint::from_bytes_be(1, bytes_buffer_.data(), bytes_buffer_.size()); +                    n = -1 - n; +                    text_buffer_.clear(); +                    n.write_string(text_buffer_); +                    more_ = visitor.string_value(text_buffer_, semantic_tag::bigint, *this, ec); +                    break; +                } +                case 0x15: +                { +                    read(bytes_buffer_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    more_ = visitor.byte_string_value(bytes_buffer_, semantic_tag::base64url, *this, ec); +                    break; +                } +                case 0x16: +                { +                    read(bytes_buffer_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    more_ = visitor.byte_string_value(bytes_buffer_, semantic_tag::base64, *this, ec); +                    break; +                } +                case 0x17: +                { +                    read(bytes_buffer_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    more_ = visitor.byte_string_value(bytes_buffer_, semantic_tag::base16, *this, ec); +                    break; +                } +                case 0x40: +                { +                    typed_array_.clear(); +                    read(typed_array_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    uint8_t* data = reinterpret_cast<uint8_t*>(typed_array_.data()); +                    std::size_t size = typed_array_.size(); +                    more_ = visitor.typed_array(jsoncons::span<const uint8_t>(data,size), semantic_tag::none, *this, ec); +                    break; +                } +                case 0x44: +                { +                    typed_array_.clear(); +                    read(typed_array_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    uint8_t* data = reinterpret_cast<uint8_t*>(typed_array_.data()); +                    std::size_t size = typed_array_.size(); +                    more_ = visitor.typed_array(jsoncons::span<const uint8_t>(data,size), semantic_tag::clamped, *this, ec); +                    break; +                } +                case 0x41: +                case 0x45: +                { +                    typed_array_.clear(); +                    read(typed_array_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    const uint8_t tag = (uint8_t)item_tag_; +                    jsoncons::endian e = get_typed_array_endianness(tag);  +                    const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag); + +                    uint16_t* data = reinterpret_cast<uint16_t*>(typed_array_.data()); +                    std::size_t size = typed_array_.size()/bytes_per_elem; + +                    if (e != jsoncons::endian::native) +                    { +                        for (std::size_t i = 0; i < size; ++i) +                        { +                            data[i] = binary::byte_swap<uint16_t>(data[i]); +                        } +                    } +                    more_ = visitor.typed_array(jsoncons::span<const uint16_t>(data,size), semantic_tag::none, *this, ec); +                    break; +                } +                case 0x42: +                case 0x46: +                { +                    typed_array_.clear(); +                    read(typed_array_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    const uint8_t tag = (uint8_t)item_tag_; +                    jsoncons::endian e = get_typed_array_endianness(tag); +                    const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag); + +                    uint32_t* data = reinterpret_cast<uint32_t*>(typed_array_.data()); +                    std::size_t size = typed_array_.size()/bytes_per_elem; +                    if (e != jsoncons::endian::native) +                    { +                        for (std::size_t i = 0; i < size; ++i) +                        { +                            data[i] = binary::byte_swap<uint32_t>(data[i]); +                        } +                    } +                    more_ = visitor.typed_array(jsoncons::span<const uint32_t>(data,size), semantic_tag::none, *this, ec); +                    break; +                } +                case 0x43: +                case 0x47: +                { +                    typed_array_.clear(); +                    read(typed_array_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    const uint8_t tag = (uint8_t)item_tag_; +                    jsoncons::endian e = get_typed_array_endianness(tag);  +                    const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag); + +                    uint64_t* data = reinterpret_cast<uint64_t*>(typed_array_.data()); +                    std::size_t size = typed_array_.size()/bytes_per_elem; +                    if (e != jsoncons::endian::native) +                    { +                        for (std::size_t i = 0; i < size; ++i) +                        { +                            data[i] = binary::byte_swap<uint64_t>(data[i]); +                        } +                    } +                    more_ = visitor.typed_array(jsoncons::span<const uint64_t>(data,size), semantic_tag::none, *this, ec); +                    break; +                } +                case 0x48: +                { +                    typed_array_.clear(); +                    read(typed_array_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    int8_t* data = reinterpret_cast<int8_t*>(typed_array_.data()); +                    std::size_t size = typed_array_.size(); +                    more_ = visitor.typed_array(jsoncons::span<const int8_t>(data,size), semantic_tag::none, *this, ec); +                    break; +                } +                case 0x49: +                case 0x4d: +                { +                    typed_array_.clear(); +                    read(typed_array_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    const uint8_t tag = (uint8_t)item_tag_; +                    jsoncons::endian e = get_typed_array_endianness(tag);  +                    const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag); + +                    int16_t* data = reinterpret_cast<int16_t*>(typed_array_.data()); +                    std::size_t size = typed_array_.size()/bytes_per_elem; +                    if (e != jsoncons::endian::native) +                    { +                        for (std::size_t i = 0; i < size; ++i) +                        { +                            data[i] = binary::byte_swap<int16_t>(data[i]); +                        } +                    } +                    more_ = visitor.typed_array(jsoncons::span<const int16_t>(data,size), semantic_tag::none, *this, ec); +                    break; +                } +                case 0x4a: +                case 0x4e: +                { +                    typed_array_.clear(); +                    read(typed_array_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    const uint8_t tag = (uint8_t)item_tag_; +                    jsoncons::endian e = get_typed_array_endianness(tag);  +                    const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag); + +                    int32_t* data = reinterpret_cast<int32_t*>(typed_array_.data()); +                    std::size_t size = typed_array_.size()/bytes_per_elem; +                    if (e != jsoncons::endian::native) +                    { +                        for (std::size_t i = 0; i < size; ++i) +                        { +                            data[i] = binary::byte_swap<int32_t>(data[i]); +                        } +                    } +                    more_ = visitor.typed_array(jsoncons::span<const int32_t>(data,size), semantic_tag::none, *this, ec); +                    break; +                } +                case 0x4b: +                case 0x4f: +                { +                    typed_array_.clear(); +                    read(typed_array_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    const uint8_t tag = (uint8_t)item_tag_; +                    jsoncons::endian e = get_typed_array_endianness(tag);  +                    const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag); + +                    int64_t* data = reinterpret_cast<int64_t*>(typed_array_.data()); +                    std::size_t size = typed_array_.size()/bytes_per_elem; +                    if (e != jsoncons::endian::native) +                    { +                        for (std::size_t i = 0; i < size; ++i) +                        { +                            data[i] = binary::byte_swap<int64_t>(data[i]); +                        } +                    } +                    more_ = visitor.typed_array(jsoncons::span<const int64_t>(data,size), semantic_tag::none, *this, ec); +                    break; +                } +                case 0x50: +                case 0x54: +                { +                    typed_array_.clear(); +                    read(typed_array_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    const uint8_t tag = (uint8_t)item_tag_; +                    jsoncons::endian e = get_typed_array_endianness(tag);  +                    const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag); + +                    uint16_t* data = reinterpret_cast<uint16_t*>(typed_array_.data()); +                    std::size_t size = typed_array_.size()/bytes_per_elem; +                    if (e != jsoncons::endian::native) +                    { +                        for (std::size_t i = 0; i < size; ++i) +                        { +                            data[i] = binary::byte_swap<uint16_t>(data[i]); +                        } +                    } +                    more_ = visitor.typed_array(half_arg, jsoncons::span<const uint16_t>(data,size), semantic_tag::none, *this, ec); +                    break; +                } +                case 0x51: +                case 0x55: +                { +                    typed_array_.clear(); +                    read(typed_array_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    const uint8_t tag = (uint8_t)item_tag_; +                    jsoncons::endian e = get_typed_array_endianness(tag);  +                    const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag); + +                    float* data = reinterpret_cast<float*>(typed_array_.data()); +                    std::size_t size = typed_array_.size()/bytes_per_elem; +                    if (e != jsoncons::endian::native) +                    { +                        for (std::size_t i = 0; i < size; ++i) +                        { +                            data[i] = binary::byte_swap<float>(data[i]); +                        } +                    } +                    more_ = visitor.typed_array(jsoncons::span<const float>(data,size), semantic_tag::none, *this, ec); +                    break; +                } +                case 0x52: +                case 0x56: +                { +                    typed_array_.clear(); +                    read(typed_array_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    const uint8_t tag = (uint8_t)item_tag_; +                    jsoncons::endian e = get_typed_array_endianness(tag);  +                    const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag); + +                    double* data = reinterpret_cast<double*>(typed_array_.data()); +                    std::size_t size = typed_array_.size()/bytes_per_elem; + +                    if (e != jsoncons::endian::native) +                    { +                        for (std::size_t i = 0; i < size; ++i) +                        { +                            data[i] = binary::byte_swap<double>(data[i]); +                        } +                    } +                    more_ = visitor.typed_array(jsoncons::span<const double>(data,size), semantic_tag::none, *this, ec); +                    break; +                } +                default: +                { +                    read(bytes_buffer_,ec); +                    if (ec) +                    { +                        more_ = false; +                        return; +                    } +                    more_ = visitor.byte_string_value(bytes_buffer_, item_tag_, *this, ec); +                    break; +                } +            } +            other_tags_[item_tag] = false; +        } +        else +        { +            read(bytes_buffer_,ec); +            if (ec) +            { +                return; +            } +            more_ = visitor.byte_string_value(bytes_buffer_, semantic_tag::none, *this, ec); +        } +    } + +    void produce_begin_multi_dim(json_visitor2& visitor,  +                                 semantic_tag tag, +                                 std::error_code& ec) +    { +        uint8_t b; +        if (source_.read(&b, 1) == 0) +        { +            ec = cbor_errc::unexpected_eof; +            more_ = false; +            return; +        } +        jsoncons::cbor::detail::cbor_major_type major_type = get_major_type(b); +        JSONCONS_ASSERT(major_type == jsoncons::cbor::detail::cbor_major_type::array); +        uint8_t info = get_additional_information_value(b); +        +        read_shape(info, ec);    +        if (ec) +        { +            return; +        } + +        state_stack_.emplace_back(parse_mode::multi_dim, 0); +        more_ = visitor.begin_multi_dim(shape_, tag, *this, ec); +    } + +    void produce_end_multi_dim(json_visitor2& visitor, std::error_code& ec) +    { +        more_ = visitor.end_multi_dim(*this, ec); +        state_stack_.pop_back(); +    } + +    void read_shape(uint8_t info, std::error_code& ec) +    { +        shape_.clear(); +        switch (info) +        { +            case jsoncons::cbor::detail::additional_info::indefinite_length: +            { +                while (true) +                { +                    auto c = source_.peek(); +                    if (c.eof) +                    { +                        ec = cbor_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } +                    if (c.value == 0xff) +                    { +                        source_.ignore(1); +                    } +                    else +                    { +                        std::size_t dim = get_size(ec); +                        if (!more_) +                        { +                            return; +                        } +                        shape_.push_back(dim); +                    } +                } +                break; +            } +            default: +            { +                std::size_t size = get_size(ec); +                if (!more_) +                { +                    return; +                } +                for (std::size_t i = 0; more_ && i < size; ++i) +                { +                    std::size_t dim = get_size(ec); +                    if (!more_) +                    { +                        return; +                    } +                    shape_.push_back(dim); +                } +                break; +            } +        } +    } +}; + +}} + +#endif diff --git a/include/jsoncons_ext/cbor/cbor_reader.hpp b/include/jsoncons_ext/cbor/cbor_reader.hpp new file mode 100644 index 0000000..a46a52e --- /dev/null +++ b/include/jsoncons_ext/cbor/cbor_reader.hpp @@ -0,0 +1,116 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_CBOR_READER_HPP +#define JSONCONS_CBOR_CBOR_READER_HPP + +#include <string> +#include <vector> +#include <memory> +#include <utility> // std::move +#include <jsoncons/json.hpp> +#include <jsoncons/source.hpp> +#include <jsoncons/config/jsoncons_config.hpp> +#include <jsoncons_ext/cbor/cbor_encoder.hpp> +#include <jsoncons_ext/cbor/cbor_error.hpp> +#include <jsoncons_ext/cbor/cbor_detail.hpp> +#include <jsoncons_ext/cbor/cbor_parser.hpp> + +namespace jsoncons { namespace cbor { + +template <class Source,class Allocator=std::allocator<char>> +class basic_cbor_reader  +{ +    using char_type = char; + +    basic_cbor_parser<Source,Allocator> parser_; +    basic_json_visitor2_to_visitor_adaptor<char_type,Allocator> adaptor_; +    json_visitor2& visitor_; +public: +    template <class Sourceable> +    basic_cbor_reader(Sourceable&& source,  +                      json_visitor& visitor,  +                      const Allocator alloc) +       : basic_cbor_reader(std::forward<Sourceable>(source), +                           visitor, +                           cbor_decode_options(), +                           alloc) +    { +    } + +    template <class Sourceable> +    basic_cbor_reader(Sourceable&& source,  +                      json_visitor& visitor,  +                      const cbor_decode_options& options = cbor_decode_options(), +                      const Allocator alloc=Allocator()) +       : parser_(std::forward<Sourceable>(source), options, alloc), +         adaptor_(visitor, alloc), visitor_(adaptor_) +    { +    } +    template <class Sourceable> +    basic_cbor_reader(Sourceable&& source,  +                      json_visitor2& visitor,  +                      const Allocator alloc) +       : basic_cbor_reader(std::forward<Sourceable>(source), +                           visitor, +                           cbor_decode_options(), +                           alloc) +    { +    } + +    template <class Sourceable> +    basic_cbor_reader(Sourceable&& source,  +                      json_visitor2& visitor,  +                      const cbor_decode_options& options = cbor_decode_options(), +                      const Allocator alloc=Allocator()) +       : parser_(std::forward<Sourceable>(source), options, alloc), +         visitor_(visitor) +    { +    } + +    void read() +    { +        std::error_code ec; +        read(ec); +        if (ec) +        { +            JSONCONS_THROW(ser_error(ec,line(),column())); +        } +    } + +    void read(std::error_code& ec) +    { +        parser_.reset(); +        parser_.parse(visitor_, ec); +        if (ec) +        { +            return; +        } +    } + +    std::size_t line() const +    { +        return parser_.line(); +    } + +    std::size_t column() const +    { +        return parser_.column(); +    } +}; + +using cbor_stream_reader = basic_cbor_reader<jsoncons::binary_stream_source>; + +using cbor_bytes_reader = basic_cbor_reader<jsoncons::bytes_source>; + +#if !defined(JSONCONS_NO_DEPRECATED) +JSONCONS_DEPRECATED_MSG("Instead, use cbor_stream_reader") typedef cbor_stream_reader cbor_reader; +JSONCONS_DEPRECATED_MSG("Instead, use cbor_bytes_reader") typedef cbor_bytes_reader cbor_buffer_reader; +#endif + +}} + +#endif diff --git a/include/jsoncons_ext/cbor/decode_cbor.hpp b/include/jsoncons_ext/cbor/decode_cbor.hpp new file mode 100644 index 0000000..ab5c913 --- /dev/null +++ b/include/jsoncons_ext/cbor/decode_cbor.hpp @@ -0,0 +1,203 @@ +// Copyright 2017 Daniel Parkerstd +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_DECODE_CBOR_HPP +#define JSONCONS_CBOR_DECODE_CBOR_HPP + +#include <string> +#include <vector> +#include <memory> +#include <type_traits> // std::enable_if +#include <istream> // std::basic_istream +#include <jsoncons/json.hpp> +#include <jsoncons/json_filter.hpp> +#include <jsoncons/decode_traits.hpp> +#include <jsoncons/config/jsoncons_config.hpp> +#include <jsoncons_ext/cbor/cbor_reader.hpp> +#include <jsoncons_ext/cbor/cbor_cursor.hpp> + +namespace jsoncons {  +namespace cbor { + +    template<class T, class Source> +    typename std::enable_if<type_traits::is_basic_json<T>::value && +                            type_traits::is_byte_sequence<Source>::value,T>::type  +    decode_cbor(const Source& v,  +                const cbor_decode_options& options = cbor_decode_options()) +    { +        jsoncons::json_decoder<T> decoder; +        auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); +        basic_cbor_reader<jsoncons::bytes_source> reader(v, adaptor, options); +        reader.read(); +        if (!decoder.is_valid()) +        { +            JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column())); +        } +        return decoder.get_result(); +    } + +    template<class T, class Source> +    typename std::enable_if<!type_traits::is_basic_json<T>::value && +                            type_traits::is_byte_sequence<Source>::value,T>::type  +    decode_cbor(const Source& v,  +                const cbor_decode_options& options = cbor_decode_options()) +    { +        basic_cbor_cursor<bytes_source> cursor(v, options); +        json_decoder<basic_json<char,sorted_policy>> decoder{}; + +        std::error_code ec; +        T val = decode_traits<T,char>::decode(cursor, decoder, ec); +        if (ec) +        { +            JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column())); +        } +        return val; +    } + +    template<class T> +    typename std::enable_if<type_traits::is_basic_json<T>::value,T>::type  +    decode_cbor(std::istream& is,  +                const cbor_decode_options& options = cbor_decode_options()) +    { +        jsoncons::json_decoder<T> decoder; +        auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); +        cbor_stream_reader reader(is, adaptor, options); +        reader.read(); +        if (!decoder.is_valid()) +        { +            JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column())); +        } +        return decoder.get_result(); +    } +      +    template<class T> +    typename std::enable_if<!type_traits::is_basic_json<T>::value,T>::type  +    decode_cbor(std::istream& is,  +                const cbor_decode_options& options = cbor_decode_options()) +    { +        basic_cbor_cursor<binary_stream_source> cursor(is, options); +        json_decoder<basic_json<char,sorted_policy>> decoder{}; + +        std::error_code ec; +        T val = decode_traits<T,char>::decode(cursor, decoder, ec); +        if (ec) +        { +            JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column())); +        } +        return val; +    } + +    template<class T, class InputIt> +    typename std::enable_if<type_traits::is_basic_json<T>::value,T>::type  +    decode_cbor(InputIt first, InputIt last, +                const cbor_decode_options& options = cbor_decode_options()) +    { +        jsoncons::json_decoder<T> decoder; +        auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); +        basic_cbor_reader<binary_iterator_source<InputIt>> reader(binary_iterator_source<InputIt>(first, last), adaptor, options); +        reader.read(); +        if (!decoder.is_valid()) +        { +            JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column())); +        } +        return decoder.get_result(); +    } + +    template<class T, class InputIt> +    typename std::enable_if<!type_traits::is_basic_json<T>::value,T>::type  +    decode_cbor(InputIt first, InputIt last, +                const cbor_decode_options& options = cbor_decode_options()) +    { +        basic_cbor_cursor<binary_iterator_source<InputIt>> cursor(binary_iterator_source<InputIt>(first, last), options); +        json_decoder<basic_json<char,sorted_policy>> decoder{}; + +        std::error_code ec; +        T val = decode_traits<T,char>::decode(cursor, decoder, ec); +        if (ec) +        { +            JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column())); +        } +        return val; +    } + +    // With leading allocator parameter + +    template<class T, class Source, class TempAllocator> +    typename std::enable_if<type_traits::is_basic_json<T>::value && +                            type_traits::is_byte_sequence<Source>::value,T>::type  +    decode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                const Source& v,  +                const cbor_decode_options& options = cbor_decode_options()) +    { +        json_decoder<T,TempAllocator> decoder(temp_alloc); +        auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); +        basic_cbor_reader<jsoncons::bytes_source,TempAllocator> reader(v, adaptor, options, temp_alloc); +        reader.read(); +        if (!decoder.is_valid()) +        { +            JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column())); +        } +        return decoder.get_result(); +    } + +    template<class T, class Source, class TempAllocator> +    typename std::enable_if<!type_traits::is_basic_json<T>::value && +                            type_traits::is_byte_sequence<Source>::value,T>::type  +    decode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                const Source& v,  +                const cbor_decode_options& options = cbor_decode_options()) +    { +        basic_cbor_cursor<bytes_source,TempAllocator> cursor(v, options, temp_alloc); +        json_decoder<basic_json<char,sorted_policy,TempAllocator>,TempAllocator> decoder(temp_alloc, temp_alloc); + +        std::error_code ec; +        T val = decode_traits<T,char>::decode(cursor, decoder, ec); +        if (ec) +        { +            JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column())); +        } +        return val; +    } + +    template<class T,class TempAllocator> +    typename std::enable_if<type_traits::is_basic_json<T>::value,T>::type  +    decode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                std::istream& is,  +                const cbor_decode_options& options = cbor_decode_options()) +    { +        json_decoder<T,TempAllocator> decoder(temp_alloc); +        auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); +        basic_cbor_reader<jsoncons::binary_stream_source,TempAllocator> reader(is, adaptor, options, temp_alloc); +        reader.read(); +        if (!decoder.is_valid()) +        { +            JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column())); +        } +        return decoder.get_result(); +    } + +    template<class T,class TempAllocator> +    typename std::enable_if<!type_traits::is_basic_json<T>::value,T>::type  +    decode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                std::istream& is,  +                const cbor_decode_options& options = cbor_decode_options()) +    { +        basic_cbor_cursor<binary_stream_source,TempAllocator> cursor(is, options, temp_alloc); +        json_decoder<basic_json<char,sorted_policy,TempAllocator>,TempAllocator> decoder(temp_alloc, temp_alloc); + +        std::error_code ec; +        T val = decode_traits<T,char>::decode(cursor, decoder, ec); +        if (ec) +        { +            JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column())); +        } +        return val; +    } + +} // namespace cbor +} // namespace jsoncons + +#endif diff --git a/include/jsoncons_ext/cbor/encode_cbor.hpp b/include/jsoncons_ext/cbor/encode_cbor.hpp new file mode 100644 index 0000000..8576f1c --- /dev/null +++ b/include/jsoncons_ext/cbor/encode_cbor.hpp @@ -0,0 +1,151 @@ +// Copyright 2017 Daniel Parkerstd +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_ENCODE_CBOR_HPP +#define JSONCONS_CBOR_ENCODE_CBOR_HPP + +#include <string> +#include <vector> +#include <memory> +#include <type_traits> // std::enable_if +#include <istream> // std::basic_istream +#include <jsoncons/json.hpp> +#include <jsoncons/json_filter.hpp> +#include <jsoncons/config/jsoncons_config.hpp> +#include <jsoncons/encode_traits.hpp> +#include <jsoncons_ext/cbor/cbor_encoder.hpp> + +namespace jsoncons {  +namespace cbor { + +    // to bytes  + +    template<class T, class Container> +    typename std::enable_if<type_traits::is_basic_json<T>::value && +                            type_traits::is_back_insertable_byte_container<Container>::value,void>::type  +    encode_cbor(const T& j,  +                Container& v,  +                const cbor_encode_options& options = cbor_encode_options()) +    { +        using char_type = typename T::char_type; +        basic_cbor_encoder<jsoncons::bytes_sink<Container>> encoder(v, options); +        auto adaptor = make_json_visitor_adaptor<basic_json_visitor<char_type>>(encoder); +        j.dump(adaptor); +    } + +    template<class T, class Container> +    typename std::enable_if<!type_traits::is_basic_json<T>::value && +                            type_traits::is_back_insertable_byte_container<Container>::value,void>::type  +    encode_cbor(const T& val, Container& v,  +                const cbor_encode_options& options = cbor_encode_options()) +    { +        basic_cbor_encoder<jsoncons::bytes_sink<Container>> encoder(v, options); +        std::error_code ec; +        encode_traits<T,char>::encode(val, encoder, json(), ec); +        if (ec) +        { +            JSONCONS_THROW(ser_error(ec)); +        } +    } + +    // stream + +    template<class T> +    typename std::enable_if<type_traits::is_basic_json<T>::value,void>::type  +    encode_cbor(const T& j,  +                std::ostream& os,  +                const cbor_encode_options& options = cbor_encode_options()) +    { +        using char_type = typename T::char_type; +        cbor_stream_encoder encoder(os, options); +        auto adaptor = make_json_visitor_adaptor<basic_json_visitor<char_type>>(encoder); +        j.dump(adaptor); +    } + +    template<class T> +    typename std::enable_if<!type_traits::is_basic_json<T>::value,void>::type  +    encode_cbor(const T& val,  +                std::ostream& os,  +                const cbor_encode_options& options = cbor_encode_options()) +    { +        cbor_stream_encoder encoder(os, options); +        std::error_code ec; +        encode_traits<T,char>::encode(val, encoder, json(), ec); +        if (ec) +        { +            JSONCONS_THROW(ser_error(ec)); +        } +    } + +    // temp_allocator_arg + +    // to bytes  + +    template<class T, class Container, class TempAllocator> +    typename std::enable_if<type_traits::is_basic_json<T>::value && +                            type_traits::is_back_insertable_byte_container<Container>::value,void>::type  +    encode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                const T& j,  +                Container& v,  +                const cbor_encode_options& options = cbor_encode_options()) +    { +        using char_type = typename T::char_type; +        basic_cbor_encoder<bytes_sink<Container>,TempAllocator> encoder(v, options, temp_alloc); +        auto adaptor = make_json_visitor_adaptor<basic_json_visitor<char_type>>(encoder); +        j.dump(adaptor); +    } + +    template<class T, class Container, class TempAllocator> +    typename std::enable_if<!type_traits::is_basic_json<T>::value && +                            type_traits::is_back_insertable_byte_container<Container>::value,void>::type  +    encode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                const T& val,  +                Container& v,  +                const cbor_encode_options& options = cbor_encode_options()) +    { +        basic_cbor_encoder<jsoncons::bytes_sink<Container>,TempAllocator> encoder(v, options, temp_alloc); +        std::error_code ec; +        encode_traits<T,char>::encode(val, encoder, json(), ec); +        if (ec) +        { +            JSONCONS_THROW(ser_error(ec)); +        } +    } + +    // stream + +    template<class T,class TempAllocator> +    typename std::enable_if<type_traits::is_basic_json<T>::value,void>::type  +    encode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                const T& j,  +                std::ostream& os,  +                const cbor_encode_options& options = cbor_encode_options()) +    { +        using char_type = typename T::char_type; +        basic_cbor_encoder<binary_stream_sink,TempAllocator> encoder(os, options, temp_alloc); +        auto adaptor = make_json_visitor_adaptor<basic_json_visitor<char_type>>(encoder); +        j.dump(adaptor); +    } + +    template<class T,class TempAllocator> +    typename std::enable_if<!type_traits::is_basic_json<T>::value,void>::type  +    encode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                const T& val,  +                std::ostream& os,  +                const cbor_encode_options& options = cbor_encode_options()) +    { +        std::error_code ec; +        encode_cbor(temp_allocator_arg, temp_alloc, val, os, options, ec); +        if (ec) +        { +            JSONCONS_THROW(ser_error(ec)); +        } +    } + +} // namespace cbor +} // namespace jsoncons + +#endif |