build_exe.py compiles every unit in data/compile.json with the pinned toolchain and links Ragexe.exe. Not part of the decompilation and not in data/compile.json: imports/*.def (original DLL import tables), jsoncons/ (v0.170.2 headers + JsonCppLoader glue), nProtect/GameGuard.cpp (no-op GameGuard stand-in).
2887 lines
101 KiB
C++
2887 lines
101 KiB
C++
// Copyright 2013-2023 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 <memory> // std::allocator
|
|
#include <string>
|
|
#include <vector>
|
|
#include <stdexcept>
|
|
#include <system_error>
|
|
#include <unordered_map>
|
|
#include <limits> // std::numeric_limits
|
|
#include <functional> // std::function
|
|
#include <jsoncons/json_exception.hpp>
|
|
#include <jsoncons/json_filter.hpp>
|
|
#include <jsoncons/json_options.hpp>
|
|
#include <jsoncons/json_visitor.hpp>
|
|
#include <jsoncons/json_error.hpp>
|
|
#include <jsoncons/detail/parse_number.hpp>
|
|
|
|
#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 CharT, class TempAllocator = std::allocator<char>>
|
|
class basic_json_parser : public ser_context
|
|
{
|
|
public:
|
|
using char_type = CharT;
|
|
using string_view_type = typename basic_json_visitor<CharT>::string_view_type;
|
|
private:
|
|
struct string_maps_to_double
|
|
{
|
|
string_view_type s;
|
|
|
|
bool operator()(const std::pair<string_view_type,double>& val) const
|
|
{
|
|
return val.first == s;
|
|
}
|
|
};
|
|
|
|
using temp_allocator_type = TempAllocator;
|
|
using char_allocator_type = typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<CharT>;
|
|
using parse_state_allocator_type = typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<json_parse_state>;
|
|
|
|
static constexpr std::size_t initial_string_buffer_capacity_ = 1024;
|
|
static constexpr std::size_t default_initial_stack_capacity_ = 100;
|
|
|
|
basic_json_decode_options<char_type> options_;
|
|
|
|
std::function<bool(json_errc,const ser_context&)> 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_type,std::char_traits<char_type>,char_allocator_type> string_buffer_;
|
|
jsoncons::detail::chars_to to_double_;
|
|
|
|
std::vector<json_parse_state,parse_state_allocator_type> state_stack_;
|
|
std::vector<std::pair<std::basic_string<char_type>,double>> 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<char_type>(), default_json_parsing(), alloc)
|
|
{
|
|
}
|
|
|
|
basic_json_parser(std::function<bool(json_errc,const ser_context&)> err_handler,
|
|
const TempAllocator& alloc = TempAllocator())
|
|
: basic_json_parser(basic_json_decode_options<char_type>(), err_handler, alloc)
|
|
{
|
|
}
|
|
|
|
basic_json_parser(const basic_json_decode_options<char_type>& options,
|
|
const TempAllocator& alloc = TempAllocator())
|
|
: basic_json_parser(options, default_json_parsing(), alloc)
|
|
{
|
|
}
|
|
|
|
basic_json_parser(const basic_json_decode_options<char_type>& options,
|
|
std::function<bool(json_errc,const ser_context&)> 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<double>::infinity());
|
|
}
|
|
if (options_.enable_str_to_neginf())
|
|
{
|
|
string_double_map_.emplace_back(options_.neginf_to_str(),-std::numeric_limits<double>::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<char_type>& 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<char_type>& 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<char_type>& 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<char_type>& 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<char_type>& visitor)
|
|
{
|
|
std::error_code ec;
|
|
parse_some(visitor, ec);
|
|
if (ec)
|
|
{
|
|
JSONCONS_THROW(ser_error(ec,line_,column()));
|
|
}
|
|
}
|
|
|
|
void parse_some(basic_json_visitor<char_type>& visitor, std::error_code& ec)
|
|
{
|
|
parse_some_(visitor, ec);
|
|
}
|
|
|
|
void finish_parse(basic_json_visitor<char_type>& visitor)
|
|
{
|
|
std::error_code ec;
|
|
finish_parse(visitor, ec);
|
|
if (ec)
|
|
{
|
|
JSONCONS_THROW(ser_error(ec,line_,column()));
|
|
}
|
|
}
|
|
|
|
void finish_parse(basic_json_visitor<char_type>& visitor, std::error_code& ec)
|
|
{
|
|
while (!finished())
|
|
{
|
|
parse_some(visitor, ec);
|
|
}
|
|
}
|
|
|
|
void parse_some_(basic_json_visitor<char_type>& 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:
|
|
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 '{':
|
|
saved_position_ = position_;
|
|
++input_ptr_;
|
|
++position_;
|
|
begin_object(visitor, ec);
|
|
if (ec) return;
|
|
break;
|
|
case '[':
|
|
saved_position_ = position_;
|
|
++input_ptr_;
|
|
++position_;
|
|
begin_array(visitor, ec);
|
|
if (ec) return;
|
|
break;
|
|
case '\"':
|
|
state_ = json_parse_state::string;
|
|
saved_position_ = position_;
|
|
++input_ptr_;
|
|
++position_;
|
|
string_buffer_.clear();
|
|
parse_string(visitor, ec);
|
|
if (ec) return;
|
|
break;
|
|
case '-':
|
|
string_buffer_.clear();
|
|
string_buffer_.push_back('-');
|
|
saved_position_ = position_;
|
|
++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<char>(*input_ptr_));
|
|
state_ = json_parse_state::zero;
|
|
saved_position_ = position_;
|
|
++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<char>(*input_ptr_));
|
|
saved_position_ = position_;
|
|
++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 '}':
|
|
saved_position_ = position_;
|
|
++input_ptr_;
|
|
++position_;
|
|
end_object(visitor, ec);
|
|
if (ec) return;
|
|
break;
|
|
case ']':
|
|
saved_position_ = position_;
|
|
++input_ptr_;
|
|
++position_;
|
|
end_array(visitor, ec);
|
|
if (ec) return;
|
|
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 '}':
|
|
saved_position_ = position_;
|
|
++input_ptr_;
|
|
++position_;
|
|
end_object(visitor, ec);
|
|
if (ec) return;
|
|
break;
|
|
case '\"':
|
|
saved_position_ = position_;
|
|
++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 '\"':
|
|
saved_position_ = position_;
|
|
++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;
|
|
}
|
|
saved_position_ = position_;
|
|
++input_ptr_;
|
|
++position_;
|
|
end_object(visitor, ec); // Recover
|
|
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_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 '{':
|
|
saved_position_ = position_;
|
|
++input_ptr_;
|
|
++position_;
|
|
begin_object(visitor, ec);
|
|
if (ec) return;
|
|
break;
|
|
case '[':
|
|
saved_position_ = position_;
|
|
++input_ptr_;
|
|
++position_;
|
|
begin_array(visitor, ec);
|
|
if (ec) return;
|
|
break;
|
|
case '\"':
|
|
saved_position_ = position_;
|
|
++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('-');
|
|
saved_position_ = position_;
|
|
++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<char>(*input_ptr_));
|
|
saved_position_ = position_;
|
|
++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<char>(*input_ptr_));
|
|
saved_position_ = position_;
|
|
++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 ']':
|
|
saved_position_ = position_;
|
|
++input_ptr_;
|
|
++position_;
|
|
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;
|
|
}
|
|
}
|
|
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 '{':
|
|
saved_position_ = position_;
|
|
++input_ptr_;
|
|
++position_;
|
|
begin_object(visitor, ec);
|
|
if (ec) return;
|
|
break;
|
|
case '[':
|
|
saved_position_ = position_;
|
|
++input_ptr_;
|
|
++position_;
|
|
begin_array(visitor, ec);
|
|
if (ec) return;
|
|
break;
|
|
case ']':
|
|
saved_position_ = position_;
|
|
++input_ptr_;
|
|
++position_;
|
|
end_array(visitor, ec);
|
|
if (ec) return;
|
|
break;
|
|
case '\"':
|
|
saved_position_ = position_;
|
|
++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('-');
|
|
saved_position_ = position_;
|
|
++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<char>(*input_ptr_));
|
|
saved_position_ = position_;
|
|
++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<char>(*input_ptr_));
|
|
saved_position_ = position_;
|
|
++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':
|
|
++input_ptr_;
|
|
++position_;
|
|
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;
|
|
}
|
|
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':
|
|
++input_ptr_;
|
|
++position_;
|
|
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;
|
|
}
|
|
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:
|
|
++position_;
|
|
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_;
|
|
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':
|
|
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<char_type>& 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')
|
|
{
|
|
input_ptr_ += 4;
|
|
position_ += 4;
|
|
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;
|
|
}
|
|
}
|
|
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<char_type>& 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')
|
|
{
|
|
input_ptr_ += 4;
|
|
position_ += 4;
|
|
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;
|
|
}
|
|
}
|
|
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<char_type>& 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')
|
|
{
|
|
input_ptr_ += 5;
|
|
position_ += 5;
|
|
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;
|
|
}
|
|
}
|
|
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<char_type>& visitor, std::error_code& ec)
|
|
{
|
|
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<char>(*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<char>(*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 '}':
|
|
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<char>(*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 '}':
|
|
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<char>(*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<char>(*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<char>(*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<char>(*input_ptr_));
|
|
++input_ptr_;
|
|
++position_;
|
|
goto fraction2;
|
|
case 'e':case 'E':
|
|
string_buffer_.push_back(static_cast<char>(*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<char>(*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<char>(*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<char>(*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<char>(*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<char_type>& visitor, std::error_code& ec)
|
|
{
|
|
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 '\"':
|
|
{
|
|
position_ += (input_ptr_ - sb + 1);
|
|
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;}
|
|
}
|
|
++input_ptr_;
|
|
return;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
++input_ptr_;
|
|
}
|
|
|
|
// Buffer exhausted
|
|
{
|
|
string_buffer_.append(sb,input_ptr_-sb);
|
|
position_ += (input_ptr_ - sb);
|
|
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<char_type>&)")
|
|
void end_parse(basic_json_visitor<char_type>& 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<char_type>&, std::error_code&)")
|
|
void end_parse(basic_json_visitor<char_type>& 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 end_position() const override
|
|
{
|
|
return position_;
|
|
}
|
|
|
|
std::size_t offset() const
|
|
{
|
|
return input_ptr_ - begin_input_;
|
|
}
|
|
private:
|
|
|
|
void end_integer_value(basic_json_visitor<char_type>& 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<char_type>& 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<char_type>& 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<char_type>& 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<char_type>& 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<char>;
|
|
using wjson_parser = basic_json_parser<wchar_t>;
|
|
|
|
}
|
|
|
|
#endif
|
|
|