* CharReaderBuilder is similar to StreamWriterBuilder.
* use rdbuf(), since getline(string) is not required to handle EOF as delimiter
#include <iosfwd>
#include <stack>
#include <string>
+#include <istream>
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
document to read.
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
document to read.
- \ Must be >= beginDoc.
+ * Must be >= beginDoc.
* \param root [out] Contains the root value of the document if it was
* successfully parsed.
* \param collectComments \c true to collect comment and allow writing them
std::string commentsBefore_;
Features features_;
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'.
Always keep comments from the input JSON.
#include <cassert>
#include <cstring>
#include <istream>
+#include <sstream>
+#include <memory>
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
#define snprintf _snprintf
namespace Json {
+#if __cplusplus >= 201103L
+typedef std::unique_ptr<CharReader> CharReaderPtr;
+#else
+typedef std::auto_ptr<CharReader> CharReaderPtr;
+#endif
+
// Implementation of class Features
// ////////////////////////////////
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) {
- Json::Reader reader;
- bool ok = reader.parse(sin, root, true);
+ CharReaderBuilder b;
+ std::string errs;
+ bool ok = parseFromStream(b, sin, &root, &errs);
if (!ok) {
fprintf(stderr,
"Error from reader: %s",
- reader.getFormattedErrorMessages().c_str());
+ errs.c_str());
JSON_FAIL_MESSAGE("reader error");
}
#include <json/config.h>
#include <json/json.h>
#include <stdexcept>
+#include <cstring>
// Make numeric limits more convenient to talk about.
// Assumes int type in 32 bits.
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[]) {
JsonTest::Runner runner;
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, checkNormalizeFloatingPointStr);
JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseChineseWithOneError);
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);
return runner.runCommandLine(argc, argv);