// 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_PARSER_HPP #define JSONCONS_JSON_PARSER_HPP #include // std::allocator #include #include #include #include #include #include // std::numeric_limits #include // std::function #include #include #include #include #include #include #define JSONCONS_ILLEGAL_CONTROL_CHARACTER \ case 0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x0b: \ case 0x0c:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16: \ case 0x17:case 0x18:case 0x19:case 0x1a:case 0x1b:case 0x1c:case 0x1d:case 0x1e:case 0x1f namespace jsoncons { namespace detail { } enum class json_parse_state : uint8_t { root, start, accept, slash, slash_slash, slash_star, slash_star_star, expect_comma_or_end, object, expect_member_name_or_end, expect_member_name, expect_colon, expect_value_or_end, expect_value, array, string, member_name, escape, escape_u1, escape_u2, escape_u3, escape_u4, escape_expect_surrogate_pair1, escape_expect_surrogate_pair2, escape_u5, escape_u6, escape_u7, escape_u8, minus, zero, integer, fraction1, fraction2, exp1, exp2, exp3, n, nu, nul, t, tr, tru, f, fa, fal, fals, cr, done }; struct default_json_parsing { bool operator()(json_errc ec, const ser_context&) noexcept { if (ec == json_errc::illegal_comment) { return true; // Recover, allow comments } else { return false; } } }; struct strict_json_parsing { bool operator()(json_errc, const ser_context&) noexcept { return false; } }; #if !defined(JSONCONS_NO_DEPRECATED) JSONCONS_DEPRECATED_MSG("Instead, use default_json_parsing") typedef default_json_parsing default_parse_error_handler; JSONCONS_DEPRECATED_MSG("Instead, use strict_json_parsing") typedef strict_json_parsing strict_parse_error_handler; #endif template > class basic_json_parser : public ser_context { public: using char_type = CharT; using string_view_type = typename basic_json_visitor::string_view_type; private: struct string_maps_to_double { string_view_type s; bool operator()(const std::pair& val) const { return val.first == s; } }; using temp_allocator_type = TempAllocator; using char_allocator_type = typename std::allocator_traits:: template rebind_alloc; using parse_state_allocator_type = typename std::allocator_traits:: template rebind_alloc; static constexpr std::size_t initial_string_buffer_capacity_ = 1024; static constexpr std::size_t default_initial_stack_capacity_ = 100; basic_json_decode_options options_; std::function err_handler_; int initial_stack_capacity_; int nesting_depth_; uint32_t cp_; uint32_t cp2_; std::size_t line_; std::size_t position_; std::size_t mark_position_; std::size_t saved_position_; const char_type* begin_input_; const char_type* end_input_; const char_type* input_ptr_; json_parse_state state_; bool more_; bool done_; std::basic_string,char_allocator_type> string_buffer_; jsoncons::detail::chars_to to_double_; std::vector state_stack_; std::vector> string_double_map_; // Noncopyable and nonmoveable basic_json_parser(const basic_json_parser&) = delete; basic_json_parser& operator=(const basic_json_parser&) = delete; public: basic_json_parser(const TempAllocator& alloc = TempAllocator()) : basic_json_parser(basic_json_decode_options(), default_json_parsing(), alloc) { } basic_json_parser(std::function err_handler, const TempAllocator& alloc = TempAllocator()) : basic_json_parser(basic_json_decode_options(), err_handler, alloc) { } basic_json_parser(const basic_json_decode_options& options, const TempAllocator& alloc = TempAllocator()) : basic_json_parser(options, default_json_parsing(), alloc) { } basic_json_parser(const basic_json_decode_options& options, std::function err_handler, const TempAllocator& alloc = TempAllocator()) : options_(options), err_handler_(err_handler), initial_stack_capacity_(default_initial_stack_capacity_), nesting_depth_(0), cp_(0), cp2_(0), line_(1), position_(0), mark_position_(0), saved_position_(0), begin_input_(nullptr), end_input_(nullptr), input_ptr_(nullptr), state_(json_parse_state::start), more_(true), done_(false), string_buffer_(alloc), state_stack_(alloc) { string_buffer_.reserve(initial_string_buffer_capacity_); state_stack_.reserve(initial_stack_capacity_); push_state(json_parse_state::root); if (options_.enable_str_to_nan()) { string_double_map_.emplace_back(options_.nan_to_str(),std::nan("")); } if (options_.enable_str_to_inf()) { string_double_map_.emplace_back(options_.inf_to_str(),std::numeric_limits::infinity()); } if (options_.enable_str_to_neginf()) { string_double_map_.emplace_back(options_.neginf_to_str(),-std::numeric_limits::infinity()); } } bool source_exhausted() const { return input_ptr_ == end_input_; } ~basic_json_parser() noexcept { } json_parse_state parent() const { JSONCONS_ASSERT(state_stack_.size() >= 1); return state_stack_.back(); } bool done() const { return done_; } bool enter() const { return state_ == json_parse_state::start; } bool accept() const { return state_ == json_parse_state::accept || done_; } bool stopped() const { return !more_; } json_parse_state state() const { return state_; } bool finished() const { return !more_ && state_ != json_parse_state::accept; } const char_type* first() const { return begin_input_; } const char_type* current() const { return input_ptr_; } const char_type* last() const { return end_input_; } void skip_space() { const char_type* local_input_end = end_input_; while (input_ptr_ != local_input_end) { switch (*input_ptr_) { case ' ': case '\t': ++input_ptr_; ++position_; break; case '\r': push_state(state_); ++input_ptr_; ++position_; state_ = json_parse_state::cr; return; case '\n': ++input_ptr_; ++line_; ++position_; mark_position_ = position_; return; default: return; } } } void skip_whitespace() { const char_type* local_input_end = end_input_; while (input_ptr_ != local_input_end) { switch (state_) { case json_parse_state::cr: ++line_; ++position_; mark_position_ = position_; switch (*input_ptr_) { case '\n': ++input_ptr_; ++position_; state_ = pop_state(); break; default: state_ = pop_state(); break; } break; default: switch (*input_ptr_) { case ' ': case '\t': case '\n': case '\r': skip_space(); break; default: return; } break; } } } void begin_object(basic_json_visitor& visitor, std::error_code& ec) { if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) { more_ = err_handler_(json_errc::max_nesting_depth_exceeded, *this); if (!more_) { ec = json_errc::max_nesting_depth_exceeded; return; } } push_state(json_parse_state::object); state_ = json_parse_state::expect_member_name_or_end; more_ = visitor.begin_object(semantic_tag::none, *this, ec); } void end_object(basic_json_visitor& visitor, std::error_code& ec) { if (JSONCONS_UNLIKELY(nesting_depth_ < 1)) { err_handler_(json_errc::unexpected_rbrace, *this); ec = json_errc::unexpected_rbrace; more_ = false; return; } --nesting_depth_; state_ = pop_state(); if (state_ == json_parse_state::object) { more_ = visitor.end_object(*this, ec); } else if (state_ == json_parse_state::array) { err_handler_(json_errc::expected_comma_or_rbracket, *this); ec = json_errc::expected_comma_or_rbracket; more_ = false; return; } else { err_handler_(json_errc::unexpected_rbrace, *this); ec = json_errc::unexpected_rbrace; more_ = false; return; } if (parent() == json_parse_state::root) { state_ = json_parse_state::accept; } else { state_ = json_parse_state::expect_comma_or_end; } } void begin_array(basic_json_visitor& visitor, std::error_code& ec) { if (++nesting_depth_ > options_.max_nesting_depth()) { more_ = err_handler_(json_errc::max_nesting_depth_exceeded, *this); if (!more_) { ec = json_errc::max_nesting_depth_exceeded; return; } } push_state(json_parse_state::array); state_ = json_parse_state::expect_value_or_end; more_ = visitor.begin_array(semantic_tag::none, *this, ec); } void end_array(basic_json_visitor& visitor, std::error_code& ec) { if (nesting_depth_ < 1) { err_handler_(json_errc::unexpected_rbracket, *this); ec = json_errc::unexpected_rbracket; more_ = false; return; } --nesting_depth_; state_ = pop_state(); if (state_ == json_parse_state::array) { more_ = visitor.end_array(*this, ec); } else if (state_ == json_parse_state::object) { err_handler_(json_errc::expected_comma_or_rbrace, *this); ec = json_errc::expected_comma_or_rbrace; more_ = false; return; } else { err_handler_(json_errc::unexpected_rbracket, *this); ec = json_errc::unexpected_rbracket; more_ = false; return; } if (parent() == json_parse_state::root) { state_ = json_parse_state::accept; } else { state_ = json_parse_state::expect_comma_or_end; } } void reinitialize() { reset(); cp_ = 0; cp2_ = 0; saved_position_ = 0; begin_input_ = nullptr; end_input_ = nullptr; input_ptr_ = nullptr; string_buffer_.clear(); } void reset() { state_stack_.clear(); state_stack_.reserve(initial_stack_capacity_); push_state(json_parse_state::root); state_ = json_parse_state::start; more_ = true; done_ = false; line_ = 1; position_ = 0; mark_position_ = 0; nesting_depth_ = 0; } void restart() { more_ = true; } void check_done() { std::error_code ec; check_done(ec); if (ec) { JSONCONS_THROW(ser_error(ec,line_,column())); } } void check_done(std::error_code& ec) { for (; input_ptr_ != end_input_; ++input_ptr_) { char_type curr_char_ = *input_ptr_; switch (curr_char_) { case '\n': case '\r': case '\t': case ' ': break; default: more_ = err_handler_(json_errc::extra_character, *this); if (!more_) { ec = json_errc::extra_character; return; } break; } } } void update(const string_view_type sv) { update(sv.data(),sv.length()); } void update(const char_type* data, std::size_t length) { begin_input_ = data; end_input_ = data + length; input_ptr_ = begin_input_; } void parse_some(basic_json_visitor& visitor) { std::error_code ec; parse_some(visitor, ec); if (ec) { JSONCONS_THROW(ser_error(ec,line_,column())); } } void parse_some(basic_json_visitor& visitor, std::error_code& ec) { parse_some_(visitor, ec); } void finish_parse(basic_json_visitor& visitor) { std::error_code ec; finish_parse(visitor, ec); if (ec) { JSONCONS_THROW(ser_error(ec,line_,column())); } } void finish_parse(basic_json_visitor& visitor, std::error_code& ec) { while (!finished()) { parse_some(visitor, ec); } } void parse_some_(basic_json_visitor& visitor, std::error_code& ec) { if (state_ == json_parse_state::accept) { visitor.flush(); done_ = true; state_ = json_parse_state::done; more_ = false; return; } const char_type* local_input_end = end_input_; if (input_ptr_ == local_input_end && more_) { switch (state_) { case json_parse_state::zero: case json_parse_state::integer: end_integer_value(visitor, ec); if (ec) return; break; case json_parse_state::fraction2: end_fraction_value(visitor, ec); if (ec) return; break; case json_parse_state::exp3: end_fraction_value(visitor, ec); if (ec) return; break; case json_parse_state::accept: visitor.flush(); done_ = true; state_ = json_parse_state::done; more_ = false; break; case json_parse_state::start: case json_parse_state::done: more_ = false; break; case json_parse_state::cr: state_ = pop_state(); break; default: err_handler_(json_errc::unexpected_eof, *this); ec = json_errc::unexpected_eof; more_ = false; return; } } while ((input_ptr_ < local_input_end) && more_) { switch (state_) { case json_parse_state::accept: visitor.flush(); done_ = true; state_ = json_parse_state::done; more_ = false; break; case json_parse_state::cr: ++line_; mark_position_ = position_; switch (*input_ptr_) { case '\n': ++input_ptr_; ++position_; state_ = pop_state(); break; default: state_ = pop_state(); break; } break; case json_parse_state::start: { switch (*input_ptr_) { JSONCONS_ILLEGAL_CONTROL_CHARACTER: more_ = err_handler_(json_errc::illegal_control_character, *this); if (!more_) { ec = json_errc::illegal_control_character; return; } break; case '\r': push_state(state_); ++input_ptr_; ++position_; state_ = json_parse_state::cr; break; case '\n': ++input_ptr_; ++line_; ++position_; mark_position_ = position_; break; case ' ':case '\t': skip_space(); break; case '/': ++input_ptr_; ++position_; push_state(state_); state_ = json_parse_state::slash; break; case '{': begin_object(visitor, ec); if (ec) return; ++input_ptr_; ++position_; break; case '[': begin_array(visitor, ec); if (ec) return; ++input_ptr_; ++position_; break; case '\"': state_ = json_parse_state::string; ++input_ptr_; ++position_; string_buffer_.clear(); parse_string(visitor, ec); if (ec) return; break; case '-': string_buffer_.clear(); string_buffer_.push_back('-'); ++input_ptr_; ++position_; state_ = json_parse_state::minus; parse_number(visitor, ec); if (ec) {return;} break; case '0': string_buffer_.clear(); string_buffer_.push_back(static_cast(*input_ptr_)); state_ = json_parse_state::zero; ++input_ptr_; ++position_; parse_number(visitor, ec); if (ec) {return;} break; case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': string_buffer_.clear(); string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; state_ = json_parse_state::integer; parse_number(visitor, ec); if (ec) {return;} break; case 'n': parse_null(visitor, ec); if (ec) {return;} break; case 't': parse_true(visitor, ec); if (ec) {return;} break; case 'f': parse_false(visitor, ec); if (ec) {return;} break; case '}': err_handler_(json_errc::unexpected_rbrace, *this); ec = json_errc::unexpected_rbrace; more_ = false; return; case ']': err_handler_(json_errc::unexpected_rbracket, *this); ec = json_errc::unexpected_rbracket; more_ = false; return; default: err_handler_(json_errc::syntax_error, *this); ec = json_errc::syntax_error; more_ = false; return; } } break; case json_parse_state::expect_comma_or_end: { switch (*input_ptr_) { JSONCONS_ILLEGAL_CONTROL_CHARACTER: more_ = err_handler_(json_errc::illegal_control_character, *this); if (!more_) { ec = json_errc::illegal_control_character; return; } ++input_ptr_; ++position_; break; case '\r': ++input_ptr_; ++position_; push_state(state_); state_ = json_parse_state::cr; break; case '\n': ++input_ptr_; ++line_; ++position_; mark_position_ = position_; break; case ' ':case '\t': skip_space(); break; case '/': ++input_ptr_; ++position_; push_state(state_); state_ = json_parse_state::slash; break; case '}': end_object(visitor, ec); if (ec) return; ++input_ptr_; ++position_; break; case ']': end_array(visitor, ec); if (ec) return; ++input_ptr_; ++position_; break; case ',': begin_member_or_element(ec); if (ec) return; ++input_ptr_; ++position_; break; default: if (parent() == json_parse_state::array) { more_ = err_handler_(json_errc::expected_comma_or_rbracket, *this); if (!more_) { ec = json_errc::expected_comma_or_rbracket; return; } } else if (parent() == json_parse_state::object) { more_ = err_handler_(json_errc::expected_comma_or_rbrace, *this); if (!more_) { ec = json_errc::expected_comma_or_rbrace; return; } } ++input_ptr_; ++position_; break; } } break; case json_parse_state::expect_member_name_or_end: { switch (*input_ptr_) { JSONCONS_ILLEGAL_CONTROL_CHARACTER: more_ = err_handler_(json_errc::illegal_control_character, *this); if (!more_) { ec = json_errc::illegal_control_character; return; } ++input_ptr_; ++position_; break; case '\r': ++input_ptr_; ++position_; push_state(state_); state_ = json_parse_state::cr; break; case '\n': ++input_ptr_; ++line_; ++position_; mark_position_ = position_; break; case ' ':case '\t': skip_space(); break; case '/': ++input_ptr_; ++position_; push_state(state_); state_ = json_parse_state::slash; break; case '}': end_object(visitor, ec); if (ec) return; ++input_ptr_; ++position_; break; case '\"': ++input_ptr_; ++position_; push_state(json_parse_state::member_name); state_ = json_parse_state::string; string_buffer_.clear(); parse_string(visitor, ec); if (ec) return; break; case '\'': more_ = err_handler_(json_errc::single_quote, *this); if (!more_) { ec = json_errc::single_quote; return; } ++input_ptr_; ++position_; break; default: more_ = err_handler_(json_errc::expected_key, *this); if (!more_) { ec = json_errc::expected_key; return; } ++input_ptr_; ++position_; break; } } break; case json_parse_state::expect_member_name: { switch (*input_ptr_) { JSONCONS_ILLEGAL_CONTROL_CHARACTER: more_ = err_handler_(json_errc::illegal_control_character, *this); if (!more_) { ec = json_errc::illegal_control_character; return; } ++input_ptr_; ++position_; break; case '\r': ++input_ptr_; ++position_; push_state(state_); state_ = json_parse_state::cr; break; case '\n': ++input_ptr_; ++line_; ++position_; mark_position_ = position_; break; case ' ':case '\t': skip_space(); break; case '/': ++input_ptr_; ++position_; push_state(state_); state_ = json_parse_state::slash; break; case '\"': ++input_ptr_; ++position_; push_state(json_parse_state::member_name); state_ = json_parse_state::string; string_buffer_.clear(); parse_string(visitor, ec); if (ec) return; break; case '}': more_ = err_handler_(json_errc::extra_comma, *this); if (!more_) { ec = json_errc::extra_comma; return; } end_object(visitor, ec); // Recover if (ec) return; ++input_ptr_; ++position_; break; case '\'': more_ = err_handler_(json_errc::single_quote, *this); if (!more_) { ec = json_errc::single_quote; return; } ++input_ptr_; ++position_; break; default: more_ = err_handler_(json_errc::expected_key, *this); if (!more_) { ec = json_errc::expected_key; return; } ++input_ptr_; ++position_; break; } } break; case json_parse_state::expect_colon: { switch (*input_ptr_) { JSONCONS_ILLEGAL_CONTROL_CHARACTER: more_ = err_handler_(json_errc::illegal_control_character, *this); if (!more_) { ec = json_errc::illegal_control_character; return; } ++input_ptr_; ++position_; break; case '\r': push_state(state_); state_ = json_parse_state::cr; ++input_ptr_; ++position_; break; case '\n': ++input_ptr_; ++line_; ++position_; mark_position_ = position_; break; case ' ':case '\t': skip_space(); break; case '/': push_state(state_); state_ = json_parse_state::slash; ++input_ptr_; ++position_; break; case ':': state_ = json_parse_state::expect_value; ++input_ptr_; ++position_; break; default: more_ = err_handler_(json_errc::expected_colon, *this); if (!more_) { ec = json_errc::expected_colon; return; } ++input_ptr_; ++position_; break; } } break; case json_parse_state::expect_value: { switch (*input_ptr_) { JSONCONS_ILLEGAL_CONTROL_CHARACTER: more_ = err_handler_(json_errc::illegal_control_character, *this); if (!more_) { ec = json_errc::illegal_control_character; return; } ++input_ptr_; ++position_; break; case '\r': push_state(state_); ++input_ptr_; ++position_; state_ = json_parse_state::cr; break; case '\n': ++input_ptr_; ++line_; ++position_; mark_position_ = position_; break; case ' ':case '\t': skip_space(); break; case '/': push_state(state_); ++input_ptr_; ++position_; state_ = json_parse_state::slash; break; case '{': begin_object(visitor, ec); if (ec) return; ++input_ptr_; ++position_; break; case '[': begin_array(visitor, ec); if (ec) return; ++input_ptr_; ++position_; break; case '\"': ++input_ptr_; ++position_; state_ = json_parse_state::string; string_buffer_.clear(); parse_string(visitor, ec); if (ec) return; break; case '-': string_buffer_.clear(); string_buffer_.push_back('-'); ++input_ptr_; ++position_; state_ = json_parse_state::minus; parse_number(visitor, ec); if (ec) {return;} break; case '0': string_buffer_.clear(); string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; state_ = json_parse_state::zero; parse_number(visitor, ec); if (ec) {return;} break; case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': string_buffer_.clear(); string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; state_ = json_parse_state::integer; parse_number(visitor, ec); if (ec) {return;} break; case 'n': parse_null(visitor, ec); if (ec) {return;} break; case 't': parse_true(visitor, ec); if (ec) {return;} break; case 'f': parse_false(visitor, ec); if (ec) {return;} break; case ']': if (parent() == json_parse_state::array) { more_ = err_handler_(json_errc::extra_comma, *this); if (!more_) { ec = json_errc::extra_comma; return; } end_array(visitor, ec); // Recover if (ec) return; } else { more_ = err_handler_(json_errc::expected_value, *this); if (!more_) { ec = json_errc::expected_value; return; } } ++input_ptr_; ++position_; break; case '\'': more_ = err_handler_(json_errc::single_quote, *this); if (!more_) { ec = json_errc::single_quote; return; } ++input_ptr_; ++position_; break; default: more_ = err_handler_(json_errc::expected_value, *this); if (!more_) { ec = json_errc::expected_value; return; } ++input_ptr_; ++position_; break; } } break; case json_parse_state::expect_value_or_end: { switch (*input_ptr_) { JSONCONS_ILLEGAL_CONTROL_CHARACTER: more_ = err_handler_(json_errc::illegal_control_character, *this); if (!more_) { ec = json_errc::illegal_control_character; return; } ++input_ptr_; ++position_; break; case '\r': ++input_ptr_; ++position_; push_state(state_); state_ = json_parse_state::cr; break; case '\n': ++input_ptr_; ++line_; ++position_; mark_position_ = position_; break; case ' ':case '\t': skip_space(); break; case '/': ++input_ptr_; ++position_; push_state(state_); state_ = json_parse_state::slash; break; case '{': begin_object(visitor, ec); if (ec) return; ++input_ptr_; ++position_; break; case '[': begin_array(visitor, ec); if (ec) return; ++input_ptr_; ++position_; break; case ']': end_array(visitor, ec); if (ec) return; ++input_ptr_; ++position_; break; case '\"': ++input_ptr_; ++position_; state_ = json_parse_state::string; string_buffer_.clear(); parse_string(visitor, ec); if (ec) return; break; case '-': string_buffer_.clear(); string_buffer_.push_back('-'); ++input_ptr_; ++position_; state_ = json_parse_state::minus; parse_number(visitor, ec); if (ec) {return;} break; case '0': string_buffer_.clear(); string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; state_ = json_parse_state::zero; parse_number(visitor, ec); if (ec) {return;} break; case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': string_buffer_.clear(); string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; state_ = json_parse_state::integer; parse_number(visitor, ec); if (ec) {return;} break; case 'n': parse_null(visitor, ec); if (ec) {return;} break; case 't': parse_true(visitor, ec); if (ec) {return;} break; case 'f': parse_false(visitor, ec); if (ec) {return;} break; case '\'': more_ = err_handler_(json_errc::single_quote, *this); if (!more_) { ec = json_errc::single_quote; return; } ++input_ptr_; ++position_; break; default: more_ = err_handler_(json_errc::expected_value, *this); if (!more_) { ec = json_errc::expected_value; return; } ++input_ptr_; ++position_; break; } } break; case json_parse_state::string: case json_parse_state::escape: case json_parse_state::escape_u1: case json_parse_state::escape_u2: case json_parse_state::escape_u3: case json_parse_state::escape_u4: case json_parse_state::escape_expect_surrogate_pair1: case json_parse_state::escape_expect_surrogate_pair2: case json_parse_state::escape_u5: case json_parse_state::escape_u6: case json_parse_state::escape_u7: case json_parse_state::escape_u8: parse_string(visitor, ec); if (ec) return; break; case json_parse_state::minus: case json_parse_state::zero: case json_parse_state::integer: case json_parse_state::fraction1: case json_parse_state::fraction2: case json_parse_state::exp1: case json_parse_state::exp2: case json_parse_state::exp3: parse_number(visitor, ec); if (ec) return; break; case json_parse_state::t: switch (*input_ptr_) { case 'r': ++input_ptr_; ++position_; state_ = json_parse_state::tr; break; default: err_handler_(json_errc::invalid_value, *this); ec = json_errc::invalid_value; more_ = false; return; } break; case json_parse_state::tr: switch (*input_ptr_) { case 'u': state_ = json_parse_state::tru; break; default: err_handler_(json_errc::invalid_value, *this); ec = json_errc::invalid_value; more_ = false; return; } ++input_ptr_; ++position_; break; case json_parse_state::tru: switch (*input_ptr_) { case 'e': more_ = visitor.bool_value(true, semantic_tag::none, *this, ec); if (parent() == json_parse_state::root) { state_ = json_parse_state::accept; } else { state_ = json_parse_state::expect_comma_or_end; } break; default: err_handler_(json_errc::invalid_value, *this); ec = json_errc::invalid_value; more_ = false; return; } ++input_ptr_; ++position_; break; case json_parse_state::f: switch (*input_ptr_) { case 'a': ++input_ptr_; ++position_; state_ = json_parse_state::fa; break; default: err_handler_(json_errc::invalid_value, *this); ec = json_errc::invalid_value; more_ = false; return; } break; case json_parse_state::fa: switch (*input_ptr_) { case 'l': state_ = json_parse_state::fal; break; default: err_handler_(json_errc::invalid_value, *this); ec = json_errc::invalid_value; more_ = false; return; } ++input_ptr_; ++position_; break; case json_parse_state::fal: switch (*input_ptr_) { case 's': state_ = json_parse_state::fals; break; default: err_handler_(json_errc::invalid_value, *this); ec = json_errc::invalid_value; more_ = false; return; } ++input_ptr_; ++position_; break; case json_parse_state::fals: switch (*input_ptr_) { case 'e': more_ = visitor.bool_value(false, semantic_tag::none, *this, ec); if (parent() == json_parse_state::root) { state_ = json_parse_state::accept; } else { state_ = json_parse_state::expect_comma_or_end; } break; default: err_handler_(json_errc::invalid_value, *this); ec = json_errc::invalid_value; more_ = false; return; } ++input_ptr_; ++position_; break; case json_parse_state::n: switch (*input_ptr_) { case 'u': ++input_ptr_; ++position_; state_ = json_parse_state::nu; break; default: err_handler_(json_errc::invalid_value, *this); ec = json_errc::invalid_value; more_ = false; return; } break; case json_parse_state::nu: switch (*input_ptr_) { case 'l': state_ = json_parse_state::nul; break; default: err_handler_(json_errc::invalid_value, *this); ec = json_errc::invalid_value; more_ = false; return; } ++input_ptr_; ++position_; break; case json_parse_state::nul: switch (*input_ptr_) { case 'l': more_ = visitor.null_value(semantic_tag::none, *this, ec); if (parent() == json_parse_state::root) { state_ = json_parse_state::accept; } else { state_ = json_parse_state::expect_comma_or_end; } break; default: err_handler_(json_errc::invalid_value, *this); ec = json_errc::invalid_value; more_ = false; return; } ++input_ptr_; ++position_; break; case json_parse_state::slash: { switch (*input_ptr_) { case '*': state_ = json_parse_state::slash_star; more_ = err_handler_(json_errc::illegal_comment, *this); if (!more_) { ec = json_errc::illegal_comment; return; } break; case '/': state_ = json_parse_state::slash_slash; more_ = err_handler_(json_errc::illegal_comment, *this); if (!more_) { ec = json_errc::illegal_comment; return; } break; default: more_ = err_handler_(json_errc::syntax_error, *this); if (!more_) { ec = json_errc::syntax_error; return; } break; } ++input_ptr_; ++position_; break; } case json_parse_state::slash_star: { switch (*input_ptr_) { case '\r': push_state(state_); ++input_ptr_; ++position_; state_ = json_parse_state::cr; break; case '\n': ++input_ptr_; ++line_; ++position_; mark_position_ = position_; break; case '*': ++input_ptr_; ++position_; state_ = json_parse_state::slash_star_star; break; default: ++input_ptr_; ++position_; break; } break; } case json_parse_state::slash_slash: { switch (*input_ptr_) { case '\r': state_ = pop_state(); break; case '\n': state_ = pop_state(); break; default: ++input_ptr_; ++position_; } break; } case json_parse_state::slash_star_star: { switch (*input_ptr_) { case '/': state_ = pop_state(); break; default: state_ = json_parse_state::slash_star; break; } ++input_ptr_; ++position_; break; } default: JSONCONS_ASSERT(false); break; } } } void parse_true(basic_json_visitor& visitor, std::error_code& ec) { saved_position_ = position_; if (JSONCONS_LIKELY(end_input_ - input_ptr_ >= 4)) { if (*(input_ptr_+1) == 'r' && *(input_ptr_+2) == 'u' && *(input_ptr_+3) == 'e') { more_ = visitor.bool_value(true, semantic_tag::none, *this, ec); input_ptr_ += 4; position_ += 4; if (parent() == json_parse_state::root) { state_ = json_parse_state::accept; } else { state_ = json_parse_state::expect_comma_or_end; } } else { err_handler_(json_errc::invalid_value, *this); ec = json_errc::invalid_value; more_ = false; return; } } else { ++input_ptr_; ++position_; state_ = json_parse_state::t; } } void parse_null(basic_json_visitor& visitor, std::error_code& ec) { saved_position_ = position_; if (JSONCONS_LIKELY(end_input_ - input_ptr_ >= 4)) { if (*(input_ptr_+1) == 'u' && *(input_ptr_+2) == 'l' && *(input_ptr_+3) == 'l') { more_ = visitor.null_value(semantic_tag::none, *this, ec); input_ptr_ += 4; position_ += 4; if (parent() == json_parse_state::root) { state_ = json_parse_state::accept; } else { state_ = json_parse_state::expect_comma_or_end; } } else { err_handler_(json_errc::invalid_value, *this); ec = json_errc::invalid_value; more_ = false; return; } } else { ++input_ptr_; ++position_; state_ = json_parse_state::n; } } void parse_false(basic_json_visitor& visitor, std::error_code& ec) { saved_position_ = position_; if (JSONCONS_LIKELY(end_input_ - input_ptr_ >= 5)) { if (*(input_ptr_+1) == 'a' && *(input_ptr_+2) == 'l' && *(input_ptr_+3) == 's' && *(input_ptr_+4) == 'e') { more_ = visitor.bool_value(false, semantic_tag::none, *this, ec); input_ptr_ += 5; position_ += 5; if (parent() == json_parse_state::root) { state_ = json_parse_state::accept; } else { state_ = json_parse_state::expect_comma_or_end; } } else { err_handler_(json_errc::invalid_value, *this); ec = json_errc::invalid_value; more_ = false; return; } } else { ++input_ptr_; ++position_; state_ = json_parse_state::f; } } void parse_number(basic_json_visitor& visitor, std::error_code& ec) { saved_position_ = position_ - 1; const char_type* local_input_end = end_input_; switch (state_) { case json_parse_state::minus: goto minus_sign; case json_parse_state::zero: goto zero; case json_parse_state::integer: goto integer; case json_parse_state::fraction1: goto fraction1; case json_parse_state::fraction2: goto fraction2; case json_parse_state::exp1: goto exp1; case json_parse_state::exp2: goto exp2; case json_parse_state::exp3: goto exp3; default: JSONCONS_UNREACHABLE(); } minus_sign: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::minus; return; } switch (*input_ptr_) { case '0': string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; goto zero; case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; goto integer; default: err_handler_(json_errc::invalid_number, *this); ec = json_errc::expected_value; more_ = false; return; } zero: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::zero; return; } switch (*input_ptr_) { case '\r': end_integer_value(visitor, ec); if (ec) return; ++input_ptr_; ++position_; push_state(state_); state_ = json_parse_state::cr; return; case '\n': end_integer_value(visitor, ec); if (ec) return; ++input_ptr_; ++line_; ++position_; mark_position_ = position_; return; case ' ':case '\t': end_integer_value(visitor, ec); if (ec) return; skip_space(); return; case '/': end_integer_value(visitor, ec); if (ec) return; ++input_ptr_; ++position_; push_state(state_); state_ = json_parse_state::slash; return; case '}': end_integer_value(visitor, ec); if (ec) return; state_ = json_parse_state::expect_comma_or_end; return; case ']': end_integer_value(visitor, ec); if (ec) return; state_ = json_parse_state::expect_comma_or_end; return; case '.': string_buffer_.push_back(to_double_.get_decimal_point()); ++input_ptr_; ++position_; goto fraction1; case 'e':case 'E': string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; goto exp1; case ',': end_integer_value(visitor, ec); if (ec) return; begin_member_or_element(ec); if (ec) return; ++input_ptr_; ++position_; return; case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': err_handler_(json_errc::leading_zero, *this); ec = json_errc::leading_zero; more_ = false; state_ = json_parse_state::zero; return; default: err_handler_(json_errc::invalid_number, *this); ec = json_errc::invalid_number; more_ = false; state_ = json_parse_state::zero; return; } integer: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::integer; return; } switch (*input_ptr_) { case '\r': end_integer_value(visitor, ec); if (ec) return; push_state(state_); ++input_ptr_; ++position_; state_ = json_parse_state::cr; return; case '\n': end_integer_value(visitor, ec); if (ec) return; ++input_ptr_; ++line_; ++position_; mark_position_ = position_; return; case ' ':case '\t': end_integer_value(visitor, ec); if (ec) return; skip_space(); return; case '/': end_integer_value(visitor, ec); if (ec) return; push_state(state_); ++input_ptr_; ++position_; state_ = json_parse_state::slash; return; case '}': end_integer_value(visitor, ec); if (ec) return; state_ = json_parse_state::expect_comma_or_end; return; case ']': end_integer_value(visitor, ec); if (ec) return; state_ = json_parse_state::expect_comma_or_end; return; case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; goto integer; case '.': string_buffer_.push_back(to_double_.get_decimal_point()); ++input_ptr_; ++position_; goto fraction1; case 'e':case 'E': string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; goto exp1; case ',': end_integer_value(visitor, ec); if (ec) return; begin_member_or_element(ec); if (ec) return; ++input_ptr_; ++position_; return; default: err_handler_(json_errc::invalid_number, *this); ec = json_errc::invalid_number; more_ = false; state_ = json_parse_state::integer; return; } fraction1: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::fraction1; return; } switch (*input_ptr_) { case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; goto fraction2; default: err_handler_(json_errc::invalid_number, *this); ec = json_errc::invalid_number; more_ = false; state_ = json_parse_state::fraction1; return; } fraction2: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::fraction2; return; } switch (*input_ptr_) { case '\r': end_fraction_value(visitor, ec); if (ec) return; push_state(state_); ++input_ptr_; ++position_; state_ = json_parse_state::cr; return; case '\n': end_fraction_value(visitor, ec); if (ec) return; ++input_ptr_; ++line_; ++position_; mark_position_ = position_; return; case ' ':case '\t': end_fraction_value(visitor, ec); if (ec) return; skip_space(); return; case '/': end_fraction_value(visitor, ec); if (ec) return; push_state(state_); ++input_ptr_; ++position_; state_ = json_parse_state::slash; return; case '}': end_fraction_value(visitor, ec); if (ec) return; state_ = json_parse_state::expect_comma_or_end; return; case ']': end_fraction_value(visitor, ec); if (ec) return; state_ = json_parse_state::expect_comma_or_end; return; case ',': end_fraction_value(visitor, ec); if (ec) return; begin_member_or_element(ec); if (ec) return; ++input_ptr_; ++position_; return; case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; goto fraction2; case 'e':case 'E': string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; goto exp1; default: err_handler_(json_errc::invalid_number, *this); ec = json_errc::invalid_number; more_ = false; state_ = json_parse_state::fraction2; return; } exp1: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::exp1; return; } switch (*input_ptr_) { case '+': ++input_ptr_; ++position_; goto exp2; case '-': string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; goto exp2; case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; goto exp3; default: err_handler_(json_errc::invalid_number, *this); ec = json_errc::expected_value; more_ = false; state_ = json_parse_state::exp1; return; } exp2: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::exp2; return; } switch (*input_ptr_) { case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; goto exp3; default: err_handler_(json_errc::invalid_number, *this); ec = json_errc::expected_value; more_ = false; state_ = json_parse_state::exp2; return; } exp3: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::exp3; return; } switch (*input_ptr_) { case '\r': end_fraction_value(visitor, ec); if (ec) return; ++input_ptr_; ++position_; push_state(state_); state_ = json_parse_state::cr; return; case '\n': end_fraction_value(visitor, ec); if (ec) return; ++input_ptr_; ++line_; ++position_; mark_position_ = position_; return; case ' ':case '\t': end_fraction_value(visitor, ec); if (ec) return; skip_space(); return; case '/': end_fraction_value(visitor, ec); if (ec) return; push_state(state_); ++input_ptr_; ++position_; state_ = json_parse_state::slash; return; case '}': end_fraction_value(visitor, ec); if (ec) return; state_ = json_parse_state::expect_comma_or_end; return; case ']': end_fraction_value(visitor, ec); if (ec) return; state_ = json_parse_state::expect_comma_or_end; return; case ',': end_fraction_value(visitor, ec); if (ec) return; begin_member_or_element(ec); if (ec) return; ++input_ptr_; ++position_; return; case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': string_buffer_.push_back(static_cast(*input_ptr_)); ++input_ptr_; ++position_; goto exp3; default: err_handler_(json_errc::invalid_number, *this); ec = json_errc::invalid_number; more_ = false; state_ = json_parse_state::exp3; return; } JSONCONS_UNREACHABLE(); } void parse_string(basic_json_visitor& visitor, std::error_code& ec) { saved_position_ = position_ - 1; const char_type* local_input_end = end_input_; const char_type* sb = input_ptr_; switch (state_) { case json_parse_state::string: goto string_u1; case json_parse_state::escape: goto escape; case json_parse_state::escape_u1: goto escape_u1; case json_parse_state::escape_u2: goto escape_u2; case json_parse_state::escape_u3: goto escape_u3; case json_parse_state::escape_u4: goto escape_u4; case json_parse_state::escape_expect_surrogate_pair1: goto escape_expect_surrogate_pair1; case json_parse_state::escape_expect_surrogate_pair2: goto escape_expect_surrogate_pair2; case json_parse_state::escape_u5: goto escape_u5; case json_parse_state::escape_u6: goto escape_u6; case json_parse_state::escape_u7: goto escape_u7; case json_parse_state::escape_u8: goto escape_u8; default: JSONCONS_UNREACHABLE(); } string_u1: while (input_ptr_ < local_input_end) { switch (*input_ptr_) { JSONCONS_ILLEGAL_CONTROL_CHARACTER: { position_ += (input_ptr_ - sb + 1); more_ = err_handler_(json_errc::illegal_control_character, *this); if (!more_) { ec = json_errc::illegal_control_character; state_ = json_parse_state::string; return; } // recovery - skip string_buffer_.append(sb,input_ptr_-sb); ++input_ptr_; state_ = json_parse_state::string; return; } case '\r': { position_ += (input_ptr_ - sb + 1); more_ = err_handler_(json_errc::illegal_character_in_string, *this); if (!more_) { ec = json_errc::illegal_character_in_string; state_ = json_parse_state::string; return; } // recovery - keep string_buffer_.append(sb, input_ptr_ - sb + 1); ++input_ptr_; push_state(state_); state_ = json_parse_state::cr; return; } case '\n': { ++line_; ++position_; mark_position_ = position_; more_ = err_handler_(json_errc::illegal_character_in_string, *this); if (!more_) { ec = json_errc::illegal_character_in_string; state_ = json_parse_state::string; return; } // recovery - keep string_buffer_.append(sb, input_ptr_ - sb + 1); ++input_ptr_; return; } case '\t': { position_ += (input_ptr_ - sb + 1); more_ = err_handler_(json_errc::illegal_character_in_string, *this); if (!more_) { ec = json_errc::illegal_character_in_string; state_ = json_parse_state::string; return; } // recovery - keep string_buffer_.append(sb, input_ptr_ - sb + 1); ++input_ptr_; state_ = json_parse_state::string; return; } case '\\': { string_buffer_.append(sb,input_ptr_-sb); position_ += (input_ptr_ - sb + 1); ++input_ptr_; goto escape; } case '\"': { if (string_buffer_.length() == 0) { end_string_value(sb,input_ptr_-sb, visitor, ec); if (ec) {return;} } else { string_buffer_.append(sb,input_ptr_-sb); end_string_value(string_buffer_.data(),string_buffer_.length(), visitor, ec); if (ec) {return;} } position_ += (input_ptr_ - sb + 1); ++input_ptr_; return; } default: break; } ++input_ptr_; } // Buffer exhausted { string_buffer_.append(sb,input_ptr_-sb); position_ += (input_ptr_ - sb + 1); state_ = json_parse_state::string; return; } escape: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::escape; return; } switch (*input_ptr_) { case '\"': string_buffer_.push_back('\"'); sb = ++input_ptr_; ++position_; goto string_u1; case '\\': string_buffer_.push_back('\\'); sb = ++input_ptr_; ++position_; goto string_u1; case '/': string_buffer_.push_back('/'); sb = ++input_ptr_; ++position_; goto string_u1; case 'b': string_buffer_.push_back('\b'); sb = ++input_ptr_; ++position_; goto string_u1; case 'f': string_buffer_.push_back('\f'); sb = ++input_ptr_; ++position_; goto string_u1; case 'n': string_buffer_.push_back('\n'); sb = ++input_ptr_; ++position_; goto string_u1; case 'r': string_buffer_.push_back('\r'); sb = ++input_ptr_; ++position_; goto string_u1; case 't': string_buffer_.push_back('\t'); sb = ++input_ptr_; ++position_; goto string_u1; case 'u': cp_ = 0; ++input_ptr_; ++position_; goto escape_u1; default: err_handler_(json_errc::illegal_escaped_character, *this); ec = json_errc::illegal_escaped_character; more_ = false; state_ = json_parse_state::escape; return; } escape_u1: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::escape_u1; return; } { cp_ = append_to_codepoint(0, *input_ptr_, ec); if (ec) { state_ = json_parse_state::escape_u1; return; } ++input_ptr_; ++position_; goto escape_u2; } escape_u2: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::escape_u2; return; } { cp_ = append_to_codepoint(cp_, *input_ptr_, ec); if (ec) { state_ = json_parse_state::escape_u2; return; } ++input_ptr_; ++position_; goto escape_u3; } escape_u3: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::escape_u3; return; } { cp_ = append_to_codepoint(cp_, *input_ptr_, ec); if (ec) { state_ = json_parse_state::escape_u3; return; } ++input_ptr_; ++position_; goto escape_u4; } escape_u4: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::escape_u4; return; } { cp_ = append_to_codepoint(cp_, *input_ptr_, ec); if (ec) { state_ = json_parse_state::escape_u4; return; } if (unicode_traits::is_high_surrogate(cp_)) { ++input_ptr_; ++position_; goto escape_expect_surrogate_pair1; } else { unicode_traits::convert(&cp_, 1, string_buffer_); sb = ++input_ptr_; ++position_; state_ = json_parse_state::string; return; } } escape_expect_surrogate_pair1: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::escape_expect_surrogate_pair1; return; } { switch (*input_ptr_) { case '\\': cp2_ = 0; ++input_ptr_; ++position_; goto escape_expect_surrogate_pair2; default: err_handler_(json_errc::expected_codepoint_surrogate_pair, *this); ec = json_errc::expected_codepoint_surrogate_pair; more_ = false; state_ = json_parse_state::escape_expect_surrogate_pair1; return; } } escape_expect_surrogate_pair2: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::escape_expect_surrogate_pair2; return; } { switch (*input_ptr_) { case 'u': ++input_ptr_; ++position_; goto escape_u5; default: err_handler_(json_errc::expected_codepoint_surrogate_pair, *this); ec = json_errc::expected_codepoint_surrogate_pair; more_ = false; state_ = json_parse_state::escape_expect_surrogate_pair2; return; } } escape_u5: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::escape_u5; return; } { cp2_ = append_to_codepoint(0, *input_ptr_, ec); if (ec) { state_ = json_parse_state::escape_u5; return; } } ++input_ptr_; ++position_; goto escape_u6; escape_u6: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::escape_u6; return; } { cp2_ = append_to_codepoint(cp2_, *input_ptr_, ec); if (ec) { state_ = json_parse_state::escape_u6; return; } ++input_ptr_; ++position_; goto escape_u7; } escape_u7: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::escape_u7; return; } { cp2_ = append_to_codepoint(cp2_, *input_ptr_, ec); if (ec) { state_ = json_parse_state::escape_u7; return; } ++input_ptr_; ++position_; goto escape_u8; } escape_u8: if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted { state_ = json_parse_state::escape_u8; return; } { cp2_ = append_to_codepoint(cp2_, *input_ptr_, ec); if (ec) { state_ = json_parse_state::escape_u8; return; } uint32_t cp = 0x10000 + ((cp_ & 0x3FF) << 10) + (cp2_ & 0x3FF); unicode_traits::convert(&cp, 1, string_buffer_); sb = ++input_ptr_; ++position_; goto string_u1; } JSONCONS_UNREACHABLE(); } void translate_conv_errc(unicode_traits::conv_errc result, std::error_code& ec) { switch (result) { case unicode_traits::conv_errc(): break; case unicode_traits::conv_errc::over_long_utf8_sequence: more_ = err_handler_(json_errc::over_long_utf8_sequence, *this); if (!more_) { ec = json_errc::over_long_utf8_sequence; return; } break; case unicode_traits::conv_errc::unpaired_high_surrogate: more_ = err_handler_(json_errc::unpaired_high_surrogate, *this); if (!more_) { ec = json_errc::unpaired_high_surrogate; return; } break; case unicode_traits::conv_errc::expected_continuation_byte: more_ = err_handler_(json_errc::expected_continuation_byte, *this); if (!more_) { ec = json_errc::expected_continuation_byte; return; } break; case unicode_traits::conv_errc::illegal_surrogate_value: more_ = err_handler_(json_errc::illegal_surrogate_value, *this); if (!more_) { ec = json_errc::illegal_surrogate_value; return; } break; default: more_ = err_handler_(json_errc::illegal_codepoint, *this); if (!more_) { ec = json_errc::illegal_codepoint; return; } break; } } #if !defined(JSONCONS_NO_DEPRECATED) JSONCONS_DEPRECATED_MSG("Instead, use finish_parse(basic_json_visitor&)") void end_parse(basic_json_visitor& visitor) { std::error_code ec; finish_parse(visitor, ec); if (ec) { JSONCONS_THROW(ser_error(ec,line_,column())); } } JSONCONS_DEPRECATED_MSG("Instead, use finish_parse(basic_json_visitor&, std::error_code&)") void end_parse(basic_json_visitor& visitor, std::error_code& ec) { while (!finished()) { parse_some(visitor, ec); } } JSONCONS_DEPRECATED_MSG("Instead, use update(const char_type*, std::size_t)") void set_source(const char_type* data, std::size_t length) { begin_input_ = data; end_input_ = data + length; input_ptr_ = begin_input_; } #endif std::size_t line() const override { return line_; } std::size_t column() const override { return (position_ - mark_position_) + 1; } std::size_t position() const override { return saved_position_; } std::size_t offset() const { return input_ptr_ - begin_input_; } private: void end_integer_value(basic_json_visitor& visitor, std::error_code& ec) { if (string_buffer_[0] == '-') { end_negative_value(visitor, ec); } else { end_positive_value(visitor, ec); } } void end_negative_value(basic_json_visitor& visitor, std::error_code& ec) { int64_t val; auto result = jsoncons::detail::to_integer_unchecked(string_buffer_.data(), string_buffer_.length(), val); if (result) { more_ = visitor.int64_value(val, semantic_tag::none, *this, ec); } else // Must be overflow { more_ = visitor.string_value(string_buffer_, semantic_tag::bigint, *this, ec); } after_value(ec); } void end_positive_value(basic_json_visitor& visitor, std::error_code& ec) { uint64_t val; auto result = jsoncons::detail::to_integer_unchecked(string_buffer_.data(), string_buffer_.length(), val); if (result) { more_ = visitor.uint64_value(val, semantic_tag::none, *this, ec); } else // Must be overflow { more_ = visitor.string_value(string_buffer_, semantic_tag::bigint, *this, ec); } after_value(ec); } void end_fraction_value(basic_json_visitor& visitor, std::error_code& ec) { JSONCONS_TRY { if (options_.lossless_number()) { more_ = visitor.string_value(string_buffer_, semantic_tag::bigdec, *this, ec); } else { double d = to_double_(string_buffer_.c_str(), string_buffer_.length()); more_ = visitor.double_value(d, semantic_tag::none, *this, ec); } } JSONCONS_CATCH(...) { more_ = err_handler_(json_errc::invalid_number, *this); if (!more_) { ec = json_errc::invalid_number; return; } more_ = visitor.null_value(semantic_tag::none, *this, ec); // recovery } after_value(ec); } void end_string_value(const char_type* s, std::size_t length, basic_json_visitor& visitor, std::error_code& ec) { string_view_type sv(s, length); auto result = unicode_traits::validate(s, length); if (result.ec != unicode_traits::conv_errc()) { translate_conv_errc(result.ec,ec); position_ += (result.ptr - s); return; } switch (parent()) { case json_parse_state::member_name: more_ = visitor.key(sv, *this, ec); pop_state(); state_ = json_parse_state::expect_colon; break; case json_parse_state::object: case json_parse_state::array: { auto it = std::find_if(string_double_map_.begin(), string_double_map_.end(), string_maps_to_double{ sv }); if (it != string_double_map_.end()) { more_ = visitor.double_value(it->second, semantic_tag::none, *this, ec); } else { more_ = visitor.string_value(sv, semantic_tag::none, *this, ec); } state_ = json_parse_state::expect_comma_or_end; break; } case json_parse_state::root: { auto it = std::find_if(string_double_map_.begin(),string_double_map_.end(),string_maps_to_double{sv}); if (it != string_double_map_.end()) { more_ = visitor.double_value(it->second, semantic_tag::none, *this, ec); } else { more_ = visitor.string_value(sv, semantic_tag::none, *this, ec); } state_ = json_parse_state::accept; break; } default: more_ = err_handler_(json_errc::syntax_error, *this); if (!more_) { ec = json_errc::syntax_error; return; } break; } } void begin_member_or_element(std::error_code& ec) { switch (parent()) { case json_parse_state::object: state_ = json_parse_state::expect_member_name; break; case json_parse_state::array: state_ = json_parse_state::expect_value; break; case json_parse_state::root: break; default: more_ = err_handler_(json_errc::syntax_error, *this); if (!more_) { ec = json_errc::syntax_error; return; } break; } } void after_value(std::error_code& ec) { switch (parent()) { case json_parse_state::array: case json_parse_state::object: state_ = json_parse_state::expect_comma_or_end; break; case json_parse_state::root: state_ = json_parse_state::accept; break; default: more_ = err_handler_(json_errc::syntax_error, *this); if (!more_) { ec = json_errc::syntax_error; return; } break; } } void push_state(json_parse_state state) { state_stack_.push_back(state); } json_parse_state pop_state() { JSONCONS_ASSERT(!state_stack_.empty()) json_parse_state state = state_stack_.back(); state_stack_.pop_back(); return state; } uint32_t append_to_codepoint(uint32_t cp, int c, std::error_code& ec) { cp *= 16; if (c >= '0' && c <= '9') { cp += c - '0'; } else if (c >= 'a' && c <= 'f') { cp += c - 'a' + 10; } else if (c >= 'A' && c <= 'F') { cp += c - 'A' + 10; } else { more_ = err_handler_(json_errc::invalid_unicode_escape_sequence, *this); if (!more_) { ec = json_errc::invalid_unicode_escape_sequence; return cp; } } return cp; } }; using json_parser = basic_json_parser; using wjson_parser = basic_json_parser; } #endif