diff options
Diffstat (limited to 'include/jsoncons/json_reader.hpp')
-rw-r--r-- | include/jsoncons/json_reader.hpp | 731 |
1 files changed, 731 insertions, 0 deletions
diff --git a/include/jsoncons/json_reader.hpp b/include/jsoncons/json_reader.hpp new file mode 100644 index 0000000..eeb351f --- /dev/null +++ b/include/jsoncons/json_reader.hpp @@ -0,0 +1,731 @@ +// Copyright 2015 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_JSON_READER_HPP +#define JSONCONS_JSON_READER_HPP + +#include <memory> // std::allocator +#include <string> +#include <vector> +#include <stdexcept> +#include <system_error> +#include <ios> +#include <utility> // std::move +#include <jsoncons/source.hpp> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/json_visitor.hpp> +#include <jsoncons/json_parser.hpp> +#include <jsoncons/source_adaptor.hpp> + +namespace jsoncons { + + // utf8_other_json_input_adapter + + template <class CharT> + class json_utf8_to_other_visitor_adaptor : public json_visitor + { + public: + using json_visitor::string_view_type; + private: + basic_default_json_visitor<CharT> default_visitor_; + basic_json_visitor<CharT>& other_visitor_; + //std::function<bool(json_errc,const ser_context&)> err_handler_; + + // noncopyable and nonmoveable + json_utf8_to_other_visitor_adaptor(const json_utf8_to_other_visitor_adaptor<CharT>&) = delete; + json_utf8_to_other_visitor_adaptor<CharT>& operator=(const json_utf8_to_other_visitor_adaptor<CharT>&) = delete; + + public: + json_utf8_to_other_visitor_adaptor() + : other_visitor_(default_visitor_) + { + } + + json_utf8_to_other_visitor_adaptor(basic_json_visitor<CharT>& other_visitor/*, + std::function<bool(json_errc,const ser_context&)> err_handler*/) + : other_visitor_(other_visitor)/*, + err_handler_(err_handler)*/ + { + } + + private: + + void visit_flush() override + { + other_visitor_.flush(); + } + + bool visit_begin_object(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return other_visitor_.begin_object(tag, context, ec); + } + + bool visit_end_object(const ser_context& context, std::error_code& ec) override + { + return other_visitor_.end_object(context, ec); + } + + bool visit_begin_array(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return other_visitor_.begin_array(tag, context, ec); + } + + bool visit_end_array(const ser_context& context, std::error_code& ec) override + { + return other_visitor_.end_array(context, ec); + } + + bool visit_key(const string_view_type& name, const ser_context& context, std::error_code& ec) override + { + std::basic_string<CharT> target; + auto result = unicode_traits::convert( + name.data(), name.size(), target, + unicode_traits::conv_flags::strict); + if (result.ec != unicode_traits::conv_errc()) + { + JSONCONS_THROW(ser_error(result.ec,context.line(),context.column())); + } + return other_visitor_.key(target, context, ec); + } + + bool visit_string(const string_view_type& value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + std::basic_string<CharT> target; + auto result = unicode_traits::convert( + value.data(), value.size(), target, + unicode_traits::conv_flags::strict); + if (result.ec != unicode_traits::conv_errc()) + { + ec = result.ec; + return false; + } + return other_visitor_.string_value(target, tag, context, ec); + } + + bool visit_int64(int64_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return other_visitor_.int64_value(value, tag, context, ec); + } + + bool visit_uint64(uint64_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return other_visitor_.uint64_value(value, tag, context, ec); + } + + bool visit_half(uint16_t value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return other_visitor_.half_value(value, tag, context, ec); + } + + bool visit_double(double value, + semantic_tag tag, + const ser_context& context, + std::error_code& ec) override + { + return other_visitor_.double_value(value, tag, context, ec); + } + + bool visit_bool(bool value, semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return other_visitor_.bool_value(value, tag, context, ec); + } + + bool visit_null(semantic_tag tag, const ser_context& context, std::error_code& ec) override + { + return other_visitor_.null_value(tag, context, ec); + } + }; + + template<class CharT,class Source=jsoncons::stream_source<CharT>,class Allocator=std::allocator<char>> + class basic_json_reader + { + public: + using char_type = CharT; + using source_type = Source; + using string_view_type = jsoncons::basic_string_view<CharT>; + private: + typedef typename std::allocator_traits<Allocator>:: template rebind_alloc<CharT> char_allocator_type; + + static constexpr size_t default_max_buffer_size = 16384; + + json_source_adaptor<Source> source_; + basic_default_json_visitor<CharT> default_visitor_; + basic_json_visitor<CharT>& visitor_; + basic_json_parser<CharT,Allocator> parser_; + + // Noncopyable and nonmoveable + basic_json_reader(const basic_json_reader&) = delete; + basic_json_reader& operator=(const basic_json_reader&) = delete; + + public: + template <class Sourceable> + explicit basic_json_reader(Sourceable&& source, const Allocator& alloc = Allocator()) + : basic_json_reader(std::forward<Sourceable>(source), + default_visitor_, + basic_json_decode_options<CharT>(), + default_json_parsing(), + alloc) + { + } + + template <class Sourceable> + basic_json_reader(Sourceable&& source, + const basic_json_decode_options<CharT>& options, + const Allocator& alloc = Allocator()) + : basic_json_reader(std::forward<Sourceable>(source), + default_visitor_, + options, + default_json_parsing(), + alloc) + { + } + + template <class Sourceable> + basic_json_reader(Sourceable&& source, + std::function<bool(json_errc,const ser_context&)> err_handler, + const Allocator& alloc = Allocator()) + : basic_json_reader(std::forward<Sourceable>(source), + default_visitor_, + basic_json_decode_options<CharT>(), + err_handler, + alloc) + { + } + + template <class Sourceable> + basic_json_reader(Sourceable&& source, + const basic_json_decode_options<CharT>& options, + std::function<bool(json_errc,const ser_context&)> err_handler, + const Allocator& alloc = Allocator()) + : basic_json_reader(std::forward<Sourceable>(source), + default_visitor_, + options, + err_handler, + alloc) + { + } + + template <class Sourceable> + basic_json_reader(Sourceable&& source, + basic_json_visitor<CharT>& visitor, + const Allocator& alloc = Allocator()) + : basic_json_reader(std::forward<Sourceable>(source), + visitor, + basic_json_decode_options<CharT>(), + default_json_parsing(), + alloc) + { + } + + template <class Sourceable> + basic_json_reader(Sourceable&& source, + basic_json_visitor<CharT>& visitor, + const basic_json_decode_options<CharT>& options, + const Allocator& alloc = Allocator()) + : basic_json_reader(std::forward<Sourceable>(source), + visitor, + options, + default_json_parsing(), + alloc) + { + } + + template <class Sourceable> + basic_json_reader(Sourceable&& source, + basic_json_visitor<CharT>& visitor, + std::function<bool(json_errc,const ser_context&)> err_handler, + const Allocator& alloc = Allocator()) + : basic_json_reader(std::forward<Sourceable>(source), + visitor, + basic_json_decode_options<CharT>(), + err_handler, + alloc) + { + } + + template <class Sourceable> + basic_json_reader(Sourceable&& source, + basic_json_visitor<CharT>& visitor, + const basic_json_decode_options<CharT>& options, + std::function<bool(json_errc,const ser_context&)> err_handler, + const Allocator& alloc = Allocator()) + : source_(std::forward<Sourceable>(source)), + visitor_(visitor), + parser_(options,err_handler,alloc) + { + } + +#if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use max_nesting_depth() on options") + int max_nesting_depth() const + { + return parser_.max_nesting_depth(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use max_nesting_depth(int) on options") + void max_nesting_depth(int depth) + { + parser_.max_nesting_depth(depth); + } +#endif + void read_next() + { + std::error_code ec; + read_next(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); + } + } + + void read_next(std::error_code& ec) + { + if (source_.is_error()) + { + ec = json_errc::source_error; + return; + } + parser_.reset(); + while (!parser_.stopped()) + { + if (parser_.source_exhausted()) + { + auto s = source_.read_buffer(ec); + if (ec) return; + if (s.size() > 0) + { + parser_.update(s.data(),s.size()); + } + } + bool eof = parser_.source_exhausted(); + parser_.parse_some(visitor_, ec); + if (ec) return; + if (eof) + { + if (parser_.enter()) + { + break; + } + else if (!parser_.accept()) + { + ec = json_errc::unexpected_eof; + return; + } + } + } + + while (!source_.eof()) + { + parser_.skip_whitespace(); + if (parser_.source_exhausted()) + { + auto s = source_.read_buffer(ec); + if (ec) return; + if (s.size() > 0) + { + parser_.update(s.data(),s.size()); + } + } + else + { + break; + } + } + } + + void check_done() + { + std::error_code ec; + check_done(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); + } + } + + std::size_t line() const + { + return parser_.line(); + } + + std::size_t column() const + { + return parser_.column(); + } + + void check_done(std::error_code& ec) + { + if (source_.is_error()) + { + ec = json_errc::source_error; + return; + } + if (source_.eof()) + { + parser_.check_done(ec); + if (ec) return; + } + else + { + do + { + if (parser_.source_exhausted()) + { + auto s = source_.read_buffer(ec); + if (ec) return; + if (s.size() > 0) + { + parser_.update(s.data(),s.size()); + } + } + if (!parser_.source_exhausted()) + { + parser_.check_done(ec); + if (ec) return; + } + } + while (!eof()); + } + } + + bool eof() const + { + return parser_.source_exhausted() && source_.eof(); + } + + void read() + { + read_next(); + check_done(); + } + + void read(std::error_code& ec) + { + read_next(ec); + if (!ec) + { + check_done(ec); + } + } + }; + + template<class CharT,class Source=jsoncons::stream_source<CharT>,class Allocator=std::allocator<char>> + class legacy_basic_json_reader + { + public: + using char_type = CharT; + using source_type = Source; + using string_view_type = jsoncons::basic_string_view<CharT>; + private: + typedef typename std::allocator_traits<Allocator>:: template rebind_alloc<CharT> char_allocator_type; + + static constexpr size_t default_max_buffer_size = 16384; + + json_source_adaptor<Source> source_; + basic_default_json_visitor<CharT> default_visitor_; + basic_json_visitor<CharT>& visitor_; + basic_json_parser<CharT,Allocator> parser_; + + // Noncopyable and nonmoveable + legacy_basic_json_reader(const legacy_basic_json_reader&) = delete; + legacy_basic_json_reader& operator=(const legacy_basic_json_reader&) = delete; + + public: + template <class Sourceable> + explicit legacy_basic_json_reader(Sourceable&& source, const Allocator& alloc = Allocator()) + : legacy_basic_json_reader(std::forward<Sourceable>(source), + default_visitor_, + basic_json_decode_options<CharT>(), + default_json_parsing(), + alloc) + { + } + + template <class Sourceable> + legacy_basic_json_reader(Sourceable&& source, + const basic_json_decode_options<CharT>& options, + const Allocator& alloc = Allocator()) + : legacy_basic_json_reader(std::forward<Sourceable>(source), + default_visitor_, + options, + default_json_parsing(), + alloc) + { + } + + template <class Sourceable> + legacy_basic_json_reader(Sourceable&& source, + std::function<bool(json_errc,const ser_context&)> err_handler, + const Allocator& alloc = Allocator()) + : legacy_basic_json_reader(std::forward<Sourceable>(source), + default_visitor_, + basic_json_decode_options<CharT>(), + err_handler, + alloc) + { + } + + template <class Sourceable> + legacy_basic_json_reader(Sourceable&& source, + const basic_json_decode_options<CharT>& options, + std::function<bool(json_errc,const ser_context&)> err_handler, + const Allocator& alloc = Allocator()) + : legacy_basic_json_reader(std::forward<Sourceable>(source), + default_visitor_, + options, + err_handler, + alloc) + { + } + + template <class Sourceable> + legacy_basic_json_reader(Sourceable&& source, + basic_json_visitor<CharT>& visitor, + const Allocator& alloc = Allocator()) + : legacy_basic_json_reader(std::forward<Sourceable>(source), + visitor, + basic_json_decode_options<CharT>(), + default_json_parsing(), + alloc) + { + } + + template <class Sourceable> + legacy_basic_json_reader(Sourceable&& source, + basic_json_visitor<CharT>& visitor, + const basic_json_decode_options<CharT>& options, + const Allocator& alloc = Allocator()) + : legacy_basic_json_reader(std::forward<Sourceable>(source), + visitor, + options, + default_json_parsing(), + alloc) + { + } + + template <class Sourceable> + legacy_basic_json_reader(Sourceable&& source, + basic_json_visitor<CharT>& visitor, + std::function<bool(json_errc,const ser_context&)> err_handler, + const Allocator& alloc = Allocator()) + : legacy_basic_json_reader(std::forward<Sourceable>(source), + visitor, + basic_json_decode_options<CharT>(), + err_handler, + alloc) + { + } + + template <class Sourceable> + legacy_basic_json_reader(Sourceable&& source, + basic_json_visitor<CharT>& visitor, + const basic_json_decode_options<CharT>& options, + std::function<bool(json_errc,const ser_context&)> err_handler, + const Allocator& alloc = Allocator(), + typename std::enable_if<!std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type* = 0) + : source_(std::forward<Sourceable>(source)), + visitor_(visitor), + parser_(options,err_handler,alloc) + { + } + + template <class Sourceable> + legacy_basic_json_reader(Sourceable&& source, + basic_json_visitor<CharT>& visitor, + const basic_json_decode_options<CharT>& options, + std::function<bool(json_errc,const ser_context&)> err_handler, + const Allocator& alloc = Allocator(), + typename std::enable_if<std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type* = 0) + : source_(), + visitor_(visitor), + parser_(options,err_handler,alloc) + { + jsoncons::basic_string_view<CharT> sv(std::forward<Sourceable>(source)); + + auto r = unicode_traits::detect_json_encoding(sv.data(), sv.size()); + if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected)) + { + JSONCONS_THROW(ser_error(json_errc::illegal_unicode_character,parser_.line(),parser_.column())); + } + std::size_t offset = (r.ptr - sv.data()); + parser_.update(sv.data()+offset,sv.size()-offset); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + JSONCONS_DEPRECATED_MSG("Instead, use max_nesting_depth() on options") + int max_nesting_depth() const + { + return parser_.max_nesting_depth(); + } + + JSONCONS_DEPRECATED_MSG("Instead, use max_nesting_depth(int) on options") + void max_nesting_depth(int depth) + { + parser_.max_nesting_depth(depth); + } +#endif + void read_next() + { + std::error_code ec; + read_next(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); + } + } + + void read_next(std::error_code& ec) + { + if (source_.is_error()) + { + ec = json_errc::source_error; + return; + } + parser_.reset(); + while (!parser_.stopped()) + { + if (parser_.source_exhausted()) + { + auto s = source_.read_buffer(ec); + if (ec) return; + if (s.size() > 0) + { + parser_.update(s.data(),s.size()); + } + } + bool eof = parser_.source_exhausted(); + parser_.parse_some(visitor_, ec); + if (ec) return; + if (eof) + { + if (parser_.enter()) + { + break; + } + else if (!parser_.accept()) + { + ec = json_errc::unexpected_eof; + return; + } + } + } + + while (!source_.eof()) + { + parser_.skip_whitespace(); + if (parser_.source_exhausted()) + { + auto s = source_.read_buffer(ec); + if (ec) return; + if (s.size() > 0) + { + parser_.update(s.data(),s.size()); + } + } + else + { + break; + } + } + } + + void check_done() + { + std::error_code ec; + check_done(ec); + if (ec) + { + JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column())); + } + } + + std::size_t line() const + { + return parser_.line(); + } + + std::size_t column() const + { + return parser_.column(); + } + + void check_done(std::error_code& ec) + { + if (source_.is_error()) + { + ec = json_errc::source_error; + return; + } + if (source_.eof()) + { + parser_.check_done(ec); + if (ec) return; + } + else + { + do + { + if (parser_.source_exhausted()) + { + auto s = source_.read_buffer(ec); + if (ec) return; + if (s.size() > 0) + { + parser_.update(s.data(),s.size()); + } + } + if (!parser_.source_exhausted()) + { + parser_.check_done(ec); + if (ec) return; + } + } + while (!eof()); + } + } + + bool eof() const + { + return parser_.source_exhausted() && source_.eof(); + } + + void read() + { + read_next(); + check_done(); + } + + void read(std::error_code& ec) + { + read_next(ec); + if (!ec) + { + check_done(ec); + } + } + }; + +#if !defined(JSONCONS_NO_DEPRECATED) + using json_reader = legacy_basic_json_reader<char>; + using wjson_reader = legacy_basic_json_reader<wchar_t>; +#endif + using json_string_reader = basic_json_reader<char,string_source<char>>; + using wjson_string_reader = basic_json_reader<wchar_t,string_source<wchar_t>>; + using json_stream_reader = basic_json_reader<char,stream_source<char>>; + using wjson_stream_reader = basic_json_reader<wchar_t,stream_source<wchar_t>>; +} + +#endif + |