mirror of
https://github.com/boostorg/json.git
synced 2025-05-11 05:33:57 +00:00
basic_parser is a base
This commit is contained in:
parent
845d7af5e3
commit
2545475bdd
@ -359,10 +359,9 @@ public:
|
||||
|
||||
class boost_vec_impl : public any_impl
|
||||
{
|
||||
struct vec_parser
|
||||
struct vec_parser : basic_parser
|
||||
{
|
||||
friend class basic_parser;
|
||||
basic_parser p_;
|
||||
std::vector<double> vec_;
|
||||
double d_ = 0;
|
||||
|
||||
@ -394,7 +393,8 @@ class boost_vec_impl : public any_impl
|
||||
std::size_t size,
|
||||
error_code& ec)
|
||||
{
|
||||
auto const n = p_.write_some(
|
||||
auto const n =
|
||||
this->basic_parser::write_some(
|
||||
*this, false, data, size, ec);
|
||||
if(! ec && n < size)
|
||||
ec = error::extra_data;
|
||||
@ -438,10 +438,9 @@ public:
|
||||
|
||||
class boost_null_impl : public any_impl
|
||||
{
|
||||
struct null_parser
|
||||
struct null_parser : basic_parser
|
||||
{
|
||||
friend class basic_parser;
|
||||
basic_parser p_;
|
||||
|
||||
null_parser() {}
|
||||
~null_parser() {}
|
||||
@ -460,18 +459,18 @@ class boost_null_impl : public any_impl
|
||||
bool on_double(double, error_code&) { return true; }
|
||||
bool on_bool(bool, error_code&) { return true; }
|
||||
bool on_null(error_code&) { return true; }
|
||||
void reset()
|
||||
{
|
||||
p_.reset();
|
||||
}
|
||||
|
||||
using basic_parser::reset;
|
||||
|
||||
std::size_t
|
||||
write(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
error_code& ec)
|
||||
{
|
||||
auto const n = p_.write_some(
|
||||
*this, false, data, size, ec);
|
||||
auto const n =
|
||||
basic_parser::write_some(
|
||||
*this, false, data, size, ec);
|
||||
if(! ec && n < size)
|
||||
ec = error::extra_data;
|
||||
return n;
|
||||
|
@ -32,10 +32,9 @@ validate( string_view s )
|
||||
{
|
||||
// The null parser discards all the data
|
||||
|
||||
class null_parser
|
||||
class null_parser : public basic_parser
|
||||
{
|
||||
friend class boost::json::basic_parser;
|
||||
boost::json::basic_parser p_;
|
||||
|
||||
public:
|
||||
null_parser() {}
|
||||
@ -56,25 +55,14 @@ validate( string_view s )
|
||||
bool on_bool( bool, error_code& ) { return true; }
|
||||
bool on_null( error_code& ) { return true; }
|
||||
|
||||
bool
|
||||
is_done() const noexcept
|
||||
{
|
||||
return p_.is_done();
|
||||
}
|
||||
|
||||
void
|
||||
reset()
|
||||
{
|
||||
p_.reset();
|
||||
}
|
||||
|
||||
std::size_t
|
||||
write(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
error_code& ec)
|
||||
{
|
||||
auto const n = p_.write_some(
|
||||
auto const n =
|
||||
basic_parser::write_some(
|
||||
*this, false, data, size, ec);
|
||||
if(! ec && n < size)
|
||||
ec = error::extra_data;
|
||||
|
@ -1333,6 +1333,12 @@ parse_object(
|
||||
{
|
||||
BOOST_ASSERT(*cs == '{');
|
||||
++depth_;
|
||||
if(BOOST_JSON_UNLIKELY(
|
||||
depth_ > max_depth_))
|
||||
{
|
||||
ec_ = error::too_deep;
|
||||
return result::fail;
|
||||
}
|
||||
if(BOOST_JSON_UNLIKELY(
|
||||
! h.on_object_begin(ec_)))
|
||||
return result::fail;
|
||||
@ -1471,6 +1477,12 @@ parse_array(
|
||||
{
|
||||
BOOST_ASSERT(*cs == '[');
|
||||
++depth_;
|
||||
if(BOOST_JSON_UNLIKELY(
|
||||
depth_ > max_depth_))
|
||||
{
|
||||
ec_ = error::too_deep;
|
||||
return result::fail;
|
||||
}
|
||||
if(BOOST_JSON_UNLIKELY(
|
||||
! h.on_array_begin(ec_)))
|
||||
return result::fail;
|
||||
|
@ -50,6 +50,24 @@ namespace json {
|
||||
to cheaply re-use this memory when parsing
|
||||
subsequent JSONs, improving performance.
|
||||
|
||||
@par Usage
|
||||
|
||||
Users who wish to parse JSON into the DOM container
|
||||
@ref value will not use this class directly; instead
|
||||
they will create an instance of @ref parser and
|
||||
use that instead. Alternatively, they may call the
|
||||
function @ref parse. This class is designed for
|
||||
users who wish to perform custom actions instead of
|
||||
building a @ref value. For example, to produce a
|
||||
DOM from an external library.
|
||||
|
||||
<br>
|
||||
|
||||
To use this class it is necessary to create a derived
|
||||
class which calls @ref reset at the beginning of
|
||||
parsing a new JSON, and then calls @ref write_some one
|
||||
or more times with the serialized JSON.
|
||||
|
||||
@note
|
||||
|
||||
The parser is strict: no extensions are supported.
|
||||
@ -82,6 +100,7 @@ class basic_parser
|
||||
error_code ec_;
|
||||
detail::stack st_;
|
||||
std::size_t depth_ = 0;
|
||||
std::size_t max_depth_ = 32;
|
||||
unsigned u1_;
|
||||
unsigned u2_;
|
||||
bool more_; // false for final buffer
|
||||
@ -161,6 +180,30 @@ public:
|
||||
return depth_;
|
||||
}
|
||||
|
||||
/** Returns the maximum allowed depth of input JSON.
|
||||
|
||||
The maximum allowed depth may be configured.
|
||||
*/
|
||||
std::size_t
|
||||
max_depth() const noexcept
|
||||
{
|
||||
return max_depth_;
|
||||
}
|
||||
|
||||
/** Set the maximum allowed depth of input JSON.
|
||||
|
||||
When the maximum depth is exceeded, parser
|
||||
operations will return @ref error::too_deep.
|
||||
|
||||
@param levels The maximum depth.
|
||||
*/
|
||||
void
|
||||
max_depth(unsigned long levels) noexcept
|
||||
{
|
||||
max_depth_ = levels;
|
||||
}
|
||||
|
||||
protected:
|
||||
/** Reset the state, to parse a new document.
|
||||
*/
|
||||
inline
|
||||
|
@ -182,7 +182,7 @@ clear() noexcept
|
||||
{
|
||||
destroy();
|
||||
rs_.clear();
|
||||
p_.reset();
|
||||
basic_parser::reset();
|
||||
lev_.count = 0;
|
||||
key_size_ = 0;
|
||||
str_size_ = 0;
|
||||
@ -197,7 +197,7 @@ write_some(
|
||||
std::size_t const size,
|
||||
error_code& ec)
|
||||
{
|
||||
return p_.write_some(
|
||||
return basic_parser::write_some(
|
||||
*this, true, data, size, ec);
|
||||
}
|
||||
|
||||
@ -223,9 +223,9 @@ write(
|
||||
std::size_t size,
|
||||
error_code& ec)
|
||||
{
|
||||
auto const n = p_.write_some(
|
||||
*this, true,
|
||||
data, size, ec);
|
||||
auto const n =
|
||||
basic_parser::write_some(
|
||||
*this, true, data, size, ec);
|
||||
if(! ec)
|
||||
{
|
||||
if(n < size)
|
||||
@ -253,8 +253,9 @@ finish(
|
||||
std::size_t size,
|
||||
error_code& ec)
|
||||
{
|
||||
auto const n = p_.write_some(
|
||||
*this, false, data, size, ec);
|
||||
auto const n =
|
||||
basic_parser::write_some(
|
||||
*this, false, data, size, ec);
|
||||
if(! ec)
|
||||
{
|
||||
if(n < size)
|
||||
@ -302,7 +303,7 @@ release()
|
||||
std::logic_error(
|
||||
"no value"));
|
||||
BOOST_ASSERT(lev_.count == 1);
|
||||
BOOST_ASSERT(p_.depth() == 0);
|
||||
BOOST_ASSERT(depth() == 0);
|
||||
auto ua = pop_array();
|
||||
BOOST_ASSERT(rs_.empty());
|
||||
union U
|
||||
@ -313,7 +314,7 @@ release()
|
||||
};
|
||||
U u;
|
||||
ua.relocate(&u.v);
|
||||
p_.reset();
|
||||
basic_parser::reset();
|
||||
lev_.st = state::need_start;
|
||||
sp_ = {};
|
||||
return pilfer(u.v);
|
||||
@ -484,11 +485,6 @@ bool
|
||||
parser::
|
||||
on_object_begin(error_code& ec)
|
||||
{
|
||||
if(p_.depth() >= max_depth_)
|
||||
{
|
||||
ec = error::too_deep;
|
||||
return false;
|
||||
}
|
||||
// prevent splits from exceptions
|
||||
rs_.prepare(
|
||||
sizeof(level) +
|
||||
@ -528,11 +524,6 @@ bool
|
||||
parser::
|
||||
on_array_begin(error_code& ec)
|
||||
{
|
||||
if(p_.depth() >= max_depth_)
|
||||
{
|
||||
ec = error::too_deep;
|
||||
return false;
|
||||
}
|
||||
// prevent splits from exceptions
|
||||
rs_.prepare(
|
||||
sizeof(level) +
|
||||
|
@ -65,7 +65,7 @@ namespace json {
|
||||
to cheaply re-use this memory when parsing
|
||||
subsequent JSONs, improving performance.
|
||||
*/
|
||||
class parser
|
||||
class parser : public basic_parser
|
||||
{
|
||||
friend class basic_parser;
|
||||
enum class state : char;
|
||||
@ -76,10 +76,8 @@ class parser
|
||||
state st;
|
||||
};
|
||||
|
||||
basic_parser p_;
|
||||
storage_ptr sp_;
|
||||
detail::raw_stack rs_;
|
||||
std::size_t max_depth_ = 32;
|
||||
std::uint32_t key_size_ = 0;
|
||||
std::uint32_t str_size_ = 0;
|
||||
level lev_;
|
||||
@ -140,62 +138,6 @@ public:
|
||||
void
|
||||
start(storage_ptr sp = {}) noexcept;
|
||||
|
||||
/** Returns the current depth of the JSON being parsed.
|
||||
|
||||
The parsing depth is the total current nesting
|
||||
level of arrays and objects.
|
||||
*/
|
||||
std::size_t
|
||||
depth() const noexcept
|
||||
{
|
||||
return p_.depth();
|
||||
}
|
||||
|
||||
/** Returns the maximum allowed depth of input JSON.
|
||||
|
||||
The maximum allowed depth may be configured.
|
||||
*/
|
||||
std::size_t
|
||||
max_depth() const noexcept
|
||||
{
|
||||
return max_depth_;
|
||||
}
|
||||
|
||||
/** Set the maximum allowed depth of input JSON.
|
||||
|
||||
When the maximum depth is exceeded, parser
|
||||
operations will return @ref error::too_deep.
|
||||
|
||||
@param levels The maximum depth.
|
||||
*/
|
||||
void
|
||||
max_depth(unsigned long levels) noexcept
|
||||
{
|
||||
max_depth_ = levels;
|
||||
}
|
||||
|
||||
/** Return true if a complete JSON has been parsed.
|
||||
|
||||
This function returns `true` when all of these
|
||||
conditions are met:
|
||||
|
||||
@li A complete serialized JSON has been
|
||||
presented to the parser, and
|
||||
|
||||
@li No error has occurred since the parser
|
||||
was constructed, or since the last call
|
||||
to @ref reset,
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
*/
|
||||
bool
|
||||
is_done() const noexcept
|
||||
{
|
||||
return p_.is_done();
|
||||
}
|
||||
|
||||
/** Parse JSON incrementally.
|
||||
|
||||
This function parses the JSON in the specified
|
||||
|
@ -106,10 +106,9 @@ validate( string_view s )
|
||||
{
|
||||
// The null parser discards all the data
|
||||
|
||||
class null_parser
|
||||
class null_parser : public basic_parser
|
||||
{
|
||||
friend class boost::json::basic_parser;
|
||||
boost::json::basic_parser p_;
|
||||
|
||||
public:
|
||||
null_parser() {}
|
||||
@ -130,25 +129,14 @@ validate( string_view s )
|
||||
bool on_bool( bool, error_code& ) { return true; }
|
||||
bool on_null( error_code& ) { return true; }
|
||||
|
||||
bool
|
||||
is_done() const noexcept
|
||||
{
|
||||
return p_.is_done();
|
||||
}
|
||||
|
||||
void
|
||||
reset()
|
||||
{
|
||||
p_.reset();
|
||||
}
|
||||
|
||||
std::size_t
|
||||
write(
|
||||
char const* data,
|
||||
std::size_t size,
|
||||
error_code& ec)
|
||||
{
|
||||
auto const n = p_.write_some(
|
||||
auto const n =
|
||||
basic_parser::write_some(
|
||||
*this, false, data, size, ec);
|
||||
if(! ec && n < size)
|
||||
ec = error::extra_data;
|
||||
|
@ -142,12 +142,11 @@ struct unique_storage
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
class fail_parser
|
||||
class fail_parser : public basic_parser
|
||||
{
|
||||
friend class basic_parser;
|
||||
|
||||
std::size_t n_ = std::size_t(-1);
|
||||
basic_parser p_;
|
||||
|
||||
bool
|
||||
maybe_fail(error_code& ec)
|
||||
@ -282,18 +281,6 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
is_done() const noexcept
|
||||
{
|
||||
return p_.is_done();
|
||||
}
|
||||
|
||||
void
|
||||
reset()
|
||||
{
|
||||
p_.reset();
|
||||
}
|
||||
|
||||
std::size_t
|
||||
write_some(
|
||||
bool more,
|
||||
@ -301,7 +288,7 @@ public:
|
||||
std::size_t size,
|
||||
error_code& ec)
|
||||
{
|
||||
return p_.write_some(
|
||||
return basic_parser::write_some(
|
||||
*this, more, data, size, ec);
|
||||
}
|
||||
|
||||
@ -312,8 +299,9 @@ public:
|
||||
std::size_t size,
|
||||
error_code& ec)
|
||||
{
|
||||
auto const n = p_.write_some(
|
||||
*this, more, data, size, ec);
|
||||
auto const n =
|
||||
basic_parser::write_some(
|
||||
*this, more, data, size, ec);
|
||||
if(! ec && n < size)
|
||||
ec = error::extra_data;
|
||||
return n;
|
||||
@ -333,10 +321,9 @@ struct test_exception
|
||||
};
|
||||
|
||||
// Exercises every exception path
|
||||
class throw_parser
|
||||
class throw_parser : public basic_parser
|
||||
{
|
||||
friend class basic_parser;
|
||||
basic_parser p_;
|
||||
std::size_t n_ = std::size_t(-1);
|
||||
|
||||
bool
|
||||
@ -471,18 +458,6 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
is_done() const noexcept
|
||||
{
|
||||
return p_.is_done();
|
||||
}
|
||||
|
||||
void
|
||||
reset()
|
||||
{
|
||||
p_.reset();
|
||||
}
|
||||
|
||||
std::size_t
|
||||
write(
|
||||
bool more,
|
||||
@ -490,8 +465,9 @@ public:
|
||||
std::size_t size,
|
||||
error_code& ec)
|
||||
{
|
||||
auto const n = p_.write_some(
|
||||
*this, more, data, size, ec);
|
||||
auto const n =
|
||||
basic_parser::write_some(
|
||||
*this, more, data, size, ec);
|
||||
if(! ec && n < size)
|
||||
ec = error::extra_data;
|
||||
return n;
|
||||
|
Loading…
x
Reference in New Issue
Block a user