// 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