Commit 465fab45 authored by Milo Yip's avatar Milo Yip Committed by GitHub

Merge pull request #897 from StilesCrisis/issue-889-pretty-writer

Issue 889 pretty writer
parents 266870df d5d18cf6
...@@ -19,15 +19,15 @@ ...@@ -19,15 +19,15 @@
// //
// After calling EnterObject, you retrieve keys via NextObjectKey() and values via // After calling EnterObject, you retrieve keys via NextObjectKey() and values via
// the normal getters. When NextObjectKey() returns null, you have exited the // the normal getters. When NextObjectKey() returns null, you have exited the
// object, or you can call ExitObject() to skip to the end of the object // object, or you can call SkipObject() to skip to the end of the object
// immediately. If you fetch the entire object (i.e. NextObjectKey() returned null), // immediately. If you fetch the entire object (i.e. NextObjectKey() returned null),
// you should not call ExitObject(). // you should not call SkipObject().
// //
// After calling EnterArray(), you must alternate between calling NextArrayValue() // After calling EnterArray(), you must alternate between calling NextArrayValue()
// to see if the array has more data, and then retrieving values via the normal // to see if the array has more data, and then retrieving values via the normal
// getters. You can call ExitArray() to skip to the end of the array immediately. // getters. You can call SkipArray() to skip to the end of the array immediately.
// If you fetch the entire array (i.e. NextArrayValue() returned null), // If you fetch the entire array (i.e. NextArrayValue() returned null),
// you should not call ExitArray(). // you should not call SkipArray().
// //
// This parser uses in-situ strings, so the JSON buffer will be altered during the // This parser uses in-situ strings, so the JSON buffer will be altered during the
// parse. // parse.
...@@ -37,15 +37,15 @@ using namespace rapidjson; ...@@ -37,15 +37,15 @@ using namespace rapidjson;
class LookaheadParserHandler { class LookaheadParserHandler {
public: public:
bool Null() { st_ = kHasValue; v_.SetNull(); return true; } bool Null() { st_ = kHasNull; v_.SetNull(); return true; }
bool Bool(bool b) { st_ = kHasValue; v_.SetBool(b); return true; } bool Bool(bool b) { st_ = kHasBool; v_.SetBool(b); return true; }
bool Int(int i) { st_ = kHasValue; v_.SetInt(i); return true; } bool Int(int i) { st_ = kHasNumber; v_.SetInt(i); return true; }
bool Uint(unsigned u) { st_ = kHasValue; v_.SetUint(u); return true; } bool Uint(unsigned u) { st_ = kHasNumber; v_.SetUint(u); return true; }
bool Int64(int64_t i) { st_ = kHasValue; v_.SetInt64(i); return true; } bool Int64(int64_t i) { st_ = kHasNumber; v_.SetInt64(i); return true; }
bool Uint64(uint64_t u) { st_ = kHasValue; v_.SetUint64(u); return true; } bool Uint64(uint64_t u) { st_ = kHasNumber; v_.SetUint64(u); return true; }
bool Double(double d) { st_ = kHasValue; v_.SetDouble(d); return true; } bool Double(double d) { st_ = kHasNumber; v_.SetDouble(d); return true; }
bool RawNumber(const char*, SizeType, bool) { return false; } bool RawNumber(const char*, SizeType, bool) { return false; }
bool String(const char* str, SizeType length, bool) { st_ = kHasValue; v_.SetString(str, length); return true; } bool String(const char* str, SizeType length, bool) { st_ = kHasString; v_.SetString(str, length); return true; }
bool StartObject() { st_ = kEnteringObject; return true; } bool StartObject() { st_ = kEnteringObject; return true; }
bool Key(const char* str, SizeType length, bool) { st_ = kHasKey; v_.SetString(str, length); return true; } bool Key(const char* str, SizeType length, bool) { st_ = kHasKey; v_.SetString(str, length); return true; }
bool EndObject(SizeType) { st_ = kExitingObject; return true; } bool EndObject(SizeType) { st_ = kExitingObject; return true; }
...@@ -58,8 +58,12 @@ protected: ...@@ -58,8 +58,12 @@ protected:
protected: protected:
enum LookaheadParsingState { enum LookaheadParsingState {
kInit,
kError, kError,
kHasValue, kHasNull,
kHasBool,
kHasNumber,
kHasString,
kHasKey, kHasKey,
kEnteringObject, kEnteringObject,
kExitingObject, kExitingObject,
...@@ -75,7 +79,7 @@ protected: ...@@ -75,7 +79,7 @@ protected:
static const int parseFlags = kParseDefaultFlags | kParseInsituFlag; static const int parseFlags = kParseDefaultFlags | kParseInsituFlag;
}; };
LookaheadParserHandler::LookaheadParserHandler(char* str) : ss_(str) { LookaheadParserHandler::LookaheadParserHandler(char* str) : v_(), st_(kInit), r_(), ss_(str) {
r_.IterativeParseInit(); r_.IterativeParseInit();
ParseNext(); ParseNext();
} }
...@@ -93,10 +97,8 @@ class LookaheadParser : protected LookaheadParserHandler { ...@@ -93,10 +97,8 @@ class LookaheadParser : protected LookaheadParserHandler {
public: public:
LookaheadParser(char* str) : LookaheadParserHandler(str) {} LookaheadParser(char* str) : LookaheadParserHandler(str) {}
void EnterObject(); bool EnterObject();
void EnterArray(); bool EnterArray();
void ExitObject();
void ExitArray();
const char* NextObjectKey(); const char* NextObjectKey();
bool NextArrayValue(); bool NextArrayValue();
int GetInt(); int GetInt();
...@@ -105,57 +107,52 @@ public: ...@@ -105,57 +107,52 @@ public:
bool GetBool(); bool GetBool();
void GetNull(); void GetNull();
void SkipObject();
void SkipArray();
void SkipValue(); void SkipValue();
Value* PeekValue(); Value* PeekValue();
int PeekType(); // returns a rapidjson::Type, or -1 for no value (at end of object/array) int PeekType(); // returns a rapidjson::Type, or -1 for no value (at end of object/array)
bool IsValid() { return st_ != kError; } bool IsValid() { return st_ != kError; }
protected:
void SkipOut(int depth);
}; };
void LookaheadParser::EnterObject() { bool LookaheadParser::EnterObject() {
if (st_ != kEnteringObject) { if (st_ != kEnteringObject) {
st_ = kError; st_ = kError;
return; return false;
} }
ParseNext(); ParseNext();
return true;
} }
void LookaheadParser::EnterArray() { bool LookaheadParser::EnterArray() {
if (st_ != kEnteringArray) { if (st_ != kEnteringArray) {
st_ = kError; st_ = kError;
return; return false;
} }
ParseNext(); ParseNext();
} return true;
void LookaheadParser::ExitObject() {
while (NextObjectKey()) {
SkipValue();
}
}
void LookaheadParser::ExitArray() {
while (NextArrayValue()) {
SkipValue();
}
} }
const char* LookaheadParser::NextObjectKey() { const char* LookaheadParser::NextObjectKey() {
if (st_ == kExitingObject) { if (st_ == kHasKey) {
const char* result = v_.GetString();
ParseNext(); ParseNext();
return 0; return result;
} }
if (st_ != kHasKey || !v_.IsString()) { if (st_ != kExitingObject) {
st_ = kError; st_ = kError;
return 0; return 0;
} }
const char* result = v_.GetString();
ParseNext(); ParseNext();
return result; return 0;
} }
bool LookaheadParser::NextArrayValue() { bool LookaheadParser::NextArrayValue() {
...@@ -164,11 +161,16 @@ bool LookaheadParser::NextArrayValue() { ...@@ -164,11 +161,16 @@ bool LookaheadParser::NextArrayValue() {
return false; return false;
} }
if (st_ == kError || st_ == kExitingObject || st_ == kHasKey) {
st_ = kError;
return false;
}
return true; return true;
} }
int LookaheadParser::GetInt() { int LookaheadParser::GetInt() {
if (st_ != kHasValue || !v_.IsInt()) { if (st_ != kHasNumber || !v_.IsInt()) {
st_ = kError; st_ = kError;
return 0; return 0;
} }
...@@ -179,7 +181,7 @@ int LookaheadParser::GetInt() { ...@@ -179,7 +181,7 @@ int LookaheadParser::GetInt() {
} }
double LookaheadParser::GetDouble() { double LookaheadParser::GetDouble() {
if (st_ != kHasValue || !v_.IsNumber()) { if (st_ != kHasNumber) {
st_ = kError; st_ = kError;
return 0.; return 0.;
} }
...@@ -190,7 +192,7 @@ double LookaheadParser::GetDouble() { ...@@ -190,7 +192,7 @@ double LookaheadParser::GetDouble() {
} }
bool LookaheadParser::GetBool() { bool LookaheadParser::GetBool() {
if (st_ != kHasValue || !v_.IsBool()) { if (st_ != kHasBool) {
st_ = kError; st_ = kError;
return false; return false;
} }
...@@ -201,7 +203,7 @@ bool LookaheadParser::GetBool() { ...@@ -201,7 +203,7 @@ bool LookaheadParser::GetBool() {
} }
void LookaheadParser::GetNull() { void LookaheadParser::GetNull() {
if (st_ != kHasValue || !v_.IsNull()) { if (st_ != kHasNull) {
st_ = kError; st_ = kError;
return; return;
} }
...@@ -210,7 +212,7 @@ void LookaheadParser::GetNull() { ...@@ -210,7 +212,7 @@ void LookaheadParser::GetNull() {
} }
const char* LookaheadParser::GetString() { const char* LookaheadParser::GetString() {
if (st_ != kHasValue || !v_.IsString()) { if (st_ != kHasString) {
st_ = kError; st_ = kError;
return 0; return 0;
} }
...@@ -220,34 +222,37 @@ const char* LookaheadParser::GetString() { ...@@ -220,34 +222,37 @@ const char* LookaheadParser::GetString() {
return result; return result;
} }
void LookaheadParser::SkipValue() { void LookaheadParser::SkipOut(int depth) {
int depth = 0;
do { do {
switch (st_) { if (st_ == kEnteringArray || st_ == kEnteringObject) {
case kEnteringArray: ++depth;
case kEnteringObject:
++depth;
break;
case kExitingArray:
case kExitingObject:
--depth;
break;
case kError:
return;
case kHasKey:
case kHasValue:
break;
} }
else if (st_ == kExitingArray || st_ == kExitingObject) {
--depth;
}
else if (st_ == kError) {
return;
}
ParseNext(); ParseNext();
} }
while (depth > 0); while (depth > 0);
} }
void LookaheadParser::SkipValue() {
SkipOut(0);
}
void LookaheadParser::SkipArray() {
SkipOut(1);
}
void LookaheadParser::SkipObject() {
SkipOut(1);
}
Value* LookaheadParser::PeekValue() { Value* LookaheadParser::PeekValue() {
if (st_ == kHasValue || st_ == kHasKey) { if (st_ >= kHasNull && st_ <= kHasKey) {
return &v_; return &v_;
} }
...@@ -255,23 +260,19 @@ Value* LookaheadParser::PeekValue() { ...@@ -255,23 +260,19 @@ Value* LookaheadParser::PeekValue() {
} }
int LookaheadParser::PeekType() { int LookaheadParser::PeekType() {
switch (st_) { if (st_ >= kHasNull && st_ <= kHasKey) {
case kHasValue: return v_.GetType();
case kHasKey:
return v_.GetType();
case kEnteringArray:
return kArrayType;
case kEnteringObject:
return kObjectType;
case kExitingArray:
case kExitingObject:
case kError:
default:
return -1;
} }
if (st_ == kEnteringArray) {
return kArrayType;
}
if (st_ == kEnteringObject) {
return kObjectType;
}
return -1;
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
...@@ -325,7 +326,7 @@ int main() { ...@@ -325,7 +326,7 @@ int main() {
cout << r.GetString() << " "; cout << r.GetString() << " ";
} }
else { else {
r.ExitArray(); r.SkipArray();
break; break;
} }
} }
......
...@@ -107,8 +107,7 @@ public: ...@@ -107,8 +107,7 @@ public:
return Base::WriteString(str, length); return Base::WriteString(str, length);
} }
template <typename T> bool String(const Ch* str, SizeType length, bool copy = false) {
RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) String(const T* str, SizeType length, bool copy = false) {
RAPIDJSON_ASSERT(str != 0); RAPIDJSON_ASSERT(str != 0);
(void)copy; (void)copy;
PrettyPrefix(kStringType); PrettyPrefix(kStringType);
...@@ -127,8 +126,7 @@ public: ...@@ -127,8 +126,7 @@ public:
return Base::WriteStartObject(); return Base::WriteStartObject();
} }
template <typename T> bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) Key(const T* str, SizeType length, bool copy = false) { return String(str, length, copy); }
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
bool Key(const std::basic_string<Ch>& str) { bool Key(const std::basic_string<Ch>& str) {
...@@ -186,22 +184,8 @@ public: ...@@ -186,22 +184,8 @@ public:
//@{ //@{
//! Simpler but slower overload. //! Simpler but slower overload.
template <typename T> bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) String(const T* const& str) { return String(str, internal::StrLen(str)); } bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
template <typename T>
RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) Key(const T* const& str) { return Key(str, internal::StrLen(str)); }
//! The compiler can give us the length of quoted strings for free.
template <typename T, size_t N>
RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) String(const T (&str)[N]) {
RAPIDJSON_ASSERT(str[N-1] == '\0'); // you must pass in a null-terminated string (quoted constant strings are always null-terminated)
return String(str, N-1);
}
template <typename T, size_t N>
RAPIDJSON_ENABLEIF_RETURN((internal::IsSame<Ch, T>), (bool)) Key(const T (&str)[N]) {
RAPIDJSON_ASSERT(str[N-1] == '\0'); // you must pass in a null-terminated string (quoted constant strings are always null-terminated)
return Key(str, N-1);
}
//@} //@}
......
...@@ -258,6 +258,20 @@ TEST(PrettyWriter, InvalidEventSequence) { ...@@ -258,6 +258,20 @@ TEST(PrettyWriter, InvalidEventSequence) {
} }
} }
TEST(PrettyWriter, Issue_889) {
char buf[100] = "Hello";
StringBuffer buffer;
PrettyWriter<StringBuffer> writer(buffer);
writer.StartArray();
writer.String(buf);
writer.EndArray();
EXPECT_STREQ("[\n \"Hello\"\n]", buffer.GetString());
EXPECT_TRUE(writer.IsComplete()); \
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
static PrettyWriter<StringBuffer> WriterGen(StringBuffer &target) { static PrettyWriter<StringBuffer> WriterGen(StringBuffer &target) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment