mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-01-22 10:25:47 +01:00
CharReader/Builder
* CharReaderBuilder is similar to StreamWriterBuilder. * use rdbuf(), since getline(string) is not required to handle EOF as delimiter
This commit is contained in:
parent
2a94618589
commit
2c1197c2c8
@ -14,6 +14,7 @@
|
|||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <istream>
|
||||||
|
|
||||||
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
|
||||||
// be used by...
|
// be used by...
|
||||||
@ -78,7 +79,7 @@ public:
|
|||||||
document to read.
|
document to read.
|
||||||
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
|
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
|
||||||
document to read.
|
document to read.
|
||||||
\ Must be >= beginDoc.
|
* Must be >= beginDoc.
|
||||||
* \param root [out] Contains the root value of the document if it was
|
* \param root [out] Contains the root value of the document if it was
|
||||||
* successfully parsed.
|
* successfully parsed.
|
||||||
* \param collectComments \c true to collect comment and allow writing them
|
* \param collectComments \c true to collect comment and allow writing them
|
||||||
@ -238,8 +239,69 @@ private:
|
|||||||
std::string commentsBefore_;
|
std::string commentsBefore_;
|
||||||
Features features_;
|
Features features_;
|
||||||
bool collectComments_;
|
bool collectComments_;
|
||||||
|
}; // Reader
|
||||||
|
|
||||||
|
/** Interface for reading JSON from a char array.
|
||||||
|
*/
|
||||||
|
class JSON_API CharReader {
|
||||||
|
public:
|
||||||
|
virtual ~CharReader() {}
|
||||||
|
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||||
|
document.
|
||||||
|
* The document must be a UTF-8 encoded string containing the document to read.
|
||||||
|
*
|
||||||
|
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
|
||||||
|
document to read.
|
||||||
|
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
|
||||||
|
document to read.
|
||||||
|
* Must be >= beginDoc.
|
||||||
|
* \param root [out] Contains the root value of the document if it was
|
||||||
|
* successfully parsed.
|
||||||
|
* \param errs [out] Formatted error messages (if not NULL)
|
||||||
|
* a user friendly string that lists errors in the parsed
|
||||||
|
* document.
|
||||||
|
* \return \c true if the document was successfully parsed, \c false if an
|
||||||
|
error occurred.
|
||||||
|
*/
|
||||||
|
virtual bool parse(
|
||||||
|
char const* beginDoc, char const* endDoc,
|
||||||
|
Value* root, std::string* errs) = 0;
|
||||||
|
|
||||||
|
class Factory {
|
||||||
|
public:
|
||||||
|
/// \brief Allocate a CharReader via operator new().
|
||||||
|
virtual CharReader* newCharReader() const = 0;
|
||||||
|
}; // Factory
|
||||||
|
}; // CharReader
|
||||||
|
|
||||||
|
class CharReaderBuilder : public CharReader::Factory {
|
||||||
|
bool collectComments_;
|
||||||
|
Features features_;
|
||||||
|
public:
|
||||||
|
CharReaderBuilder();
|
||||||
|
|
||||||
|
CharReaderBuilder& withCollectComments(bool v) {
|
||||||
|
collectComments_ = v;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CharReaderBuilder& withFeatures(Features const& v) {
|
||||||
|
features_ = v;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual CharReader* newCharReader() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Consume entire stream and use its begin/end.
|
||||||
|
* Someday we might have a real StreamReader, but for now this
|
||||||
|
* is convenient.
|
||||||
|
*/
|
||||||
|
bool parseFromStream(
|
||||||
|
CharReader::Factory const&,
|
||||||
|
std::istream&,
|
||||||
|
Value* root, std::string* errs);
|
||||||
|
|
||||||
/** \brief Read from 'sin' into 'root'.
|
/** \brief Read from 'sin' into 'root'.
|
||||||
|
|
||||||
Always keep comments from the input JSON.
|
Always keep comments from the input JSON.
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <istream>
|
#include <istream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
|
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
@ -26,6 +28,12 @@
|
|||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
typedef std::unique_ptr<CharReader> CharReaderPtr;
|
||||||
|
#else
|
||||||
|
typedef std::auto_ptr<CharReader> CharReaderPtr;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Implementation of class Features
|
// Implementation of class Features
|
||||||
// ////////////////////////////////
|
// ////////////////////////////////
|
||||||
|
|
||||||
@ -882,13 +890,61 @@ bool Reader::good() const {
|
|||||||
return !errors_.size();
|
return !errors_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class OldReader : public CharReader {
|
||||||
|
bool const collectComments_;
|
||||||
|
Reader reader_;
|
||||||
|
public:
|
||||||
|
OldReader(
|
||||||
|
bool collectComments,
|
||||||
|
Features const& features)
|
||||||
|
: collectComments_(collectComments)
|
||||||
|
, reader_(features)
|
||||||
|
{}
|
||||||
|
virtual bool parse(
|
||||||
|
char const* beginDoc, char const* endDoc,
|
||||||
|
Value* root, std::string* errs) {
|
||||||
|
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
|
||||||
|
if (errs) {
|
||||||
|
*errs = reader_.getFormattedErrorMessages();
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CharReaderBuilder::CharReaderBuilder()
|
||||||
|
: collectComments_(true)
|
||||||
|
, features_(Features::all())
|
||||||
|
{}
|
||||||
|
CharReader* CharReaderBuilder::newCharReader() const
|
||||||
|
{
|
||||||
|
return new OldReader(collectComments_, features_);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////
|
||||||
|
// global functions
|
||||||
|
|
||||||
|
bool parseFromStream(
|
||||||
|
CharReader::Factory const& fact, std::istream& sin,
|
||||||
|
Value* root, std::string* errs)
|
||||||
|
{
|
||||||
|
std::ostringstream ssin;
|
||||||
|
ssin << sin.rdbuf();
|
||||||
|
std::string doc = ssin.str();
|
||||||
|
char const* begin = doc.data();
|
||||||
|
char const* end = begin + doc.size();
|
||||||
|
// Note that we do not actually need a null-terminator.
|
||||||
|
CharReaderPtr const reader(fact.newCharReader());
|
||||||
|
return reader->parse(begin, end, root, errs);
|
||||||
|
}
|
||||||
|
|
||||||
std::istream& operator>>(std::istream& sin, Value& root) {
|
std::istream& operator>>(std::istream& sin, Value& root) {
|
||||||
Json::Reader reader;
|
CharReaderBuilder b;
|
||||||
bool ok = reader.parse(sin, root, true);
|
std::string errs;
|
||||||
|
bool ok = parseFromStream(b, sin, &root, &errs);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Error from reader: %s",
|
"Error from reader: %s",
|
||||||
reader.getFormattedErrorMessages().c_str());
|
errs.c_str());
|
||||||
|
|
||||||
JSON_FAIL_MESSAGE("reader error");
|
JSON_FAIL_MESSAGE("reader error");
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <json/config.h>
|
#include <json/config.h>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
// Make numeric limits more convenient to talk about.
|
// Make numeric limits more convenient to talk about.
|
||||||
// Assumes int type in 32 bits.
|
// Assumes int type in 32 bits.
|
||||||
@ -1617,6 +1618,90 @@ JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) {
|
|||||||
JSONTEST_ASSERT(errors.at(0).message == "Bad escape sequence in string");
|
JSONTEST_ASSERT(errors.at(0).message == "Bad escape sequence in string");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct CharReaderTest : JsonTest::TestCase {};
|
||||||
|
|
||||||
|
JSONTEST_FIXTURE(CharReaderTest, parseWithNoErrors) {
|
||||||
|
Json::CharReaderBuilder b;
|
||||||
|
Json::CharReader* reader(b.newCharReader());
|
||||||
|
std::string errs;
|
||||||
|
Json::Value root;
|
||||||
|
char const doc[] = "{ \"property\" : \"value\" }";
|
||||||
|
bool ok = reader->parse(
|
||||||
|
doc, doc + std::strlen(doc),
|
||||||
|
&root, &errs);
|
||||||
|
JSONTEST_ASSERT(ok);
|
||||||
|
JSONTEST_ASSERT(errs.size() == 0);
|
||||||
|
delete reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONTEST_FIXTURE(CharReaderTest, parseWithNoErrorsTestingOffsets) {
|
||||||
|
Json::CharReaderBuilder b;
|
||||||
|
Json::CharReader* reader(b.newCharReader());
|
||||||
|
std::string errs;
|
||||||
|
Json::Value root;
|
||||||
|
char const doc[] =
|
||||||
|
"{ \"property\" : [\"value\", \"value2\"], \"obj\" : "
|
||||||
|
"{ \"nested\" : 123, \"bool\" : true}, \"null\" : "
|
||||||
|
"null, \"false\" : false }";
|
||||||
|
bool ok = reader->parse(
|
||||||
|
doc, doc + std::strlen(doc),
|
||||||
|
&root, &errs);
|
||||||
|
JSONTEST_ASSERT(ok);
|
||||||
|
JSONTEST_ASSERT(errs.size() == 0);
|
||||||
|
delete reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONTEST_FIXTURE(CharReaderTest, parseWithOneError) {
|
||||||
|
Json::CharReaderBuilder b;
|
||||||
|
Json::CharReader* reader(b.newCharReader());
|
||||||
|
std::string errs;
|
||||||
|
Json::Value root;
|
||||||
|
char const doc[] =
|
||||||
|
"{ \"property\" :: \"value\" }";
|
||||||
|
bool ok = reader->parse(
|
||||||
|
doc, doc + std::strlen(doc),
|
||||||
|
&root, &errs);
|
||||||
|
JSONTEST_ASSERT(!ok);
|
||||||
|
JSONTEST_ASSERT(errs ==
|
||||||
|
"* Line 1, Column 15\n Syntax error: value, object or array "
|
||||||
|
"expected.\n");
|
||||||
|
delete reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONTEST_FIXTURE(CharReaderTest, parseChineseWithOneError) {
|
||||||
|
Json::CharReaderBuilder b;
|
||||||
|
Json::CharReader* reader(b.newCharReader());
|
||||||
|
std::string errs;
|
||||||
|
Json::Value root;
|
||||||
|
char const doc[] =
|
||||||
|
"{ \"pr佐藤erty\" :: \"value\" }";
|
||||||
|
bool ok = reader->parse(
|
||||||
|
doc, doc + std::strlen(doc),
|
||||||
|
&root, &errs);
|
||||||
|
JSONTEST_ASSERT(!ok);
|
||||||
|
JSONTEST_ASSERT(errs ==
|
||||||
|
"* Line 1, Column 19\n Syntax error: value, object or array "
|
||||||
|
"expected.\n");
|
||||||
|
delete reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONTEST_FIXTURE(CharReaderTest, parseWithDetailError) {
|
||||||
|
Json::CharReaderBuilder b;
|
||||||
|
Json::CharReader* reader(b.newCharReader());
|
||||||
|
std::string errs;
|
||||||
|
Json::Value root;
|
||||||
|
char const doc[] =
|
||||||
|
"{ \"property\" : \"v\\alue\" }";
|
||||||
|
bool ok = reader->parse(
|
||||||
|
doc, doc + std::strlen(doc),
|
||||||
|
&root, &errs);
|
||||||
|
JSONTEST_ASSERT(!ok);
|
||||||
|
JSONTEST_ASSERT(errs ==
|
||||||
|
"* Line 1, Column 16\n Bad escape sequence in string\nSee "
|
||||||
|
"Line 1, Column 20 for detail.\n");
|
||||||
|
delete reader;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
JsonTest::Runner runner;
|
JsonTest::Runner runner;
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, checkNormalizeFloatingPointStr);
|
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, checkNormalizeFloatingPointStr);
|
||||||
@ -1647,6 +1732,13 @@ int main(int argc, const char* argv[]) {
|
|||||||
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseChineseWithOneError);
|
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseChineseWithOneError);
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithDetailError);
|
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithDetailError);
|
||||||
|
|
||||||
|
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithNoErrors);
|
||||||
|
JSONTEST_REGISTER_FIXTURE(
|
||||||
|
runner, CharReaderTest, parseWithNoErrorsTestingOffsets);
|
||||||
|
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithOneError);
|
||||||
|
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseChineseWithOneError);
|
||||||
|
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithDetailError);
|
||||||
|
|
||||||
JSONTEST_REGISTER_FIXTURE(runner, WriterTest, dropNullPlaceholders);
|
JSONTEST_REGISTER_FIXTURE(runner, WriterTest, dropNullPlaceholders);
|
||||||
|
|
||||||
return runner.runCommandLine(argc, argv);
|
return runner.runCommandLine(argc, argv);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user