Skip to content

Commit 804d8f0

Browse files
committed
CharReader: Add StructuredError
Add getStructuredError to CharReader
1 parent a1f1613 commit 804d8f0

File tree

7 files changed

+113
-21
lines changed

7 files changed

+113
-21
lines changed

include/json/allocator.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
#include <cstring>
1010
#include <memory>
1111

12-
#pragma pack(push, 8)
12+
#pragma pack(push)
13+
#pragma pack()
1314

1415
namespace Json {
1516
template <typename T> class SecureAllocator {

include/json/json_features.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
#include "forwards.h"
1111
#endif // if !defined(JSON_IS_AMALGAMATION)
1212

13-
#pragma pack(push, 8)
13+
#pragma pack(push)
14+
#pragma pack()
1415

1516
namespace Json {
1617

include/json/reader.h

+28-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
#pragma warning(disable : 4251)
2424
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
2525

26-
#pragma pack(push, 8)
26+
#pragma pack(push)
27+
#pragma pack()
2728

2829
namespace Json {
2930

@@ -243,6 +244,12 @@ class JSON_API Reader {
243244
*/
244245
class JSON_API CharReader {
245246
public:
247+
struct JSON_API StructuredError {
248+
ptrdiff_t offset_start;
249+
ptrdiff_t offset_limit;
250+
String message;
251+
};
252+
246253
virtual ~CharReader() = default;
247254
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
248255
* document. The document must be a UTF-8 encoded string containing the
@@ -261,7 +268,12 @@ class JSON_API CharReader {
261268
* error occurred.
262269
*/
263270
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
264-
String* errs) = 0;
271+
String* errs);
272+
273+
/** \brief Returns a vector of structured errors encountered while parsing.
274+
* Each parse call resets the stored list of errors.
275+
*/
276+
std::vector<StructuredError> getStructuredErrors() const;
265277

266278
class JSON_API Factory {
267279
public:
@@ -271,6 +283,20 @@ class JSON_API CharReader {
271283
*/
272284
virtual CharReader* newCharReader() const = 0;
273285
}; // Factory
286+
287+
protected:
288+
class Impl {
289+
public:
290+
virtual ~Impl() = default;
291+
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
292+
String* errs) = 0;
293+
virtual std::vector<StructuredError> getStructuredErrors() const = 0;
294+
};
295+
296+
CharReader(Impl* impl) : _impl(impl) { }
297+
298+
private:
299+
std::unique_ptr<Impl> _impl;
274300
}; // CharReader
275301

276302
/** \brief Build a CharReader implementation.

include/json/value.h

+6-5
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@
5353
#pragma warning(disable : 4251 4275)
5454
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
5555

56-
#pragma pack(push, 8)
56+
#pragma pack(push)
57+
#pragma pack()
5758

5859
/** \brief JSON (JavaScript Object Notation).
5960
*/
@@ -436,23 +437,23 @@ class JSON_API Value {
436437
/// \post type() is arrayValue
437438
void resize(ArrayIndex newSize);
438439

439-
//@{
440+
///@{
440441
/// Access an array element (zero based index). If the array contains less
441442
/// than index element, then null value are inserted in the array so that
442443
/// its size is index+1.
443444
/// (You may need to say 'value[0u]' to get your compiler to distinguish
444445
/// this from the operator[] which takes a string.)
445446
Value& operator[](ArrayIndex index);
446447
Value& operator[](int index);
447-
//@}
448+
///@}
448449

449-
//@{
450+
///@{
450451
/// Access an array element (zero based index).
451452
/// (You may need to say 'value[0u]' to get your compiler to distinguish
452453
/// this from the operator[] which takes a string.)
453454
const Value& operator[](ArrayIndex index) const;
454455
const Value& operator[](int index) const;
455-
//@}
456+
///@}
456457

457458
/// If the array contains at least index+1 elements, returns the element
458459
/// value, otherwise returns defaultValue.

include/json/writer.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
#pragma warning(disable : 4251)
2121
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
2222

23-
#pragma pack(push, 8)
23+
#pragma pack(push)
24+
#pragma pack()
2425

2526
namespace Json {
2627

src/lib_json/json_reader.cpp

+44-11
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,7 @@ class OurReader {
900900
bool parse(const char* beginDoc, const char* endDoc, Value& root,
901901
bool collectComments = true);
902902
String getFormattedErrorMessages() const;
903-
std::vector<StructuredError> getStructuredErrors() const;
903+
std::vector<OurReader::StructuredError> getStructuredErrors() const;
904904

905905
private:
906906
OurReader(OurReader const&); // no impl
@@ -1873,20 +1873,44 @@ std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
18731873
}
18741874

18751875
class OurCharReader : public CharReader {
1876-
bool const collectComments_;
1877-
OurReader reader_;
18781876

18791877
public:
18801878
OurCharReader(bool collectComments, OurFeatures const& features)
1881-
: collectComments_(collectComments), reader_(features) {}
1882-
bool parse(char const* beginDoc, char const* endDoc, Value* root,
1883-
String* errs) override {
1884-
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1885-
if (errs) {
1886-
*errs = reader_.getFormattedErrorMessages();
1879+
: CharReader(new OurImpl(collectComments, features)) {}
1880+
1881+
protected:
1882+
class OurImpl : public Impl {
1883+
public:
1884+
OurImpl(bool collectComments, OurFeatures const& features)
1885+
: collectComments_(collectComments), reader_(features) {}
1886+
1887+
bool parse(char const* beginDoc, char const* endDoc, Value* root,
1888+
String* errs) override {
1889+
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1890+
if (errs) {
1891+
*errs = reader_.getFormattedErrorMessages();
1892+
}
1893+
return ok;
18871894
}
1888-
return ok;
1889-
}
1895+
1896+
std::vector<CharReader::StructuredError> getStructuredErrors() const override {
1897+
std::vector<OurReader::StructuredError> errors = reader_.getStructuredErrors();
1898+
std::vector<CharReader::StructuredError> out_errors;
1899+
std::transform(errors.begin(), errors.end(), std::back_inserter(out_errors),
1900+
[](OurReader::StructuredError x) {
1901+
CharReader::StructuredError y;
1902+
y.offset_start = x.offset_start;
1903+
y.offset_limit = x.offset_limit;
1904+
y.message = x.message;
1905+
return y;
1906+
});
1907+
return out_errors;
1908+
}
1909+
1910+
private:
1911+
bool const collectComments_;
1912+
OurReader reader_;
1913+
};
18901914
};
18911915

18921916
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
@@ -1976,6 +2000,15 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) {
19762000
//! [CharReaderBuilderDefaults]
19772001
}
19782002

2003+
std::vector<CharReader::StructuredError> CharReader::getStructuredErrors() const {
2004+
return _impl->getStructuredErrors();
2005+
}
2006+
2007+
bool CharReader::parse(char const* beginDoc, char const* endDoc, Value* root,
2008+
String* errs) {
2009+
return _impl->parse(beginDoc, endDoc, root, errs);
2010+
}
2011+
19792012
//////////////////////////////////
19802013
// global functions
19812014

src/test_lib_json/main.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -3903,6 +3903,35 @@ JSONTEST_FIXTURE_LOCAL(FuzzTest, fuzzDoesntCrash) {
39033903
example.size()));
39043904
}
39053905

3906+
struct ParseWithStructuredErrorsTest : JsonTest::TestCase {
3907+
void testErrors(const std::string& doc, bool success,
3908+
const std::vector<Json::CharReader::StructuredError>& expectedErrors) {
3909+
Json::CharReaderBuilder b;
3910+
CharReaderPtr reader(b.newCharReader());
3911+
Json::Value root;
3912+
JSONTEST_ASSERT_EQUAL(
3913+
reader->parse(doc.data(), doc.data() + doc.length(), &root, nullptr),
3914+
success);
3915+
auto actualErrors = reader->getStructuredErrors();
3916+
JSONTEST_ASSERT_EQUAL(expectedErrors.size(), actualErrors.size());
3917+
for (std::size_t i = 0; i < actualErrors.size(); i++) {
3918+
const auto& a = actualErrors[i];
3919+
const auto& e = expectedErrors[i];
3920+
JSONTEST_ASSERT_EQUAL(a.offset_start, e.offset_start);
3921+
JSONTEST_ASSERT_EQUAL(a.offset_limit, e.offset_limit);
3922+
JSONTEST_ASSERT_STRING_EQUAL(a.message, e.message);
3923+
}
3924+
}
3925+
};
3926+
3927+
JSONTEST_FIXTURE_LOCAL(ParseWithStructuredErrorsTest, success) {
3928+
testErrors("{}", true, {});
3929+
}
3930+
3931+
JSONTEST_FIXTURE_LOCAL(ParseWithStructuredErrorsTest, singleError) {
3932+
testErrors("{ 1 : 2 }", false, {{2, 3, "Missing '}' or object member name"}});
3933+
}
3934+
39063935
int main(int argc, const char* argv[]) {
39073936
JsonTest::Runner runner;
39083937

0 commit comments

Comments
 (0)