diff --git a/.travis.yml b/.travis.yml index 2ae9443..c15e2c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,10 +6,12 @@ compiler: env: matrix: - - config=debug64 config_suffix=debug_x64_gmake - - config=release64 config_suffix=release_x64_gmake + - CONF=debug + - CONF=release global: - secure: "CR3yKliFhwQLX+Zs1PCRcGej6jr4DIZsCqs9x6J2NN+U9Aow0gd/uiPBho/utgm+/TmSBji5n8FO/J3ORo34q4gC6EebTEaN4gCHNXVlIBJFw9x+Gs/lML5i8F2AoweFJY334OVaOf9qC8ZVJ8Z1nEwxj77fq3gcSLzRU3pIaS8=" + # prepare for 32/64 bit multi-arch support + - BITS=64 + - secure: "HrsaCb+N66EG1HR+LWH1u51SjaJyRwJEDzqJGYMB7LJ/bfqb9mWKF1fLvZGk46W5t7TVaXRDD5KHFx9DPWvKn4gRUVkwTHEy262ah5ORh8M6n/6VVVajeV/AYt2C0sswdkDBDO4Xq+xy5gdw3G8s1A4Inbm73pUh+6vx+7ltBbk=" before_install: - sudo add-apt-repository -y ppa:codegear/release @@ -22,11 +24,11 @@ before_script: - pushd build && premake4 'gmake' && popd script: - - make -C build/gmake -f test.make - - make -C build/gmake -f example.make + - make -C build/gmake -f test.make config=${CONF}${BITS} + - make -C build/gmake -f example.make config=${CONF}${BITS} - pushd bin - - ./unittest_${config_suffix} - - valgrind --leak-check=full --error-exitcode=1 ./unittest_${config_suffix} - - if [ "$config" = "release64" ]; then ./perftest_${config_suffix}; fi + - ./unittest_${CONF}_x${BITS}_gmake + - valgrind --leak-check=full --error-exitcode=1 ./unittest_${CONF}_x${BITS}_gmake + - if [ "$CONF" = "release" ]; then ./perftest_${CONF}_x${BITS}_gmake; fi - popd - ./build/travis-doxygen.sh; diff --git a/build/premake4.lua b/build/premake4.lua index 0b5dbb1..4f7d77f 100644 --- a/build/premake4.lua +++ b/build/premake4.lua @@ -156,32 +156,10 @@ solution "example" configuration "gmake" buildoptions "-Werror -Wall -Wextra -Weffc++ -Wswitch-default" - project "condense" - kind "ConsoleApp" - files "../example/condense/*" - setTargetObjDir("../bin") - - project "pretty" - kind "ConsoleApp" - files "../example/pretty/*" - setTargetObjDir("../bin") - - project "prettyauto" - kind "ConsoleApp" - files "../example/prettyauto/*" - setTargetObjDir("../bin") - - project "tutorial" - kind "ConsoleApp" - files "../example/tutorial/*" - setTargetObjDir("../bin") - - project "serialize" - kind "ConsoleApp" - files "../example/serialize/*" - setTargetObjDir("../bin") - - project "simpledom" - kind "ConsoleApp" - files "../example/simpledom/*" - setTargetObjDir("../bin") + local examplepaths = os.matchdirs("../example/*") + for _, examplepath in ipairs(examplepaths) do + project(path.getname(examplepath)) + kind "ConsoleApp" + files(examplepath .. "/*") + setTargetObjDir("../bin") + end diff --git a/build/travis-doxygen.sh b/build/travis-doxygen.sh index c63d783..ad50b3f 100755 --- a/build/travis-doxygen.sh +++ b/build/travis-doxygen.sh @@ -64,8 +64,8 @@ gh_pages_prepare() git clone --single-branch -b gh-pages ${GHPAGES_URL} html cd html # setup git config (with defaults) - git config user.name "${GIT_NAME-travis}" - git config user.email "${GIT_EMAIL-"travis@localhost"}" + git config --global user.name "${GIT_NAME-travis}" + git config --global user.email "${GIT_EMAIL-"travis@localhost"}" # clean working dir rm -f .git/index git clean -df @@ -81,15 +81,19 @@ gh_pages_push() { # check for secure variables [ "${TRAVIS_SECURE_ENV_VARS}" = "true" ] || \ skip "Secure variables not available, not updating GitHub pages." + # check for GitHub access token [ "${GH_TOKEN+set}" = set ] || \ skip "GitHub access token not available, not updating GitHub pages." + [ "${#GH_TOKEN}" -eq 40 ] || \ + abort "GitHub token invalid: found ${#GH_TOKEN} characters, expected 40." cd "${TRAVIS_BUILD_DIR}/doc/html"; # setup credentials (hide in "set -x" mode) git config core.askpass /bin/true ( set +x ; git config credential.${GHPAGES_URL}.username "${GH_TOKEN}" ) # push to GitHub - git push origin gh-pages + git push origin gh-pages || \ + skip "GitHub pages update failed, temporarily ignored." } doxygen_install diff --git a/example/simplereader/simplereader.cpp b/example/simplereader/simplereader.cpp new file mode 100644 index 0000000..ed2bd3b --- /dev/null +++ b/example/simplereader/simplereader.cpp @@ -0,0 +1,34 @@ +#include "rapidjson/reader.h" +#include + +using namespace rapidjson; +using namespace std; + +struct MyHandler { + bool Null() { cout << "Null()" << endl; return true; } + bool Bool(bool b) { cout << "Bool(" << boolalpha << b << ")" << endl; return true; } + bool Int(int i) { cout << "Int(" << i << ")" << endl; return true; } + bool Uint(unsigned u) { cout << "Uint(" << u << ")" << endl; return true; } + bool Int64(int64_t i) { cout << "Int64(" << i << ")" << endl; return true; } + bool Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return true; } + bool Double(double d) { cout << "Double(" << d << ")" << endl; return true; } + bool String(const char* str, SizeType length, bool copy) { + cout << "String(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl; + return true; + } + bool StartObject() { cout << "StartObject()" << endl; return true; } + bool EndObject(SizeType memberCount) { cout << "EndObject(" << memberCount << ")" << endl; return true; } + bool StartArray() { cout << "StartArray()" << endl; return true; } + bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount << ")" << endl; return true; } +}; + +int main() { + const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "; + + MyHandler handler; + Reader reader; + StringStream ss(json); + reader.Parse(ss, handler); + + return 0; +} diff --git a/example/simplewriter/simplewriter.cpp b/example/simplewriter/simplewriter.cpp new file mode 100644 index 0000000..98e5b2c --- /dev/null +++ b/example/simplewriter/simplewriter.cpp @@ -0,0 +1,35 @@ +#include "rapidjson/writer.h" +#include "rapidjson/stringbuffer.h" +#include + +using namespace rapidjson; +using namespace std; + +int main() { + StringBuffer s; + Writer writer(s); + + writer.StartObject(); + writer.String("hello"); + writer.String("world"); + writer.String("t"); + writer.Bool(true); + writer.String("f"); + writer.Bool(false); + writer.String("n"); + writer.Null(); + writer.String("i"); + writer.Uint(123); + writer.String("pi"); + writer.Double(3.1416); + writer.String("a"); + writer.StartArray(); + for (unsigned i = 0; i < 4; i++) + writer.Uint(i); + writer.EndArray(); + writer.EndObject(); + + cout << s.GetString() << endl; + + return 0; +} diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 042a2a3..41dff72 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1015,44 +1015,45 @@ int z = a[0u].GetInt(); // This works too. \param handler An object implementing concept Handler. */ template - const GenericValue& Accept(Handler& handler) const { + bool Accept(Handler& handler) const { switch(GetType()) { - case kNullType: handler.Null(); break; - case kFalseType: handler.Bool(false); break; - case kTrueType: handler.Bool(true); break; + case kNullType: return handler.Null(); + case kFalseType: return handler.Bool(false); + case kTrueType: return handler.Bool(true); case kObjectType: - handler.StartObject(); + if (!handler.StartObject()) + return false; for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { - handler.String(m->name.data_.s.str, m->name.data_.s.length, (m->name.flags_ & kCopyFlag) != 0); - m->value.Accept(handler); + if (!handler.String(m->name.data_.s.str, m->name.data_.s.length, (m->name.flags_ & kCopyFlag) != 0)) + return false; + if (!m->value.Accept(handler)) + return false; } - handler.EndObject(data_.o.size); - break; + return handler.EndObject(data_.o.size); case kArrayType: - handler.StartArray(); + if (!handler.StartArray()) + return false; for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) - v->Accept(handler); - handler.EndArray(data_.a.size); - break; - + if (!v->Accept(handler)) + return false; + return handler.EndArray(data_.a.size); + case kStringType: - handler.String(data_.s.str, data_.s.length, (flags_ & kCopyFlag) != 0); - break; - + return handler.String(data_.s.str, data_.s.length, (flags_ & kCopyFlag) != 0); + case kNumberType: - if (IsInt()) handler.Int(data_.n.i.i); - else if (IsUint()) handler.Uint(data_.n.u.u); - else if (IsInt64()) handler.Int64(data_.n.i64); - else if (IsUint64()) handler.Uint64(data_.n.u64); - else handler.Double(data_.n.d); - break; - + if (IsInt()) return handler.Int(data_.n.i.i); + else if (IsUint()) return handler.Uint(data_.n.u.u); + else if (IsInt64()) return handler.Int64(data_.n.i64); + else if (IsUint64()) return handler.Uint64(data_.n.u64); + else return handler.Double(data_.n.d); + default: RAPIDJSON_ASSERT(false); } - return *this; + return false; } private: @@ -1357,33 +1358,36 @@ private: friend class GenericValue; // for deep copying // Implementation of Handler - void Null() { new (stack_.template Push()) ValueType(); } - void Bool(bool b) { new (stack_.template Push()) ValueType(b); } - void Int(int i) { new (stack_.template Push()) ValueType(i); } - void Uint(unsigned i) { new (stack_.template Push()) ValueType(i); } - void Int64(int64_t i) { new (stack_.template Push()) ValueType(i); } - void Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); } - void Double(double d) { new (stack_.template Push()) ValueType(d); } + bool Null() { new (stack_.template Push()) ValueType(); return true; } + bool Bool(bool b) { new (stack_.template Push()) ValueType(b); return true; } + bool Int(int i) { new (stack_.template Push()) ValueType(i); return true; } + bool Uint(unsigned i) { new (stack_.template Push()) ValueType(i); return true; } + bool Int64(int64_t i) { new (stack_.template Push()) ValueType(i); return true; } + bool Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); return true; } + bool Double(double d) { new (stack_.template Push()) ValueType(d); return true; } - void String(const Ch* str, SizeType length, bool copy) { + bool String(const Ch* str, SizeType length, bool copy) { if (copy) new (stack_.template Push()) ValueType(str, length, GetAllocator()); else new (stack_.template Push()) ValueType(str, length); + return true; } - void StartObject() { new (stack_.template Push()) ValueType(kObjectType); } + bool StartObject() { new (stack_.template Push()) ValueType(kObjectType); return true; } - void EndObject(SizeType memberCount) { + bool EndObject(SizeType memberCount) { typename ValueType::Member* members = stack_.template Pop(memberCount); stack_.template Top()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator()); + return true; } - void StartArray() { new (stack_.template Push()) ValueType(kArrayType); } + bool StartArray() { new (stack_.template Push()) ValueType(kArrayType); return true; } - void EndArray(SizeType elementCount) { + bool EndArray(SizeType elementCount) { ValueType* elements = stack_.template Pop(elementCount); stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); + return true; } private: diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h index 031f5de..f01e53e 100644 --- a/include/rapidjson/prettywriter.h +++ b/include/rapidjson/prettywriter.h @@ -51,29 +51,27 @@ public: */ //@{ - PrettyWriter& Null() { PrettyPrefix(kNullType); Base::WriteNull(); return *this; } - PrettyWriter& Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); Base::WriteBool(b); return *this; } - PrettyWriter& Int(int i) { PrettyPrefix(kNumberType); Base::WriteInt(i); return *this; } - PrettyWriter& Uint(unsigned u) { PrettyPrefix(kNumberType); Base::WriteUint(u); return *this; } - PrettyWriter& Int64(int64_t i64) { PrettyPrefix(kNumberType); Base::WriteInt64(i64); return *this; } - PrettyWriter& Uint64(uint64_t u64) { PrettyPrefix(kNumberType); Base::WriteUint64(u64); return *this; } - PrettyWriter& Double(double d) { PrettyPrefix(kNumberType); Base::WriteDouble(d); return *this; } + bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); } + bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); } + bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); } + bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); } + bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); } + bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); } + bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } - PrettyWriter& String(const Ch* str, SizeType length, bool copy = false) { + bool String(const Ch* str, SizeType length, bool copy = false) { (void)copy; PrettyPrefix(kStringType); - Base::WriteString(str, length); - return *this; + return Base::WriteString(str, length); } - PrettyWriter& StartObject() { + bool StartObject() { PrettyPrefix(kObjectType); new (Base::level_stack_.template Push()) typename Base::Level(false); - Base::WriteStartObject(); - return *this; + return Base::WriteStartObject(); } - PrettyWriter& EndObject(SizeType memberCount = 0) { + bool EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); @@ -83,20 +81,20 @@ public: Base::os_.Put('\n'); WriteIndent(); } - Base::WriteEndObject(); + if (!Base::WriteEndObject()) + return false; if (Base::level_stack_.Empty()) // end of json text Base::os_.Flush(); - return *this; + return true; } - PrettyWriter& StartArray() { + bool StartArray() { PrettyPrefix(kArrayType); new (Base::level_stack_.template Push()) typename Base::Level(true); - Base::WriteStartArray(); - return *this; + return Base::WriteStartArray(); } - PrettyWriter& EndArray(SizeType memberCount = 0) { + bool EndArray(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); @@ -106,10 +104,11 @@ public: Base::os_.Put('\n'); WriteIndent(); } - Base::WriteEndArray(); + if (!Base::WriteEndArray()) + return false; if (Base::level_stack_.Empty()) // end of json text Base::os_.Flush(); - return *this; + return true; } //@} @@ -118,12 +117,15 @@ public: //@{ //! Simpler but slower overload. - PrettyWriter& String(const Ch* str) { return String(str, internal::StrLen(str)); } + bool String(const Ch* str) { return String(str, internal::StrLen(str)); } //! Overridden for fluent API, see \ref Writer::Double() - PrettyWriter& Double(double d, int precision) { + bool Double(double d, int precision) { int oldPrecision = Base::GetDoublePrecision(); - return SetDoublePrecision(precision).Double(d).SetDoublePrecision(oldPrecision); + SetDoublePrecision(precision); + bool ret = Double(d); + SetDoublePrecision(oldPrecision); + return ret; } //@} diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 0d77316..39afcd8 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -71,22 +71,24 @@ enum ParseFlag { /*! \class rapidjson::Handler \brief Concept for receiving events from GenericReader upon parsing. + The functions return true if no error occurs. If they return false, + the event publisher should terminate the process. \code concept Handler { typename Ch; - void Null(); - void Bool(bool b); - void Int(int i); - void Uint(unsigned i); - void Int64(int64_t i); - void Uint64(uint64_t i); - void Double(double d); - void String(const Ch* str, SizeType length, bool copy); - void StartObject(); - void EndObject(SizeType memberCount); - void StartArray(); - void EndArray(SizeType elementCount); + bool Null(); + bool Bool(bool b); + bool Int(int i); + bool Uint(unsigned i); + bool Int64(int64_t i); + bool Uint64(uint64_t i); + bool Double(double d); + bool String(const Ch* str, SizeType length, bool copy); + bool StartObject(); + bool EndObject(SizeType memberCount); + bool StartArray(); + bool EndArray(SizeType elementCount); }; \endcode */ @@ -101,19 +103,19 @@ template > struct BaseReaderHandler { typedef typename Encoding::Ch Ch; - void Default() {} - void Null() { Default(); } - void Bool(bool) { Default(); } - void Int(int) { Default(); } - void Uint(unsigned) { Default(); } - void Int64(int64_t) { Default(); } - void Uint64(uint64_t) { Default(); } - void Double(double) { Default(); } - void String(const Ch*, SizeType, bool) { Default(); } - void StartObject() { Default(); } - void EndObject(SizeType) { Default(); } - void StartArray() { Default(); } - void EndArray(SizeType) { Default(); } + bool Default() { return true; } + bool Null() { return Default(); } + bool Bool(bool) { return Default(); } + bool Int(int) { return Default(); } + bool Uint(unsigned) { return Default(); } + bool Int64(int64_t) { return Default(); } + bool Uint64(uint64_t) { return Default(); } + bool Double(double) { return Default(); } + bool String(const Ch*, SizeType, bool) { return Default(); } + bool StartObject() { return Default(); } + bool EndObject(SizeType) { return Default(); } + bool StartArray() { return Default(); } + bool EndArray(SizeType) { return Default(); } }; /////////////////////////////////////////////////////////////////////////////// @@ -353,12 +355,16 @@ private: void ParseObject(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == '{'); is.Take(); // Skip '{' - handler.StartObject(); + + if (!handler.StartObject()) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + SkipWhitespace(is); if (is.Peek() == '}') { is.Take(); - handler.EndObject(0); // empty object + if (!handler.EndObject(0)) // empty object + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } @@ -383,9 +389,13 @@ private: ++memberCount; - switch(is.Take()) { + switch (is.Take()) { case ',': SkipWhitespace(is); break; - case '}': handler.EndObject(memberCount); return; + case '}': + if (!handler.EndObject(memberCount)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + else + return; default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); } } @@ -396,12 +406,16 @@ private: void ParseArray(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == '['); is.Take(); // Skip '[' - handler.StartArray(); + + if (!handler.StartArray()) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + SkipWhitespace(is); if (is.Peek() == ']') { is.Take(); - handler.EndArray(0); // empty array + if (!handler.EndArray(0)) // empty array + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } @@ -414,7 +428,11 @@ private: switch (is.Take()) { case ',': SkipWhitespace(is); break; - case ']': handler.EndArray(elementCount); return; + case ']': + if (!handler.EndArray(elementCount)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + else + return; default: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); } } @@ -425,8 +443,10 @@ private: RAPIDJSON_ASSERT(is.Peek() == 'n'); is.Take(); - if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l') - handler.Null(); + if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l') { + if (!handler.Null()) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); } @@ -436,10 +456,12 @@ private: RAPIDJSON_ASSERT(is.Peek() == 't'); is.Take(); - if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e') - handler.Bool(true); + if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e') { + if (!handler.Bool(true)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); } template @@ -447,8 +469,10 @@ private: RAPIDJSON_ASSERT(is.Peek() == 'f'); is.Take(); - if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e') - handler.Bool(false); + if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e') { + if (!handler.Bool(false)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); } @@ -504,13 +528,15 @@ private: RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; size_t length = s.PutEnd(head) - 1; RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); - handler.String((typename TargetEncoding::Ch*)head, SizeType(length), false); + if (!handler.String((typename TargetEncoding::Ch*)head, SizeType(length), false)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); } else { StackStream stackStream(stack_); ParseStringToStream(s, stackStream); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - handler.String(stack_.template Pop(stackStream.length_), stackStream.length_ - 1, true); + if (!handler.String(stack_.template Pop(stackStream.length_), stackStream.length_ - 1, true)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); } } @@ -712,6 +738,7 @@ private: } // Finish parsing, call event according to the type of number. + bool cont = true; if (useDouble) { int expSum = exp + expFrac; if (expSum < -308) { @@ -722,22 +749,24 @@ private: else d *= internal::Pow10(expSum); - handler.Double(minus ? -d : d); + cont = handler.Double(minus ? -d : d); } else { if (try64bit) { if (minus) - handler.Int64(-(int64_t)i64); + cont = handler.Int64(-(int64_t)i64); else - handler.Uint64(i64); + cont = handler.Uint64(i64); } else { if (minus) - handler.Int(-(int)i); + cont = handler.Int(-(int)i); else - handler.Uint(i); + cont = handler.Uint(i); } } + if (!cont) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); } // Parse any JSON value diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 9652000..f3b7567 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -64,12 +64,12 @@ public: */ //@{ - Writer& Null() { Prefix(kNullType); WriteNull(); return *this; } - Writer& Bool(bool b) { Prefix(b ? kTrueType : kFalseType); WriteBool(b); return *this; } - Writer& Int(int i) { Prefix(kNumberType); WriteInt(i); return *this; } - Writer& Uint(unsigned u) { Prefix(kNumberType); WriteUint(u); return *this; } - Writer& Int64(int64_t i64) { Prefix(kNumberType); WriteInt64(i64); return *this; } - Writer& Uint64(uint64_t u64) { Prefix(kNumberType); WriteUint64(u64); return *this; } + bool Null() { Prefix(kNullType); return WriteNull(); } + bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); } + bool Int(int i) { Prefix(kNumberType); return WriteInt(i); } + bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); } + bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); } + bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); } //! Writes the given \c double value to the stream /*! @@ -80,51 +80,48 @@ public: writer.SetDoublePrecision(12).Double(M_PI); \endcode \param d The value to be written. - \return The Writer itself for fluent API. + \return Whether it is succeed. */ - Writer& Double(double d) { Prefix(kNumberType); WriteDouble(d); return *this; } + bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); } - Writer& String(const Ch* str, SizeType length, bool copy = false) { + bool String(const Ch* str, SizeType length, bool copy = false) { (void)copy; Prefix(kStringType); - WriteString(str, length); - return *this; + return WriteString(str, length); } - Writer& StartObject() { + bool StartObject() { Prefix(kObjectType); new (level_stack_.template Push()) Level(false); - WriteStartObject(); - return *this; + return WriteStartObject(); } - Writer& EndObject(SizeType memberCount = 0) { + bool EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); level_stack_.template Pop(1); - WriteEndObject(); + bool ret = WriteEndObject(); if (level_stack_.Empty()) // end of json text os_.Flush(); - return *this; + return ret; } - Writer& StartArray() { + bool StartArray() { Prefix(kArrayType); new (level_stack_.template Push()) Level(true); - WriteStartArray(); - return *this; + return WriteStartArray(); } - Writer& EndArray(SizeType elementCount = 0) { + bool EndArray(SizeType elementCount = 0) { (void)elementCount; RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); level_stack_.template Pop(1); - WriteEndArray(); + bool ret = WriteEndArray(); if (level_stack_.Empty()) // end of json text os_.Flush(); - return *this; + return ret; } //@} @@ -138,15 +135,18 @@ public: \see Double(), SetDoublePrecision(), GetDoublePrecision() \param d The value to be written \param precision The number of significant digits for this value - \return The Writer itself for fluent API. + \return Whether it is succeeded. */ - Writer& Double(double d, int precision) { + bool Double(double d, int precision) { int oldPrecision = GetDoublePrecision(); - return SetDoublePrecision(precision).Double(d).SetDoublePrecision(oldPrecision); + SetDoublePrecision(precision); + bool ret = Double(d); + SetDoublePrecision(oldPrecision); + return ret; } //! Simpler but slower overload. - Writer& String(const Ch* str) { return String(str, internal::StrLen(str)); } + bool String(const Ch* str) { return String(str, internal::StrLen(str)); } //@} @@ -160,28 +160,29 @@ protected: static const size_t kDefaultLevelDepth = 32; - void WriteNull() { - os_.Put('n'); os_.Put('u'); os_.Put('l'); os_.Put('l'); + bool WriteNull() { + os_.Put('n'); os_.Put('u'); os_.Put('l'); os_.Put('l'); return true; } - void WriteBool(bool b) { + bool WriteBool(bool b) { if (b) { os_.Put('t'); os_.Put('r'); os_.Put('u'); os_.Put('e'); } else { os_.Put('f'); os_.Put('a'); os_.Put('l'); os_.Put('s'); os_.Put('e'); } + return true; } - void WriteInt(int i) { + bool WriteInt(int i) { if (i < 0) { os_.Put('-'); i = -i; } - WriteUint((unsigned)i); + return WriteUint((unsigned)i); } - void WriteUint(unsigned u) { + bool WriteUint(unsigned u) { char buffer[10]; char *p = buffer; do { @@ -193,17 +194,19 @@ protected: --p; os_.Put(*p); } while (p != buffer); + return true; } - void WriteInt64(int64_t i64) { + bool WriteInt64(int64_t i64) { if (i64 < 0) { os_.Put('-'); i64 = -i64; } WriteUint64((uint64_t)i64); + return true; } - void WriteUint64(uint64_t u64) { + bool WriteUint64(uint64_t u64) { char buffer[20]; char *p = buffer; do { @@ -215,6 +218,7 @@ protected: --p; os_.Put(*p); } while (p != buffer); + return true; } #ifdef _MSC_VER @@ -224,16 +228,17 @@ protected: #endif //! \todo Optimization with custom double-to-string converter. - void WriteDouble(double d) { + bool WriteDouble(double d) { char buffer[100]; int ret = RAPIDJSON_SNPRINTF(buffer, sizeof(buffer), "%.*g", doublePrecision_, d); RAPIDJSON_ASSERT(ret >= 1); for (int i = 0; i < ret; i++) os_.Put(buffer[i]); + return true; } #undef RAPIDJSON_SNPRINTF - void WriteString(const Ch* str, SizeType length) { + bool WriteString(const Ch* str, SizeType length) { static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static const char escape[256] = { #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @@ -266,12 +271,13 @@ protected: Transcoder::Transcode(is, os_); } os_.Put('\"'); + return true; } - void WriteStartObject() { os_.Put('{'); } - void WriteEndObject() { os_.Put('}'); } - void WriteStartArray() { os_.Put('['); } - void WriteEndArray() { os_.Put(']'); } + bool WriteStartObject() { os_.Put('{'); return true; } + bool WriteEndObject() { os_.Put('}'); return true; } + bool WriteStartArray() { os_.Put('['); return true; } + bool WriteEndArray() { os_.Put(']'); return true; } void Prefix(Type type) { (void)type; diff --git a/test/perftest/perftest.h b/test/perftest/perftest.h index 0f42a6c..be36920 100644 --- a/test/perftest/perftest.h +++ b/test/perftest/perftest.h @@ -8,7 +8,11 @@ #define TEST_PLATFORM 0 #define TEST_MISC 0 -#if TEST_RAPIDJSON +#define TEST_VERSION_CODE(x,y,z) \ + (((x)*100000) + ((y)*100) + (z)) + +// Only gcc >4.3 supports SSE4.2 +#if TEST_RAPIDJSON && !(defined(__GNUC__) && TEST_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) < TEST_VERSION_CODE(4,3,0)) //#define RAPIDJSON_SSE2 #define RAPIDJSON_SSE42 #endif diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp index 7c58077..6f0808e 100644 --- a/test/perftest/rapidjsontest.cpp +++ b/test/perftest/rapidjsontest.cpp @@ -179,8 +179,8 @@ RAPIDJSON_DIAG_OFF(effc++) struct ValueCounter : public BaseReaderHandler<> { ValueCounter() : count_(1) {} // root - void EndObject(SizeType memberCount) { count_ += memberCount * 2; } - void EndArray(SizeType elementCount) { count_ += elementCount; } + bool EndObject(SizeType memberCount) { count_ += memberCount * 2; return true; } + bool EndArray(SizeType elementCount) { count_ += elementCount; return true; } SizeType count_; }; diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 494a9f2..a7d286e 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -13,10 +13,10 @@ RAPIDJSON_DIAG_OFF(effc++) template struct ParseBoolHandler : BaseReaderHandler<> { ParseBoolHandler() : step_(0) {} - void Default() { FAIL(); } + bool Default() { ADD_FAILURE(); return false; } // gcc 4.8.x generates warning in EXPECT_EQ(bool, bool) on this gtest version. // Workaround with EXPECT_TRUE(). - void Bool(bool b) { /*EXPECT_EQ(expect, b); */EXPECT_TRUE(expect == b); ++step_; } + bool Bool(bool b) { /*EXPECT_EQ(expect, b); */EXPECT_TRUE(expect == b); ++step_; return true; } unsigned step_; }; @@ -39,8 +39,8 @@ TEST(Reader, ParseFalse) { struct ParseIntHandler : BaseReaderHandler<> { ParseIntHandler() : step_(0), actual_() {} - void Default() { FAIL(); } - void Int(int i) { actual_ = i; step_++; } + bool Default() { ADD_FAILURE(); return false; } + bool Int(int i) { actual_ = i; step_++; return true; } unsigned step_; int actual_; @@ -48,8 +48,8 @@ struct ParseIntHandler : BaseReaderHandler<> { struct ParseUintHandler : BaseReaderHandler<> { ParseUintHandler() : step_(0), actual_() {} - void Default() { FAIL(); } - void Uint(unsigned i) { actual_ = i; step_++; } + bool Default() { ADD_FAILURE(); return false; } + bool Uint(unsigned i) { actual_ = i; step_++; return true; } unsigned step_; unsigned actual_; @@ -57,8 +57,8 @@ struct ParseUintHandler : BaseReaderHandler<> { struct ParseInt64Handler : BaseReaderHandler<> { ParseInt64Handler() : step_(0), actual_() {} - void Default() { FAIL(); } - void Int64(int64_t i) { actual_ = i; step_++; } + bool Default() { ADD_FAILURE(); return false; } + bool Int64(int64_t i) { actual_ = i; step_++; return true; } unsigned step_; int64_t actual_; @@ -66,8 +66,8 @@ struct ParseInt64Handler : BaseReaderHandler<> { struct ParseUint64Handler : BaseReaderHandler<> { ParseUint64Handler() : step_(0), actual_() {} - void Default() { FAIL(); } - void Uint64(uint64_t i) { actual_ = i; step_++; } + bool Default() { ADD_FAILURE(); return false; } + bool Uint64(uint64_t i) { actual_ = i; step_++; return true; } unsigned step_; uint64_t actual_; @@ -75,8 +75,8 @@ struct ParseUint64Handler : BaseReaderHandler<> { struct ParseDoubleHandler : BaseReaderHandler<> { ParseDoubleHandler() : step_(0), actual_() {} - void Default() { FAIL(); } - void Double(double d) { actual_ = d; step_++; } + bool Default() { ADD_FAILURE(); return false; } + bool Double(double d) { actual_ = d; step_++; return true; } unsigned step_; double actual_; @@ -194,8 +194,8 @@ struct ParseStringHandler : BaseReaderHandler { ParseStringHandler(const ParseStringHandler&); ParseStringHandler& operator=(const ParseStringHandler&); - void Default() { FAIL(); } - void String(const typename Encoding::Ch* str, size_t length, bool copy) { + bool Default() { ADD_FAILURE(); return false; } + bool String(const typename Encoding::Ch* str, size_t length, bool copy) { EXPECT_EQ(0, str_); if (copy) { str_ = (typename Encoding::Ch*)malloc((length + 1) * sizeof(typename Encoding::Ch)); @@ -204,7 +204,8 @@ struct ParseStringHandler : BaseReaderHandler { else str_ = str; length_ = length; - copy_ = copy; + copy_ = copy; + return true; } const typename Encoding::Ch* str_; @@ -411,10 +412,10 @@ template struct ParseArrayHandler : BaseReaderHandler<> { ParseArrayHandler() : step_(0) {} - void Default() { FAIL(); } - void Uint(unsigned i) { EXPECT_EQ(step_, i); step_++; } - void StartArray() { EXPECT_EQ(0u, step_); step_++; } - void EndArray(SizeType) { step_++; } + bool Default() { ADD_FAILURE(); return false; } + bool Uint(unsigned i) { EXPECT_EQ(step_, i); step_++; return true; } + bool StartArray() { EXPECT_EQ(0u, step_); step_++; return true; } + bool EndArray(SizeType) { step_++; return true; } unsigned step_; }; @@ -462,42 +463,42 @@ TEST(Reader, ParseArray_Error) { struct ParseObjectHandler : BaseReaderHandler<> { ParseObjectHandler() : step_(0) {} - void Null() { EXPECT_EQ(8u, step_); step_++; } - void Bool(bool b) { + bool Null() { EXPECT_EQ(8u, step_); step_++; return true; } + bool Bool(bool b) { switch(step_) { - case 4: EXPECT_TRUE(b); step_++; break; - case 6: EXPECT_FALSE(b); step_++; break; - default: FAIL(); + case 4: EXPECT_TRUE(b); step_++; return true; + case 6: EXPECT_FALSE(b); step_++; return true; + default: ADD_FAILURE(); return false; } } - void Int(int i) { + bool Int(int i) { switch(step_) { - case 10: EXPECT_EQ(123, i); step_++; break; - case 15: EXPECT_EQ(1, i); step_++; break; - case 16: EXPECT_EQ(2, i); step_++; break; - case 17: EXPECT_EQ(3, i); step_++; break; - default: FAIL(); + case 10: EXPECT_EQ(123, i); step_++; return true; + case 15: EXPECT_EQ(1, i); step_++; return true; + case 16: EXPECT_EQ(2, i); step_++; return true; + case 17: EXPECT_EQ(3, i); step_++; return true; + default: ADD_FAILURE(); return false; } } - void Uint(unsigned i) { Int(i); } - void Double(double d) { EXPECT_EQ(12u, step_); EXPECT_EQ(3.1416, d); step_++; } - void String(const char* str, size_t, bool) { + bool Uint(unsigned i) { return Int(i); } + bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_EQ(3.1416, d); step_++; return true; } + bool String(const char* str, size_t, bool) { switch(step_) { - case 1: EXPECT_STREQ("hello", str); step_++; break; - case 2: EXPECT_STREQ("world", str); step_++; break; - case 3: EXPECT_STREQ("t", str); step_++; break; - case 5: EXPECT_STREQ("f", str); step_++; break; - case 7: EXPECT_STREQ("n", str); step_++; break; - case 9: EXPECT_STREQ("i", str); step_++; break; - case 11: EXPECT_STREQ("pi", str); step_++; break; - case 13: EXPECT_STREQ("a", str); step_++; break; - default: FAIL(); + case 1: EXPECT_STREQ("hello", str); step_++; return true; + case 2: EXPECT_STREQ("world", str); step_++; return true; + case 3: EXPECT_STREQ("t", str); step_++; return true; + case 5: EXPECT_STREQ("f", str); step_++; return true; + case 7: EXPECT_STREQ("n", str); step_++; return true; + case 9: EXPECT_STREQ("i", str); step_++; return true; + case 11: EXPECT_STREQ("pi", str); step_++; return true; + case 13: EXPECT_STREQ("a", str); step_++; return true; + default: ADD_FAILURE(); return false; } } - void StartObject() { EXPECT_EQ(0u, step_); step_++; } - void EndObject(SizeType memberCount) { EXPECT_EQ(19u, step_); EXPECT_EQ(7u, memberCount); step_++;} - void StartArray() { EXPECT_EQ(14u, step_); step_++; } - void EndArray(SizeType elementCount) { EXPECT_EQ(18u, step_); EXPECT_EQ(3u, elementCount); step_++;} + bool StartObject() { EXPECT_EQ(0u, step_); step_++; return true; } + bool EndObject(SizeType memberCount) { EXPECT_EQ(19u, step_); EXPECT_EQ(7u, memberCount); step_++; return true; } + bool StartArray() { EXPECT_EQ(14u, step_); step_++; return true; } + bool EndArray(SizeType elementCount) { EXPECT_EQ(18u, step_); EXPECT_EQ(3u, elementCount); step_++; return true; } unsigned step_; }; @@ -529,9 +530,9 @@ TEST(Reader, ParseObject) { struct ParseEmptyObjectHandler : BaseReaderHandler<> { ParseEmptyObjectHandler() : step_(0) {} - void Default() { FAIL(); } - void StartObject() { EXPECT_EQ(0u, step_); step_++; } - void EndObject(SizeType) { EXPECT_EQ(1u, step_); step_++; } + bool Default() { ADD_FAILURE(); return false; } + bool StartObject() { EXPECT_EQ(0u, step_); step_++; return true; } + bool EndObject(SizeType) { EXPECT_EQ(1u, step_); step_++; return true; } unsigned step_; }; diff --git a/test/unittest/writertest.cpp b/test/unittest/writertest.cpp index d189fa1..be3d77b 100644 --- a/test/unittest/writertest.cpp +++ b/test/unittest/writertest.cpp @@ -83,13 +83,13 @@ TEST(Writer,DoublePrecision) { buffer.Clear(); } { // explicit individual double precisions - writer.SetDoublePrecision(2) - .StartArray() - .Double(1.2345,5) - .Double(1.2345678,9) - .Double(0.123456789012,12) - .Double(1234567.8,8) - .EndArray(); + writer.SetDoublePrecision(2); + writer.StartArray(); + writer.Double(1.2345, 5); + writer.Double(1.2345678, 9); + writer.Double(0.123456789012, 12); + writer.Double(1234567.8, 8); + writer.EndArray(); EXPECT_EQ(writer.GetDoublePrecision(), 2); EXPECT_STREQ(json, buffer.GetString());