diff options
| author | Richard <q@1bpm.net> | 2022-09-04 00:32:56 +0100 | 
|---|---|---|
| committer | Richard <q@1bpm.net> | 2022-09-04 00:32:56 +0100 | 
| commit | 1d055261b4144dbf86b2658437015b15d4dd9bff (patch) | |
| tree | 6049b19d1bf953a650383de1a5e438b8b82679f6 /include/jsoncons_ext/ubjson | |
| download | csound-json-1d055261b4144dbf86b2658437015b15d4dd9bff.tar.gz csound-json-1d055261b4144dbf86b2658437015b15d4dd9bff.tar.bz2 csound-json-1d055261b4144dbf86b2658437015b15d4dd9bff.zip | |
initial
Diffstat (limited to 'include/jsoncons_ext/ubjson')
| -rw-r--r-- | include/jsoncons_ext/ubjson/decode_ubjson.hpp | 201 | ||||
| -rw-r--r-- | include/jsoncons_ext/ubjson/encode_ubjson.hpp | 142 | ||||
| -rw-r--r-- | include/jsoncons_ext/ubjson/ubjson.hpp | 23 | ||||
| -rw-r--r-- | include/jsoncons_ext/ubjson/ubjson_cursor.hpp | 307 | ||||
| -rw-r--r-- | include/jsoncons_ext/ubjson/ubjson_encoder.hpp | 502 | ||||
| -rw-r--r-- | include/jsoncons_ext/ubjson/ubjson_error.hpp | 100 | ||||
| -rw-r--r-- | include/jsoncons_ext/ubjson/ubjson_options.hpp | 87 | ||||
| -rw-r--r-- | include/jsoncons_ext/ubjson/ubjson_parser.hpp | 880 | ||||
| -rw-r--r-- | include/jsoncons_ext/ubjson/ubjson_reader.hpp | 92 | ||||
| -rw-r--r-- | include/jsoncons_ext/ubjson/ubjson_type.hpp | 43 | 
10 files changed, 2377 insertions, 0 deletions
| diff --git a/include/jsoncons_ext/ubjson/decode_ubjson.hpp b/include/jsoncons_ext/ubjson/decode_ubjson.hpp new file mode 100644 index 0000000..91c9c0f --- /dev/null +++ b/include/jsoncons_ext/ubjson/decode_ubjson.hpp @@ -0,0 +1,201 @@ +// 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_UBJSON_DECODE_UBJSON_HPP +#define JSONCONS_UBJSON_DECODE_UBJSON_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/ubjson/ubjson_reader.hpp> +#include <jsoncons_ext/ubjson/ubjson_cursor.hpp> + +namespace jsoncons {  +namespace ubjson { + +    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_ubjson(const Source& v,  +                  const ubjson_decode_options& options = ubjson_decode_options()) +    { +        jsoncons::json_decoder<T> decoder; +        auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); +        basic_ubjson_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_ubjson(const Source& v,  +                  const ubjson_decode_options& options = ubjson_decode_options()) +    { +        basic_ubjson_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_ubjson(std::istream& is,  +                  const ubjson_decode_options& options = ubjson_decode_options()) +    { +        jsoncons::json_decoder<T> decoder; +        auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); +        ubjson_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_ubjson(std::istream& is,  +                  const ubjson_decode_options& options = ubjson_decode_options()) +    { +        basic_ubjson_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_ubjson(InputIt first, InputIt last, +                const ubjson_decode_options& options = ubjson_decode_options()) +    { +        jsoncons::json_decoder<T> decoder; +        auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); +        basic_ubjson_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_ubjson(InputIt first, InputIt last, +                const ubjson_decode_options& options = ubjson_decode_options()) +    { +        basic_ubjson_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_ubjson(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                  const Source& v,  +                  const ubjson_decode_options& options = ubjson_decode_options()) +    { +        json_decoder<T,TempAllocator> decoder(temp_alloc); +        auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); +        basic_ubjson_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_ubjson(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                  const Source& v,  +                  const ubjson_decode_options& options = ubjson_decode_options()) +    { +        basic_ubjson_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_ubjson(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                  std::istream& is,  +                  const ubjson_decode_options& options = ubjson_decode_options()) +    { +        json_decoder<T,TempAllocator> decoder(temp_alloc); +        auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder); +        basic_ubjson_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_ubjson(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                  std::istream& is,  +                  const ubjson_decode_options& options = ubjson_decode_options()) +    { +        basic_ubjson_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; +    } + +} // ubjson +} // jsoncons + +#endif diff --git a/include/jsoncons_ext/ubjson/encode_ubjson.hpp b/include/jsoncons_ext/ubjson/encode_ubjson.hpp new file mode 100644 index 0000000..e8a244b --- /dev/null +++ b/include/jsoncons_ext/ubjson/encode_ubjson.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_UBJSON_ENCODE_UBJSON_HPP +#define JSONCONS_UBJSON_ENCODE_UBJSON_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/ubjson/ubjson_encoder.hpp> +#include <jsoncons_ext/ubjson/ubjson_reader.hpp> + +namespace jsoncons {  +namespace ubjson { + +    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_ubjson(const T& j,  +                  Container& v,  +                  const ubjson_encode_options& options = ubjson_encode_options()) +    { +        using char_type = typename T::char_type; +        basic_ubjson_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_ubjson(const T& val,  +                  Container& v,  +                  const ubjson_encode_options& options = ubjson_encode_options()) +    { +        basic_ubjson_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_ubjson(const T& j,  +                  std::ostream& os,  +                  const ubjson_encode_options& options = ubjson_encode_options()) +    { +        using char_type = typename T::char_type; +        ubjson_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_ubjson(const T& val,  +                  std::ostream& os,  +                  const ubjson_encode_options& options = ubjson_encode_options()) +    { +        ubjson_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_ubjson(temp_allocator_arg_t, const TempAllocator& temp_alloc,const T& j,  +                  Container& v,  +                  const ubjson_encode_options& options = ubjson_encode_options()) +    { +        using char_type = typename T::char_type; +        basic_ubjson_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_ubjson(temp_allocator_arg_t, const TempAllocator& temp_alloc,const T& val,  +                  Container& v,  +                  const ubjson_encode_options& options = ubjson_encode_options()) +    { +        basic_ubjson_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_ubjson(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                  const T& j,  +                  std::ostream& os,  +                  const ubjson_encode_options& options = ubjson_encode_options()) +    { +        using char_type = typename T::char_type; +        basic_ubjson_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_ubjson(temp_allocator_arg_t, const TempAllocator& temp_alloc, +                  const T& val,  +                  std::ostream& os,  +                  const ubjson_encode_options& options = ubjson_encode_options()) +    { +        basic_ubjson_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)); +        } +    } + +} // ubjson +} // jsoncons + +#endif diff --git a/include/jsoncons_ext/ubjson/ubjson.hpp b/include/jsoncons_ext/ubjson/ubjson.hpp new file mode 100644 index 0000000..c2729bd --- /dev/null +++ b/include/jsoncons_ext/ubjson/ubjson.hpp @@ -0,0 +1,23 @@ +// 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_UBJSON_UBJSON_HPP +#define JSONCONS_UBJSON_UBJSON_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/ubjson/ubjson_encoder.hpp> +#include <jsoncons_ext/ubjson/ubjson_reader.hpp> +#include <jsoncons_ext/ubjson/ubjson_cursor.hpp> +#include <jsoncons_ext/ubjson/encode_ubjson.hpp> +#include <jsoncons_ext/ubjson/decode_ubjson.hpp> + +#endif diff --git a/include/jsoncons_ext/ubjson/ubjson_cursor.hpp b/include/jsoncons_ext/ubjson/ubjson_cursor.hpp new file mode 100644 index 0000000..f60825e --- /dev/null +++ b/include/jsoncons_ext/ubjson/ubjson_cursor.hpp @@ -0,0 +1,307 @@ +// 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_UBJSON_UBJSON_CURSOR_HPP +#define JSONCONS_UBJSON_UBJSON_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/ubjson/ubjson_parser.hpp> + +namespace jsoncons {  +namespace ubjson { + +template<class Source=jsoncons::binary_stream_source,class Allocator=std::allocator<char>> +class basic_ubjson_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_ubjson_parser<Source,Allocator> parser_; +    basic_staj_visitor<char_type> cursor_visitor_; +    bool eof_; + +    // Noncopyable and nonmoveable +    basic_ubjson_cursor(const basic_ubjson_cursor&) = delete; +    basic_ubjson_cursor& operator=(const basic_ubjson_cursor&) = delete; + +public: +    using string_view_type = string_view; + +    template <class Sourceable> +    basic_ubjson_cursor(Sourceable&& source, +                      const ubjson_decode_options& options = ubjson_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_ubjson_cursor(Sourceable&& source,  +                        std::error_code& ec) +       : basic_ubjson_cursor(std::allocator_arg, Allocator(), +                             std::forward<Sourceable>(source),  +                             ubjson_decode_options(),  +                             ec) +    { +    } + +    template <class Sourceable> +    basic_ubjson_cursor(Sourceable&& source,  +                        const ubjson_decode_options& options, +                        std::error_code& ec) +       : basic_ubjson_cursor(std::allocator_arg, Allocator(), +                             std::forward<Sourceable>(source),  +                             options,  +                             ec) +    { +    } + +    template <class Sourceable> +    basic_ubjson_cursor(std::allocator_arg_t, const Allocator& alloc,  +                        Sourceable&& source, +                        const ubjson_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 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 (staj_to_saj_event(cursor_visitor_.event(), 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_ubjson_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_ubjson_cursor(Sourceable&& source, +                      std::function<bool(const staj_event&, const ser_context&)> filter, +                      const ubjson_decode_options& options = ubjson_decode_options(), +                      const Allocator& alloc = Allocator()) +       : parser_(std::forward<Sourceable>(source), options, alloc),  +         cursor_visitor_(filter),  +         eof_(false) +    { +        if (!done()) +        { +            next(); +        } +    } + +    template <class Sourceable> +    JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter") +    basic_ubjson_cursor(Sourceable&& source,  +                        std::function<bool(const staj_event&, const ser_context&)> filter, +                        std::error_code& ec) +       : basic_ubjson_cursor(std::allocator_arg, Allocator(), +                             std::forward<Sourceable>(source), filter, ec) +    { +    } + +    template <class Sourceable> +    JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter") +    basic_ubjson_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), +         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) +    { +        parser_.restart(); +        while (!parser_.stopped()) +        { +            parser_.parse(cursor_visitor_, ec); +            if (ec) return; +        } +    } + +    void read_next(basic_json_visitor<char_type>& visitor, std::error_code& ec) +    { +        parser_.restart(); +        while (!parser_.stopped()) +        { +            parser_.parse(visitor, ec); +            if (ec) return; +        } +    } +}; + +using ubjson_stream_cursor = basic_ubjson_cursor<jsoncons::binary_stream_source>; +using ubjson_bytes_cursor = basic_ubjson_cursor<jsoncons::bytes_source>; + +} // namespace ubjson +} // namespace jsoncons + +#endif + diff --git a/include/jsoncons_ext/ubjson/ubjson_encoder.hpp b/include/jsoncons_ext/ubjson/ubjson_encoder.hpp new file mode 100644 index 0000000..2d90e4a --- /dev/null +++ b/include/jsoncons_ext/ubjson/ubjson_encoder.hpp @@ -0,0 +1,502 @@ +// 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_UBJSON_UBJSON_ENCODER_HPP +#define JSONCONS_UBJSON_UBJSON_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/ubjson/ubjson_type.hpp> +#include <jsoncons_ext/ubjson/ubjson_error.hpp> +#include <jsoncons_ext/ubjson/ubjson_options.hpp> + +namespace jsoncons { namespace ubjson { + +enum class ubjson_container_type {object, indefinite_length_object, array, indefinite_length_array}; + +template<class Sink=jsoncons::binary_stream_sink,class Allocator=std::allocator<char>> +class basic_ubjson_encoder final : public basic_json_visitor<char> +{ + +    enum class decimal_parse_state { start, integer, exp1, exp2, fraction1 }; +public: +    using allocator_type = Allocator; +    using typename basic_json_visitor<char>::string_view_type; +    using sink_type = Sink; + +private: +    struct stack_item +    { +        ubjson_container_type type_; +        std::size_t length_; +        std::size_t count_; + +        stack_item(ubjson_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_ == ubjson_container_type::object || type_ == ubjson_container_type::indefinite_length_object; +        } + +        bool is_indefinite_length() const +        { +            return type_ == ubjson_container_type::indefinite_length_array || type_ == ubjson_container_type::indefinite_length_object; +        } + +    }; + +    Sink sink_; +    const ubjson_encode_options options_; +    allocator_type alloc_; + +    std::vector<stack_item> stack_; +    int nesting_depth_; + +    // Noncopyable and nonmoveable +    basic_ubjson_encoder(const basic_ubjson_encoder&) = delete; +    basic_ubjson_encoder& operator=(const basic_ubjson_encoder&) = delete; +public: +    basic_ubjson_encoder(Sink&& sink,  +                         const Allocator& alloc = Allocator()) +       : basic_ubjson_encoder(std::forward<Sink>(sink), ubjson_encode_options(), alloc) +    { +    } + +    explicit basic_ubjson_encoder(Sink&& sink,  +                                  const ubjson_encode_options& options,  +                                  const Allocator& alloc = Allocator()) +       : sink_(std::forward<Sink>(sink)), +         options_(options), +         alloc_(alloc), +         nesting_depth_(0) +    { +    } + +    void reset() +    { +        stack_.clear(); +        nesting_depth_ = 0; +    } + +    void reset(Sink&& sink) +    { +        sink_ = std::move(sink); +        reset(); +    } + +    ~basic_ubjson_encoder() noexcept +    { +        JSONCONS_TRY +        { +            sink_.flush(); +        } +        JSONCONS_CATCH(...) +        { +        } +    } + +private: +    // Implementing methods + +    void visit_flush() override +    { +        sink_.flush(); +    } + +    bool visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) override +    { +        if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) +        { +            ec = ubjson_errc::max_nesting_depth_exceeded; +            return false; +        }  +        stack_.emplace_back(ubjson_container_type::indefinite_length_object); +        sink_.push_back(jsoncons::ubjson::ubjson_type::start_object_marker); + +        return true; +    } + +    bool visit_begin_object(std::size_t length, semantic_tag, const ser_context&, std::error_code& ec) override +    { +        if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) +        { +            ec = ubjson_errc::max_nesting_depth_exceeded; +            return false; +        }  +        stack_.emplace_back(ubjson_container_type::object, length); +        sink_.push_back(jsoncons::ubjson::ubjson_type::start_object_marker); +        sink_.push_back(jsoncons::ubjson::ubjson_type::count_marker); +        put_length(length); + +        return true; +    } + +    bool visit_end_object(const ser_context&, std::error_code& ec) override +    { +        JSONCONS_ASSERT(!stack_.empty()); +        --nesting_depth_; + +        if (stack_.back().is_indefinite_length()) +        { +            sink_.push_back(jsoncons::ubjson::ubjson_type::end_object_marker); +        } +        else +        { +            if (stack_.back().count() < stack_.back().length()) +            { +                ec = ubjson_errc::too_few_items; +                return false; +            } +            if (stack_.back().count() > stack_.back().length()) +            { +                ec = ubjson_errc::too_many_items; +                return false; +            } +        } +        stack_.pop_back(); +        end_value(); +        return true; +    } + +    bool visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) override +    { +        if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) +        { +            ec = ubjson_errc::max_nesting_depth_exceeded; +            return false; +        }  +        stack_.emplace_back(ubjson_container_type::indefinite_length_array); +        sink_.push_back(jsoncons::ubjson::ubjson_type::start_array_marker); + +        return true; +    } + +    bool visit_begin_array(std::size_t length, semantic_tag, const ser_context&, std::error_code& ec) override +    { +        if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) +        { +            ec = ubjson_errc::max_nesting_depth_exceeded; +            return false; +        }  +        stack_.emplace_back(ubjson_container_type::array, length); +        sink_.push_back(jsoncons::ubjson::ubjson_type::start_array_marker); +        sink_.push_back(jsoncons::ubjson::ubjson_type::count_marker); +        put_length(length); + +        return true; +    } + +    bool visit_end_array(const ser_context&, std::error_code& ec) override +    { +        JSONCONS_ASSERT(!stack_.empty()); +        --nesting_depth_; + +        if (stack_.back().is_indefinite_length()) +        { +            sink_.push_back(jsoncons::ubjson::ubjson_type::end_array_marker); +        } +        else +        { +            if (stack_.back().count() < stack_.back().length()) +            { +                ec = ubjson_errc::too_few_items; +                return false; +            } +            if (stack_.back().count() > stack_.back().length()) +            { +                ec = ubjson_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& ec) override +    { +        auto sink = unicode_traits::validate(name.data(), name.size()); +        if (sink.ec != unicode_traits::conv_errc()) +        { +            ec = ubjson_errc::invalid_utf8_text_string; +            return false; +        } + +        put_length(name.length()); + +        for (auto c : name) +        { +            sink_.push_back(c); +        } +        return true; +    } + +    bool visit_null(semantic_tag, const ser_context&, std::error_code&) override +    { +        // nil +        binary::native_to_big(static_cast<uint8_t>(jsoncons::ubjson::ubjson_type::null_type), std::back_inserter(sink_)); +        end_value(); +        return true; +    } + +    bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code& ec) override +    { +        switch (tag) +        { +            case semantic_tag::bigint: +            case semantic_tag::bigdec: +            { +                sink_.push_back(jsoncons::ubjson::ubjson_type::high_precision_number_type); +                break; +            } +            default: +            { +                sink_.push_back(jsoncons::ubjson::ubjson_type::string_type); +                break; +            } +        } + +        auto sink = unicode_traits::validate(sv.data(), sv.size()); +        if (sink.ec != unicode_traits::conv_errc()) +        { +            ec = ubjson_errc::invalid_utf8_text_string; +            return false; +        } + +        put_length(sv.length()); + +        for (auto c : sv) +        { +            sink_.push_back(c); +        } + +        end_value(); +        return true; +    } + +    void put_length(std::size_t length) +    { +        if (length <= (std::numeric_limits<uint8_t>::max)()) +        { +            sink_.push_back(ubjson_type::uint8_type); +            binary::native_to_big(static_cast<uint8_t>(length), std::back_inserter(sink_)); +        } +        else if (length <= (std::size_t)(std::numeric_limits<int16_t>::max)()) +        { +            sink_.push_back(ubjson_type::int16_type); +            binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_)); +        } +        else if (length <= (std::size_t)(std::numeric_limits<int32_t>::max)()) +        { +            sink_.push_back(ubjson_type::int32_type); +            binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_)); +        } +        else if (length <= (std::size_t)(std::numeric_limits<int64_t>::max)()) +        { +            sink_.push_back(ubjson_type::int64_type); +            binary::native_to_big(static_cast<uint64_t>(length),std::back_inserter(sink_)); +        } +        else +        { +            JSONCONS_THROW(ser_error(ubjson_errc::too_many_items)); +        } +    } + +    bool visit_byte_string(const byte_string_view& b,  +                              semantic_tag,  +                              const ser_context&, +                              std::error_code&) override +    { + +        const size_t length = b.size(); +        sink_.push_back(jsoncons::ubjson::ubjson_type::start_array_marker); +        binary::native_to_big(static_cast<uint8_t>(jsoncons::ubjson::ubjson_type::type_marker), std::back_inserter(sink_)); +        binary::native_to_big(static_cast<uint8_t>(jsoncons::ubjson::ubjson_type::uint8_type), std::back_inserter(sink_)); +        put_length(length); + +        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(static_cast<uint8_t>(jsoncons::ubjson::ubjson_type::float32_type)); +            binary::native_to_big(valf,std::back_inserter(sink_)); +        } +        else +        { +            // float 64 +            sink_.push_back(static_cast<uint8_t>(jsoncons::ubjson::ubjson_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,  +                        const ser_context&, +                        std::error_code&) override +    { +        if (val >= 0) +        { +            if (val <= (std::numeric_limits<uint8_t>::max)()) +            { +                // uint 8 stores a 8-bit unsigned integer +                sink_.push_back(jsoncons::ubjson::ubjson_type::uint8_type); +                binary::native_to_big(static_cast<uint8_t>(val),std::back_inserter(sink_)); +            } +            else if (val <= (std::numeric_limits<int16_t>::max)()) +            { +                // uint 16 stores a 16-bit big-endian unsigned integer +                sink_.push_back(jsoncons::ubjson::ubjson_type::int16_type); +                binary::native_to_big(static_cast<int16_t>(val),std::back_inserter(sink_)); +            } +            else if (val <= (std::numeric_limits<int32_t>::max)()) +            { +                // uint 32 stores a 32-bit big-endian unsigned integer +                sink_.push_back(jsoncons::ubjson::ubjson_type::int32_type); +                binary::native_to_big(static_cast<int32_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::ubjson::ubjson_type::int64_type); +                binary::native_to_big(static_cast<int64_t>(val),std::back_inserter(sink_)); +            } +            else +            { +                // big integer +            } +        } +        else +        { +            if (val >= (std::numeric_limits<int8_t>::lowest)()) +            { +                // int 8 stores a 8-bit signed integer +                sink_.push_back(jsoncons::ubjson::ubjson_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::ubjson::ubjson_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::ubjson::ubjson_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::ubjson::ubjson_type::int64_type); +                binary::native_to_big(static_cast<int64_t>(val),std::back_inserter(sink_)); +            } +        } +        end_value(); +        return true; +    } + +    bool visit_uint64(uint64_t val,  +                      semantic_tag,  +                      const ser_context&, +                      std::error_code&) override +    { +        if (val <= (std::numeric_limits<uint8_t>::max)()) +        { +            sink_.push_back(jsoncons::ubjson::ubjson_type::uint8_type); +            binary::native_to_big(static_cast<uint8_t>(val),std::back_inserter(sink_)); +        } +        else if (val <= static_cast<uint64_t>((std::numeric_limits<int16_t>::max)())) +        { +            sink_.push_back(jsoncons::ubjson::ubjson_type::int16_type); +            binary::native_to_big(static_cast<int16_t>(val),std::back_inserter(sink_)); +        } +        else if (val <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)())) +        { +            sink_.push_back(jsoncons::ubjson::ubjson_type::int32_type); +            binary::native_to_big(static_cast<int32_t>(val),std::back_inserter(sink_)); +        } +        else if (val <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)())) +        { +            sink_.push_back(jsoncons::ubjson::ubjson_type::int64_type); +            binary::native_to_big(static_cast<int64_t>(val),std::back_inserter(sink_)); +        } +        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::ubjson::ubjson_type::true_type : jsoncons::ubjson::ubjson_type::false_type)); + +        end_value(); +        return true; +    } + +    void end_value() +    { +        if (!stack_.empty()) +        { +            ++stack_.back().count_; +        } +    } +}; + +using ubjson_stream_encoder = basic_ubjson_encoder<jsoncons::binary_stream_sink>; +using ubjson_bytes_encoder = basic_ubjson_encoder<jsoncons::bytes_sink<std::vector<uint8_t>>>; + +#if !defined(JSONCONS_NO_DEPRECATED) +template<class Sink=jsoncons::binary_stream_sink> +using basic_ubjson_serializer = basic_ubjson_encoder<Sink>;  + +JSONCONS_DEPRECATED_MSG("Instead, use ubjson_stream_encoder") typedef ubjson_stream_encoder ubjson_encoder; +JSONCONS_DEPRECATED_MSG("Instead, use ubjson_stream_encoder") typedef ubjson_stream_encoder ubjson_serializer; +JSONCONS_DEPRECATED_MSG("Instead, use ubjson_bytes_encoder") typedef ubjson_bytes_encoder ubjson_buffer_serializer; +#endif + +}} +#endif diff --git a/include/jsoncons_ext/ubjson/ubjson_error.hpp b/include/jsoncons_ext/ubjson/ubjson_error.hpp new file mode 100644 index 0000000..cc7f5b8 --- /dev/null +++ b/include/jsoncons_ext/ubjson/ubjson_error.hpp @@ -0,0 +1,100 @@ +/// 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_UBJSON_UBJSON_ERROR_HPP +#define JSONCONS_UBJSON_UBJSON_ERROR_HPP + +#include <system_error> +#include <jsoncons/config/jsoncons_config.hpp> + +namespace jsoncons { namespace ubjson { + +enum class ubjson_errc +{ +    success = 0, +    unexpected_eof = 1, +    source_error, +    count_required_after_type, +    length_is_negative, +    length_must_be_integer, +    unknown_type, +    invalid_utf8_text_string, +    too_many_items, +    too_few_items, +    number_too_large, +    max_nesting_depth_exceeded, +    key_expected, +    max_items_exceeded +}; + +class ubjson_error_category_impl +   : public std::error_category +{ +public: +    const char* name() const noexcept override +    { +        return "jsoncons/ubjson"; +    } +    std::string message(int ev) const override +    { +        switch (static_cast<ubjson_errc>(ev)) +        { +            case ubjson_errc::unexpected_eof: +                return "Unexpected end of file"; +            case ubjson_errc::source_error: +                return "Source error"; +            case ubjson_errc::count_required_after_type: +                return "Type is specified for container, but count is not specified"; +            case ubjson_errc::length_is_negative: +                return "Request for the length of an array, map or string returned a negative result"; +            case ubjson_errc::length_must_be_integer: +                return "Length must be a integer numeric type (int8, uint8, int16, int32, int64)"; +            case ubjson_errc::unknown_type: +                return "Unknown type"; +            case ubjson_errc::invalid_utf8_text_string: +                return "Illegal UTF-8 encoding in text string"; +            case ubjson_errc::too_many_items: +                return "Too many items were added to a UBJSON object or array of known length"; +            case ubjson_errc::too_few_items: +                return "Too few items were added to a UBJSON object or array of known length"; +            case ubjson_errc::number_too_large: +                return "Number exceeds implementation limits"; +            case ubjson_errc::max_nesting_depth_exceeded: +                return "Data item nesting exceeds limit in options"; +            case ubjson_errc::key_expected: +                return "Text string key in a map expected"; +            case ubjson_errc::max_items_exceeded: +                return "Number of items in UBJSON object or array exceeds limit set in options"; +            default: +                return "Unknown UBJSON parser error"; +        } +    } +}; + +inline +const std::error_category& ubjson_error_category() +{ +  static ubjson_error_category_impl instance; +  return instance; +} + +inline  +std::error_code make_error_code(ubjson_errc e) +{ +    return std::error_code(static_cast<int>(e),ubjson_error_category()); +} + + +}} + +namespace std { +    template<> +    struct is_error_code_enum<jsoncons::ubjson::ubjson_errc> : public true_type +    { +    }; +} + +#endif diff --git a/include/jsoncons_ext/ubjson/ubjson_options.hpp b/include/jsoncons_ext/ubjson/ubjson_options.hpp new file mode 100644 index 0000000..1498d50 --- /dev/null +++ b/include/jsoncons_ext/ubjson/ubjson_options.hpp @@ -0,0 +1,87 @@ +// 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_UBJSON_UBJSON_OPTIONS_HPP +#define JSONCONS_UBJSON_UBJSON_OPTIONS_HPP + +#include <string> +#include <limits> // std::numeric_limits +#include <cwchar> +#include <jsoncons/json_exception.hpp> + +namespace jsoncons { namespace ubjson { + +class ubjson_options; + +class ubjson_options_common +{ +    friend class ubjson_options; + +    int max_nesting_depth_; +protected: +    virtual ~ubjson_options_common() = default; + +    ubjson_options_common() +        : max_nesting_depth_(1024) +    { +    } + +    ubjson_options_common(const ubjson_options_common&) = default; +    ubjson_options_common& operator=(const ubjson_options_common&) = default; +    ubjson_options_common(ubjson_options_common&&) = default; +    ubjson_options_common& operator=(ubjson_options_common&&) = default; +public: +    int max_nesting_depth() const  +    { +        return max_nesting_depth_; +    } +}; + +class ubjson_decode_options : public virtual ubjson_options_common +{ +    friend class ubjson_options; +    std::size_t max_items_; +public: +    ubjson_decode_options() : +         max_items_(1 << 24) +    { +    } + +    std::size_t max_items() const +    { +        return max_items_; +    } +}; + +class ubjson_encode_options : public virtual ubjson_options_common +{ +    friend class ubjson_options; +public: +    ubjson_encode_options() +    { +    } +}; + +class ubjson_options final : public ubjson_decode_options, public ubjson_encode_options +{ +public: +    using ubjson_options_common::max_nesting_depth; + +    ubjson_options& max_nesting_depth(int value) +    { +        this->max_nesting_depth_ = value; +        return *this; +    } + +    ubjson_options& max_items(std::size_t value) +    { +        this->max_items_ = value; +        return *this; +    } +}; + +}} +#endif diff --git a/include/jsoncons_ext/ubjson/ubjson_parser.hpp b/include/jsoncons_ext/ubjson/ubjson_parser.hpp new file mode 100644 index 0000000..468f139 --- /dev/null +++ b/include/jsoncons_ext/ubjson/ubjson_parser.hpp @@ -0,0 +1,880 @@ +// 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_UBJSON_UBJSON_PARSER_HPP +#define JSONCONS_UBJSON_UBJSON_PARSER_HPP + +#include <string> +#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/ubjson/ubjson_type.hpp> +#include <jsoncons_ext/ubjson/ubjson_error.hpp> +#include <jsoncons_ext/ubjson/ubjson_options.hpp> + +namespace jsoncons { namespace ubjson { + +enum class parse_mode {root,accept,array,indefinite_array,strongly_typed_array,map_key,map_value,strongly_typed_map_key,strongly_typed_map_value,indefinite_map_key,indefinite_map_value}; + +struct parse_state  +{ +    parse_mode mode;  +    std::size_t length; +    uint8_t type; +    std::size_t index; + +    parse_state(parse_mode mode, std::size_t length, uint8_t type = 0) noexcept +        : mode(mode), length(length), type(type), index(0) +    { +    } + +    parse_state(const parse_state&) = default; +    parse_state(parse_state&&) = default; +}; + +template <class Source,class Allocator=std::allocator<char>> +class basic_ubjson_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 parse_state_allocator_type = typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<parse_state>;                          + +    Source source_; +    ubjson_decode_options options_; +    bool more_; +    bool done_; +    std::basic_string<char,std::char_traits<char>,char_allocator_type> text_buffer_; +    std::vector<parse_state,parse_state_allocator_type> state_stack_; +    int nesting_depth_; +public: +    template <class Sourceable> +        basic_ubjson_parser(Sourceable&& source, +                          const ubjson_decode_options& options = ubjson_decode_options(), +                          const Allocator alloc = Allocator()) +       : source_(std::forward<Sourceable>(source)),  +         options_(options), +         more_(true),  +         done_(false), +         text_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(); +        state_stack_.clear(); +        state_stack_.emplace_back(parse_mode::root,0,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_visitor& 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_type_and_value(visitor, ec); +                        if (ec) +                        { +                            return; +                        } +                    } +                    else +                    { +                        end_array(visitor, ec); +                    } +                    break; +                } +                case parse_mode::strongly_typed_array: +                { +                    if (state_stack_.back().index < state_stack_.back().length) +                    { +                        ++state_stack_.back().index; +                        read_value(visitor, state_stack_.back().type, ec); +                        if (ec) +                        { +                            return; +                        } +                    } +                    else +                    { +                        end_array(visitor, ec); +                    } +                    break; +                } +                case parse_mode::indefinite_array: +                { +                    auto c = source_.peek(); +                    if (c.eof) +                    { +                        ec = ubjson_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } +                    if (c.value == jsoncons::ubjson::ubjson_type::end_array_marker) +                    { +                        source_.ignore(1); +                        end_array(visitor, ec); +                        if (ec) +                        { +                            return; +                        } +                    } +                    else +                    { +                        if (++state_stack_.back().index > options_.max_items()) +                        { +                            ec = ubjson_errc::max_items_exceeded; +                            more_ = false; +                            return; +                        } +                        read_type_and_value(visitor, ec); +                        if (ec) +                        { +                            return; +                        } +                    } +                    break; +                } +                case parse_mode::map_key: +                { +                    if (state_stack_.back().index < state_stack_.back().length) +                    { +                        ++state_stack_.back().index; +                        read_key(visitor, ec); +                        if (ec) +                        { +                            return; +                        } +                        state_stack_.back().mode = parse_mode::map_value; +                    } +                    else +                    { +                        end_object(visitor, ec); +                    } +                    break; +                } +                case parse_mode::map_value: +                { +                    state_stack_.back().mode = parse_mode::map_key; +                    read_type_and_value(visitor, ec); +                    if (ec) +                    { +                        return; +                    } +                    break; +                } +                case parse_mode::strongly_typed_map_key: +                { +                    if (state_stack_.back().index < state_stack_.back().length) +                    { +                        ++state_stack_.back().index; +                        read_key(visitor, ec); +                        if (ec) +                        { +                            return; +                        } +                        state_stack_.back().mode = parse_mode::strongly_typed_map_value; +                    } +                    else +                    { +                        end_object(visitor, ec); +                    } +                    break; +                } +                case parse_mode::strongly_typed_map_value: +                { +                    state_stack_.back().mode = parse_mode::strongly_typed_map_key; +                    read_value(visitor, state_stack_.back().type, ec); +                    if (ec) +                    { +                        return; +                    } +                    break; +                } +                case parse_mode::indefinite_map_key: +                { +                    auto c = source_.peek(); +                    if (c.eof) +                    { +                        ec = ubjson_errc::unexpected_eof; +                        more_ = false; +                        return; +                    } +                    if (c.value == jsoncons::ubjson::ubjson_type::end_object_marker) +                    { +                        source_.ignore(1); +                        end_object(visitor, ec); +                        if (ec) +                        { +                            return; +                        } +                    } +                    else +                    { +                        if (++state_stack_.back().index > options_.max_items()) +                        { +                            ec = ubjson_errc::max_items_exceeded; +                            more_ = false; +                            return; +                        } +                        read_key(visitor, ec); +                        if (ec) +                        { +                            return; +                        } +                        state_stack_.back().mode = parse_mode::indefinite_map_value; +                    } +                    break; +                } +                case parse_mode::indefinite_map_value: +                { +                    state_stack_.back().mode = parse_mode::indefinite_map_key; +                    read_type_and_value(visitor, ec); +                    if (ec) +                    { +                        return; +                    } +                    break; +                } +                case parse_mode::root: +                { +                    state_stack_.back().mode = parse_mode::accept; +                    read_type_and_value(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_type_and_value(json_visitor& visitor, std::error_code& ec) +    { +        if (source_.is_error()) +        { +            ec = ubjson_errc::source_error; +            more_ = false; +            return; +        }    + +        uint8_t b; +        if (source_.read(&b, 1) == 0) +        { +            ec = ubjson_errc::unexpected_eof; +            more_ = false; +            return; +        } +        read_value(visitor, b, ec); +    } + +    void read_value(json_visitor& visitor, uint8_t type, std::error_code& ec) +    { +        switch (type) +        { +            case jsoncons::ubjson::ubjson_type::null_type:  +            { +                more_ = visitor.null_value(semantic_tag::none, *this, ec); +                break; +            } +            case jsoncons::ubjson::ubjson_type::no_op_type:  +            { +                break; +            } +            case jsoncons::ubjson::ubjson_type::true_type: +            { +                more_ = visitor.bool_value(true, semantic_tag::none, *this, ec); +                break; +            } +            case jsoncons::ubjson::ubjson_type::false_type: +            { +                more_ = visitor.bool_value(false, semantic_tag::none, *this, ec); +                break; +            } +            case jsoncons::ubjson::ubjson_type::int8_type:  +            { +                uint8_t buf[sizeof(int8_t)]; +                if (source_.read(buf, sizeof(int8_t)) != sizeof(int8_t)) +                { +                    ec = ubjson_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::ubjson::ubjson_type::uint8_type:  +            { +                uint8_t b; +                if (source_.read(&b, 1) == 0) +                { +                    ec = ubjson_errc::unexpected_eof; +                    more_ = false; +                    return; +                } +                more_ = visitor.uint64_value(b, semantic_tag::none, *this, ec); +                break; +            } +            case jsoncons::ubjson::ubjson_type::int16_type:  +            { +                uint8_t buf[sizeof(int16_t)]; +                if (source_.read(buf, sizeof(int16_t)) != sizeof(int16_t)) +                { +                    ec = ubjson_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::ubjson::ubjson_type::int32_type:  +            { +                uint8_t buf[sizeof(int32_t)]; +                if (source_.read(buf, sizeof(int32_t)) != sizeof(int32_t)) +                { +                    ec = ubjson_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::ubjson::ubjson_type::int64_type:  +            { +                uint8_t buf[sizeof(int64_t)]; +                if (source_.read(buf, sizeof(int64_t)) != sizeof(int64_t)) +                { +                    ec = ubjson_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::ubjson::ubjson_type::float32_type:  +            { +                uint8_t buf[sizeof(float)]; +                if (source_.read(buf, sizeof(float)) != sizeof(float)) +                { +                    ec = ubjson_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::ubjson::ubjson_type::float64_type:  +            { +                uint8_t buf[sizeof(double)]; +                if (source_.read(buf, sizeof(double)) != sizeof(double)) +                { +                    ec = ubjson_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::ubjson::ubjson_type::char_type:  +            { +                text_buffer_.clear(); +                if (source_reader<Source>::read(source_,text_buffer_,1) != 1) +                { +                    ec = ubjson_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 = ubjson_errc::invalid_utf8_text_string; +                    more_ = false; +                    return; +                } +                more_ = visitor.string_value(text_buffer_, semantic_tag::none, *this, ec); +                break; +            } +            case jsoncons::ubjson::ubjson_type::string_type:  +            { +                std::size_t length = get_length(ec); +                if (ec) +                { +                    return; +                } +                text_buffer_.clear(); +                if (source_reader<Source>::read(source_,text_buffer_,length) != length) +                { +                    ec = ubjson_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 = ubjson_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::ubjson::ubjson_type::high_precision_number_type:  +            { +                std::size_t length = get_length(ec); +                if (ec) +                { +                    return; +                } +                text_buffer_.clear(); +                if (source_reader<Source>::read(source_,text_buffer_,length) != length) +                { +                    ec = ubjson_errc::unexpected_eof; +                    more_ = false; +                    return; +                } +                if (jsoncons::detail::is_base10(text_buffer_.data(),text_buffer_.length())) +                { +                    more_ = visitor.string_value(jsoncons::basic_string_view<char>(text_buffer_.data(),text_buffer_.length()), semantic_tag::bigint, *this, ec); +                } +                else +                { +                    more_ = visitor.string_value(jsoncons::basic_string_view<char>(text_buffer_.data(),text_buffer_.length()), semantic_tag::bigdec, *this, ec); +                } +                break; +            } +            case jsoncons::ubjson::ubjson_type::start_array_marker:  +            { +                begin_array(visitor,ec); +                break; +            } +            case jsoncons::ubjson::ubjson_type::start_object_marker:  +            { +                begin_object(visitor, ec); +                break; +            } +            default: +            { +                ec = ubjson_errc::unknown_type; +                break; +            } +        } +        if (ec) +        { +            more_ = false; +        } +    } + +    void begin_array(json_visitor& visitor, std::error_code& ec) +    { +        if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) +        { +            ec = ubjson_errc::max_nesting_depth_exceeded; +            more_ = false; +            return; +        }  + +        auto c = source_.peek(); +        if (c.eof) +        { +            ec = ubjson_errc::unexpected_eof; +            more_ = false; +            return; +        } +        if (c.value == jsoncons::ubjson::ubjson_type::type_marker) +        { +            source_.ignore(1); +            uint8_t b; +            if (source_.read(&b, 1) == 0) +            { +                ec = ubjson_errc::unexpected_eof; +                more_ = false; +                return; +            } +            c = source_.peek(); +            if (c.eof) +            { +                ec = ubjson_errc::unexpected_eof; +                more_ = false; +                return; +            } +            if (c.value == jsoncons::ubjson::ubjson_type::count_marker) +            { +                source_.ignore(1); +                std::size_t length = get_length(ec); +                if (ec) +                { +                    return; +                } +                if (length > options_.max_items()) +                { +                    ec = ubjson_errc::max_items_exceeded; +                    more_ = false; +                    return; +                } +                state_stack_.emplace_back(parse_mode::strongly_typed_array,length,b); +                more_ = visitor.begin_array(length, semantic_tag::none, *this, ec); +            } +            else +            { +                ec = ubjson_errc::count_required_after_type; +                more_ = false; +                return; +            } +        } +        else if (c.value == jsoncons::ubjson::ubjson_type::count_marker) +        { +            source_.ignore(1); +            std::size_t length = get_length(ec); +            if (ec) +            { +                return; +            } +            if (length > options_.max_items()) +            { +                ec = ubjson_errc::max_items_exceeded; +                more_ = false; +                return; +            } +            state_stack_.emplace_back(parse_mode::array,length); +            more_ = visitor.begin_array(length, semantic_tag::none, *this, ec); +        } +        else +        { +            state_stack_.emplace_back(parse_mode::indefinite_array,0); +            more_ = visitor.begin_array(semantic_tag::none, *this, ec); +        } +    } + +    void end_array(json_visitor& visitor, std::error_code& ec) +    { +        --nesting_depth_; + +        more_ = visitor.end_array(*this, ec); +        state_stack_.pop_back(); +    } + +    void begin_object(json_visitor& visitor, std::error_code& ec) +    { +        if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) +        { +            ec = ubjson_errc::max_nesting_depth_exceeded; +            more_ = false; +            return; +        }  + +        auto c = source_.peek(); +        if (c.eof) +        { +            ec = ubjson_errc::unexpected_eof; +            more_ = false; +            return; +        } +        if (c.value == jsoncons::ubjson::ubjson_type::type_marker) +        { +            source_.ignore(1); +            uint8_t b; +            if (source_.read(&b, 1) == 0) +            { +                ec = ubjson_errc::unexpected_eof; +                more_ = false; +                return; +            } +            c = source_.peek(); +            if (c.eof) +            { +                ec = ubjson_errc::unexpected_eof; +                more_ = false; +                return; +            } +            if (c.value == jsoncons::ubjson::ubjson_type::count_marker) +            { +                source_.ignore(1); +                std::size_t length = get_length(ec); +                if (ec) +                { +                    return; +                } +                if (length > options_.max_items()) +                { +                    ec = ubjson_errc::max_items_exceeded; +                    more_ = false; +                    return; +                } +                state_stack_.emplace_back(parse_mode::strongly_typed_map_key,length,b); +                more_ = visitor.begin_object(length, semantic_tag::none, *this, ec); +            } +            else +            { +                ec = ubjson_errc::count_required_after_type; +                more_ = false; +                return; +            } +        } +        else +        { +            c = source_.peek(); +            if (c.eof) +            { +                ec = ubjson_errc::unexpected_eof; +                more_ = false; +                return; +            } +            if (c.value == jsoncons::ubjson::ubjson_type::count_marker) +            { +                source_.ignore(1); +                std::size_t length = get_length(ec); +                if (ec) +                { +                    return; +                } +                if (length > options_.max_items()) +                { +                    ec = ubjson_errc::max_items_exceeded; +                    more_ = false; +                    return; +                } +                state_stack_.emplace_back(parse_mode::map_key,length); +                more_ = visitor.begin_object(length, semantic_tag::none, *this, ec); +            } +            else +            { +                state_stack_.emplace_back(parse_mode::indefinite_map_key,0); +                more_ = visitor.begin_object(semantic_tag::none, *this, ec); +            } +        } +    } + +    void end_object(json_visitor& visitor, std::error_code& ec) +    { +        --nesting_depth_; +        more_ = visitor.end_object(*this, ec); +        state_stack_.pop_back(); +    } + +    std::size_t get_length(std::error_code& ec) +    { +        std::size_t length = 0; +        uint8_t type; +        if (source_.read(&type, 1) == 0) +        { +            ec = ubjson_errc::unexpected_eof; +            more_ = false; +            return length; +        } +        switch (type) +        { +            case jsoncons::ubjson::ubjson_type::int8_type:  +            { +                uint8_t buf[sizeof(int8_t)]; +                if (source_.read(buf, sizeof(int8_t)) != sizeof(int8_t)) +                { +                    ec = ubjson_errc::unexpected_eof; +                    more_ = false; +                    return length; +                } +                int8_t val = binary::big_to_native<int8_t>(buf, sizeof(buf)); +                if (val >= 0) +                { +                    length = val; +                } +                else +                { +                    ec = ubjson_errc::length_is_negative; +                    more_ = false; +                    return length; +                } +                break; +            } +            case jsoncons::ubjson::ubjson_type::uint8_type:  +            { +                uint8_t b; +                if (source_.read(&b, 1) == 0) +                { +                    ec = ubjson_errc::unexpected_eof; +                    more_ = false; +                    return length; +                } +                length = b; +                break; +            } +            case jsoncons::ubjson::ubjson_type::int16_type:  +            { +                uint8_t buf[sizeof(int16_t)]; +                if (source_.read(buf, sizeof(int16_t)) != sizeof(int16_t)) +                { +                    ec = ubjson_errc::unexpected_eof; +                    more_ = false; +                    return length; +                } +                int16_t val = binary::big_to_native<int16_t>(buf, sizeof(buf)); +                if (val >= 0) +                { +                    length = val; +                } +                else +                { +                    ec = ubjson_errc::length_is_negative; +                    more_ = false; +                    return length; +                } +                break; +            } +            case jsoncons::ubjson::ubjson_type::int32_type:  +            { +                uint8_t buf[sizeof(int32_t)]; +                if (source_.read(buf, sizeof(int32_t)) != sizeof(int32_t)) +                { +                    ec = ubjson_errc::unexpected_eof; +                    more_ = false; +                    return length; +                } +                int32_t val = binary::big_to_native<int32_t>(buf, sizeof(buf)); +                if (val >= 0) +                { +                    length = static_cast<std::size_t>(val); +                } +                else +                { +                    ec = ubjson_errc::length_is_negative; +                    more_ = false; +                    return length; +                } +                break; +            } +            case jsoncons::ubjson::ubjson_type::int64_type:  +            { +                uint8_t buf[sizeof(int64_t)]; +                if (source_.read(buf, sizeof(int64_t)) != sizeof(int64_t)) +                { +                    ec = ubjson_errc::unexpected_eof; +                    more_ = false; +                    return length; +                } +                int64_t val = binary::big_to_native<int64_t>(buf, sizeof(buf)); +                if (val >= 0) +                { +                    length = (std::size_t)val; +                    if (length != (uint64_t)val) +                    { +                        ec = ubjson_errc::number_too_large; +                        more_ = false; +                        return length; +                    } +                } +                else +                { +                    ec = ubjson_errc::length_is_negative; +                    more_ = false; +                    return length; +                } +                break; +            } +            default: +            { +                ec = ubjson_errc::length_must_be_integer; +                more_ = false; +                return length; +            } +        } +        return length; +    } + +    void read_key(json_visitor& visitor, std::error_code& ec) +    { +        std::size_t length = get_length(ec); +        if (ec) +        { +            ec = ubjson_errc::key_expected; +            more_ = false; +            return; +        } +        text_buffer_.clear(); +        if (source_reader<Source>::read(source_,text_buffer_,length) != length) +        { +            ec = ubjson_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 = ubjson_errc::invalid_utf8_text_string; +            more_ = false; +            return; +        } +        more_ = visitor.key(jsoncons::basic_string_view<char>(text_buffer_.data(),text_buffer_.length()), *this, ec); +    } +}; + +}} + +#endif diff --git a/include/jsoncons_ext/ubjson/ubjson_reader.hpp b/include/jsoncons_ext/ubjson/ubjson_reader.hpp new file mode 100644 index 0000000..210403a --- /dev/null +++ b/include/jsoncons_ext/ubjson/ubjson_reader.hpp @@ -0,0 +1,92 @@ +// 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_UBJSON_UBJSON_READER_HPP +#define JSONCONS_UBJSON_UBJSON_READER_HPP + +#include <string> +#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/ubjson/ubjson_type.hpp> +#include <jsoncons_ext/ubjson/ubjson_error.hpp> +#include <jsoncons_ext/ubjson/ubjson_parser.hpp> + +namespace jsoncons { namespace ubjson { + +template <class Source,class Allocator=std::allocator<char>> +class basic_ubjson_reader +{ +    basic_ubjson_parser<Source,Allocator> parser_; +    json_visitor& visitor_; +public: +    template <class Sourceable> +    basic_ubjson_reader(Sourceable&& source,  +                      json_visitor& visitor,  +                      const Allocator alloc) +       : basic_ubjson_reader(std::forward<Sourceable>(source), +                           visitor, +                           ubjson_decode_options(), +                           alloc) +    { +    } + +    template <class Sourceable> +    basic_ubjson_reader(Sourceable&& source,  +                      json_visitor& visitor,  +                      const ubjson_decode_options& options = ubjson_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 ubjson_stream_reader = basic_ubjson_reader<jsoncons::binary_stream_source>; + +using ubjson_bytes_reader = basic_ubjson_reader<jsoncons::bytes_source>; + +#if !defined(JSONCONS_NO_DEPRECATED) +JSONCONS_DEPRECATED_MSG("Instead, use ubjson_stream_reader") typedef ubjson_stream_reader ubjson_reader; +JSONCONS_DEPRECATED_MSG("Instead, use ubjson_bytes_reader") typedef ubjson_bytes_reader ubjson_buffer_reader; +#endif + +}} + +#endif diff --git a/include/jsoncons_ext/ubjson/ubjson_type.hpp b/include/jsoncons_ext/ubjson/ubjson_type.hpp new file mode 100644 index 0000000..ef219ce --- /dev/null +++ b/include/jsoncons_ext/ubjson/ubjson_type.hpp @@ -0,0 +1,43 @@ +// 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_UBJSON_UBJSON_TYPE_HPP +#define JSONCONS_UBJSON_UBJSON_TYPE_HPP + +#include <string> +#include <memory> +#include <jsoncons/config/jsoncons_config.hpp> + +namespace jsoncons { namespace ubjson {  + +    namespace ubjson_type +    { +        const uint8_t null_type = 'Z'; +        const uint8_t no_op_type = 'N'; +        const uint8_t true_type = 'T'; +        const uint8_t false_type = 'F'; +        const uint8_t int8_type = 'i'; +        const uint8_t uint8_type = 'U'; +        const uint8_t int16_type = 'I'; +        const uint8_t int32_type = 'l'; +        const uint8_t int64_type = 'L'; +        const uint8_t float32_type = 'd'; +        const uint8_t float64_type = 'D'; +        const uint8_t high_precision_number_type = 'H'; +        const uint8_t char_type = 'C'; +        const uint8_t string_type = 'S'; +        const uint8_t start_array_marker = '['; +        const uint8_t end_array_marker = ']'; +        const uint8_t start_object_marker = '{'; +        const uint8_t end_object_marker = '}'; +        const uint8_t type_marker = '$'; +        const uint8_t count_marker = '#'; +    } +  +} // namespace ubjson +} // namespace jsoncons + +#endif |