Merge pull request #897 from StilesCrisis/issue-889-pretty-writer
Issue 889 pretty writer
This commit is contained in:
commit
465fab45c1
@ -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;
|
|||||||
|
|
||||||
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:
|
|||||||
|
|
||||||
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:
|
|||||||
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 {
|
|||||||
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:
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
|||||||
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() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
|||||||
cout << r.GetString() << " ";
|
cout << r.GetString() << " ";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
r.ExitArray();
|
r.SkipArray();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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:
|
|||||||
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:
|
|||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! 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) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user