diff --git a/include/json/reader.h b/include/json/reader.h
index be0d7676a..4fabe6b14 100644
--- a/include/json/reader.h
+++ b/include/json/reader.h
@@ -243,6 +243,13 @@ class JSON_API Reader {
*/
class JSON_API CharReader {
public:
+ class JSON_API StructuredError {
+ public:
+ ptrdiff_t offset_start;
+ ptrdiff_t offset_limit;
+ String message;
+ };
+
virtual ~CharReader() = default;
/** \brief Read a Value from a JSON
* document. The document must be a UTF-8 encoded string containing the
@@ -263,6 +270,12 @@ class JSON_API CharReader {
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs) = 0;
+ /** \brief Get a list of structured error messages from parsing the document.
+ *
+ * \return list of error messages.
+ */
+ virtual std::vector getStructuredErrors() const = 0;
+
class JSON_API Factory {
public:
virtual ~Factory() = default;
diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp
index 1ac5e81ab..719a35a5a 100644
--- a/src/lib_json/json_reader.cpp
+++ b/src/lib_json/json_reader.cpp
@@ -890,17 +890,12 @@ class OurReader {
public:
using Char = char;
using Location = const Char*;
- struct StructuredError {
- ptrdiff_t offset_start;
- ptrdiff_t offset_limit;
- String message;
- };
explicit OurReader(OurFeatures const& features);
bool parse(const char* beginDoc, const char* endDoc, Value& root,
bool collectComments = true);
String getFormattedErrorMessages() const;
- std::vector getStructuredErrors() const;
+ std::vector getStructuredErrors() const;
private:
OurReader(OurReader const&); // no impl
@@ -1860,10 +1855,11 @@ String OurReader::getFormattedErrorMessages() const {
return formattedMessage;
}
-std::vector OurReader::getStructuredErrors() const {
- std::vector allErrors;
+std::vector
+OurReader::getStructuredErrors() const {
+ std::vector allErrors;
for (const auto& error : errors_) {
- OurReader::StructuredError structured;
+ CharReader::StructuredError structured;
structured.offset_start = error.token_.start_ - begin_;
structured.offset_limit = error.token_.end_ - begin_;
structured.message = error.message_;
@@ -1887,6 +1883,10 @@ class OurCharReader : public CharReader {
}
return ok;
}
+
+ std::vector getStructuredErrors() const override {
+ return reader_.getStructuredErrors();
+ }
};
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp
index d0f5364ac..d75cddf5c 100644
--- a/src/test_lib_json/main.cpp
+++ b/src/test_lib_json/main.cpp
@@ -3903,6 +3903,43 @@ JSONTEST_FIXTURE_LOCAL(FuzzTest, fuzzDoesntCrash) {
example.size()));
}
+struct ParseWithStructuredErrorsTest : JsonTest::TestCase {
+ void
+ testErrors(const std::string& doc, bool success,
+ const std::vector& errors) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::Value root;
+ JSONTEST_ASSERT_EQUAL(
+ success,
+ reader->parse(doc.data(), doc.data() + doc.length(), &root, nullptr));
+ auto actualErrors = reader->getStructuredErrors();
+ JSONTEST_ASSERT_EQUAL(errors.size(), actualErrors.size());
+ for (std::size_t i = 0; i < errors.size() && i < actualErrors.size(); i++) {
+ JSONTEST_ASSERT_EQUAL(errors[i].offset_start,
+ actualErrors[i].offset_start);
+ JSONTEST_ASSERT_EQUAL(errors[i].offset_limit,
+ actualErrors[i].offset_limit);
+ JSONTEST_ASSERT_STRING_EQUAL(errors[i].message, actualErrors[i].message);
+ }
+ }
+};
+
+JSONTEST_FIXTURE_LOCAL(ParseWithStructuredErrorsTest, success) {
+ testErrors("{}", true, {});
+}
+
+JSONTEST_FIXTURE_LOCAL(ParseWithStructuredErrorsTest, singleError) {
+ testErrors("{ 1 : 2 }", false,
+ {
+ {
+ /*offset_start=*/2,
+ /*offset_limit=*/3,
+ /*message=*/"Missing '}' or object member name",
+ },
+ });
+}
+
int main(int argc, const char* argv[]) {
JsonTest::Runner runner;