Merge a416868818 into 58d6aa5831
This commit is contained in:
commit
289743ec37
@ -1733,6 +1733,7 @@ I deeply appreciate the help of the following people.
|
|||||||
314. [Berkus Decker](https://github.com/berkus) fixed a typo in the README.
|
314. [Berkus Decker](https://github.com/berkus) fixed a typo in the README.
|
||||||
315. [Illia Polishchuk](https://github.com/effolkronium) improved the CMake testing.
|
315. [Illia Polishchuk](https://github.com/effolkronium) improved the CMake testing.
|
||||||
316. [Ikko Ashimine](https://github.com/eltociear) fixed a typo.
|
316. [Ikko Ashimine](https://github.com/eltociear) fixed a typo.
|
||||||
|
317. [Raphael Grimm](https://github.com/barcode) Added custom base classes as customization point and parser location information for sax parsers.
|
||||||
|
|
||||||
Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.
|
Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.
|
||||||
|
|
||||||
|
|||||||
@ -636,7 +636,7 @@ add_custom_target(ci_test_valgrind
|
|||||||
-DJSON_BuildTests=ON -DJSON_Valgrind=ON
|
-DJSON_BuildTests=ON -DJSON_Valgrind=ON
|
||||||
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_valgrind
|
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_valgrind
|
||||||
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_valgrind
|
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_valgrind
|
||||||
COMMAND cd ${PROJECT_BINARY_DIR}/build_valgrind && ${CMAKE_CTEST_COMMAND} -L valgrind --parallel ${N} --output-on-failure
|
COMMAND cd ${PROJECT_BINARY_DIR}/build_valgrind && ${CMAKE_CTEST_COMMAND} -L valgrind --parallel ${N} --output-on-failure --timeout 10000
|
||||||
COMMENT "Compile and test with Valgrind"
|
COMMENT "Compile and test with Valgrind"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
149
docs/examples/sax_parse_with_src_location.cpp
Normal file
149
docs/examples/sax_parse_with_src_location.cpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
// a simple event consumer that collects string representations of the passed
|
||||||
|
// values and their source locations;
|
||||||
|
// note inheriting from json::json_sax_t is not required, but can
|
||||||
|
// help not to forget a required function
|
||||||
|
class sax_event_consumer : public json::json_sax_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<std::string> events;
|
||||||
|
std::size_t next_token_start_pos = 0;
|
||||||
|
std::size_t next_token_end_pos = 0;
|
||||||
|
|
||||||
|
void next_token_start(std::size_t pos)
|
||||||
|
{
|
||||||
|
next_token_start_pos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void next_token_end(std::size_t pos)
|
||||||
|
{
|
||||||
|
next_token_end_pos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string location_as_str() const
|
||||||
|
{
|
||||||
|
return "at=[" + std::to_string(next_token_start_pos) + "," + std::to_string(next_token_end_pos) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool null() override
|
||||||
|
{
|
||||||
|
events.push_back("null(" + location_as_str() + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool boolean(bool val) override
|
||||||
|
{
|
||||||
|
events.push_back("boolean(val=" + std::string(val ? "true" : "false") + ", " + location_as_str() + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_integer(number_integer_t val) override
|
||||||
|
{
|
||||||
|
events.push_back("number_integer(val=" + std::to_string(val) + ", " + location_as_str() + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_unsigned(number_unsigned_t val) override
|
||||||
|
{
|
||||||
|
events.push_back("number_unsigned(val=" + std::to_string(val) + ", " + location_as_str() + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_float(number_float_t val, const string_t& s) override
|
||||||
|
{
|
||||||
|
events.push_back("number_float(val=" + std::to_string(val) + ", s=" + s + ", " + location_as_str() + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string(string_t& val) override
|
||||||
|
{
|
||||||
|
events.push_back("string(val=" + val + ", " + location_as_str() + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_object(std::size_t elements) override
|
||||||
|
{
|
||||||
|
events.push_back("start_object(elements=" + std::to_string(elements) + ", " + location_as_str() + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_object() override
|
||||||
|
{
|
||||||
|
events.push_back("end_object(" + location_as_str() + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_array(std::size_t elements) override
|
||||||
|
{
|
||||||
|
events.push_back("start_array(elements=" + std::to_string(elements) + ", " + location_as_str() + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_array() override
|
||||||
|
{
|
||||||
|
events.push_back("end_array(" + location_as_str() + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool key(string_t& val) override
|
||||||
|
{
|
||||||
|
events.push_back("key(val=" + val + ", " + location_as_str() + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool binary(json::binary_t& val) override
|
||||||
|
{
|
||||||
|
events.push_back("binary(val=[...], " + location_as_str() + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex) override
|
||||||
|
{
|
||||||
|
events.push_back("parse_error(position=" + std::to_string(position) + ", last_token=" + last_token + ",\n ex=" + std::string(ex.what()) + ")");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// a JSON text
|
||||||
|
auto text = R"(
|
||||||
|
{
|
||||||
|
"Image": {
|
||||||
|
"Width": 800,
|
||||||
|
"Height": 600,
|
||||||
|
"Title": "View from 15th Floor",
|
||||||
|
"Thumbnail": {
|
||||||
|
"Url": "http://www.example.com/image/481989943",
|
||||||
|
"Height": 125,
|
||||||
|
"Width": 100
|
||||||
|
},
|
||||||
|
"Animated" : false,
|
||||||
|
"IDs": [116, 943, 234, -38793],
|
||||||
|
"DeletionDate": null,
|
||||||
|
"Distance": 12.723374634
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
)";
|
||||||
|
|
||||||
|
// create a SAX event consumer object
|
||||||
|
sax_event_consumer sec;
|
||||||
|
|
||||||
|
// parse JSON
|
||||||
|
bool result = json::sax_parse(text, &sec);
|
||||||
|
|
||||||
|
// output the recorded events
|
||||||
|
for (auto& event : sec.events)
|
||||||
|
{
|
||||||
|
std::cout << event << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// output the result of sax_parse
|
||||||
|
std::cout << "\nresult: " << std::boolalpha << result << std::endl;
|
||||||
|
}
|
||||||
37
docs/examples/sax_parse_with_src_location.output
Normal file
37
docs/examples/sax_parse_with_src_location.output
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
start_object(elements=18446744073709551615, at=[5,6))
|
||||||
|
key(val=Image, at=[15,22))
|
||||||
|
start_object(elements=18446744073709551615, at=[24,25))
|
||||||
|
key(val=Width, at=[38,45))
|
||||||
|
number_unsigned(val=800, at=[48,51))
|
||||||
|
key(val=Height, at=[65,73))
|
||||||
|
number_unsigned(val=600, at=[75,78))
|
||||||
|
key(val=Title, at=[92,99))
|
||||||
|
string(val=View from 15th Floor, at=[102,124))
|
||||||
|
key(val=Thumbnail, at=[138,149))
|
||||||
|
start_object(elements=18446744073709551615, at=[151,152))
|
||||||
|
key(val=Url, at=[169,174))
|
||||||
|
string(val=http://www.example.com/image/481989943, at=[179,219))
|
||||||
|
key(val=Height, at=[237,245))
|
||||||
|
number_unsigned(val=125, at=[247,250))
|
||||||
|
key(val=Width, at=[268,275))
|
||||||
|
number_unsigned(val=100, at=[278,281))
|
||||||
|
end_object(at=[294,295))
|
||||||
|
key(val=Animated, at=[309,319))
|
||||||
|
boolean(val=false, at=[322,327))
|
||||||
|
key(val=IDs, at=[341,346))
|
||||||
|
start_array(elements=18446744073709551615, at=[348,349))
|
||||||
|
number_unsigned(val=116, at=[349,352))
|
||||||
|
number_unsigned(val=943, at=[354,357))
|
||||||
|
number_unsigned(val=234, at=[359,362))
|
||||||
|
number_integer(val=-38793, at=[364,370))
|
||||||
|
end_array(at=[370,371))
|
||||||
|
key(val=DeletionDate, at=[385,399))
|
||||||
|
null(at=[401,405))
|
||||||
|
key(val=Distance, at=[419,429))
|
||||||
|
number_float(val=12.723375, s=12.723374634, at=[431,443))
|
||||||
|
end_object(at=[452,453))
|
||||||
|
end_object(at=[458,459))
|
||||||
|
parse_error(position=460, last_token=12.723374634<U+000A> }<U+000A> }],
|
||||||
|
ex=[json.exception.parse_error.101] parse error at line 17, column 6: syntax error while parsing value - unexpected ']'; expected end of input)
|
||||||
|
|
||||||
|
result: false
|
||||||
336
docs/examples/sax_parse_with_src_location_in_json.cpp
Normal file
336
docs/examples/sax_parse_with_src_location_in_json.cpp
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
// custom base class for the json node.
|
||||||
|
// allows us to store metadata and add custom methods to each node
|
||||||
|
struct token_start_stop
|
||||||
|
{
|
||||||
|
nlohmann::position_t start{};
|
||||||
|
nlohmann::position_t stop{};
|
||||||
|
|
||||||
|
std::string start_pos_str() const
|
||||||
|
{
|
||||||
|
return "{l=" + std::to_string(start.lines_read) + ":c="
|
||||||
|
+ std::to_string(start.chars_read_current_line) + "}";
|
||||||
|
}
|
||||||
|
std::string stop_pos_str() const
|
||||||
|
{
|
||||||
|
return "{l=" + std::to_string(stop.lines_read) + ":c=" + std::to_string(stop.chars_read_current_line) + "}";
|
||||||
|
}
|
||||||
|
std::string location_str() const
|
||||||
|
{
|
||||||
|
return "[" + start_pos_str() + ", " + stop_pos_str() + ")";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//json type using token_start_stop as base class
|
||||||
|
using json_with_token_start_stop =
|
||||||
|
nlohmann::basic_json <
|
||||||
|
std::map,
|
||||||
|
std::vector,
|
||||||
|
std::string,
|
||||||
|
bool,
|
||||||
|
std::int64_t,
|
||||||
|
std::uint64_t,
|
||||||
|
double,
|
||||||
|
std::allocator,
|
||||||
|
nlohmann::adl_serializer,
|
||||||
|
std::vector<std::uint8_t>,
|
||||||
|
token_start_stop >;
|
||||||
|
|
||||||
|
// a parser storing the lexer information for each node
|
||||||
|
class sax_with_token_start_stop_metadata
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using json = json_with_token_start_stop;
|
||||||
|
using number_integer_t = typename json::number_integer_t;
|
||||||
|
using number_unsigned_t = typename json::number_unsigned_t;
|
||||||
|
using number_float_t = typename json::number_float_t;
|
||||||
|
using string_t = typename json::string_t;
|
||||||
|
using binary_t = typename json::binary_t;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@param[in,out] r reference to a JSON value that is manipulated while
|
||||||
|
parsing
|
||||||
|
@param[in] allow_exceptions_ whether parse errors yield exceptions
|
||||||
|
*/
|
||||||
|
explicit sax_with_token_start_stop_metadata(json& r, const bool allow_exceptions_ = true)
|
||||||
|
: root(r)
|
||||||
|
, ref_stack{}
|
||||||
|
, object_element{nullptr}
|
||||||
|
, errored{false}
|
||||||
|
, allow_exceptions(allow_exceptions_)
|
||||||
|
, start_stop{}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void next_token_start(const nlohmann::position_t& p)
|
||||||
|
{
|
||||||
|
start_stop.start = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void next_token_end(const nlohmann::position_t& p)
|
||||||
|
{
|
||||||
|
start_stop.stop = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool null()
|
||||||
|
{
|
||||||
|
handle_value(nullptr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool boolean(bool val)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_integer(number_integer_t val)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_unsigned(number_unsigned_t val)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_float(number_float_t val, const string_t& /*unused*/)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string(string_t& val)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool binary(binary_t& val)
|
||||||
|
{
|
||||||
|
handle_value(std::move(val));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_object(std::size_t len)
|
||||||
|
{
|
||||||
|
ref_stack.push_back(handle_value(json::value_t::object));
|
||||||
|
ref_stack.back()->start = start_stop.start;
|
||||||
|
|
||||||
|
if (len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())
|
||||||
|
{
|
||||||
|
throw nlohmann::detail::out_of_range::create(408, nlohmann::detail::concat("excessive object size: ", std::to_string(len)), ref_stack.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool key(string_t& val)
|
||||||
|
{
|
||||||
|
assert(!ref_stack.empty());
|
||||||
|
assert(ref_stack.back()->is_object());
|
||||||
|
|
||||||
|
// add null at given key and store the reference for later
|
||||||
|
object_element = &(*ref_stack.back())[val];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_object()
|
||||||
|
{
|
||||||
|
assert(!ref_stack.empty());
|
||||||
|
assert(ref_stack.back()->is_object());
|
||||||
|
|
||||||
|
ref_stack.back()->stop = start_stop.stop;
|
||||||
|
ref_stack.pop_back();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_array(std::size_t len)
|
||||||
|
{
|
||||||
|
ref_stack.push_back(handle_value(json::value_t::array));
|
||||||
|
ref_stack.back()->start = start_stop.start;
|
||||||
|
|
||||||
|
if (len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())
|
||||||
|
{
|
||||||
|
throw nlohmann::detail::out_of_range::create(408, nlohmann::detail::concat("excessive array size: ", std::to_string(len)), ref_stack.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_array()
|
||||||
|
{
|
||||||
|
assert(!ref_stack.empty());
|
||||||
|
assert(ref_stack.back()->is_array());
|
||||||
|
|
||||||
|
ref_stack.back()->stop = start_stop.stop;
|
||||||
|
ref_stack.pop_back();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Exception>
|
||||||
|
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const Exception& ex)
|
||||||
|
{
|
||||||
|
errored = true;
|
||||||
|
static_cast<void>(ex);
|
||||||
|
if (allow_exceptions)
|
||||||
|
{
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_errored() const
|
||||||
|
{
|
||||||
|
return errored;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*!
|
||||||
|
@invariant If the ref stack is empty, then the passed value will be the new
|
||||||
|
root.
|
||||||
|
@invariant If the ref stack contains a value, then it is an array or an
|
||||||
|
object to which we can add elements
|
||||||
|
*/
|
||||||
|
template<typename Value>
|
||||||
|
json*
|
||||||
|
handle_value(Value&& v)
|
||||||
|
{
|
||||||
|
if (ref_stack.empty())
|
||||||
|
{
|
||||||
|
root = json(std::forward<Value>(v));
|
||||||
|
root.start = start_stop.start;
|
||||||
|
root.stop = start_stop.stop;
|
||||||
|
return &root;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(ref_stack.back()->is_array() || ref_stack.back()->is_object());
|
||||||
|
|
||||||
|
if (ref_stack.back()->is_array())
|
||||||
|
{
|
||||||
|
auto& array_element = ref_stack.back()->emplace_back(std::forward<Value>(v));
|
||||||
|
array_element.start = start_stop.start;
|
||||||
|
array_element.stop = start_stop.stop;
|
||||||
|
return &array_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(ref_stack.back()->is_object());
|
||||||
|
assert(object_element);
|
||||||
|
*object_element = json(std::forward<Value>(v));
|
||||||
|
object_element->start = start_stop.start;
|
||||||
|
object_element->stop = start_stop.stop;
|
||||||
|
return object_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// the parsed JSON value
|
||||||
|
json& root;
|
||||||
|
/// stack to model hierarchy of values
|
||||||
|
std::vector<json*> ref_stack{};
|
||||||
|
/// helper to hold the reference for the next object element
|
||||||
|
json* object_element = nullptr;
|
||||||
|
/// whether a syntax error occurred
|
||||||
|
bool errored = false;
|
||||||
|
/// whether to throw exceptions in case of errors
|
||||||
|
const bool allow_exceptions = true;
|
||||||
|
/// start / stop information for the current token
|
||||||
|
token_start_stop start_stop{};
|
||||||
|
};
|
||||||
|
|
||||||
|
void dump(const json_with_token_start_stop& j, std::size_t indentlvl = 0)
|
||||||
|
{
|
||||||
|
const std::string indent(indentlvl * 4, ' ');
|
||||||
|
switch (j.type())
|
||||||
|
{
|
||||||
|
case nlohmann::json::value_t::null:
|
||||||
|
{
|
||||||
|
std::cout << indent << "null(at=" << j.location_str() << ")\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nlohmann::json::value_t::object:
|
||||||
|
{
|
||||||
|
std::cout << indent << "object(size=" << j.size() << ", at=" << j.location_str() << ")\n";
|
||||||
|
for (const auto& elem : j.items())
|
||||||
|
{
|
||||||
|
dump(elem.value(), indentlvl + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nlohmann::json::value_t::array:
|
||||||
|
{
|
||||||
|
std::cout << indent << "array(size=" << j.size() << ", at=" << j.location_str() << ")\n";
|
||||||
|
for (const auto& elem : j)
|
||||||
|
{
|
||||||
|
dump(elem, indentlvl + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nlohmann::json::value_t::string:
|
||||||
|
{
|
||||||
|
std::cout << indent << "string(val=" << j.get<std::string>() << ", at=" << j.location_str() << ")\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nlohmann::json::value_t::boolean:
|
||||||
|
{
|
||||||
|
std::cout << indent << "boolean(val=" << j.get<bool>() << ", at=" << j.location_str() << ")\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nlohmann::json::value_t::number_integer:
|
||||||
|
{
|
||||||
|
std::cout << indent << "number_integer(val=" << j.get<std::int64_t>() << ", at=" << j.location_str() << ")\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nlohmann::json::value_t::number_unsigned:
|
||||||
|
{
|
||||||
|
std::cout << indent << "number_unsigned(val=" << j.get<std::uint64_t>() << ", at=" << j.location_str() << ")\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nlohmann::json::value_t::number_float:
|
||||||
|
{
|
||||||
|
std::cout << indent << "number_float(val=" << j.get<double>() << ", at=" << j.location_str() << ")\n";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error{"unexpected input"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// a JSON text
|
||||||
|
auto text = R"({
|
||||||
|
"Image": {
|
||||||
|
"Width": 800,
|
||||||
|
"Height": 600,
|
||||||
|
"Title": "View from 15th Floor",
|
||||||
|
"Thumbnail": {
|
||||||
|
"Url": "http://www.example.com/image/481989943",
|
||||||
|
"Height": 125,
|
||||||
|
"Width": 100
|
||||||
|
},
|
||||||
|
"Animated" : false,
|
||||||
|
"IDs": [116, 943, 234, -38793],
|
||||||
|
"DeletionDate": null,
|
||||||
|
"Distance": 12.723374634
|
||||||
|
}
|
||||||
|
})";
|
||||||
|
|
||||||
|
// create a SAX parser object
|
||||||
|
json_with_token_start_stop parsed;
|
||||||
|
sax_with_token_start_stop_metadata sax{parsed};
|
||||||
|
|
||||||
|
// parse JSON
|
||||||
|
bool result = json::sax_parse(text, &sax);
|
||||||
|
|
||||||
|
// output the json data
|
||||||
|
dump(parsed);
|
||||||
|
|
||||||
|
// output the result of sax_parse
|
||||||
|
std::cout << "\nresult: " << std::boolalpha << result << std::endl;
|
||||||
|
}
|
||||||
19
docs/examples/sax_parse_with_src_location_in_json.output
Normal file
19
docs/examples/sax_parse_with_src_location_in_json.output
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
object(size=1, at=[{l=0:c=0}, {l=15:c=1}))
|
||||||
|
object(size=8, at=[{l=1:c=17}, {l=14:c=9}))
|
||||||
|
boolean(val=0, at=[{l=10:c=25}, {l=10:c=30}))
|
||||||
|
null(at=[{l=12:c=28}, {l=12:c=32}))
|
||||||
|
number_float(val=12.7234, at=[{l=13:c=24}, {l=13:c=0}))
|
||||||
|
number_unsigned(val=600, at=[{l=3:c=22}, {l=3:c=25}))
|
||||||
|
array(size=4, at=[{l=11:c=19}, {l=11:c=42}))
|
||||||
|
number_unsigned(val=116, at=[{l=11:c=20}, {l=11:c=23}))
|
||||||
|
number_unsigned(val=943, at=[{l=11:c=25}, {l=11:c=28}))
|
||||||
|
number_unsigned(val=234, at=[{l=11:c=30}, {l=11:c=33}))
|
||||||
|
number_integer(val=-38793, at=[{l=11:c=35}, {l=11:c=41}))
|
||||||
|
object(size=3, at=[{l=5:c=25}, {l=9:c=13}))
|
||||||
|
number_unsigned(val=125, at=[{l=7:c=26}, {l=7:c=29}))
|
||||||
|
string(val=http://www.example.com/image/481989943, at=[{l=6:c=26}, {l=6:c=66}))
|
||||||
|
number_unsigned(val=100, at=[{l=8:c=26}, {l=8:c=0}))
|
||||||
|
string(val=View from 15th Floor, at=[{l=4:c=22}, {l=4:c=44}))
|
||||||
|
number_unsigned(val=800, at=[{l=2:c=22}, {l=2:c=25}))
|
||||||
|
|
||||||
|
result: true
|
||||||
@ -37,8 +37,11 @@ processing the input.
|
|||||||
- [**start_array**](start_array.md) (_virtual_) - the beginning of an array was read
|
- [**start_array**](start_array.md) (_virtual_) - the beginning of an array was read
|
||||||
- [**start_object**](start_object.md) (_virtual_) - the beginning of an object was read
|
- [**start_object**](start_object.md) (_virtual_) - the beginning of an object was read
|
||||||
- [**string**](string.md) (_virtual_) - a string value was read
|
- [**string**](string.md) (_virtual_) - a string value was read
|
||||||
|
- [**next_token_start**](next_token_start.md) - called to provide the start of the next element in the parsed input.
|
||||||
|
- [**next_token_end**](next_token_end.md) - called to provide the end (one past convention) of the next element in the parsed input.
|
||||||
|
|
||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
- Added in version 3.2.0.
|
- Added in version 3.2.0.
|
||||||
- Support for binary values (`binary_t`, `binary`) added in version 3.8.0.
|
- Support for binary values (`binary_t`, `binary`) added in version 3.8.0.
|
||||||
|
- Support for parser location information (`next_token_start`, `next_token_end`) added in version ???.???.???.
|
||||||
|
|||||||
66
docs/mkdocs/docs/api/json_sax/next_token_end.md
Normal file
66
docs/mkdocs/docs/api/json_sax/next_token_end.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# <small>nlohmann::json_sax::</small>next_token_end
|
||||||
|
|
||||||
|
Informs the sax parser about the end of the next element.
|
||||||
|
There are two possible signatures for this method:
|
||||||
|
|
||||||
|
1.
|
||||||
|
```cpp
|
||||||
|
void next_token_end(std::size_t pos);
|
||||||
|
```
|
||||||
|
This version is called with the byte position after the next element ends.
|
||||||
|
This version also works when parsing binary formats such as [msgpack](../basic_json/input_format_t.md).
|
||||||
|
|
||||||
|
2.
|
||||||
|
```cpp
|
||||||
|
void next_token_end(const nlohmann::position_t& p)
|
||||||
|
```
|
||||||
|
This version is called with the [detailed parser position information](../position_t/index.md) after the last character of the next element was parsed.
|
||||||
|
This version only available when calling `nlohmann::json::sax_parse` with `nlohmann::json::input_format_t::json` and takes precedence.
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
1.
|
||||||
|
`pos` (in)
|
||||||
|
: Byte position one after the next elements last byte.
|
||||||
|
2.
|
||||||
|
`p` (in)
|
||||||
|
: [Detailed parser position information](../position_t/index.md) after the last char of the next element was parsed.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Implementing either version is optional, and no function is called if neither version of `next_token_end` is available in the sax parser.
|
||||||
|
|
||||||
|
It is recommended, but not required, to also implement [next_token_start](next_token_start.md).
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
??? example
|
||||||
|
|
||||||
|
The example below shows a SAX parser using the first version of this method to log the location.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/sax_parse_with_src_location.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```json
|
||||||
|
--8<-- "examples/sax_parse_with_src_location.output"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example
|
||||||
|
|
||||||
|
The example below shows a SAX parser using the second version of this method and
|
||||||
|
storing the location information in each json node using a [base class](../basic_json/json_base_class_t.md) for `nlohmann::json` as customization point.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/sax_parse_with_src_location_in_json.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```json
|
||||||
|
--8<-- "examples/sax_parse_with_src_location_in_json.output"
|
||||||
|
```
|
||||||
|
## Version history
|
||||||
|
|
||||||
|
- Added in version ???.???.???.
|
||||||
66
docs/mkdocs/docs/api/json_sax/next_token_start.md
Normal file
66
docs/mkdocs/docs/api/json_sax/next_token_start.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# <small>nlohmann::json_sax::</small>next_token_start
|
||||||
|
|
||||||
|
Informs the sax parser about the start of the next element.
|
||||||
|
There are two possible signatures for this method:
|
||||||
|
|
||||||
|
1.
|
||||||
|
```cpp
|
||||||
|
void next_token_start(std::size_t pos);
|
||||||
|
```
|
||||||
|
This version is called with the byte position where the next element starts.
|
||||||
|
This version also works when parsing binary formats such as [msgpack](../basic_json/input_format_t.md).
|
||||||
|
|
||||||
|
2.
|
||||||
|
```cpp
|
||||||
|
void next_token_start(const nlohmann::position_t& p)
|
||||||
|
```
|
||||||
|
This version is called with [detailed parser position information](../position_t/index.md).
|
||||||
|
This version only available when calling `nlohmann::json::sax_parse` with `nlohmann::json::input_format_t::json` and takes precedence.
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
1.
|
||||||
|
`pos` (in)
|
||||||
|
: Byte position where the next element starts.
|
||||||
|
2.
|
||||||
|
`p` (in)
|
||||||
|
: [Detailed parser position information](../position_t/index.md) after the first char of the next element was parsed.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Implementing either version is optional, and no function is called if neither version of `next_token_start` is available in the sax parser.
|
||||||
|
|
||||||
|
It is recommended, but not required, to also implement [next_token_end](next_token_end.md).
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
??? example
|
||||||
|
|
||||||
|
The example below shows a SAX parser using the first version of this method to log the location.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/sax_parse_with_src_location.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```json
|
||||||
|
--8<-- "examples/sax_parse_with_src_location.output"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example
|
||||||
|
|
||||||
|
The example below shows a SAX parser using the second version of this method and
|
||||||
|
storing the location information in each json node using a [base class](../basic_json/json_base_class_t.md) for `nlohmann::json` as customization point.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/sax_parse_with_src_location_in_json.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```json
|
||||||
|
--8<-- "examples/sax_parse_with_src_location_in_json.output"
|
||||||
|
```
|
||||||
|
## Version history
|
||||||
|
|
||||||
|
- Added in version ???.???.???.
|
||||||
28
docs/mkdocs/docs/api/position_t/chars_read_current_line.md
Normal file
28
docs/mkdocs/docs/api/position_t/chars_read_current_line.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# <small>nlohmann::position_t::</small>chars_read_current_line
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::size_t chars_read_current_line;
|
||||||
|
```
|
||||||
|
|
||||||
|
The number of characters read in the current line.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
??? example
|
||||||
|
|
||||||
|
The example below shows a SAX receiving the element bounds as `nlohmann::position_t` and
|
||||||
|
storing this location information in each json node using a [base class](../basic_json/json_base_class_t.md) for `nlohmann::json` as customization point.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/sax_parse_with_src_location_in_json.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```json
|
||||||
|
--8<-- "examples/sax_parse_with_src_location_in_json.output"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Version history
|
||||||
|
|
||||||
|
- Moved from namespace `nlohmann::detail` to `nlohmann` in version ???.???.???.
|
||||||
28
docs/mkdocs/docs/api/position_t/chars_read_total.md
Normal file
28
docs/mkdocs/docs/api/position_t/chars_read_total.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# <small>nlohmann::position_t::</small>chars_read_total
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::size_t chars_read_total;
|
||||||
|
```
|
||||||
|
|
||||||
|
The total number of characters read.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
??? example
|
||||||
|
|
||||||
|
The example below shows a SAX receiving the element bounds as `nlohmann::position_t` and
|
||||||
|
storing this location information in each json node using a [base class](../basic_json/json_base_class_t.md) for `nlohmann::json` as customization point.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/sax_parse_with_src_location_in_json.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```json
|
||||||
|
--8<-- "examples/sax_parse_with_src_location_in_json.output"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Version history
|
||||||
|
|
||||||
|
- Moved from namespace `nlohmann::detail` to `nlohmann` in version ???.???.???.
|
||||||
23
docs/mkdocs/docs/api/position_t/index.md
Normal file
23
docs/mkdocs/docs/api/position_t/index.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# <small>nlohmann::</small>position_t
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct position_t;
|
||||||
|
```
|
||||||
|
|
||||||
|
This type represents the parsers position when parsing a json string using.
|
||||||
|
This position can be retrieved when using a [sax parser](../json_sax/index.md) with the format `nlohmann::json::input_format_t::json`
|
||||||
|
and implementing [next_token_start](../json_sax/next_token_start.md) or [next_token_end](../json_sax/next_token_end.md).
|
||||||
|
|
||||||
|
## Member functions
|
||||||
|
|
||||||
|
- [**operator size_t**](operator_size_t.md) - return the value of [chars_read_total](chars_read_total.md).
|
||||||
|
|
||||||
|
## Member variables
|
||||||
|
|
||||||
|
- [**chars_read_total**](chars_read_total.md) - The total number of characters read.
|
||||||
|
- [**lines_read**](lines_read.md) - The number of lines read.
|
||||||
|
- [**chars_read_current_line**](chars_read_current_line.md) - The number of characters read in the current line.
|
||||||
|
|
||||||
|
## Version history
|
||||||
|
|
||||||
|
- Moved from namespace `nlohmann::detail` to `nlohmann` in version ???.???.???.
|
||||||
28
docs/mkdocs/docs/api/position_t/lines_read.md
Normal file
28
docs/mkdocs/docs/api/position_t/lines_read.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# <small>nlohmann::position_t::</small>lines_read
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::size_t lines_read;
|
||||||
|
```
|
||||||
|
|
||||||
|
The number of lines read.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
??? example
|
||||||
|
|
||||||
|
The example below shows a SAX receiving the element bounds as `nlohmann::position_t` and
|
||||||
|
storing this location information in each json node using a [base class](../basic_json/json_base_class_t.md) for `nlohmann::json` as customization point.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/sax_parse_with_src_location_in_json.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```json
|
||||||
|
--8<-- "examples/sax_parse_with_src_location_in_json.output"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Version history
|
||||||
|
|
||||||
|
- Moved from namespace `nlohmann::detail` to `nlohmann` in version ???.???.???.
|
||||||
28
docs/mkdocs/docs/api/position_t/operator_size_t.md
Normal file
28
docs/mkdocs/docs/api/position_t/operator_size_t.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# <small>nlohmann::position_t::</small>
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
constexpr operator size_t() const;
|
||||||
|
```
|
||||||
|
|
||||||
|
return the value of [chars_read_total](chars_read_total.md).
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
??? example
|
||||||
|
|
||||||
|
The example below shows a SAX receiving the element bounds as `nlohmann::position_t` and
|
||||||
|
storing this location information in each json node using a [base class](../basic_json/json_base_class_t.md) for `nlohmann::json` as customization point.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
--8<-- "examples/sax_parse_with_src_location_in_json.cpp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```json
|
||||||
|
--8<-- "examples/sax_parse_with_src_location_in_json.output"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Version history
|
||||||
|
|
||||||
|
- Moved from namespace `nlohmann::detail` to `nlohmann` in version ???.???.???.
|
||||||
@ -67,6 +67,30 @@ To implement your own SAX handler, proceed as follows:
|
|||||||
|
|
||||||
Note the `sax_parse` function only returns a `#!cpp bool` indicating the result of the last executed SAX event. It does not return `json` value - it is up to you to decide what to do with the SAX events. Furthermore, no exceptions are thrown in case of a parse error - it is up to you what to do with the exception object passed to your `parse_error` implementation. Internally, the SAX interface is used for the DOM parser (class `json_sax_dom_parser`) as well as the acceptor (`json_sax_acceptor`), see file `json_sax.hpp`.
|
Note the `sax_parse` function only returns a `#!cpp bool` indicating the result of the last executed SAX event. It does not return `json` value - it is up to you to decide what to do with the SAX events. Furthermore, no exceptions are thrown in case of a parse error - it is up to you what to do with the exception object passed to your `parse_error` implementation. Internally, the SAX interface is used for the DOM parser (class `json_sax_dom_parser`) as well as the acceptor (`json_sax_acceptor`), see file `json_sax.hpp`.
|
||||||
|
|
||||||
|
## Element position information
|
||||||
|
|
||||||
|
The position of a parsed element can be retrieved by implementing the optional methods [next_token_start](../../api/json_sax/next_token_start.md) and [next_token_end](../../api/json_sax/next_token_end.md).
|
||||||
|
These methods will be called with the parser position before any of the other methods are called and can be used to retrieve the half open bounds (`[start, end)`) of a parsed element.
|
||||||
|
|
||||||
|
These Methods come in two flavors:
|
||||||
|
|
||||||
|
1.
|
||||||
|
```cpp
|
||||||
|
void next_token_start(std::size_t pos);
|
||||||
|
void next_token_end(std::size_t pos);
|
||||||
|
```
|
||||||
|
This flavor is called with the byte positions of each element and are available for any `nlohmann::json::input_format_t` passed to `nlohmann::json::sax_parse`.
|
||||||
|
|
||||||
|
2.
|
||||||
|
```cpp
|
||||||
|
void next_token_start(const nlohmann::position_t& p);
|
||||||
|
void next_token_end(const nlohmann::position_t& p);
|
||||||
|
```
|
||||||
|
This flavor is called with the [detailed parser position information](../../api/position_t/index.md) of each element and are only available if `nlohmann::json::sax_parse` is called with `nlohmann::json::input_format_t::json`.
|
||||||
|
Furthermore this flavor takes precedence over the first flavor.
|
||||||
|
|
||||||
|
Depending on the required information it is possible for the SAX parser to implement all four or only one or none of these methods.
|
||||||
|
|
||||||
## See also
|
## See also
|
||||||
|
|
||||||
- [json_sax](../../api/json_sax/index.md) - documentation of the SAX interface
|
- [json_sax](../../api/json_sax/index.md) - documentation of the SAX interface
|
||||||
|
|||||||
@ -250,6 +250,8 @@ nav:
|
|||||||
- 'start_array': api/json_sax/start_array.md
|
- 'start_array': api/json_sax/start_array.md
|
||||||
- 'start_object': api/json_sax/start_object.md
|
- 'start_object': api/json_sax/start_object.md
|
||||||
- 'string': api/json_sax/string.md
|
- 'string': api/json_sax/string.md
|
||||||
|
- 'next_token_start' : api/json_sax/next_token_start.md
|
||||||
|
- 'next_token_end' : api/json_sax/next_token_end.md
|
||||||
- 'operator<<(basic_json)': api/operator_ltlt.md
|
- 'operator<<(basic_json)': api/operator_ltlt.md
|
||||||
- 'operator<<(json_pointer)': api/operator_ltlt.md
|
- 'operator<<(json_pointer)': api/operator_ltlt.md
|
||||||
- 'operator>>(basic_json)': api/operator_gtgt.md
|
- 'operator>>(basic_json)': api/operator_gtgt.md
|
||||||
@ -257,6 +259,12 @@ nav:
|
|||||||
- 'operator""_json_pointer': api/operator_literal_json_pointer.md
|
- 'operator""_json_pointer': api/operator_literal_json_pointer.md
|
||||||
- 'ordered_json': api/ordered_json.md
|
- 'ordered_json': api/ordered_json.md
|
||||||
- 'ordered_map': api/ordered_map.md
|
- 'ordered_map': api/ordered_map.md
|
||||||
|
- position_t:
|
||||||
|
- 'Overview': api/position_t/index.md
|
||||||
|
- 'operator size_t': api/position_t/operator_size_t.md
|
||||||
|
- 'chars_read_total': api/position_t/chars_read_total.md
|
||||||
|
- 'lines_read': api/position_t/lines_read.md
|
||||||
|
- 'chars_read_current_line': api/position_t/chars_read_current_line.md
|
||||||
- macros:
|
- macros:
|
||||||
- 'Overview': api/macros/index.md
|
- 'Overview': api/macros/index.md
|
||||||
- 'JSON_ASSERT': api/macros/json_assert.md
|
- 'JSON_ASSERT': api/macros/json_assert.md
|
||||||
|
|||||||
@ -167,8 +167,9 @@ class binary_reader
|
|||||||
bool parse_bson_internal()
|
bool parse_bson_internal()
|
||||||
{
|
{
|
||||||
std::int32_t document_size{};
|
std::int32_t document_size{};
|
||||||
|
detail::sax_call_next_token_start_pos(sax, chars_read);
|
||||||
get_number<std::int32_t, true>(input_format_t::bson, document_size);
|
get_number<std::int32_t, true>(input_format_t::bson, document_size);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
|
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -179,6 +180,7 @@ class binary_reader
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->end_object();
|
return sax->end_object();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,6 +278,7 @@ class binary_reader
|
|||||||
case 0x01: // double
|
case 0x01: // double
|
||||||
{
|
{
|
||||||
double number{};
|
double number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read, chars_read + sizeof(number));
|
||||||
return get_number<double, true>(input_format_t::bson, number) && sax->number_float(static_cast<number_float_t>(number), "");
|
return get_number<double, true>(input_format_t::bson, number) && sax->number_float(static_cast<number_float_t>(number), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,7 +286,10 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
std::int32_t len{};
|
std::int32_t len{};
|
||||||
string_t value;
|
string_t value;
|
||||||
return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value);
|
detail::sax_call_next_token_start_pos(sax, chars_read);
|
||||||
|
const bool result_get = get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_string(len, value);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
return result_get && sax->string(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x03: // object
|
case 0x03: // object
|
||||||
@ -300,28 +306,35 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
std::int32_t len{};
|
std::int32_t len{};
|
||||||
binary_t value;
|
binary_t value;
|
||||||
return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value);
|
detail::sax_call_next_token_start_pos(sax, chars_read);
|
||||||
|
const bool result_get = get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_binary(len, value);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
return result_get && sax->binary(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x08: // boolean
|
case 0x08: // boolean
|
||||||
{
|
{
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read, chars_read + 1);
|
||||||
return sax->boolean(get() != 0);
|
return sax->boolean(get() != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x0A: // null
|
case 0x0A: // null
|
||||||
{
|
{
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read);
|
||||||
return sax->null();
|
return sax->null();
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x10: // int32
|
case 0x10: // int32
|
||||||
{
|
{
|
||||||
std::int32_t value{};
|
std::int32_t value{};
|
||||||
return get_number<std::int32_t, true>(input_format_t::bson, value) && sax->number_integer(value);
|
detail::sax_call_next_token_start_end_pos(sax, chars_read, chars_read + sizeof(value));
|
||||||
|
return get_number<std::int32_t, true>(input_format_t::bson, value) && sax->number_integer(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x12: // int64
|
case 0x12: // int64
|
||||||
{
|
{
|
||||||
std::int64_t value{};
|
std::int64_t value{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read, chars_read + sizeof(value));
|
||||||
return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value);
|
return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,14 +373,22 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
|
|
||||||
const std::size_t element_type_parse_position = chars_read;
|
const std::size_t element_type_parse_position = chars_read;
|
||||||
|
if (!is_array)
|
||||||
|
{
|
||||||
|
detail::sax_call_next_token_start_pos(sax, chars_read);
|
||||||
|
}
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key)))
|
if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_array && !sax->key(key))
|
if (!is_array)
|
||||||
{
|
{
|
||||||
return false;
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
if (!sax->key(key))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position)))
|
if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position)))
|
||||||
@ -389,6 +410,7 @@ class binary_reader
|
|||||||
bool parse_bson_array()
|
bool parse_bson_array()
|
||||||
{
|
{
|
||||||
std::int32_t document_size{};
|
std::int32_t document_size{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read, chars_read + sizeof(std::int32_t));
|
||||||
get_number<std::int32_t, true>(input_format_t::bson, document_size);
|
get_number<std::int32_t, true>(input_format_t::bson, document_size);
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
|
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
|
||||||
@ -401,6 +423,7 @@ class binary_reader
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->end_array();
|
return sax->end_array();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,29 +473,34 @@ class binary_reader
|
|||||||
case 0x15:
|
case 0x15:
|
||||||
case 0x16:
|
case 0x16:
|
||||||
case 0x17:
|
case 0x17:
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->number_unsigned(static_cast<number_unsigned_t>(current));
|
return sax->number_unsigned(static_cast<number_unsigned_t>(current));
|
||||||
|
|
||||||
case 0x18: // Unsigned integer (one-byte uint8_t follows)
|
case 0x18: // Unsigned integer (one-byte uint8_t follows)
|
||||||
{
|
{
|
||||||
std::uint8_t number{};
|
std::uint8_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
|
return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x19: // Unsigned integer (two-byte uint16_t follows)
|
case 0x19: // Unsigned integer (two-byte uint16_t follows)
|
||||||
{
|
{
|
||||||
std::uint16_t number{};
|
std::uint16_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
|
return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x1A: // Unsigned integer (four-byte uint32_t follows)
|
case 0x1A: // Unsigned integer (four-byte uint32_t follows)
|
||||||
{
|
{
|
||||||
std::uint32_t number{};
|
std::uint32_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
|
return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x1B: // Unsigned integer (eight-byte uint64_t follows)
|
case 0x1B: // Unsigned integer (eight-byte uint64_t follows)
|
||||||
{
|
{
|
||||||
std::uint64_t number{};
|
std::uint64_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
|
return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -501,29 +529,34 @@ class binary_reader
|
|||||||
case 0x35:
|
case 0x35:
|
||||||
case 0x36:
|
case 0x36:
|
||||||
case 0x37:
|
case 0x37:
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));
|
return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));
|
||||||
|
|
||||||
case 0x38: // Negative integer (one-byte uint8_t follows)
|
case 0x38: // Negative integer (one-byte uint8_t follows)
|
||||||
{
|
{
|
||||||
std::uint8_t number{};
|
std::uint8_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
|
return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
|
case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
|
||||||
{
|
{
|
||||||
std::uint16_t number{};
|
std::uint16_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
|
return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
|
case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
|
||||||
{
|
{
|
||||||
std::uint32_t number{};
|
std::uint32_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
|
return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
|
case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
|
||||||
{
|
{
|
||||||
std::uint64_t number{};
|
std::uint64_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1)
|
return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1)
|
||||||
- static_cast<number_integer_t>(number));
|
- static_cast<number_integer_t>(number));
|
||||||
}
|
}
|
||||||
@ -560,7 +593,10 @@ class binary_reader
|
|||||||
case 0x5F: // Binary data (indefinite length)
|
case 0x5F: // Binary data (indefinite length)
|
||||||
{
|
{
|
||||||
binary_t b;
|
binary_t b;
|
||||||
return get_cbor_binary(b) && sax->binary(b);
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_cbor_binary(b);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
return result_get && sax->binary(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// UTF-8 string (0x00..0x17 bytes follow)
|
// UTF-8 string (0x00..0x17 bytes follow)
|
||||||
@ -595,7 +631,10 @@ class binary_reader
|
|||||||
case 0x7F: // UTF-8 string (indefinite length)
|
case 0x7F: // UTF-8 string (indefinite length)
|
||||||
{
|
{
|
||||||
string_t s;
|
string_t s;
|
||||||
return get_cbor_string(s) && sax->string(s);
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_cbor_string(s);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
return result_get && sax->string(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// array (0x00..0x17 data items follow)
|
// array (0x00..0x17 data items follow)
|
||||||
@ -623,35 +662,51 @@ class binary_reader
|
|||||||
case 0x95:
|
case 0x95:
|
||||||
case 0x96:
|
case 0x96:
|
||||||
case 0x97:
|
case 0x97:
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return get_cbor_array(
|
return get_cbor_array(
|
||||||
conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
|
conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
|
||||||
|
|
||||||
case 0x98: // array (one-byte uint8_t for n follows)
|
case 0x98: // array (one-byte uint8_t for n follows)
|
||||||
{
|
{
|
||||||
std::uint8_t len{};
|
std::uint8_t len{};
|
||||||
return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_number(input_format_t::cbor, len);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
return result_get && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x99: // array (two-byte uint16_t for n follow)
|
case 0x99: // array (two-byte uint16_t for n follow)
|
||||||
{
|
{
|
||||||
std::uint16_t len{};
|
std::uint16_t len{};
|
||||||
return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_number(input_format_t::cbor, len);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
return result_get && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x9A: // array (four-byte uint32_t for n follow)
|
case 0x9A: // array (four-byte uint32_t for n follow)
|
||||||
{
|
{
|
||||||
std::uint32_t len{};
|
std::uint32_t len{};
|
||||||
return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler);
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_number(input_format_t::cbor, len);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
return result_get && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x9B: // array (eight-byte uint64_t for n follow)
|
case 0x9B: // array (eight-byte uint64_t for n follow)
|
||||||
{
|
{
|
||||||
std::uint64_t len{};
|
std::uint64_t len{};
|
||||||
return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler);
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_number(input_format_t::cbor, len);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
return result_get && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x9F: // array (indefinite length)
|
case 0x9F: // array (indefinite length)
|
||||||
|
{
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return get_cbor_array(static_cast<std::size_t>(-1), tag_handler);
|
return get_cbor_array(static_cast<std::size_t>(-1), tag_handler);
|
||||||
|
}
|
||||||
|
|
||||||
// map (0x00..0x17 pairs of data items follow)
|
// map (0x00..0x17 pairs of data items follow)
|
||||||
case 0xA0:
|
case 0xA0:
|
||||||
@ -678,33 +733,47 @@ class binary_reader
|
|||||||
case 0xB5:
|
case 0xB5:
|
||||||
case 0xB6:
|
case 0xB6:
|
||||||
case 0xB7:
|
case 0xB7:
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return get_cbor_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
|
return get_cbor_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
|
||||||
|
|
||||||
case 0xB8: // map (one-byte uint8_t for n follows)
|
case 0xB8: // map (one-byte uint8_t for n follows)
|
||||||
{
|
{
|
||||||
std::uint8_t len{};
|
std::uint8_t len{};
|
||||||
return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_number(input_format_t::cbor, len);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
return result_get && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xB9: // map (two-byte uint16_t for n follow)
|
case 0xB9: // map (two-byte uint16_t for n follow)
|
||||||
{
|
{
|
||||||
std::uint16_t len{};
|
std::uint16_t len{};
|
||||||
return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_number(input_format_t::cbor, len);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
return result_get && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xBA: // map (four-byte uint32_t for n follow)
|
case 0xBA: // map (four-byte uint32_t for n follow)
|
||||||
{
|
{
|
||||||
std::uint32_t len{};
|
std::uint32_t len{};
|
||||||
return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler);
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_number(input_format_t::cbor, len);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
return result_get && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xBB: // map (eight-byte uint64_t for n follow)
|
case 0xBB: // map (eight-byte uint64_t for n follow)
|
||||||
{
|
{
|
||||||
std::uint64_t len{};
|
std::uint64_t len{};
|
||||||
return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler);
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_number(input_format_t::cbor, len);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
return result_get && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xBF: // map (indefinite length)
|
case 0xBF: // map (indefinite length)
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return get_cbor_object(static_cast<std::size_t>(-1), tag_handler);
|
return get_cbor_object(static_cast<std::size_t>(-1), tag_handler);
|
||||||
|
|
||||||
case 0xC6: // tagged item
|
case 0xC6: // tagged item
|
||||||
@ -809,7 +878,10 @@ class binary_reader
|
|||||||
return parse_cbor_internal(true, tag_handler);
|
return parse_cbor_internal(true, tag_handler);
|
||||||
}
|
}
|
||||||
get();
|
get();
|
||||||
return get_cbor_binary(b) && sax->binary(b);
|
detail::sax_call_next_token_start_pos(sax, chars_read);
|
||||||
|
const bool result_get = get_cbor_binary(b);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
return result_get && sax->binary(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
default: // LCOV_EXCL_LINE
|
default: // LCOV_EXCL_LINE
|
||||||
@ -819,16 +891,20 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 0xF4: // false
|
case 0xF4: // false
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->boolean(false);
|
return sax->boolean(false);
|
||||||
|
|
||||||
case 0xF5: // true
|
case 0xF5: // true
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->boolean(true);
|
return sax->boolean(true);
|
||||||
|
|
||||||
case 0xF6: // null
|
case 0xF6: // null
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->null();
|
return sax->null();
|
||||||
|
|
||||||
case 0xF9: // Half-Precision Float (two-byte IEEE 754)
|
case 0xF9: // Half-Precision Float (two-byte IEEE 754)
|
||||||
{
|
{
|
||||||
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
const auto byte1_raw = get();
|
const auto byte1_raw = get();
|
||||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number")))
|
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number")))
|
||||||
{
|
{
|
||||||
@ -870,6 +946,7 @@ class binary_reader
|
|||||||
return std::ldexp(mant + 1024, exp - 25);
|
return std::ldexp(mant + 1024, exp - 25);
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
return sax->number_float((half & 0x8000u) != 0
|
return sax->number_float((half & 0x8000u) != 0
|
||||||
? static_cast<number_float_t>(-val)
|
? static_cast<number_float_t>(-val)
|
||||||
: static_cast<number_float_t>(val), "");
|
: static_cast<number_float_t>(val), "");
|
||||||
@ -878,12 +955,14 @@ class binary_reader
|
|||||||
case 0xFA: // Single-Precision Float (four-byte IEEE 754)
|
case 0xFA: // Single-Precision Float (four-byte IEEE 754)
|
||||||
{
|
{
|
||||||
float number{};
|
float number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), "");
|
return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xFB: // Double-Precision Float (eight-byte IEEE 754)
|
case 0xFB: // Double-Precision Float (eight-byte IEEE 754)
|
||||||
{
|
{
|
||||||
double number{};
|
double number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), "");
|
return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1127,6 +1206,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read);
|
||||||
return sax->end_array();
|
return sax->end_array();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1152,7 +1232,10 @@ class binary_reader
|
|||||||
for (std::size_t i = 0; i < len; ++i)
|
for (std::size_t i = 0; i < len; ++i)
|
||||||
{
|
{
|
||||||
get();
|
get();
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_cbor_string(key);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!result_get || !sax->key(key)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1168,7 +1251,10 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
while (get() != 0xFF)
|
while (get() != 0xFF)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_cbor_string(key);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!result_get || !sax->key(key)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1182,6 +1268,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read);
|
||||||
return sax->end_object();
|
return sax->end_object();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1329,6 +1416,7 @@ class binary_reader
|
|||||||
case 0x7D:
|
case 0x7D:
|
||||||
case 0x7E:
|
case 0x7E:
|
||||||
case 0x7F:
|
case 0x7F:
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->number_unsigned(static_cast<number_unsigned_t>(current));
|
return sax->number_unsigned(static_cast<number_unsigned_t>(current));
|
||||||
|
|
||||||
// fixmap
|
// fixmap
|
||||||
@ -1348,6 +1436,7 @@ class binary_reader
|
|||||||
case 0x8D:
|
case 0x8D:
|
||||||
case 0x8E:
|
case 0x8E:
|
||||||
case 0x8F:
|
case 0x8F:
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return get_msgpack_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
|
return get_msgpack_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
|
||||||
|
|
||||||
// fixarray
|
// fixarray
|
||||||
@ -1367,6 +1456,7 @@ class binary_reader
|
|||||||
case 0x9D:
|
case 0x9D:
|
||||||
case 0x9E:
|
case 0x9E:
|
||||||
case 0x9F:
|
case 0x9F:
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return get_msgpack_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
|
return get_msgpack_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
|
||||||
|
|
||||||
// fixstr
|
// fixstr
|
||||||
@ -1407,16 +1497,22 @@ class binary_reader
|
|||||||
case 0xDB: // str 32
|
case 0xDB: // str 32
|
||||||
{
|
{
|
||||||
string_t s;
|
string_t s;
|
||||||
return get_msgpack_string(s) && sax->string(s);
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_msgpack_string(s);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
return result_get && sax->string(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xC0: // nil
|
case 0xC0: // nil
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->null();
|
return sax->null();
|
||||||
|
|
||||||
case 0xC2: // false
|
case 0xC2: // false
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->boolean(false);
|
return sax->boolean(false);
|
||||||
|
|
||||||
case 0xC3: // true
|
case 0xC3: // true
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->boolean(true);
|
return sax->boolean(true);
|
||||||
|
|
||||||
case 0xC4: // bin 8
|
case 0xC4: // bin 8
|
||||||
@ -1432,90 +1528,107 @@ class binary_reader
|
|||||||
case 0xD8: // fixext 16
|
case 0xD8: // fixext 16
|
||||||
{
|
{
|
||||||
binary_t b;
|
binary_t b;
|
||||||
return get_msgpack_binary(b) && sax->binary(b);
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_msgpack_binary(b);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
return result_get && sax->binary(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xCA: // float 32
|
case 0xCA: // float 32
|
||||||
{
|
{
|
||||||
float number{};
|
float number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), "");
|
return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xCB: // float 64
|
case 0xCB: // float 64
|
||||||
{
|
{
|
||||||
double number{};
|
double number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), "");
|
return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xCC: // uint 8
|
case 0xCC: // uint 8
|
||||||
{
|
{
|
||||||
std::uint8_t number{};
|
std::uint8_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
|
return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xCD: // uint 16
|
case 0xCD: // uint 16
|
||||||
{
|
{
|
||||||
std::uint16_t number{};
|
std::uint16_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
|
return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xCE: // uint 32
|
case 0xCE: // uint 32
|
||||||
{
|
{
|
||||||
std::uint32_t number{};
|
std::uint32_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
|
return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xCF: // uint 64
|
case 0xCF: // uint 64
|
||||||
{
|
{
|
||||||
std::uint64_t number{};
|
std::uint64_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
|
return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xD0: // int 8
|
case 0xD0: // int 8
|
||||||
{
|
{
|
||||||
std::int8_t number{};
|
std::int8_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
|
return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xD1: // int 16
|
case 0xD1: // int 16
|
||||||
{
|
{
|
||||||
std::int16_t number{};
|
std::int16_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
|
return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xD2: // int 32
|
case 0xD2: // int 32
|
||||||
{
|
{
|
||||||
std::int32_t number{};
|
std::int32_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
|
return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xD3: // int 64
|
case 0xD3: // int 64
|
||||||
{
|
{
|
||||||
std::int64_t number{};
|
std::int64_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
|
return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xDC: // array 16
|
case 0xDC: // array 16
|
||||||
{
|
{
|
||||||
std::uint16_t len{};
|
std::uint16_t len{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(len));
|
||||||
return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len));
|
return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xDD: // array 32
|
case 0xDD: // array 32
|
||||||
{
|
{
|
||||||
std::uint32_t len{};
|
std::uint32_t len{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(len));
|
||||||
return get_number(input_format_t::msgpack, len) && get_msgpack_array(conditional_static_cast<std::size_t>(len));
|
return get_number(input_format_t::msgpack, len) && get_msgpack_array(conditional_static_cast<std::size_t>(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xDE: // map 16
|
case 0xDE: // map 16
|
||||||
{
|
{
|
||||||
std::uint16_t len{};
|
std::uint16_t len{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(len));
|
||||||
return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len));
|
return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xDF: // map 32
|
case 0xDF: // map 32
|
||||||
{
|
{
|
||||||
std::uint32_t len{};
|
std::uint32_t len{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(len));
|
||||||
return get_number(input_format_t::msgpack, len) && get_msgpack_object(conditional_static_cast<std::size_t>(len));
|
return get_number(input_format_t::msgpack, len) && get_msgpack_object(conditional_static_cast<std::size_t>(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1552,6 +1665,7 @@ class binary_reader
|
|||||||
case 0xFD:
|
case 0xFD:
|
||||||
case 0xFE:
|
case 0xFE:
|
||||||
case 0xFF:
|
case 0xFF:
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->number_integer(static_cast<std::int8_t>(current));
|
return sax->number_integer(static_cast<std::int8_t>(current));
|
||||||
|
|
||||||
default: // anything else
|
default: // anything else
|
||||||
@ -1782,6 +1896,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read);
|
||||||
return sax->end_array();
|
return sax->end_array();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1800,7 +1915,10 @@ class binary_reader
|
|||||||
for (std::size_t i = 0; i < len; ++i)
|
for (std::size_t i = 0; i < len; ++i)
|
||||||
{
|
{
|
||||||
get();
|
get();
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key)))
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_msgpack_string(key);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!result_get || !sax->key(key)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1812,6 +1930,7 @@ class binary_reader
|
|||||||
key.clear();
|
key.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read);
|
||||||
return sax->end_object();
|
return sax->end_object();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2174,7 +2293,6 @@ class binary_reader
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string_t key = "_ArraySize_";
|
string_t key = "_ArraySize_";
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3) || !sax->key(key) || !sax->start_array(dim.size())))
|
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3) || !sax->key(key) || !sax->start_array(dim.size())))
|
||||||
{
|
{
|
||||||
@ -2235,7 +2353,6 @@ class binary_reader
|
|||||||
bool is_ndarray = false;
|
bool is_ndarray = false;
|
||||||
|
|
||||||
get_ignore_noop();
|
get_ignore_noop();
|
||||||
|
|
||||||
if (current == '$')
|
if (current == '$')
|
||||||
{
|
{
|
||||||
result.second = get(); // must not ignore 'N', because 'N' maybe the type
|
result.second = get(); // must not ignore 'N', because 'N' maybe the type
|
||||||
@ -2264,7 +2381,9 @@ class binary_reader
|
|||||||
exception_message(input_format, concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr));
|
exception_message(input_format, concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
|
const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
|
||||||
|
//detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
if (input_format == input_format_t::bjdata && is_ndarray)
|
if (input_format == input_format_t::bjdata && is_ndarray)
|
||||||
{
|
{
|
||||||
if (inside_ndarray)
|
if (inside_ndarray)
|
||||||
@ -2279,7 +2398,9 @@ class binary_reader
|
|||||||
|
|
||||||
if (current == '#')
|
if (current == '#')
|
||||||
{
|
{
|
||||||
|
// detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
|
const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
|
||||||
|
// detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
if (input_format == input_format_t::bjdata && is_ndarray)
|
if (input_format == input_format_t::bjdata && is_ndarray)
|
||||||
{
|
{
|
||||||
return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
|
return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
|
||||||
@ -2288,6 +2409,7 @@ class binary_reader
|
|||||||
return is_error;
|
return is_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// detail::sax_call_next_token_start_end_pos(sax, chars_read - 2, chars_read - 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2303,40 +2425,47 @@ class binary_reader
|
|||||||
return unexpect_eof(input_format, "value");
|
return unexpect_eof(input_format, "value");
|
||||||
|
|
||||||
case 'T': // true
|
case 'T': // true
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->boolean(true);
|
return sax->boolean(true);
|
||||||
case 'F': // false
|
case 'F': // false
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->boolean(false);
|
return sax->boolean(false);
|
||||||
|
|
||||||
case 'Z': // null
|
case 'Z': // null
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->null();
|
return sax->null();
|
||||||
|
|
||||||
case 'U':
|
case 'U':
|
||||||
{
|
{
|
||||||
std::uint8_t number{};
|
std::uint8_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format, number) && sax->number_unsigned(number);
|
return get_number(input_format, number) && sax->number_unsigned(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
{
|
{
|
||||||
std::int8_t number{};
|
std::int8_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format, number) && sax->number_integer(number);
|
return get_number(input_format, number) && sax->number_integer(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'I':
|
case 'I':
|
||||||
{
|
{
|
||||||
std::int16_t number{};
|
std::int16_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format, number) && sax->number_integer(number);
|
return get_number(input_format, number) && sax->number_integer(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
{
|
{
|
||||||
std::int32_t number{};
|
std::int32_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format, number) && sax->number_integer(number);
|
return get_number(input_format, number) && sax->number_integer(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'L':
|
case 'L':
|
||||||
{
|
{
|
||||||
std::int64_t number{};
|
std::int64_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format, number) && sax->number_integer(number);
|
return get_number(input_format, number) && sax->number_integer(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2347,6 +2476,7 @@ class binary_reader
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
std::uint16_t number{};
|
std::uint16_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format, number) && sax->number_unsigned(number);
|
return get_number(input_format, number) && sax->number_unsigned(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2357,6 +2487,7 @@ class binary_reader
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
std::uint32_t number{};
|
std::uint32_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format, number) && sax->number_unsigned(number);
|
return get_number(input_format, number) && sax->number_unsigned(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2367,11 +2498,13 @@ class binary_reader
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
std::uint64_t number{};
|
std::uint64_t number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format, number) && sax->number_unsigned(number);
|
return get_number(input_format, number) && sax->number_unsigned(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
{
|
{
|
||||||
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
if (input_format != input_format_t::bjdata)
|
if (input_format != input_format_t::bjdata)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@ -2417,25 +2550,30 @@ class binary_reader
|
|||||||
return std::ldexp(mant + 1024, exp - 25);
|
return std::ldexp(mant + 1024, exp - 25);
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
return sax->number_float((half & 0x8000u) != 0
|
return sax->number_float((half & 0x8000u) != 0
|
||||||
? static_cast<number_float_t>(-val)
|
? static_cast<number_float_t>(-val)
|
||||||
: static_cast<number_float_t>(val), "");
|
: static_cast<number_float_t>(val),
|
||||||
|
"");
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
{
|
{
|
||||||
float number{};
|
float number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), "");
|
return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'D':
|
case 'D':
|
||||||
{
|
{
|
||||||
double number{};
|
double number{};
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read + sizeof(number));
|
||||||
return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), "");
|
return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'H':
|
case 'H':
|
||||||
{
|
{
|
||||||
|
// call to detail::sax_call_next_token_start_end_pos inside of the method
|
||||||
return get_ubjson_high_precision_number();
|
return get_ubjson_high_precision_number();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2453,19 +2591,25 @@ class binary_reader
|
|||||||
exception_message(input_format, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr));
|
exception_message(input_format, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr));
|
||||||
}
|
}
|
||||||
string_t s(1, static_cast<typename string_t::value_type>(current));
|
string_t s(1, static_cast<typename string_t::value_type>(current));
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 2, chars_read);
|
||||||
return sax->string(s);
|
return sax->string(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'S': // string
|
case 'S': // string
|
||||||
{
|
{
|
||||||
string_t s;
|
string_t s;
|
||||||
return get_ubjson_string(s) && sax->string(s);
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_ubjson_string(s);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
return result_get && sax->string(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
case '[': // array
|
case '[': // array
|
||||||
|
// call to detail::sax_call_next_token_start_end_pos inside of the method
|
||||||
return get_ubjson_array();
|
return get_ubjson_array();
|
||||||
|
|
||||||
case '{': // object
|
case '{': // object
|
||||||
|
// call to detail::sax_call_next_token_start_end_pos inside of the method
|
||||||
return get_ubjson_object();
|
return get_ubjson_object();
|
||||||
|
|
||||||
default: // anything else
|
default: // anything else
|
||||||
@ -2480,6 +2624,7 @@ class binary_reader
|
|||||||
*/
|
*/
|
||||||
bool get_ubjson_array()
|
bool get_ubjson_array()
|
||||||
{
|
{
|
||||||
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
std::pair<std::size_t, char_int_type> size_and_type;
|
std::pair<std::size_t, char_int_type> size_and_type;
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))
|
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))
|
||||||
{
|
{
|
||||||
@ -2504,6 +2649,7 @@ class binary_reader
|
|||||||
exception_message(input_format, "invalid byte: 0x" + last_token, "type"), nullptr));
|
exception_message(input_format, "invalid byte: 0x" + last_token, "type"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
string_t type = it->second; // sax->string() takes a reference
|
string_t type = it->second; // sax->string() takes a reference
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type)))
|
if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type)))
|
||||||
{
|
{
|
||||||
@ -2515,6 +2661,7 @@ class binary_reader
|
|||||||
size_and_type.second = 'U';
|
size_and_type.second = 'U';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read);
|
||||||
key = "_ArrayData_";
|
key = "_ArrayData_";
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(size_and_type.first) ))
|
if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(size_and_type.first) ))
|
||||||
{
|
{
|
||||||
@ -2523,17 +2670,20 @@ class binary_reader
|
|||||||
|
|
||||||
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
||||||
{
|
{
|
||||||
|
// call to detail::sax_call_next_token_start_end_pos inside of the method
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
|
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read);
|
||||||
return (sax->end_array() && sax->end_object());
|
return (sax->end_array() && sax->end_object());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size_and_type.first != npos)
|
if (size_and_type.first != npos)
|
||||||
{
|
{
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first)))
|
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -2545,6 +2695,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
||||||
{
|
{
|
||||||
|
// call to detail::sax_call_next_token_start_end_pos inside of the method
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
|
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -2556,6 +2707,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
||||||
{
|
{
|
||||||
|
// call to detail::sax_call_next_token_start_end_pos inside of the method
|
||||||
if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
|
if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -2565,6 +2717,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read - 1);
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
|
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -2580,6 +2733,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->end_array();
|
return sax->end_array();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2588,6 +2742,7 @@ class binary_reader
|
|||||||
*/
|
*/
|
||||||
bool get_ubjson_object()
|
bool get_ubjson_object()
|
||||||
{
|
{
|
||||||
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
std::pair<std::size_t, char_int_type> size_and_type;
|
std::pair<std::size_t, char_int_type> size_and_type;
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))
|
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))
|
||||||
{
|
{
|
||||||
@ -2605,6 +2760,7 @@ class binary_reader
|
|||||||
string_t key;
|
string_t key;
|
||||||
if (size_and_type.first != npos)
|
if (size_and_type.first != npos)
|
||||||
{
|
{
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read - 1);
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first)))
|
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -2614,7 +2770,10 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_ubjson_string(key);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!result_get || !sax->key(key)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2629,7 +2788,10 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_ubjson_string(key);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!result_get || !sax->key(key)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2643,6 +2805,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read - 1);
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
|
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -2650,7 +2813,10 @@ class binary_reader
|
|||||||
|
|
||||||
while (current != '}')
|
while (current != '}')
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key)))
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
|
const bool result_get = get_ubjson_string(key, false);
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!result_get || !sax->key(key)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2663,6 +2829,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detail::sax_call_next_token_start_end_pos(sax, chars_read - 1, chars_read);
|
||||||
return sax->end_object();
|
return sax->end_object();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2671,6 +2838,7 @@ class binary_reader
|
|||||||
|
|
||||||
bool get_ubjson_high_precision_number()
|
bool get_ubjson_high_precision_number()
|
||||||
{
|
{
|
||||||
|
detail::sax_call_next_token_start_pos(sax, chars_read - 1);
|
||||||
// get size of following number string
|
// get size of following number string
|
||||||
std::size_t size{};
|
std::size_t size{};
|
||||||
bool no_ndarray = true;
|
bool no_ndarray = true;
|
||||||
@ -2691,6 +2859,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
number_vector.push_back(static_cast<char>(current));
|
number_vector.push_back(static_cast<char>(current));
|
||||||
}
|
}
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
|
|
||||||
// parse number string
|
// parse number string
|
||||||
using ia_type = decltype(detail::input_adapter(number_vector));
|
using ia_type = decltype(detail::input_adapter(number_vector));
|
||||||
@ -2888,6 +3057,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(current == std::char_traits<char_type>::eof()))
|
if (JSON_HEDLEY_UNLIKELY(current == std::char_traits<char_type>::eof()))
|
||||||
{
|
{
|
||||||
|
detail::sax_call_next_token_end_pos(sax, chars_read);
|
||||||
return sax->parse_error(chars_read, "<end of file>",
|
return sax->parse_error(chars_read, "<end of file>",
|
||||||
parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr));
|
parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1506,13 +1506,13 @@ scan_number_done:
|
|||||||
while (current == ' ' || current == '\t' || current == '\n' || current == '\r');
|
while (current == ' ' || current == '\t' || current == '\n' || current == '\r');
|
||||||
}
|
}
|
||||||
|
|
||||||
token_type scan()
|
bool scan_start()
|
||||||
{
|
{
|
||||||
// initially, skip the BOM
|
// initially, skip the BOM
|
||||||
if (position.chars_read_total == 0 && !skip_bom())
|
if (position.chars_read_total == 0 && !skip_bom())
|
||||||
{
|
{
|
||||||
error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given";
|
error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given";
|
||||||
return token_type::parse_error;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read next character and ignore whitespace
|
// read next character and ignore whitespace
|
||||||
@ -1523,13 +1523,17 @@ scan_number_done:
|
|||||||
{
|
{
|
||||||
if (!scan_comment())
|
if (!scan_comment())
|
||||||
{
|
{
|
||||||
return token_type::parse_error;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip following whitespace
|
// skip following whitespace
|
||||||
skip_whitespace();
|
skip_whitespace();
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
token_type scan_end()
|
||||||
|
{
|
||||||
switch (current)
|
switch (current)
|
||||||
{
|
{
|
||||||
// structural characters
|
// structural characters
|
||||||
@ -1593,6 +1597,10 @@ scan_number_done:
|
|||||||
return token_type::parse_error;
|
return token_type::parse_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
token_type scan()
|
||||||
|
{
|
||||||
|
return !scan_start() ? token_type::parse_error : scan_end();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// input adapter
|
/// input adapter
|
||||||
|
|||||||
@ -76,8 +76,6 @@ class parser
|
|||||||
, m_lexer(std::move(adapter), skip_comments)
|
, m_lexer(std::move(adapter), skip_comments)
|
||||||
, allow_exceptions(allow_exceptions_)
|
, allow_exceptions(allow_exceptions_)
|
||||||
{
|
{
|
||||||
// read first token
|
|
||||||
get_token();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -98,7 +96,7 @@ class parser
|
|||||||
sax_parse_internal(&sdp);
|
sax_parse_internal(&sdp);
|
||||||
|
|
||||||
// in strict mode, input must be completely read
|
// in strict mode, input must be completely read
|
||||||
if (strict && (get_token() != token_type::end_of_input))
|
if (strict && (get_token(&sdp) != token_type::end_of_input))
|
||||||
{
|
{
|
||||||
sdp.parse_error(m_lexer.get_position(),
|
sdp.parse_error(m_lexer.get_position(),
|
||||||
m_lexer.get_token_string(),
|
m_lexer.get_token_string(),
|
||||||
@ -126,7 +124,7 @@ class parser
|
|||||||
sax_parse_internal(&sdp);
|
sax_parse_internal(&sdp);
|
||||||
|
|
||||||
// in strict mode, input must be completely read
|
// in strict mode, input must be completely read
|
||||||
if (strict && (get_token() != token_type::end_of_input))
|
if (strict && (get_token(&sdp) != token_type::end_of_input))
|
||||||
{
|
{
|
||||||
sdp.parse_error(m_lexer.get_position(),
|
sdp.parse_error(m_lexer.get_position(),
|
||||||
m_lexer.get_token_string(),
|
m_lexer.get_token_string(),
|
||||||
@ -164,7 +162,7 @@ class parser
|
|||||||
const bool result = sax_parse_internal(sax);
|
const bool result = sax_parse_internal(sax);
|
||||||
|
|
||||||
// strict mode: next byte must be EOF
|
// strict mode: next byte must be EOF
|
||||||
if (result && strict && (get_token() != token_type::end_of_input))
|
if (result && strict && (get_token(sax) != token_type::end_of_input))
|
||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
m_lexer.get_token_string(),
|
m_lexer.get_token_string(),
|
||||||
@ -185,6 +183,8 @@ class parser
|
|||||||
// value to avoid a goto (see comment where set to true)
|
// value to avoid a goto (see comment where set to true)
|
||||||
bool skip_to_state_evaluation = false;
|
bool skip_to_state_evaluation = false;
|
||||||
|
|
||||||
|
// read first token
|
||||||
|
get_token(sax);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (!skip_to_state_evaluation)
|
if (!skip_to_state_evaluation)
|
||||||
@ -200,7 +200,7 @@ class parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
// closing } -> we are done
|
// closing } -> we are done
|
||||||
if (get_token() == token_type::end_object)
|
if (get_token(sax) == token_type::end_object)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
|
if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
|
||||||
{
|
{
|
||||||
@ -222,7 +222,7 @@ class parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parse separator (:)
|
// parse separator (:)
|
||||||
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
|
if (JSON_HEDLEY_UNLIKELY(get_token(sax) != token_type::name_separator))
|
||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
m_lexer.get_token_string(),
|
m_lexer.get_token_string(),
|
||||||
@ -233,7 +233,7 @@ class parser
|
|||||||
states.push_back(false);
|
states.push_back(false);
|
||||||
|
|
||||||
// parse values
|
// parse values
|
||||||
get_token();
|
get_token(sax);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,7 +245,7 @@ class parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
// closing ] -> we are done
|
// closing ] -> we are done
|
||||||
if (get_token() == token_type::end_array)
|
if (get_token(sax) == token_type::end_array)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
|
if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
|
||||||
{
|
{
|
||||||
@ -372,10 +372,10 @@ class parser
|
|||||||
if (states.back()) // array
|
if (states.back()) // array
|
||||||
{
|
{
|
||||||
// comma -> next value
|
// comma -> next value
|
||||||
if (get_token() == token_type::value_separator)
|
if (get_token(sax) == token_type::value_separator)
|
||||||
{
|
{
|
||||||
// parse a new value
|
// parse a new value
|
||||||
get_token();
|
get_token(sax);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,10 +405,10 @@ class parser
|
|||||||
// states.back() is false -> object
|
// states.back() is false -> object
|
||||||
|
|
||||||
// comma -> next value
|
// comma -> next value
|
||||||
if (get_token() == token_type::value_separator)
|
if (get_token(sax) == token_type::value_separator)
|
||||||
{
|
{
|
||||||
// parse key
|
// parse key
|
||||||
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string))
|
if (JSON_HEDLEY_UNLIKELY(get_token(sax) != token_type::value_string))
|
||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
m_lexer.get_token_string(),
|
m_lexer.get_token_string(),
|
||||||
@ -421,7 +421,7 @@ class parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parse separator (:)
|
// parse separator (:)
|
||||||
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
|
if (JSON_HEDLEY_UNLIKELY(get_token(sax) != token_type::name_separator))
|
||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
m_lexer.get_token_string(),
|
m_lexer.get_token_string(),
|
||||||
@ -429,7 +429,7 @@ class parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parse values
|
// parse values
|
||||||
get_token();
|
get_token(sax);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,10 +457,19 @@ class parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get next token from lexer
|
/// get next token from lexer and pass position info to sax (if it is accepted)
|
||||||
token_type get_token()
|
template<class SAX>
|
||||||
|
token_type get_token(SAX* sax)
|
||||||
{
|
{
|
||||||
return last_token = m_lexer.scan();
|
if (!m_lexer.scan_start())
|
||||||
|
{
|
||||||
|
last_token = token_type::parse_error;
|
||||||
|
return token_type::parse_error;
|
||||||
|
}
|
||||||
|
detail::sax_call_next_token_start_pos(sax, m_lexer);
|
||||||
|
last_token = m_lexer.scan_end();
|
||||||
|
detail::sax_call_next_token_end_pos(sax, m_lexer);
|
||||||
|
return last_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string exception_message(const token_type expected, const std::string& context)
|
std::string exception_message(const token_type expected, const std::string& context)
|
||||||
|
|||||||
@ -13,9 +13,6 @@
|
|||||||
#include <nlohmann/detail/abi_macros.hpp>
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
|
||||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
/// struct to capture the start position of the current token
|
/// struct to capture the start position of the current token
|
||||||
struct position_t
|
struct position_t
|
||||||
{
|
{
|
||||||
@ -32,6 +29,4 @@ struct position_t
|
|||||||
return chars_read_total;
|
return chars_read_total;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
NLOHMANN_JSON_NAMESPACE_END
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|||||||
@ -15,10 +15,180 @@
|
|||||||
#include <nlohmann/detail/abi_macros.hpp>
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
#include <nlohmann/detail/meta/detected.hpp>
|
#include <nlohmann/detail/meta/detected.hpp>
|
||||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||||
|
#include <nlohmann/detail/input/position_t.hpp>
|
||||||
|
|
||||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
// helper struct to call sax->next_token_start
|
||||||
|
//(we want this functionality as a type to ease passing it as template argument)
|
||||||
|
struct sax_call_next_token_start_pos_direct
|
||||||
|
{
|
||||||
|
template<typename SAX, typename...Ts>
|
||||||
|
static auto call(SAX* sax, Ts&& ...ts)
|
||||||
|
-> decltype(sax->next_token_start(std::forward<Ts>(ts)...))
|
||||||
|
{
|
||||||
|
sax->next_token_start(std::forward<Ts>(ts)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// helper struct to call sax->next_token_end
|
||||||
|
// (we want this functionality as a type to ease passing it as template argument)
|
||||||
|
struct sax_call_next_token_end_pos_direct
|
||||||
|
{
|
||||||
|
template<typename SAX, typename...Ts>
|
||||||
|
static auto call(SAX* sax, Ts&& ...ts)
|
||||||
|
-> decltype(sax->next_token_end(std::forward<Ts>(ts)...))
|
||||||
|
{
|
||||||
|
sax->next_token_end(std::forward<Ts>(ts)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// dispatch the calls to next_token_start next_token_end
|
||||||
|
// and drop the calls if the sax parser does not support these methods.
|
||||||
|
//
|
||||||
|
// DirectCaller can be set to one of sax_call_next_token_{start,end}_pos_direct to
|
||||||
|
// determine which method is called
|
||||||
|
template <typename DirectCaller, typename SAX, typename LexOrPos>
|
||||||
|
struct sax_call_function
|
||||||
|
{
|
||||||
|
// is the parameter a lexer or a byte position
|
||||||
|
static constexpr bool called_with_byte_pos = std::is_same<LexOrPos, std::size_t>::value;
|
||||||
|
|
||||||
|
template<typename SAX2, typename...Ts2>
|
||||||
|
using call_t = decltype(DirectCaller::call(std::declval<SAX2*>(), std::declval<Ts2>()...));
|
||||||
|
|
||||||
|
//the sax parser supports calls with a position
|
||||||
|
static constexpr bool detected_call_with_byte_pos =
|
||||||
|
is_detected_exact<void, call_t, SAX, std::size_t>::value;
|
||||||
|
|
||||||
|
//the sax parser supports calls with a lexer
|
||||||
|
static constexpr bool detected_call_with_lex_pos =
|
||||||
|
!called_with_byte_pos &&
|
||||||
|
is_detected_exact<void, call_t, SAX, position_t >::value;
|
||||||
|
|
||||||
|
//there either has to be a version accepting a lexer or a position
|
||||||
|
static constexpr bool valid = detected_call_with_byte_pos || detected_call_with_lex_pos;
|
||||||
|
|
||||||
|
//called with byte pos and byte pos is method supported -> pass data on
|
||||||
|
template<typename SaxT = SAX>
|
||||||
|
static typename std::enable_if <
|
||||||
|
std::is_same<SaxT, SAX>::value &&
|
||||||
|
valid &&
|
||||||
|
detected_call_with_byte_pos
|
||||||
|
>::type
|
||||||
|
call(SaxT* sax, std::size_t pos)
|
||||||
|
{
|
||||||
|
DirectCaller::call(sax, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
//the sax parser has no version of the method -> drop call
|
||||||
|
template<typename SaxT = SAX>
|
||||||
|
static typename std::enable_if <
|
||||||
|
std::is_same<SaxT, SAX>::value &&
|
||||||
|
!valid
|
||||||
|
>::type
|
||||||
|
call(SaxT* /*unused*/, const LexOrPos& /*unused*/) {}
|
||||||
|
|
||||||
|
//called with lex and lex pos method is supported -> call with position from lexer
|
||||||
|
// the start pos in the lexer is last read char -> chars_read_total-1
|
||||||
|
template<typename SaxT = SAX>
|
||||||
|
static typename std::enable_if <
|
||||||
|
std::is_same<SaxT, SAX>::value &&
|
||||||
|
valid &&
|
||||||
|
!called_with_byte_pos &&
|
||||||
|
detected_call_with_lex_pos &&
|
||||||
|
std::is_same<DirectCaller, sax_call_next_token_start_pos_direct>::value
|
||||||
|
>::type
|
||||||
|
call(SaxT* sax, const LexOrPos& lex)
|
||||||
|
{
|
||||||
|
JSON_ASSERT(lex.get_position().chars_read_total > 0);
|
||||||
|
JSON_ASSERT(lex.get_position().chars_read_current_line > 0);
|
||||||
|
//the lexer has already read the first char of the current element -> fix this
|
||||||
|
auto pos_copy = lex.get_position();
|
||||||
|
--pos_copy.chars_read_total;
|
||||||
|
--pos_copy.chars_read_current_line;
|
||||||
|
DirectCaller::call(sax, pos_copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
//called with lex and lex pos method is supported -> pass data on
|
||||||
|
// the one past end pos in the lexer is the current index -> chars_read_total
|
||||||
|
template<typename SaxT = SAX>
|
||||||
|
static typename std::enable_if <
|
||||||
|
std::is_same<SaxT, SAX>::value &&
|
||||||
|
valid &&
|
||||||
|
!called_with_byte_pos &&
|
||||||
|
detected_call_with_lex_pos &&
|
||||||
|
std::is_same<DirectCaller, sax_call_next_token_end_pos_direct>::value
|
||||||
|
>::type
|
||||||
|
call(SaxT* sax, const LexOrPos& lex)
|
||||||
|
{
|
||||||
|
DirectCaller::call(sax, lex.get_position());
|
||||||
|
}
|
||||||
|
|
||||||
|
// called with lex and only byte pos method is supported -> call with byte position from lexer
|
||||||
|
// the start pos in the lexer is last read char -> chars_read_total-1
|
||||||
|
template<typename SaxT = SAX>
|
||||||
|
static typename std::enable_if <
|
||||||
|
std::is_same<SaxT, SAX>::value &&
|
||||||
|
valid &&
|
||||||
|
!called_with_byte_pos &&
|
||||||
|
!detected_call_with_lex_pos &&
|
||||||
|
std::is_same<DirectCaller, sax_call_next_token_start_pos_direct>::value
|
||||||
|
>::type
|
||||||
|
call(SaxT* sax, const LexOrPos& lex)
|
||||||
|
{
|
||||||
|
JSON_ASSERT(lex.get_position().chars_read_total > 0);
|
||||||
|
DirectCaller::call(sax, lex.get_position().chars_read_total - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// called with lex and only byte pos method is supported -> call with byte position from lexer
|
||||||
|
// the one past end pos in the lexer is the current index -> chars_read_total
|
||||||
|
template<typename SaxT = SAX>
|
||||||
|
static typename std::enable_if <
|
||||||
|
std::is_same<SaxT, SAX>::value &&
|
||||||
|
valid &&
|
||||||
|
!called_with_byte_pos &&
|
||||||
|
!detected_call_with_lex_pos &&
|
||||||
|
std::is_same<DirectCaller, sax_call_next_token_end_pos_direct>::value
|
||||||
|
>::type
|
||||||
|
call(SaxT* sax, const LexOrPos& lex)
|
||||||
|
{
|
||||||
|
DirectCaller::call(sax, lex.get_position().chars_read_total);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//set the element start pos of a sax parser by calling any version of sax->next_token_start (if available)
|
||||||
|
template<class SAX, class LexOrPos>
|
||||||
|
void sax_call_next_token_start_pos(SAX* sax, const LexOrPos& lexOrPos)
|
||||||
|
{
|
||||||
|
using call_t = sax_call_function<sax_call_next_token_start_pos_direct, SAX, LexOrPos>;
|
||||||
|
call_t::call(sax, lexOrPos);
|
||||||
|
}
|
||||||
|
//set the element end pos of a sax parser by calling any version of sax->next_token_end (if available)
|
||||||
|
template<class SAX, class LexOrPos>
|
||||||
|
void sax_call_next_token_end_pos(SAX* sax, const LexOrPos& lexOrPos)
|
||||||
|
{
|
||||||
|
using call_t = sax_call_function<sax_call_next_token_end_pos_direct, SAX, LexOrPos>;
|
||||||
|
call_t::call(sax, lexOrPos);
|
||||||
|
}
|
||||||
|
//set the element start end pos of a sax parser by calling any version of
|
||||||
|
// sax->next_token_start and sax->next_token_end (if available)
|
||||||
|
template<class SAX, class LexOrPos1, class LexOrPos2>
|
||||||
|
void sax_call_next_token_start_end_pos(SAX* sax, const LexOrPos1& lexOrPos1, const LexOrPos2& lexOrPos2)
|
||||||
|
{
|
||||||
|
sax_call_next_token_start_pos(sax, lexOrPos1);
|
||||||
|
sax_call_next_token_end_pos(sax, lexOrPos2);
|
||||||
|
}
|
||||||
|
//set the element start end pos of a sax parser by calling any version of
|
||||||
|
// sax->next_token_start and sax->next_token_end (if available)
|
||||||
|
template<class SAX, class LexOrPos>
|
||||||
|
void sax_call_next_token_start_end_pos(SAX* sax, const LexOrPos& lexOrPos)
|
||||||
|
{
|
||||||
|
sax_call_next_token_start_pos(sax, lexOrPos);
|
||||||
|
sax_call_next_token_end_pos(sax, lexOrPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
using null_function_t = decltype(std::declval<T&>().null());
|
using null_function_t = decltype(std::declval<T&>().null());
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
1821
tests/src/unit-sax-parser-extended.cpp
Normal file
1821
tests/src/unit-sax-parser-extended.cpp
Normal file
File diff suppressed because it is too large
Load Diff
340
tests/src/unit-sax-parser-store-source-location.cpp
Normal file
340
tests/src/unit-sax-parser-store-source-location.cpp
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
/*
|
||||||
|
__ _____ _____ _____
|
||||||
|
__| | __| | | | JSON for Modern C++ (test suite)
|
||||||
|
| | |__ | | | | | | version 3.10.2
|
||||||
|
|_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||||
|
|
||||||
|
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||||
|
SPDX-License-Identifier: MIT
|
||||||
|
Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "doctest_compatibility.h"
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
//prototype to make -Wmissing-prototypes happy
|
||||||
|
std::ostream& operator<<(std::ostream& out, const nlohmann::position_t& p);
|
||||||
|
|
||||||
|
//test json parser with detailed line / col information as metadata
|
||||||
|
|
||||||
|
struct token_start_stop
|
||||||
|
{
|
||||||
|
nlohmann::position_t start{};
|
||||||
|
nlohmann::position_t stop{};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, const nlohmann::position_t& p)
|
||||||
|
{
|
||||||
|
out << p.chars_read_total << '(' << p.lines_read << ':' << p.chars_read_current_line << ')';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
using json_with_token_start_stop =
|
||||||
|
nlohmann::basic_json <
|
||||||
|
std::map,
|
||||||
|
std::vector,
|
||||||
|
std::string,
|
||||||
|
bool,
|
||||||
|
std::int64_t,
|
||||||
|
std::uint64_t,
|
||||||
|
double,
|
||||||
|
std::allocator,
|
||||||
|
nlohmann::adl_serializer,
|
||||||
|
std::vector<std::uint8_t>,
|
||||||
|
token_start_stop >;
|
||||||
|
|
||||||
|
//adapted from detail::json_sax_dom_parser
|
||||||
|
class sax_with_token_start_stop_metadata
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using json = json_with_token_start_stop;
|
||||||
|
using number_integer_t = typename json::number_integer_t;
|
||||||
|
using number_unsigned_t = typename json::number_unsigned_t;
|
||||||
|
using number_float_t = typename json::number_float_t;
|
||||||
|
using string_t = typename json::string_t;
|
||||||
|
using binary_t = typename json::binary_t;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@param[in,out] r reference to a JSON value that is manipulated while
|
||||||
|
parsing
|
||||||
|
@param[in] allow_exceptions_ whether parse errors yield exceptions
|
||||||
|
*/
|
||||||
|
explicit sax_with_token_start_stop_metadata(json& r, const bool allow_exceptions_ = true)
|
||||||
|
: root(r)
|
||||||
|
, object_element{nullptr} // NOLINT(modernize-use-default-member-init)
|
||||||
|
, errored{false} // NOLINT(modernize-use-default-member-init)
|
||||||
|
, allow_exceptions(allow_exceptions_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
sax_with_token_start_stop_metadata(sax_with_token_start_stop_metadata&&) = delete;
|
||||||
|
sax_with_token_start_stop_metadata(const sax_with_token_start_stop_metadata&) = delete;
|
||||||
|
sax_with_token_start_stop_metadata& operator=(sax_with_token_start_stop_metadata&&) = delete;
|
||||||
|
sax_with_token_start_stop_metadata& operator=(const sax_with_token_start_stop_metadata&) = delete;
|
||||||
|
|
||||||
|
~sax_with_token_start_stop_metadata() = default;
|
||||||
|
|
||||||
|
void next_token_start(const nlohmann::position_t& p)
|
||||||
|
{
|
||||||
|
start_stop.start = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void next_token_end(const nlohmann::position_t& p)
|
||||||
|
{
|
||||||
|
start_stop.stop = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool null()
|
||||||
|
{
|
||||||
|
handle_value(nullptr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool boolean(bool val)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_integer(number_integer_t val)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_unsigned(number_unsigned_t val)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_float(number_float_t val, const string_t& /*unused*/)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string(string_t& val)
|
||||||
|
{
|
||||||
|
handle_value(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool binary(binary_t& val)
|
||||||
|
{
|
||||||
|
handle_value(std::move(val));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_object(std::size_t len)
|
||||||
|
{
|
||||||
|
ref_stack.push_back(handle_value(json::value_t::object));
|
||||||
|
ref_stack.back()->start = start_stop.start;
|
||||||
|
|
||||||
|
if (len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())
|
||||||
|
{
|
||||||
|
throw nlohmann::detail::out_of_range::create(408, nlohmann::detail::concat("excessive object size: ", std::to_string(len)), ref_stack.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool key(string_t& val)
|
||||||
|
{
|
||||||
|
assert(!ref_stack.empty());
|
||||||
|
assert(ref_stack.back()->is_object());
|
||||||
|
|
||||||
|
// add null at given key and store the reference for later
|
||||||
|
object_element = &(*ref_stack.back())[val];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_object()
|
||||||
|
{
|
||||||
|
assert(!ref_stack.empty());
|
||||||
|
assert(ref_stack.back()->is_object());
|
||||||
|
|
||||||
|
ref_stack.back()->stop = start_stop.stop;
|
||||||
|
ref_stack.pop_back();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_array(std::size_t len)
|
||||||
|
{
|
||||||
|
ref_stack.push_back(handle_value(json::value_t::array));
|
||||||
|
ref_stack.back()->start = start_stop.start;
|
||||||
|
|
||||||
|
if (len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())
|
||||||
|
{
|
||||||
|
throw nlohmann::detail::out_of_range::create(408, nlohmann::detail::concat("excessive array size: ", std::to_string(len)), ref_stack.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_array()
|
||||||
|
{
|
||||||
|
assert(!ref_stack.empty());
|
||||||
|
assert(ref_stack.back()->is_array());
|
||||||
|
|
||||||
|
ref_stack.back()->stop = start_stop.stop;
|
||||||
|
ref_stack.pop_back();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Exception>
|
||||||
|
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const Exception& ex)
|
||||||
|
{
|
||||||
|
errored = true;
|
||||||
|
static_cast<void>(ex);
|
||||||
|
if (allow_exceptions)
|
||||||
|
{
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_errored() const
|
||||||
|
{
|
||||||
|
return errored;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*!
|
||||||
|
@invariant If the ref stack is empty, then the passed value will be the new
|
||||||
|
root.
|
||||||
|
@invariant If the ref stack contains a value, then it is an array or an
|
||||||
|
object to which we can add elements
|
||||||
|
*/
|
||||||
|
template<typename Value>
|
||||||
|
json*
|
||||||
|
handle_value(Value&& v)
|
||||||
|
{
|
||||||
|
if (ref_stack.empty())
|
||||||
|
{
|
||||||
|
root = json(std::forward<Value>(v));
|
||||||
|
root.start = start_stop.start;
|
||||||
|
root.stop = start_stop.stop;
|
||||||
|
return &root;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(ref_stack.back()->is_array() || ref_stack.back()->is_object());
|
||||||
|
|
||||||
|
if (ref_stack.back()->is_array())
|
||||||
|
{
|
||||||
|
auto& array_element = ref_stack.back()->emplace_back(std::forward<Value>(v));
|
||||||
|
array_element.start = start_stop.start;
|
||||||
|
array_element.stop = start_stop.stop;
|
||||||
|
return &array_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(ref_stack.back()->is_object());
|
||||||
|
assert(object_element);
|
||||||
|
*object_element = json(std::forward<Value>(v));
|
||||||
|
object_element->start = start_stop.start;
|
||||||
|
object_element->stop = start_stop.stop;
|
||||||
|
return object_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// the parsed JSON value
|
||||||
|
json& root;
|
||||||
|
/// stack to model hierarchy of values
|
||||||
|
std::vector<json*> ref_stack{};
|
||||||
|
/// helper to hold the reference for the next object element
|
||||||
|
json* object_element = nullptr;
|
||||||
|
/// whether a syntax error occurred
|
||||||
|
bool errored = false;
|
||||||
|
/// whether to throw exceptions in case of errors
|
||||||
|
const bool allow_exceptions = true;
|
||||||
|
/// start / stop information for the current token
|
||||||
|
token_start_stop start_stop {};
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_CASE("parse-json-with-position-info")
|
||||||
|
{
|
||||||
|
const std::string str =
|
||||||
|
/*line 0*/ R"({)"
|
||||||
|
"\n"
|
||||||
|
/*line 1*/ R"( "array" : [)"
|
||||||
|
"\n"
|
||||||
|
/*line 2*/ R"( 14294967296,)"
|
||||||
|
"\n"
|
||||||
|
/*line 3*/ R"( -1,)"
|
||||||
|
"\n"
|
||||||
|
/*line 4*/ R"( true,)"
|
||||||
|
"\n"
|
||||||
|
/*line 5*/ R"( 4.2,)"
|
||||||
|
"\n"
|
||||||
|
/*line 6*/ R"( null,)"
|
||||||
|
"\n"
|
||||||
|
/*line 7*/ R"( "str")"
|
||||||
|
"\n"
|
||||||
|
/*line 8*/ R"( ])"
|
||||||
|
"\n"
|
||||||
|
/*line 9*/ R"(})";
|
||||||
|
json_with_token_start_stop j;
|
||||||
|
sax_with_token_start_stop_metadata sax{j};
|
||||||
|
CHECK(nlohmann::json::sax_parse(str, &sax, nlohmann::json::input_format_t::json));
|
||||||
|
CHECK(j.start.lines_read == 0);
|
||||||
|
CHECK(j.start.chars_read_current_line == 0);
|
||||||
|
|
||||||
|
CHECK(j["array"].start.lines_read == 1);
|
||||||
|
CHECK(j["array"].start.chars_read_current_line == 12);
|
||||||
|
|
||||||
|
CHECK(j["array"][0].start.lines_read == 2);
|
||||||
|
CHECK(j["array"][0].start.chars_read_current_line == 4);
|
||||||
|
CHECK(j["array"][0].stop.lines_read == 2);
|
||||||
|
CHECK(j["array"][0].stop.chars_read_current_line == 15);
|
||||||
|
|
||||||
|
CHECK(j["array"][1].start.lines_read == 3);
|
||||||
|
CHECK(j["array"][1].start.chars_read_current_line == 4);
|
||||||
|
CHECK(j["array"][1].stop.lines_read == 3);
|
||||||
|
CHECK(j["array"][1].stop.chars_read_current_line == 6);
|
||||||
|
|
||||||
|
CHECK(j["array"][2].start.lines_read == 4);
|
||||||
|
CHECK(j["array"][2].start.chars_read_current_line == 4);
|
||||||
|
CHECK(j["array"][2].stop.lines_read == 4);
|
||||||
|
CHECK(j["array"][2].stop.chars_read_current_line == 8);
|
||||||
|
|
||||||
|
CHECK(j["array"][3].start.lines_read == 5);
|
||||||
|
CHECK(j["array"][3].start.chars_read_current_line == 4);
|
||||||
|
CHECK(j["array"][3].stop.lines_read == 5);
|
||||||
|
CHECK(j["array"][3].stop.chars_read_current_line == 7);
|
||||||
|
|
||||||
|
CHECK(j["array"][4].start.lines_read == 6); //starts directly after last value....
|
||||||
|
CHECK(j["array"][4].start.chars_read_current_line == 4);
|
||||||
|
CHECK(j["array"][4].stop.lines_read == 6);
|
||||||
|
CHECK(j["array"][4].stop.chars_read_current_line == 8);
|
||||||
|
|
||||||
|
CHECK(j["array"][5].start.lines_read == 7);
|
||||||
|
CHECK(j["array"][5].start.chars_read_current_line == 4);
|
||||||
|
CHECK(j["array"][5].stop.lines_read == 7);
|
||||||
|
CHECK(j["array"][5].stop.chars_read_current_line == 9);
|
||||||
|
|
||||||
|
CHECK(j["array"].stop.lines_read == 8);
|
||||||
|
CHECK(j["array"].stop.chars_read_current_line == 3);
|
||||||
|
|
||||||
|
CHECK(j.stop.lines_read == 9);
|
||||||
|
CHECK(j.stop.chars_read_current_line == 1);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user