diff options
Diffstat (limited to 'include/jsoncons_ext/msgpack')
| -rw-r--r-- | include/jsoncons_ext/msgpack/decode_msgpack.hpp | 202 | ||||
| -rw-r--r-- | include/jsoncons_ext/msgpack/encode_msgpack.hpp | 142 | ||||
| -rw-r--r-- | include/jsoncons_ext/msgpack/msgpack.hpp | 24 | ||||
| -rw-r--r-- | include/jsoncons_ext/msgpack/msgpack_cursor.hpp | 343 | ||||
| -rw-r--r-- | include/jsoncons_ext/msgpack/msgpack_cursor2.hpp | 259 | ||||
| -rw-r--r-- | include/jsoncons_ext/msgpack/msgpack_encoder.hpp | 753 | ||||
| -rw-r--r-- | include/jsoncons_ext/msgpack/msgpack_error.hpp | 94 | ||||
| -rw-r--r-- | include/jsoncons_ext/msgpack/msgpack_options.hpp | 74 | ||||
| -rw-r--r-- | include/jsoncons_ext/msgpack/msgpack_parser.hpp | 748 | ||||
| -rw-r--r-- | include/jsoncons_ext/msgpack/msgpack_reader.hpp | 116 | ||||
| -rw-r--r-- | include/jsoncons_ext/msgpack/msgpack_type.hpp | 63 | 
11 files changed, 2818 insertions, 0 deletions
| diff --git a/include/jsoncons_ext/msgpack/decode_msgpack.hpp b/include/jsoncons_ext/msgpack/decode_msgpack.hpp new file mode 100644 index 0000000..614af3d --- /dev/null +++ b/include/jsoncons_ext/msgpack/decode_msgpack.hpp @@ -0,0 +1,202 @@ +// Copyright 2013 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_MSGPACK_DECODE_MSGPACK_HPP +#define JSONCONS_MSGPACK_DECODE_MSGPACK_HPP + +#include <string> +#include <vector> +#include <memory> +#include <type_traits> // std::enable_if +#include <istream> // std::basic_istream +#include <jsoncons/json.hpp> +#include <jsoncons/config/jsoncons_config.hpp> +#include <jsoncons_ext/msgpack/msgpack_encoder.hpp> +#include <jsoncons_ext/msgpack/msgpack_reader.hpp> +#include <jsoncons_ext/msgpack/msgpack_cursor.hpp> + +namespace jsoncons {  +namespace msgpack { + +    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_msgpack(const Source& v,  +                   const msgpack_decode_options& options = msgpack_decode_options()) +    { +        jsoncons::json_decoder<T> decoder; +        auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); +        basic_msgpack_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_msgpack(const Source& v,  +                   const msgpack_decode_options& options = msgpack_decode_options()) +    { +        basic_msgpack_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_msgpack(std::istream& is,  +                   const msgpack_decode_options& options = msgpack_decode_options()) +    { +        jsoncons::json_decoder<T> decoder; +        auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); +        msgpack_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_msgpack(std::istream& is,  +                   const msgpack_decode_options& options = msgpack_decode_options()) +    { +        basic_msgpack_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_msgpack(InputIt first, InputIt last, +                const msgpack_decode_options& options = msgpack_decode_options()) +    { +        jsoncons::json_decoder<T> decoder; +        auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); +        basic_msgpack_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_msgpack(InputIt first, InputIt last, +                const msgpack_decode_options& options = msgpack_decode_options()) +    { +        basic_msgpack_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_msgpack(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                   const Source& v,  +                   const msgpack_decode_options& options = msgpack_decode_options()) +    { +        json_decoder<T,TempAllocator> decoder(temp_alloc); +        auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); +        basic_msgpack_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_msgpack(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                   const Source& v,  +                   const msgpack_decode_options& options = msgpack_decode_options()) +    { +        basic_msgpack_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_msgpack(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                   std::istream& is,  +                   const msgpack_decode_options& options = msgpack_decode_options()) +    { +        json_decoder<T,TempAllocator> decoder(temp_alloc); +        auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); +        basic_msgpack_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_msgpack(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                   std::istream& is,  +                   const msgpack_decode_options& options = msgpack_decode_options()) +    { +        basic_msgpack_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; +    } + +} // msgpack +} // jsoncons + +#endif diff --git a/include/jsoncons_ext/msgpack/encode_msgpack.hpp b/include/jsoncons_ext/msgpack/encode_msgpack.hpp new file mode 100644 index 0000000..10a61e0 --- /dev/null +++ b/include/jsoncons_ext/msgpack/encode_msgpack.hpp @@ -0,0 +1,142 @@ +// Copyright 2013 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_MSGPACK_ENCODE_MSGPACK_HPP +#define JSONCONS_MSGPACK_ENCODE_MSGPACK_HPP + +#include <string> +#include <vector> +#include <memory> +#include <type_traits> // std::enable_if +#include <istream> // std::basic_istream +#include <jsoncons/json.hpp> +#include <jsoncons/config/jsoncons_config.hpp> +#include <jsoncons_ext/msgpack/msgpack_encoder.hpp> +#include <jsoncons_ext/msgpack/msgpack_reader.hpp> + +namespace jsoncons {  +namespace msgpack { + +    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_msgpack(const T& j,  +                   Container& v,  +                   const msgpack_encode_options& options = msgpack_encode_options()) +    { +        using char_type = typename T::char_type; +        basic_msgpack_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_msgpack(const T& val,  +                   Container& v,  +                   const msgpack_encode_options& options = msgpack_encode_options()) +    { +        basic_msgpack_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)); +        } +    } + +    template<class T> +    typename std::enable_if<type_traits::is_basic_json<T>::value,void>::type  +    encode_msgpack(const T& j,  +                   std::ostream& os,  +                   const msgpack_encode_options& options = msgpack_encode_options()) +    { +        using char_type = typename T::char_type; +        msgpack_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_msgpack(const T& val,  +                   std::ostream& os,  +                   const msgpack_encode_options& options = msgpack_encode_options()) +    { +        msgpack_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)); +        } +    } + +    // with temp_allocator_arg_t + +    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_msgpack(temp_allocator_arg_t, const TempAllocator& temp_alloc, const T& j,  +                   Container& v,  +                   const msgpack_encode_options& options = msgpack_encode_options()) +    { +        using char_type = typename T::char_type; +        basic_msgpack_encoder<jsoncons::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_msgpack(temp_allocator_arg_t, const TempAllocator& temp_alloc,  +                   const T& val, Container& v,  +                   const msgpack_encode_options& options = msgpack_encode_options()) +    { +        basic_msgpack_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)); +        } +    } + +    template<class T,class TempAllocator> +    typename std::enable_if<type_traits::is_basic_json<T>::value,void>::type  +    encode_msgpack(temp_allocator_arg_t, const TempAllocator& temp_alloc,  +                   const T& j,  +                   std::ostream& os,  +                   const msgpack_encode_options& options = msgpack_encode_options()) +    { +        using char_type = typename T::char_type; +        basic_msgpack_encoder<jsoncons::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_msgpack(temp_allocator_arg_t, const TempAllocator& temp_alloc,  +                   const T& val,  +                   std::ostream& os,  +                   const msgpack_encode_options& options = msgpack_encode_options()) +    { +        basic_msgpack_encoder<jsoncons::binary_stream_sink,TempAllocator> encoder(os, options, temp_alloc); +        std::error_code ec; +        encode_traits<T,char>::encode(val, encoder, json(), ec); +        if (ec) +        { +            JSONCONS_THROW(ser_error(ec)); +        } +    } + +} // msgpack +} // jsoncons + +#endif diff --git a/include/jsoncons_ext/msgpack/msgpack.hpp b/include/jsoncons_ext/msgpack/msgpack.hpp new file mode 100644 index 0000000..307aad2 --- /dev/null +++ b/include/jsoncons_ext/msgpack/msgpack.hpp @@ -0,0 +1,24 @@ +// Copyright 2013 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_MSGPACK_MSGPACK_HPP +#define JSONCONS_MSGPACK_MSGPACK_HPP + +#include <string> +#include <vector> +#include <memory> +#include <type_traits> // std::enable_if +#include <istream> // std::basic_istream +#include <jsoncons/json.hpp> +#include <jsoncons/config/jsoncons_config.hpp> +#include <jsoncons_ext/msgpack/msgpack_encoder.hpp> +#include <jsoncons_ext/msgpack/msgpack_reader.hpp> +#include <jsoncons_ext/msgpack/msgpack_cursor.hpp> +#include <jsoncons_ext/msgpack/encode_msgpack.hpp> +#include <jsoncons_ext/msgpack/decode_msgpack.hpp> + +#endif + diff --git a/include/jsoncons_ext/msgpack/msgpack_cursor.hpp b/include/jsoncons_ext/msgpack/msgpack_cursor.hpp new file mode 100644 index 0000000..a813429 --- /dev/null +++ b/include/jsoncons_ext/msgpack/msgpack_cursor.hpp @@ -0,0 +1,343 @@ +// 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_MSGPACK_MSGPACK_CURSOR_HPP +#define JSONCONS_MSGPACK_MSGPACK_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/msgpack/msgpack_parser.hpp> + +namespace jsoncons {  +namespace msgpack { + +template<class Source=jsoncons::binary_stream_source,class Allocator=std::allocator<char>> +class basic_msgpack_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_msgpack_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_msgpack_cursor(const basic_msgpack_cursor&) = delete; +    basic_msgpack_cursor& operator=(const basic_msgpack_cursor&) = delete; + +public: +    using string_view_type = string_view; + +    template <class Sourceable> +    basic_msgpack_cursor(Sourceable&& source, +                         const msgpack_decode_options& options = msgpack_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_msgpack_cursor(Sourceable&& source, +                         std::error_code& ec) +       : basic_msgpack_cursor(std::allocator_arg, Allocator(), +                              std::forward<Sourceable>(source),  +                              msgpack_decode_options(),  +                              ec) +    { +    } + +    template <class Sourceable> +    basic_msgpack_cursor(Sourceable&& source, +                         const msgpack_decode_options& options, +                         std::error_code& ec) +       : basic_msgpack_cursor(std::allocator_arg, Allocator(), +                              std::forward<Sourceable>(source),  +                              options,  +                              ec) +    { +    } + +    template <class Sourceable> +    basic_msgpack_cursor(std::allocator_arg_t, const Allocator& alloc,  +                         Sourceable&& source, +                         const msgpack_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(); +    } + +    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_msgpack_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_msgpack_cursor(Sourceable&& source, +                      std::function<bool(const staj_event&, const ser_context&)> filter, +                      const msgpack_decode_options& options = msgpack_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_msgpack_cursor(Sourceable&& source, +                         std::function<bool(const staj_event&, const ser_context&)> filter, +                         std::error_code& ec) +       : basic_msgpack_cursor(std::allocator_arg, Allocator(), +                              std::forward<Sourceable>(source), filter, ec) +    { +    } + +    template <class Sourceable> +    JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter") +    basic_msgpack_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 msgpack_stream_cursor = basic_msgpack_cursor<jsoncons::binary_stream_source>; +using msgpack_bytes_cursor = basic_msgpack_cursor<jsoncons::bytes_source>; + +} // namespace msgpack +} // namespace jsoncons + +#endif + diff --git a/include/jsoncons_ext/msgpack/msgpack_cursor2.hpp b/include/jsoncons_ext/msgpack/msgpack_cursor2.hpp new file mode 100644 index 0000000..8fce1ca --- /dev/null +++ b/include/jsoncons_ext/msgpack/msgpack_cursor2.hpp @@ -0,0 +1,259 @@ +// 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_MSGPACK_MSGPACK_CURSOR2_HPP +#define JSONCONS_MSGPACK_MSGPACK_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/msgpack/msgpack_parser.hpp> + +namespace jsoncons {  +namespace msgpack { + +    template<class Source=jsoncons::binary_stream_source,class Allocator=std::allocator<char>> +    class basic_msgpack_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_msgpack_parser<Source,Allocator> parser_; +        basic_staj2_visitor<char_type> cursor_visitor_; +        bool eof_; + +        // Noncopyable and nonmoveable +        basic_msgpack_cursor2(const basic_msgpack_cursor2&) = delete; +        basic_msgpack_cursor2& operator=(const basic_msgpack_cursor2&) = delete; + +    public: +        using string_view_type = string_view; + +        template <class Sourceable> +        basic_msgpack_cursor2(Sourceable&& source, +                             const msgpack_decode_options& options = msgpack_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_msgpack_cursor2(Sourceable&& source, +                             std::error_code& ec) +           : basic_msgpack_cursor2(std::allocator_arg, Allocator(), +                                  std::forward<Sourceable>(source),  +                                  msgpack_decode_options(),  +                                  ec) +        { +        } + +        template <class Sourceable> +        basic_msgpack_cursor2(Sourceable&& source, +                             const msgpack_decode_options& options, +                             std::error_code& ec) +           : basic_msgpack_cursor2(std::allocator_arg, Allocator(), +                                  std::forward<Sourceable>(source),  +                                  options,  +                                  ec) +        { +        } + +        template <class Sourceable> +        basic_msgpack_cursor2(std::allocator_arg_t, const Allocator& alloc,  +                             Sourceable&& source, +                             const msgpack_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(); +        } + +        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_msgpack_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 msgpack_stream_cursor2 = basic_msgpack_cursor2<jsoncons::binary_stream_source>; +    using msgpack_bytes_cursor2 = basic_msgpack_cursor2<jsoncons::bytes_source>; + +} // namespace msgpack +} // namespace jsoncons + +#endif + diff --git a/include/jsoncons_ext/msgpack/msgpack_encoder.hpp b/include/jsoncons_ext/msgpack/msgpack_encoder.hpp new file mode 100644 index 0000000..34e882b --- /dev/null +++ b/include/jsoncons_ext/msgpack/msgpack_encoder.hpp @@ -0,0 +1,753 @@ +// 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_MSGPACK_MSGPACK_ENCODER_HPP +#define JSONCONS_MSGPACK_MSGPACK_ENCODER_HPP + +#include <string> +#include <vector> +#include <limits> // std::numeric_limits +#include <memory> +#include <utility> // std::move +#include <jsoncons/json_exception.hpp> +#include <jsoncons/json_visitor.hpp> +#include <jsoncons/config/jsoncons_config.hpp> +#include <jsoncons/sink.hpp> +#include <jsoncons/detail/parse_number.hpp> +#include <jsoncons_ext/msgpack/msgpack_type.hpp> +#include <jsoncons_ext/msgpack/msgpack_error.hpp> +#include <jsoncons_ext/msgpack/msgpack_options.hpp> + +namespace jsoncons {  +namespace msgpack { + +    enum class msgpack_container_type {object, array}; + +    template<class Sink=jsoncons::binary_stream_sink,class Allocator=std::allocator<char>> +    class basic_msgpack_encoder final : public basic_json_visitor<char> +    { +        enum class decimal_parse_state { start, integer, exp1, exp2, fraction1 }; + +        static constexpr int64_t nanos_in_milli = 1000000; +        static constexpr int64_t nanos_in_second = 1000000000; +        static constexpr int64_t millis_in_second = 1000; +    public: +        using allocator_type = Allocator; +        using char_type = char; +        using typename basic_json_visitor<char>::string_view_type; +        using sink_type = Sink; + +    private: +        struct stack_item +        { +            msgpack_container_type type_; +            std::size_t length_; +            std::size_t count_; + +            stack_item(msgpack_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_ == msgpack_container_type::object; +            } +        }; + +        Sink sink_; +        const msgpack_encode_options options_; +        allocator_type alloc_; + +        std::vector<stack_item> stack_; +        int nesting_depth_; + +        // Noncopyable and nonmoveable +        basic_msgpack_encoder(const basic_msgpack_encoder&) = delete; +        basic_msgpack_encoder& operator=(const basic_msgpack_encoder&) = delete; +    public: +        explicit basic_msgpack_encoder(Sink&& sink,  +                                       const Allocator& alloc = Allocator()) +           : basic_msgpack_encoder(std::forward<Sink>(sink), msgpack_encode_options(), alloc) +        { +        } + +        explicit basic_msgpack_encoder(Sink&& sink,  +                                       const msgpack_encode_options& options,  +                                       const Allocator& alloc = Allocator()) +           : sink_(std::forward<Sink>(sink)), +             options_(options), +             alloc_(alloc), +             nesting_depth_(0) +        { +        } + +        ~basic_msgpack_encoder() noexcept +        { +            sink_.flush(); +        } + +        void reset() +        { +            stack_.clear(); +            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 +        { +            ec = msgpack_errc::object_length_required; +            return false; +        } + +        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 = msgpack_errc::max_nesting_depth_exceeded; +                return false; +            }  +            stack_.emplace_back(msgpack_container_type::object, length); + +            if (length <= 15) +            { +                // fixmap +                sink_.push_back(jsoncons::msgpack::msgpack_type::fixmap_base_type | (length & 0xf)); +            } +            else if (length <= 65535) +            { +                // map 16 +                sink_.push_back(jsoncons::msgpack::msgpack_type::map16_type); +                binary::native_to_big(static_cast<uint16_t>(length),  +                                      std::back_inserter(sink_)); +            } +            else if (length <= 4294967295) +            { +                // map 32 +                sink_.push_back(jsoncons::msgpack::msgpack_type::map32_type); +                binary::native_to_big(static_cast<uint32_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().count() < stack_.back().length()) +            { +                ec = msgpack_errc::too_few_items; +                return false; +            } +            else if (stack_.back().count() > stack_.back().length()) +            { +                ec = msgpack_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 +        { +            ec = msgpack_errc::array_length_required; +            return false; +        } + +        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 = msgpack_errc::max_nesting_depth_exceeded; +                return false; +            }  +            stack_.emplace_back(msgpack_container_type::array, length); +            if (length <= 15) +            { +                // fixarray +                sink_.push_back(jsoncons::msgpack::msgpack_type::fixarray_base_type | (length & 0xf)); +            } +            else if (length <= (std::numeric_limits<uint16_t>::max)()) +            { +                // array 16 +                sink_.push_back(jsoncons::msgpack::msgpack_type::array16_type); +                binary::native_to_big(static_cast<uint16_t>(length),std::back_inserter(sink_)); +            } +            else if (length <= (std::numeric_limits<uint32_t>::max)()) +            { +                // array 32 +                sink_.push_back(jsoncons::msgpack::msgpack_type::array32_type); +                binary::native_to_big(static_cast<uint32_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().count() < stack_.back().length()) +            { +                ec = msgpack_errc::too_few_items; +                return false; +            } +            else if (stack_.back().count() > stack_.back().length()) +            { +                ec = msgpack_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_value(name); +            return true; +        } + +        bool visit_null(semantic_tag, const ser_context&, std::error_code&) override +        { +            // nil +            sink_.push_back(jsoncons::msgpack::msgpack_type::nil_type); +            end_value(); +            return true; +        } + +        void write_timestamp(int64_t seconds, int64_t nanoseconds) +        { +            if ((seconds >> 34) == 0)  +            { +                uint64_t data64 = (nanoseconds << 34) | seconds; +                if ((data64 & 0xffffffff00000000L) == 0)  +                { +                    // timestamp 32 +                    sink_.push_back(jsoncons::msgpack::msgpack_type::fixext4_type); +                    sink_.push_back(0xff); +                    binary::native_to_big(static_cast<uint32_t>(data64), std::back_inserter(sink_)); +                } +                else  +                { +                    // timestamp 64 +                    sink_.push_back(jsoncons::msgpack::msgpack_type::fixext8_type); +                    sink_.push_back(0xff); +                    binary::native_to_big(static_cast<uint64_t>(data64), std::back_inserter(sink_)); +                } +            } +            else  +            { +                // timestamp 96 +                sink_.push_back(jsoncons::msgpack::msgpack_type::ext8_type); +                sink_.push_back(0x0c); // 12 +                sink_.push_back(0xff); +                binary::native_to_big(static_cast<uint32_t>(nanoseconds), std::back_inserter(sink_)); +                binary::native_to_big(static_cast<uint64_t>(seconds), std::back_inserter(sink_)); +            } +        } + +        bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code& ec) override +        { +            switch (tag) +            { +                case semantic_tag::epoch_second: +                { +                    int64_t seconds; +                    auto result = jsoncons::detail::to_integer(sv.data(), sv.length(), seconds); +                    if (!result) +                    { +                        ec = msgpack_errc::invalid_timestamp; +                        return false; +                    } +                    write_timestamp(seconds, 0); +                    break; +                } +                case semantic_tag::epoch_milli: +                { +                    bigint n = bigint::from_string(sv.data(), sv.length()); +                    if (n != 0) +                    { +                        bigint q; +                        bigint rem; +                        n.divide(millis_in_second, q, rem, true); +                        int64_t seconds = static_cast<int64_t>(q); +                        int64_t nanoseconds = static_cast<int64_t>(rem) * nanos_in_milli; +                        if (nanoseconds < 0) +                        { +                            nanoseconds = -nanoseconds;  +                        } +                        write_timestamp(seconds, nanoseconds); +                    } +                    else +                    { +                        write_timestamp(0, 0); +                    } +                    break; +                } +                case semantic_tag::epoch_nano: +                { +                    bigint n = bigint::from_string(sv.data(), sv.length()); +                    if (n != 0) +                    { +                        bigint q; +                        bigint rem; +                        n.divide(nanos_in_second, q, rem, true); +                        int64_t seconds = static_cast<int64_t>(q); +                        int64_t nanoseconds = static_cast<int64_t>(rem); +                        if (nanoseconds < 0) +                        { +                            nanoseconds = -nanoseconds;  +                        } +                        write_timestamp(seconds, nanoseconds); +                    } +                    else +                    { +                        write_timestamp(0, 0); +                    } +                    break; +                } +                default: +                { +                    write_string_value(sv); +                    end_value(); +                    break; +                } +            } +            return true; +        } + +        void write_string_value(const string_view_type& sv)  +        { +            auto sink = unicode_traits::validate(sv.data(), sv.size()); +            if (sink.ec != unicode_traits::conv_errc()) +            { +                JSONCONS_THROW(ser_error(msgpack_errc::invalid_utf8_text_string)); +            } + +            const size_t length = sv.length(); +            if (length <= 31) +            { +                // fixstr stores a byte array whose length is upto 31 bytes +                sink_.push_back(jsoncons::msgpack::msgpack_type::fixstr_base_type | static_cast<uint8_t>(length)); +            } +            else if (length <= (std::numeric_limits<uint8_t>::max)()) +            { +                // str 8 stores a byte array whose length is upto (2^8)-1 bytes +                sink_.push_back(jsoncons::msgpack::msgpack_type::str8_type); +                sink_.push_back(static_cast<uint8_t>(length)); +            } +            else if (length <= (std::numeric_limits<uint16_t>::max)()) +            { +                // str 16 stores a byte array whose length is upto (2^16)-1 bytes +                sink_.push_back(jsoncons::msgpack::msgpack_type::str16_type); +                binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_)); +            } +            else if (length <= (std::numeric_limits<uint32_t>::max)()) +            { +                // str 32 stores a byte array whose length is upto (2^32)-1 bytes +                sink_.push_back(jsoncons::msgpack::msgpack_type::str32_type); +                binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_)); +            } + +            for (auto c : sv) +            { +                sink_.push_back(c); +            } +        } + +        bool visit_byte_string(const byte_string_view& b,  +                               semantic_tag,  +                               const ser_context&, +                               std::error_code&) override +        { + +            const std::size_t length = b.size(); +            if (length <= (std::numeric_limits<uint8_t>::max)()) +            { +                // bin 8 stores a byte array whose length is upto (2^8)-1 bytes +                sink_.push_back(jsoncons::msgpack::msgpack_type::bin8_type); +                sink_.push_back(static_cast<uint8_t>(length)); +            } +            else if (length <= (std::numeric_limits<uint16_t>::max)()) +            { +                // bin 16 stores a byte array whose length is upto (2^16)-1 bytes +                sink_.push_back(jsoncons::msgpack::msgpack_type::bin16_type); +                binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_)); +            } +            else if (length <= (std::numeric_limits<uint32_t>::max)()) +            { +                // bin 32 stores a byte array whose length is upto (2^32)-1 bytes +                sink_.push_back(jsoncons::msgpack::msgpack_type::bin32_type); +                binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_)); +            } + +            for (auto c : b) +            { +                sink_.push_back(c); +            } + +            end_value(); +            return true; +        } + +        bool visit_byte_string(const byte_string_view& b,  +                               uint64_t ext_tag,  +                               const ser_context&, +                               std::error_code&) override +        { +            const std::size_t length = b.size(); +            switch (length) +            { +                case 1: +                    sink_.push_back(jsoncons::msgpack::msgpack_type::fixext1_type); +                    sink_.push_back(static_cast<uint8_t>(ext_tag)); +                    break; +                case 2: +                    sink_.push_back(jsoncons::msgpack::msgpack_type::fixext2_type); +                    sink_.push_back(static_cast<uint8_t>(ext_tag)); +                    break; +                case 4: +                    sink_.push_back(jsoncons::msgpack::msgpack_type::fixext4_type); +                    sink_.push_back(static_cast<uint8_t>(ext_tag)); +                    break; +                case 8: +                    sink_.push_back(jsoncons::msgpack::msgpack_type::fixext8_type); +                    sink_.push_back(static_cast<uint8_t>(ext_tag)); +                    break; +                case 16: +                    sink_.push_back(jsoncons::msgpack::msgpack_type::fixext16_type); +                    sink_.push_back(static_cast<uint8_t>(ext_tag)); +                    break; +                default: +                    if (length <= (std::numeric_limits<uint8_t>::max)()) +                    { +                        sink_.push_back(jsoncons::msgpack::msgpack_type::ext8_type); +                        sink_.push_back(static_cast<uint8_t>(length)); +                        sink_.push_back(static_cast<uint8_t>(ext_tag)); +                    } +                    else if (length <= (std::numeric_limits<uint16_t>::max)()) +                    { +                        sink_.push_back(jsoncons::msgpack::msgpack_type::ext16_type); +                        binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_)); +                        sink_.push_back(static_cast<uint8_t>(ext_tag)); +                    } +                    else if (length <= (std::numeric_limits<uint32_t>::max)()) +                    { +                        sink_.push_back(jsoncons::msgpack::msgpack_type::ext32_type); +                        binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_)); +                        sink_.push_back(static_cast<uint8_t>(ext_tag)); +                    } +                    break; +            } + +            for (auto c : b) +            { +                sink_.push_back(c); +            } + +            end_value(); +            return true; +        } + +        bool visit_double(double val,  +                             semantic_tag, +                             const ser_context&, +                             std::error_code&) override +        { +            float valf = (float)val; +            if ((double)valf == val) +            { +                // float 32 +                sink_.push_back(jsoncons::msgpack::msgpack_type::float32_type); +                binary::native_to_big(valf,std::back_inserter(sink_)); +            } +            else +            { +                // float 64 +                sink_.push_back(jsoncons::msgpack::msgpack_type::float64_type); +                binary::native_to_big(val,std::back_inserter(sink_)); +            } + +            // write double + +            end_value(); +            return true; +        } + +        bool visit_int64(int64_t val,  +                         semantic_tag tag,  +                         const ser_context&, +                         std::error_code&) override +        { +            switch (tag) +            { +                case semantic_tag::epoch_second: +                    write_timestamp(val, 0); +                    break; +                case semantic_tag::epoch_milli: +                { +                    if (val != 0) +                    { +                        auto dv = std::div(val,millis_in_second); +                        int64_t seconds = dv.quot; +                        int64_t nanoseconds = dv.rem*nanos_in_milli; +                        if (nanoseconds < 0) +                        { +                            nanoseconds = -nanoseconds;  +                        } +                        write_timestamp(seconds, nanoseconds); +                    } +                    else +                    { +                        write_timestamp(0, 0); +                    } +                    break; +                } +                case semantic_tag::epoch_nano: +                { +                    if (val != 0) +                    { +                        auto dv = std::div(val,static_cast<int64_t>(nanos_in_second)); +                        int64_t seconds = dv.quot; +                        int64_t nanoseconds = dv.rem; +                        if (nanoseconds < 0) +                        { +                            nanoseconds = -nanoseconds;  +                        } +                        write_timestamp(seconds, nanoseconds); +                    } +                    else +                    { +                        write_timestamp(0, 0); +                    } +                    break; +                } +                default: +                { +                    if (val >= 0) +                    { +                        if (val <= 0x7f) +                        { +                            // positive fixnum stores 7-bit positive integer +                            sink_.push_back(static_cast<uint8_t>(val)); +                        } +                        else if (val <= (std::numeric_limits<uint8_t>::max)()) +                        { +                            // uint 8 stores a 8-bit unsigned integer +                            sink_.push_back(jsoncons::msgpack::msgpack_type::uint8_type); +                            sink_.push_back(static_cast<uint8_t>(val)); +                        } +                        else if (val <= (std::numeric_limits<uint16_t>::max)()) +                        { +                            // uint 16 stores a 16-bit big-endian unsigned integer +                            sink_.push_back(jsoncons::msgpack::msgpack_type::uint16_type); +                            binary::native_to_big(static_cast<uint16_t>(val),std::back_inserter(sink_)); +                        } +                        else if (val <= (std::numeric_limits<uint32_t>::max)()) +                        { +                            // uint 32 stores a 32-bit big-endian unsigned integer +                            sink_.push_back(jsoncons::msgpack::msgpack_type::uint32_type); +                            binary::native_to_big(static_cast<uint32_t>(val),std::back_inserter(sink_)); +                        } +                        else if (val <= (std::numeric_limits<int64_t>::max)()) +                        { +                            // int 64 stores a 64-bit big-endian signed integer +                            sink_.push_back(jsoncons::msgpack::msgpack_type::uint64_type); +                            binary::native_to_big(static_cast<uint64_t>(val),std::back_inserter(sink_)); +                        } +                    } +                    else +                    { +                        if (val >= -32) +                        { +                            // negative fixnum stores 5-bit negative integer +                            binary::native_to_big(static_cast<int8_t>(val), std::back_inserter(sink_)); +                        } +                        else if (val >= (std::numeric_limits<int8_t>::lowest)()) +                        { +                            // int 8 stores a 8-bit signed integer +                            sink_.push_back(jsoncons::msgpack::msgpack_type::int8_type); +                            binary::native_to_big(static_cast<int8_t>(val),std::back_inserter(sink_)); +                        } +                        else if (val >= (std::numeric_limits<int16_t>::lowest)()) +                        { +                            // int 16 stores a 16-bit big-endian signed integer +                            sink_.push_back(jsoncons::msgpack::msgpack_type::int16_type); +                            binary::native_to_big(static_cast<int16_t>(val),std::back_inserter(sink_)); +                        } +                        else if (val >= (std::numeric_limits<int32_t>::lowest)()) +                        { +                            // int 32 stores a 32-bit big-endian signed integer +                            sink_.push_back(jsoncons::msgpack::msgpack_type::int32_type); +                            binary::native_to_big(static_cast<int32_t>(val),std::back_inserter(sink_)); +                        } +                        else if (val >= (std::numeric_limits<int64_t>::lowest)()) +                        { +                            // int 64 stores a 64-bit big-endian signed integer +                            sink_.push_back(jsoncons::msgpack::msgpack_type::int64_type); +                            binary::native_to_big(static_cast<int64_t>(val),std::back_inserter(sink_)); +                        } +                    } +                } +                break; +            } +            end_value(); +            return true; +        } + +        bool visit_uint64(uint64_t val,  +                          semantic_tag tag,  +                          const ser_context&, +                          std::error_code&) override +        { +            switch (tag) +            { +                case semantic_tag::epoch_second: +                    write_timestamp(static_cast<int64_t>(val), 0); +                    break; +                case semantic_tag::epoch_milli: +                { +                    if (val != 0) +                    { +                        auto dv = std::div(static_cast<int64_t>(val), static_cast<int64_t>(millis_in_second)); +                        int64_t seconds = dv.quot; +                        int64_t nanoseconds = dv.rem*nanos_in_milli; +                        if (nanoseconds < 0) +                        { +                            nanoseconds = -nanoseconds;  +                        } +                        write_timestamp(seconds, nanoseconds); +                    } +                    else +                    { +                        write_timestamp(0, 0); +                    } +                    break; +                } +                case semantic_tag::epoch_nano: +                { +                    if (val != 0) +                    { +                        auto dv = std::div(static_cast<int64_t>(val), static_cast<int64_t>(nanos_in_second)); +                        int64_t seconds = dv.quot; +                        int64_t nanoseconds = dv.rem; +                        if (nanoseconds < 0) +                        { +                            nanoseconds = -nanoseconds;  +                        } +                        write_timestamp(seconds, nanoseconds); +                    } +                    else +                    { +                        write_timestamp(0, 0); +                    } +                    break; +                } +                default: +                { +                    if (val <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)())) +                    { +                        // positive fixnum stores 7-bit positive integer +                        sink_.push_back(static_cast<uint8_t>(val)); +                    } +                    else if (val <= (std::numeric_limits<uint8_t>::max)()) +                    { +                        // uint 8 stores a 8-bit unsigned integer +                        sink_.push_back(jsoncons::msgpack::msgpack_type::uint8_type); +                        sink_.push_back(static_cast<uint8_t>(val)); +                    } +                    else if (val <= (std::numeric_limits<uint16_t>::max)()) +                    { +                        // uint 16 stores a 16-bit big-endian unsigned integer +                        sink_.push_back(jsoncons::msgpack::msgpack_type::uint16_type); +                        binary::native_to_big(static_cast<uint16_t>(val),std::back_inserter(sink_)); +                    } +                    else if (val <= (std::numeric_limits<uint32_t>::max)()) +                    { +                        // uint 32 stores a 32-bit big-endian unsigned integer +                        sink_.push_back(jsoncons::msgpack::msgpack_type::uint32_type); +                        binary::native_to_big(static_cast<uint32_t>(val),std::back_inserter(sink_)); +                    } +                    else if (val <= (std::numeric_limits<uint64_t>::max)()) +                    { +                        // uint 64 stores a 64-bit big-endian unsigned integer +                        sink_.push_back(jsoncons::msgpack::msgpack_type::uint64_type); +                        binary::native_to_big(static_cast<uint64_t>(val),std::back_inserter(sink_)); +                    } +                    break; +                } +            } +            end_value(); +            return true; +        } + +        bool visit_bool(bool val, semantic_tag, const ser_context&, std::error_code&) override +        { +            // true and false +            sink_.push_back(static_cast<uint8_t>(val ? jsoncons::msgpack::msgpack_type::true_type : jsoncons::msgpack::msgpack_type::false_type)); + +            end_value(); +            return true; +        } + +        void end_value() +        { +            if (!stack_.empty()) +            { +                ++stack_.back().count_; +            } +        } +    }; + +    using msgpack_stream_encoder = basic_msgpack_encoder<jsoncons::binary_stream_sink>; +    using msgpack_bytes_encoder = basic_msgpack_encoder<jsoncons::bytes_sink<std::vector<uint8_t>>>; + +    #if !defined(JSONCONS_NO_DEPRECATED) +    JSONCONS_DEPRECATED_MSG("Instead, use msgpack_bytes_encoder") typedef msgpack_bytes_encoder msgpack_bytes_serializer; + +    template<class Sink=jsoncons::binary_stream_sink> +    using basic_msgpack_serializer = basic_msgpack_encoder<Sink>;  + +    JSONCONS_DEPRECATED_MSG("Instead, use msgpack_stream_encoder") typedef msgpack_stream_encoder msgpack_encoder; +    JSONCONS_DEPRECATED_MSG("Instead, use msgpack_stream_encoder") typedef msgpack_stream_encoder msgpack_serializer; +    JSONCONS_DEPRECATED_MSG("Instead, use msgpack_bytes_encoder") typedef msgpack_bytes_encoder msgpack_buffer_serializer; +    #endif + +} // namespace msgpack +} // namespace jsoncons + +#endif diff --git a/include/jsoncons_ext/msgpack/msgpack_error.hpp b/include/jsoncons_ext/msgpack/msgpack_error.hpp new file mode 100644 index 0000000..80c76b6 --- /dev/null +++ b/include/jsoncons_ext/msgpack/msgpack_error.hpp @@ -0,0 +1,94 @@ +/// 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_MSGPACK_MSGPACK_ERROR_HPP +#define JSONCONS_MSGPACK_MSGPACK_ERROR_HPP + +#include <system_error> +#include <jsoncons/config/jsoncons_config.hpp> + +namespace jsoncons { namespace msgpack { + +enum class msgpack_errc +{ +    success = 0, +    unexpected_eof = 1, +    source_error, +    invalid_utf8_text_string, +    array_length_required, +    object_length_required, +    too_many_items, +    too_few_items, +    max_nesting_depth_exceeded, +    length_is_negative, +    invalid_timestamp, +    unknown_type +}; + +class msgpack_error_category_impl +   : public std::error_category +{ +public: +    const char* name() const noexcept override +    { +        return "jsoncons/msgpack"; +    } +    std::string message(int ev) const override +    { +        switch (static_cast<msgpack_errc>(ev)) +        { +            case msgpack_errc::unexpected_eof: +                return "Unexpected end of file"; +            case msgpack_errc::source_error: +                return "Source error"; +            case msgpack_errc::invalid_utf8_text_string: +                return "Illegal UTF-8 encoding in text string"; +            case msgpack_errc::array_length_required: +                return "MessagePack encoder requires array length"; +            case msgpack_errc::object_length_required: +                return "MessagePack encoder requires object length"; +            case msgpack_errc::too_many_items: +                return "Too many items were added to a MessagePack object or array"; +            case msgpack_errc::too_few_items: +                return "Too few items were added to a MessagePack object or array"; +            case msgpack_errc::max_nesting_depth_exceeded: +                return "Data item nesting exceeds limit in options"; +            case msgpack_errc::length_is_negative: +                return "Request for the length of an array, map or string returned a negative result"; +            case msgpack_errc::invalid_timestamp: +                return "Invalid timestamp"; +            case msgpack_errc::unknown_type: +                return "An unknown type was found in the stream"; +            default: +                return "Unknown MessagePack parser error"; +        } +    } +}; + +inline +const std::error_category& msgpack_error_category() +{ +  static msgpack_error_category_impl instance; +  return instance; +} + +inline  +std::error_code make_error_code(msgpack_errc e) +{ +    return std::error_code(static_cast<int>(e),msgpack_error_category()); +} + + +}} + +namespace std { +    template<> +    struct is_error_code_enum<jsoncons::msgpack::msgpack_errc> : public true_type +    { +    }; +} + +#endif diff --git a/include/jsoncons_ext/msgpack/msgpack_options.hpp b/include/jsoncons_ext/msgpack/msgpack_options.hpp new file mode 100644 index 0000000..17bddf1 --- /dev/null +++ b/include/jsoncons_ext/msgpack/msgpack_options.hpp @@ -0,0 +1,74 @@ +// 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_MSGPACK_MSGPACK_OPTIONS_HPP +#define JSONCONS_MSGPACK_MSGPACK_OPTIONS_HPP + +#include <string> +#include <limits> // std::numeric_limits +#include <cwchar> +#include <jsoncons/json_exception.hpp> + +namespace jsoncons { namespace msgpack { + +class msgpack_options; + +class msgpack_options_common +{ +    friend class msgpack_options; + +    int max_nesting_depth_; +protected: +    virtual ~msgpack_options_common() = default; + +    msgpack_options_common() +        : max_nesting_depth_(1024) +    { +    } + +    msgpack_options_common(const msgpack_options_common&) = default; +    msgpack_options_common& operator=(const msgpack_options_common&) = default; +    msgpack_options_common(msgpack_options_common&&) = default; +    msgpack_options_common& operator=(msgpack_options_common&&) = default; +public: +    int max_nesting_depth() const  +    { +        return max_nesting_depth_; +    } +}; + +class msgpack_decode_options : public virtual msgpack_options_common +{ +    friend class msgpack_options; +public: +    msgpack_decode_options() +    { +    } +}; + +class msgpack_encode_options : public virtual msgpack_options_common +{ +    friend class msgpack_options; +public: +    msgpack_encode_options() +    { +    } +}; + +class msgpack_options final : public msgpack_decode_options, public msgpack_encode_options +{ +public: +    using msgpack_options_common::max_nesting_depth; + +    msgpack_options& max_nesting_depth(int value) +    { +        this->max_nesting_depth_ = value; +        return *this; +    } +}; + +}} +#endif diff --git a/include/jsoncons_ext/msgpack/msgpack_parser.hpp b/include/jsoncons_ext/msgpack/msgpack_parser.hpp new file mode 100644 index 0000000..cf2d507 --- /dev/null +++ b/include/jsoncons_ext/msgpack/msgpack_parser.hpp @@ -0,0 +1,748 @@ +// 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_MSGPACK_MSGPACK_PARSER_HPP +#define JSONCONS_MSGPACK_MSGPACK_PARSER_HPP + +#include <string> +#include <vector> +#include <memory> +#include <utility> // std::move +#include <jsoncons/json.hpp> +#include <jsoncons/source.hpp> +#include <jsoncons/bigint.hpp> +#include <jsoncons/json_visitor.hpp> +#include <jsoncons/config/jsoncons_config.hpp> +#include <jsoncons_ext/msgpack/msgpack_type.hpp> +#include <jsoncons_ext/msgpack/msgpack_error.hpp> +#include <jsoncons_ext/msgpack/msgpack_options.hpp> +#include <jsoncons/json_visitor2.hpp> + +namespace jsoncons { namespace msgpack { + +enum class parse_mode {root,accept,array,map_key,map_value}; + +struct parse_state  +{ +    parse_mode mode;  +    std::size_t length; +    std::size_t index; + +    parse_state(parse_mode mode, std::size_t length) noexcept +        : mode(mode), length(length), index(0) +    { +    } + +    parse_state(const parse_state&) = default; +    parse_state(parse_state&&) = default; +}; + +template <class Source,class Allocator=std::allocator<char>> +class basic_msgpack_parser : public ser_context +{ +    using char_type = char; +    using char_traits_type = std::char_traits<char>; +    using temp_allocator_type = Allocator; +    using char_allocator_type = typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<char_type>;                   +    using byte_allocator_type = typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<uint8_t>;                   +    using int64_allocator_type = typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<int64_t>;                   +    using parse_state_allocator_type = typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<parse_state>;                          + +    static constexpr int64_t nanos_in_second = 1000000000; + +    Source source_; +    msgpack_decode_options options_; +    bool more_; +    bool done_; +    std::basic_string<char,std::char_traits<char>,char_allocator_type> text_buffer_; +    std::vector<uint8_t,byte_allocator_type> bytes_buffer_; +    std::vector<parse_state,parse_state_allocator_type> state_stack_; +    int nesting_depth_; + +public: +    template <class Sourceable> +    basic_msgpack_parser(Sourceable&& source, +                         const msgpack_decode_options& options = msgpack_decode_options(), +                         const Allocator alloc = Allocator()) +       : source_(std::forward<Sourceable>(source)), +         options_(options), +         more_(true),  +         done_(false), +         text_buffer_(alloc), +         bytes_buffer_(alloc), +         state_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(); +        state_stack_.clear(); +        state_stack_.emplace_back(parse_mode::root,0); +        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::array: +                { +                    if (state_stack_.back().index < state_stack_.back().length) +                    { +                        ++state_stack_.back().index; +                        read_item(visitor, ec); +                        if (ec) +                        { +                            return; +                        } +                    } +                    else +                    { +                        end_array(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); +                        if (ec) +                        { +                            return; +                        } +                    } +                    else +                    { +                        end_object(visitor, ec); +                    } +                    break; +                } +                case parse_mode::map_value: +                { +                    state_stack_.back().mode = parse_mode::map_key; +                    read_item(visitor, ec); +                    if (ec) +                    { +                        return; +                    } +                    break; +                } +                case parse_mode::root: +                { +                    state_stack_.back().mode = parse_mode::accept; +                    read_item(visitor, ec); +                    if (ec) +                    { +                        return; +                    } +                    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) +    { +        if (source_.is_error()) +        { +            ec = msgpack_errc::source_error; +            more_ = false; +            return; +        }    + +        uint8_t type; +        if (source_.read(&type, 1) == 0) +        { +            ec = msgpack_errc::unexpected_eof; +            more_ = false; +            return; +        } + +        if (type <= 0xbf) +        { +            if (type <= 0x7f)  +            { +                // positive fixint +                more_ = visitor.uint64_value(type, semantic_tag::none, *this, ec); +            } +            else if (type <= 0x8f)  +            { +                begin_object(visitor,type,ec); // fixmap +            } +            else if (type <= 0x9f)  +            { +                begin_array(visitor,type,ec); // fixarray +            } +            else  +            { +                // fixstr +                const size_t len = type & 0x1f; + +                text_buffer_.clear(); + +                if (source_reader<Source>::read(source_,text_buffer_,len) != static_cast<std::size_t>(len)) +                { +                    ec = msgpack_errc::unexpected_eof; +                    more_ = false; +                    return; +                } + +                auto result = unicode_traits::validate(text_buffer_.data(),text_buffer_.size()); +                if (result.ec != unicode_traits::conv_errc()) +                { +                    ec = msgpack_errc::invalid_utf8_text_string; +                    more_ = false; +                    return; +                } +                more_ = visitor.string_value(jsoncons::basic_string_view<char>(text_buffer_.data(),text_buffer_.length()), semantic_tag::none, *this, ec); +            } +        } +        else if (type >= 0xe0)  +        { +            // negative fixint +            more_ = visitor.int64_value(static_cast<int8_t>(type), semantic_tag::none, *this, ec); +        } +        else +        { +            switch (type) +            { +                case jsoncons::msgpack::msgpack_type::nil_type:  +                { +                    more_ = visitor.null_value(semantic_tag::none, *this, ec); +                    break; +                } +                case jsoncons::msgpack::msgpack_type::true_type: +                { +                    more_ = visitor.bool_value(true, semantic_tag::none, *this, ec); +                    break; +                } +                case jsoncons::msgpack::msgpack_type::false_type: +                { +                    more_ = visitor.bool_value(false, semantic_tag::none, *this, ec); +                    break; +                } +                case jsoncons::msgpack::msgpack_type::float32_type:  +                { +                    uint8_t buf[sizeof(float)]; +                    if (source_.read(buf, sizeof(float)) != sizeof(float)) +                    { +                        ec = msgpack_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } +                    float val = binary::big_to_native<float>(buf, sizeof(buf)); +                    more_ = visitor.double_value(val, semantic_tag::none, *this, ec); +                    break; +                } + +                case jsoncons::msgpack::msgpack_type::float64_type:  +                { +                    uint8_t buf[sizeof(double)]; +                    if (source_.read(buf, sizeof(double)) != sizeof(double)) +                    { +                        ec = msgpack_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } +                    double val = binary::big_to_native<double>(buf, sizeof(buf)); +                    more_ = visitor.double_value(val, semantic_tag::none, *this, ec); +                    break; +                } + +                case jsoncons::msgpack::msgpack_type::uint8_type:  +                { +                    uint8_t b; +                    if (source_.read(&b, 1) == 0) +                    { +                        ec = msgpack_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } +                    more_ = visitor.uint64_value(b, semantic_tag::none, *this, ec); +                    break; +                } + +                case jsoncons::msgpack::msgpack_type::uint16_type:  +                { +                    uint8_t buf[sizeof(uint16_t)]; +                    if (source_.read(buf, sizeof(uint16_t)) !=sizeof(uint16_t))  +                    { +                        ec = msgpack_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } +                    uint16_t val = binary::big_to_native<uint16_t>(buf, sizeof(buf)); +                    more_ = visitor.uint64_value(val, semantic_tag::none, *this, ec); +                    break; +                } + +                case jsoncons::msgpack::msgpack_type::uint32_type:  +                { +                    uint8_t buf[sizeof(uint32_t)]; +                    if (source_.read(buf, sizeof(uint32_t)) != sizeof(uint32_t)) +                    { +                        ec = msgpack_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } +                    uint32_t val = binary::big_to_native<uint32_t>(buf, sizeof(buf)); +                    more_ = visitor.uint64_value(val, semantic_tag::none, *this, ec); +                    break; +                } + +                case jsoncons::msgpack::msgpack_type::uint64_type:  +                { +                    uint8_t buf[sizeof(uint64_t)]; +                    if (source_.read(buf, sizeof(uint64_t)) != sizeof(uint64_t)) +                    { +                        ec = msgpack_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } +                    uint64_t val = binary::big_to_native<uint64_t>(buf, sizeof(buf)); +                    more_ = visitor.uint64_value(val, semantic_tag::none, *this, ec); +                    break; +                } + +                case jsoncons::msgpack::msgpack_type::int8_type:  +                { +                    uint8_t buf[sizeof(int8_t)]; +                    if (source_.read(buf, sizeof(int8_t)) != sizeof(int8_t)) +                    { +                        ec = msgpack_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } +                    int8_t val = binary::big_to_native<int8_t>(buf, sizeof(buf)); +                    more_ = visitor.int64_value(val, semantic_tag::none, *this, ec); +                    break; +                } + +                case jsoncons::msgpack::msgpack_type::int16_type:  +                { +                    uint8_t buf[sizeof(int16_t)]; +                    if (source_.read(buf, sizeof(int16_t)) != sizeof(int16_t)) +                    { +                        ec = msgpack_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } +                    int16_t val = binary::big_to_native<int16_t>(buf, sizeof(buf)); +                    more_ = visitor.int64_value(val, semantic_tag::none, *this, ec); +                    break; +                } + +                case jsoncons::msgpack::msgpack_type::int32_type:  +                { +                    uint8_t buf[sizeof(int32_t)]; +                    if (source_.read(buf, sizeof(int32_t)) != sizeof(int32_t)) +                    { +                        ec = msgpack_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } +                    int32_t val = binary::big_to_native<int32_t>(buf, sizeof(buf)); +                    more_ = visitor.int64_value(val, semantic_tag::none, *this, ec); +                    break; +                } + +                case jsoncons::msgpack::msgpack_type::int64_type:  +                { +                    uint8_t buf[sizeof(int64_t)]; +                    if (source_.read(buf, sizeof(int64_t)) != sizeof(int64_t)) +                    { +                        ec = msgpack_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } +                    int64_t val = binary::big_to_native<int64_t>(buf, sizeof(buf)); +                    more_ = visitor.int64_value(val, semantic_tag::none, *this, ec); +                    break; +                } + +                case jsoncons::msgpack::msgpack_type::str8_type:  +                case jsoncons::msgpack::msgpack_type::str16_type:  +                case jsoncons::msgpack::msgpack_type::str32_type:  +                { +                    std::size_t len = get_size(type, ec); +                    if (!more_) +                    { +                        return; +                    } + +                    text_buffer_.clear(); +                    if (source_reader<Source>::read(source_,text_buffer_,len) != static_cast<std::size_t>(len)) +                    { +                        ec = msgpack_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } + +                    auto result = unicode_traits::validate(text_buffer_.data(),text_buffer_.size()); +                    if (result.ec != unicode_traits::conv_errc()) +                    { +                        ec = msgpack_errc::invalid_utf8_text_string; +                        more_ = false; +                        return; +                    } +                    more_ = visitor.string_value(jsoncons::basic_string_view<char>(text_buffer_.data(),text_buffer_.length()), semantic_tag::none, *this, ec); +                    break; +                } + +                case jsoncons::msgpack::msgpack_type::bin8_type:  +                case jsoncons::msgpack::msgpack_type::bin16_type:  +                case jsoncons::msgpack::msgpack_type::bin32_type:  +                { +                    std::size_t len = get_size(type,ec); +                    if (!more_) +                    { +                        return; +                    } +                    bytes_buffer_.clear(); +                    if (source_reader<Source>::read(source_,bytes_buffer_,len) != static_cast<std::size_t>(len)) +                    { +                        ec = msgpack_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } + +                    more_ = visitor.byte_string_value(byte_string_view(bytes_buffer_.data(),bytes_buffer_.size()),  +                                                      semantic_tag::none,  +                                                      *this, +                                                      ec); +                    break; +                } +                case jsoncons::msgpack::msgpack_type::fixext1_type:  +                case jsoncons::msgpack::msgpack_type::fixext2_type:  +                case jsoncons::msgpack::msgpack_type::fixext4_type:  +                case jsoncons::msgpack::msgpack_type::fixext8_type:  +                case jsoncons::msgpack::msgpack_type::fixext16_type:  +                case jsoncons::msgpack::msgpack_type::ext8_type:  +                case jsoncons::msgpack::msgpack_type::ext16_type:  +                case jsoncons::msgpack::msgpack_type::ext32_type:  +                { +                    std::size_t len = get_size(type,ec); +                    if (!more_) +                    { +                        return; +                    } + +                    // type +                    uint8_t buf[sizeof(int8_t)]; +                    if (source_.read(buf, sizeof(int8_t)) != sizeof(int8_t)) +                    { +                        ec = msgpack_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } + +                    int8_t ext_type = binary::big_to_native<int8_t>(buf, sizeof(buf)); + +                    bool is_timestamp = false;  +                    if (ext_type == -1) +                    { +                        is_timestamp = true;; +                    } + +                    // payload +                    if (is_timestamp && len == 4) +                    { +                        uint8_t buf32[sizeof(uint32_t)]; +                        if (source_.read(buf32, sizeof(uint32_t)) != sizeof(uint32_t)) +                        { +                            ec = msgpack_errc::unexpected_eof; +                            more_ = false; +                            return; +                        } +                        uint32_t val = binary::big_to_native<uint32_t>(buf32, sizeof(buf32)); +                        more_ = visitor.uint64_value(val, semantic_tag::epoch_second, *this, ec); +                    } +                    else if (is_timestamp && len == 8) +                    { +                        uint8_t buf64[sizeof(uint64_t)]; +                        if (source_.read(buf64, sizeof(uint64_t)) != sizeof(uint64_t)) +                        { +                            ec = msgpack_errc::unexpected_eof; +                            more_ = false; +                            return; +                        } +                        uint64_t data64 = binary::big_to_native<uint64_t>(buf64, sizeof(buf64)); +                        uint64_t sec = data64 & 0x00000003ffffffffL; +                        uint64_t nsec = data64 >> 34; + +                        bigint nano(sec); +                        nano *= uint64_t(nanos_in_second); +                        nano += nsec; +                        text_buffer_.clear(); +                        nano.write_string(text_buffer_); +                        more_ = visitor.string_value(text_buffer_, semantic_tag::epoch_nano, *this, ec); +                        if (!more_) return; +                    } +                    else if (is_timestamp && len == 12) +                    { +                        uint8_t buf1[sizeof(uint32_t)]; +                        if (source_.read(buf1, sizeof(uint32_t)) != sizeof(uint32_t)) +                        { +                            ec = msgpack_errc::unexpected_eof; +                            more_ = false; +                            return; +                        } +                        uint32_t nsec = binary::big_to_native<uint32_t>(buf1, sizeof(buf1)); + +                        uint8_t buf2[sizeof(int64_t)]; +                        if (source_.read(buf2, sizeof(int64_t)) != sizeof(int64_t)) +                        { +                            ec = msgpack_errc::unexpected_eof; +                            more_ = false; +                            return; +                        } +                        int64_t sec = binary::big_to_native<int64_t>(buf2, sizeof(buf2)); + +                        bigint nano(sec); + +                        nano *= uint64_t(nanos_in_second); + +                        if (nano < 0) +                        { +                            nano -= nsec; +                        } +                        else +                        { +                            nano += nsec; +                        } + +                        text_buffer_.clear(); +                        nano.write_string(text_buffer_); +                        more_ = visitor.string_value(text_buffer_, semantic_tag::epoch_nano, *this, ec); +                        if (!more_) return; +                    } +                    else +                    { +                        bytes_buffer_.clear(); +                        if (source_reader<Source>::read(source_,bytes_buffer_,len) != static_cast<std::size_t>(len)) +                        { +                            ec = msgpack_errc::unexpected_eof; +                            more_ = false; +                            return; +                        } + +                        more_ = visitor.byte_string_value(byte_string_view(bytes_buffer_.data(),bytes_buffer_.size()),  +                                                          static_cast<uint8_t>(ext_type),  +                                                          *this, +                                                          ec); +                    } +                    break; +                } + +                case jsoncons::msgpack::msgpack_type::array16_type:  +                case jsoncons::msgpack::msgpack_type::array32_type:  +                { +                    begin_array(visitor,type,ec); +                    break; +                } + +                case jsoncons::msgpack::msgpack_type::map16_type :  +                case jsoncons::msgpack::msgpack_type::map32_type :  +                { +                    begin_object(visitor, type, ec); +                    break; +                } + +                default: +                { +                    ec = msgpack_errc::unknown_type; +                    more_ = false; +                    return; +                } +            } +        } +    } + +    void begin_array(json_visitor2& visitor, uint8_t type, std::error_code& ec) +    { +        if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) +        { +            ec = msgpack_errc::max_nesting_depth_exceeded; +            more_ = false; +            return; +        }  +        std::size_t length = get_size(type, ec); +        if (!more_) +        { +            return; +        } +        state_stack_.emplace_back(parse_mode::array,length); +        more_ = visitor.begin_array(length, semantic_tag::none, *this, ec); +    } + +    void end_array(json_visitor2& visitor, std::error_code& ec) +    { +        --nesting_depth_; + +        more_ = visitor.end_array(*this, ec); +        state_stack_.pop_back(); +    } + +    void begin_object(json_visitor2& visitor, uint8_t type, std::error_code& ec) +    { +        if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) +        { +            ec = msgpack_errc::max_nesting_depth_exceeded; +            more_ = false; +            return; +        }  +        std::size_t length = get_size(type, ec); +        if (!more_) +        { +            return; +        } +        state_stack_.emplace_back(parse_mode::map_key,length); +        more_ = visitor.begin_object(length, semantic_tag::none, *this, ec); +    } + +    void end_object(json_visitor2& visitor, std::error_code& ec) +    { +        --nesting_depth_; +        more_ = visitor.end_object(*this, ec); +        state_stack_.pop_back(); +    } + +    std::size_t get_size(uint8_t type, std::error_code& ec) +    { +        switch (type) +        { +            case jsoncons::msgpack::msgpack_type::str8_type:  +            case jsoncons::msgpack::msgpack_type::bin8_type:  +            case jsoncons::msgpack::msgpack_type::ext8_type:  +            { +                uint8_t buf[sizeof(int8_t)]; +                if (source_.read(buf, sizeof(int8_t)) != sizeof(int8_t)) +                { +                    ec = msgpack_errc::unexpected_eof; +                    more_ = false; +                    return 0; +                } +                uint8_t len = binary::big_to_native<uint8_t>(buf, sizeof(buf)); +                return static_cast<std::size_t>(len); +            } + +            case jsoncons::msgpack::msgpack_type::str16_type:  +            case jsoncons::msgpack::msgpack_type::bin16_type:  +            case jsoncons::msgpack::msgpack_type::ext16_type:  +            case jsoncons::msgpack::msgpack_type::array16_type:  +            case jsoncons::msgpack::msgpack_type::map16_type: +            { +                uint8_t buf[sizeof(int16_t)]; +                if (source_.read(buf, sizeof(int16_t)) != sizeof(int16_t)) +                { +                    ec = msgpack_errc::unexpected_eof; +                    more_ = false; +                    return 0; +                } +                uint16_t len = binary::big_to_native<uint16_t>(buf, sizeof(buf)); +                return static_cast<std::size_t>(len); +            } + +            case jsoncons::msgpack::msgpack_type::str32_type:  +            case jsoncons::msgpack::msgpack_type::bin32_type:  +            case jsoncons::msgpack::msgpack_type::ext32_type:  +            case jsoncons::msgpack::msgpack_type::array32_type:  +            case jsoncons::msgpack::msgpack_type::map32_type :  +            { +                uint8_t buf[sizeof(int32_t)]; +                if (source_.read(buf, sizeof(int32_t)) != sizeof(int32_t)) +                { +                    ec = msgpack_errc::unexpected_eof; +                    more_ = false; +                    return 0; +                } +                uint32_t len = binary::big_to_native<uint32_t>(buf, sizeof(buf)); +                return static_cast<std::size_t>(len); +            } +            case jsoncons::msgpack::msgpack_type::fixext1_type:  +                return 1; +            case jsoncons::msgpack::msgpack_type::fixext2_type:  +                return 2; +            case jsoncons::msgpack::msgpack_type::fixext4_type:  +                return 4; +            case jsoncons::msgpack::msgpack_type::fixext8_type:  +                return 8; +            case jsoncons::msgpack::msgpack_type::fixext16_type:  +                return 16; +            default: +                if ((type > 0x8f && type <= 0x9f) // fixarray +                    || (type > 0x7f && type <= 0x8f) // fixmap +                   ) +                { +                    return type & 0x0f; +                } +                else +                { +                    ec = msgpack_errc::unknown_type; +                    more_ = false; +                    return 0; +                } +                break; +        } +    } +}; + +}} + +#endif diff --git a/include/jsoncons_ext/msgpack/msgpack_reader.hpp b/include/jsoncons_ext/msgpack/msgpack_reader.hpp new file mode 100644 index 0000000..c0d788a --- /dev/null +++ b/include/jsoncons_ext/msgpack/msgpack_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_MSGPACK_MSGPACK_READER_HPP +#define JSONCONS_MSGPACK_MSGPACK_READER_HPP + +#include <string> +#include <vector> +#include <memory> +#include <utility> // std::move +#include <jsoncons/json.hpp> +#include <jsoncons/source.hpp> +#include <jsoncons/json_visitor.hpp> +#include <jsoncons/config/jsoncons_config.hpp> +#include <jsoncons_ext/msgpack/msgpack_type.hpp> +#include <jsoncons_ext/msgpack/msgpack_error.hpp> +#include <jsoncons_ext/msgpack/msgpack_parser.hpp> + +namespace jsoncons { namespace msgpack { + +template <class Source,class Allocator=std::allocator<char>> +class basic_msgpack_reader +{ +    using char_type = char; + +    basic_msgpack_parser<Source,Allocator> parser_; +    basic_json_visitor2_to_visitor_adaptor<char_type,Allocator> adaptor_; +    json_visitor2& visitor_; +public: +    template <class Sourceable> +    basic_msgpack_reader(Sourceable&& source,  +                      json_visitor& visitor,  +                      const Allocator alloc) +       : basic_msgpack_reader(std::forward<Sourceable>(source), +                           visitor, +                           msgpack_decode_options(), +                           alloc) +    { +    } + +    template <class Sourceable> +    basic_msgpack_reader(Sourceable&& source,  +                      json_visitor& visitor,  +                      const msgpack_decode_options& options = msgpack_decode_options(), +                      const Allocator alloc=Allocator()) +       : parser_(std::forward<Sourceable>(source), options, alloc), +         adaptor_(visitor, alloc), visitor_(adaptor_) +    { +    } +    template <class Sourceable> +    basic_msgpack_reader(Sourceable&& source,  +                      json_visitor2& visitor,  +                      const Allocator alloc) +       : basic_msgpack_reader(std::forward<Sourceable>(source), +                           visitor, +                           msgpack_decode_options(), +                           alloc) +    { +    } + +    template <class Sourceable> +    basic_msgpack_reader(Sourceable&& source,  +                      json_visitor2& visitor,  +                      const msgpack_decode_options& options = msgpack_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 msgpack_stream_reader = basic_msgpack_reader<jsoncons::binary_stream_source>; + +using msgpack_bytes_reader = basic_msgpack_reader<jsoncons::bytes_source>; + +#if !defined(JSONCONS_NO_DEPRECATED) +JSONCONS_DEPRECATED_MSG("Instead, use msgpack_stream_reader") typedef msgpack_stream_reader msgpack_reader; +JSONCONS_DEPRECATED_MSG("Instead, use msgpack_bytes_reader") typedef msgpack_bytes_reader msgpack_buffer_reader; +#endif + +}} + +#endif diff --git a/include/jsoncons_ext/msgpack/msgpack_type.hpp b/include/jsoncons_ext/msgpack/msgpack_type.hpp new file mode 100644 index 0000000..aa9f8fd --- /dev/null +++ b/include/jsoncons_ext/msgpack/msgpack_type.hpp @@ -0,0 +1,63 @@ +// Copyright 2013 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_MSGPACK_MSGPACK_TYPE_HPP +#define JSONCONS_MSGPACK_MSGPACK_TYPE_HPP + +#include <string> +#include <memory> +#include <jsoncons/config/jsoncons_config.hpp> + +namespace jsoncons { namespace msgpack { + +    namespace msgpack_type +    { +        const uint8_t positive_fixint_base_type = 0x00; +        const uint8_t nil_type = 0xc0; +        const uint8_t false_type = 0xc2; +        const uint8_t true_type = 0xc3; +        const uint8_t float32_type = 0xca; +        const uint8_t float64_type = 0xcb; +        const uint8_t uint8_type = 0xcc; +        const uint8_t uint16_type = 0xcd; +        const uint8_t uint32_type = 0xce; +        const uint8_t uint64_type = 0xcf; +        const uint8_t int8_type = 0xd0; +        const uint8_t int16_type = 0xd1; +        const uint8_t int32_type = 0xd2; +        const uint8_t int64_type = 0xd3; + +        const uint8_t fixmap_base_type = 0x80; +        const uint8_t fixarray_base_type = 0x90; +        const uint8_t fixstr_base_type = 0xa0; +        const uint8_t str8_type = 0xd9; +        const uint8_t str16_type = 0xda; +        const uint8_t str32_type = 0xdb; + +        const uint8_t bin8_type = 0xc4; //  0xC4 +        const uint8_t bin16_type = 0xc5; +        const uint8_t bin32_type = 0xc6; + +        const uint8_t fixext1_type = 0xd4; +        const uint8_t fixext2_type = 0xd5; +        const uint8_t fixext4_type = 0xd6; +        const uint8_t fixext8_type = 0xd7; +        const uint8_t fixext16_type = 0xd8; +        const uint8_t ext8_type = 0xc7; //  0xC4 +        const uint8_t ext16_type = 0xc8; +        const uint8_t ext32_type = 0xc9; + +        const uint8_t array16_type = 0xdc; +        const uint8_t array32_type = 0xdd; +        const uint8_t map16_type = 0xde; +        const uint8_t map32_type = 0xdf; +        const uint8_t negative_fixint_base_type = 0xe0; +    } +  +} // namespace msgpack +} // namespace jsoncons + +#endif |