From b37bd85318170c179494911bbb29dfbf677aa8b2 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Thu, 3 Jul 2014 17:58:59 +0200 Subject: [PATCH 1/7] move ParseErrorCode to error/error.h In order to enable the customization of the error macros - RAPIDJSON_PARSE_ERROR_NORETURN - RAPIDJSON_PARSE_ERROR_EARLY_RETURN the user may need to have access to the ParseErrorCode enum already. This requires a separate header location than the GenericReader. --- include/rapidjson/error/error.h | 35 +++++++++++++++++++++++++++++++-- include/rapidjson/reader.h | 29 ++------------------------- 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h index ba45e7e4..af597d27 100644 --- a/include/rapidjson/error/error.h +++ b/include/rapidjson/error/error.h @@ -1,8 +1,6 @@ #ifndef RAPIDJSON_ERROR_ERROR_H__ #define RAPIDJSON_ERROR_ERROR_H__ -#include "../reader.h" // ParseErrorCode - /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ERROR_CHARTYPE @@ -29,6 +27,39 @@ namespace rapidjson { +/////////////////////////////////////////////////////////////////////////////// +// ParseErrorCode + +//! Error code of parsing. +/*! \see GenericReader::Parse, GenericReader::GetParseErrorCode +*/ +enum ParseErrorCode { + kParseErrorNone = 0, //!< No error. + + kParseErrorDocumentEmpty, //!< The document is empty. + kParseErrorDocumentRootNotObjectOrArray, //!< The document root must be either object or array. + kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. + + kParseErrorValueInvalid, //!< Invalid value. + + kParseErrorObjectMissName, //!< Missing a name for object member. + kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. + kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. + + kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. + + kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. + kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. + kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. + kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. + kParseErrorStringInvalidEncoding, //!< Invalid encoidng in string. + + kParseErrorNumberTooBig, //!< Number too big to be stored in double. + kParseErrorNumberMissFraction, //!< Miss fraction part in number. + kParseErrorNumberMissExponent //!< Miss exponent in number. +}; + + //! Function pointer type of GetParseError(). /*! This is the prototype for GetParseError_X(), where X is a locale. User can dynamically change locale in runtime, e.g.: diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index bd141a1f..1396fc2a 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -41,6 +41,8 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_MULTILINEMACRO_END #endif +#include "error/error.h" // ParseErrorCode + namespace rapidjson { /////////////////////////////////////////////////////////////////////////////// @@ -55,33 +57,6 @@ enum ParseFlag { kParseValidateEncodingFlag = 2 //!< Validate encoding of JSON strings. }; -//! Error code of parsing. -enum ParseErrorCode { - kParseErrorNone = 0, //!< No error. - - kParseErrorDocumentEmpty, //!< The document is empty. - kParseErrorDocumentRootNotObjectOrArray, //!< The document root must be either object or array. - kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. - - kParseErrorValueInvalid, //!< Invalid value. - - kParseErrorObjectMissName, //!< Missing a name for object member. - kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. - kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. - - kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. - - kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. - kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. - kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. - kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. - kParseErrorStringInvalidEncoding, //!< Invalid encoidng in string. - - kParseErrorNumberTooBig, //!< Number too big to be stored in double. - kParseErrorNumberMissFraction, //!< Miss fraction part in number. - kParseErrorNumberMissExponent //!< Miss exponent in number. -}; - /////////////////////////////////////////////////////////////////////////////// // Handler From 3c1d4bc21d7299a6abdfde9896fd2aaedb03a9c0 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Wed, 2 Jul 2014 01:04:33 +0200 Subject: [PATCH 2/7] reader.h: prepare "early return path" for exception support In case of a user-defined RAPIDJSON_PARSE_ERROR_NORETURN that throws an exception instead of using the Rapidjson ParseError API, the early return paths performing the stack unwinding manually can be omitted as well. This patch provides a customizable RAPIDJSON_PARSE_ERROR_EARLY_RETURN macro to remove these (then unneeded) control paths from the parsing implementation (with and without a return value). Secondly, clearing the parse stack is moved to a small helper struct that calls stack_.Clear() from its destructor. This avoids the need for the 'goto' in the ParseStream function and ensures proper cleanup even if e.g. a user-defined Allocator throws an exception. --- include/rapidjson/reader.h | 55 +++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 1396fc2a..00ee43ed 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -24,6 +24,16 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant #endif +#define RAPIDJSON_NOTHING /* deliberately empty */ +#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN +#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ + RAPIDJSON_MULTILINEMACRO_BEGIN \ + if (HasParseError()) { return value; } \ + RAPIDJSON_MULTILINEMACRO_END +#endif +#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) + #ifndef RAPIDJSON_PARSE_ERROR_NORETURN #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ @@ -37,7 +47,7 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant #define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ - return; \ + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ RAPIDJSON_MULTILINEMACRO_END #endif @@ -278,28 +288,30 @@ public: parseErrorCode_ = kParseErrorNone; errorOffset_ = 0; + ClearStackOnExit scope(*this); SkipWhitespace(is); - if (is.Peek() == '\0') + if (is.Peek() == '\0') { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(false); + } else { switch (is.Peek()) { case '{': ParseObject(is, handler); break; case '[': ParseArray(is, handler); break; default: RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotObjectOrArray, is.Tell()); } - if (HasParseError()) - goto out; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(false); SkipWhitespace(is); - if (is.Peek() != '\0') + if (is.Peek() != '\0') { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(false); + } } - out: - stack_.Clear(); - return !HasParseError(); + return true; } //! Parse JSON text (with \ref kParseDefaultFlags) @@ -325,6 +337,16 @@ private: GenericReader(const GenericReader&); GenericReader& operator=(const GenericReader&); + void ClearStack() { stack_.Clear(); } + + // clear stack on any exit from ParseStream, e.g. due to exception + struct ClearStackOnExit { + explicit ClearStackOnExit(GenericReader& r) : r_(r) {} + ~ClearStackOnExit() { r_.ClearStack(); } + private: + GenericReader& r_; + }; + // Parse object: { string : value, ... } template void ParseObject(InputStream& is, Handler& handler) { @@ -344,8 +366,7 @@ private: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); ParseString(is, handler); - if (HasParseError()) - return; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SkipWhitespace(is); @@ -355,8 +376,7 @@ private: SkipWhitespace(is); ParseValue(is, handler); - if (HasParseError()) - return; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SkipWhitespace(is); @@ -386,8 +406,7 @@ private: for (SizeType elementCount = 0;;) { ParseValue(is, handler); - if (HasParseError()) - return; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ++elementCount; SkipWhitespace(is); @@ -449,7 +468,7 @@ private: codepoint -= 'a' - 10; else { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, is.Tell() - 1); - return 0; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); } } return codepoint; @@ -481,8 +500,7 @@ private: if (parseFlags & kParseInsituFlag) { typename InputStream::Ch *head = s.PutBegin(); ParseStringToStream(s, s); - if (HasParseError()) - return; + 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); @@ -490,8 +508,7 @@ private: else { StackStream stackStream(stack_); ParseStringToStream(s, stackStream); - if (HasParseError()) - return; + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; handler.String(stack_.template Pop(stackStream.length_), stackStream.length_ - 1, true); } } From 4475521177ca6830a5f3840da1c8a794102ba6c5 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Wed, 2 Jul 2014 01:58:49 +0200 Subject: [PATCH 3/7] GenericDocument: simplify error handling in ParseStream * unconditionally store error state of reader after parsing * clear stack after parsing by using a ClearStackOnExit scope guard --- include/rapidjson/document.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 45b6c3fc..e397a487 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1226,17 +1226,13 @@ public: GenericDocument& ParseStream(InputStream& is) { ValueType::SetNull(); // Remove existing root if exist GenericReader reader(&GetAllocator()); + ClearStackOnExit scope(*this); if (reader.template Parse(is, *this)) { RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object this->RawAssign(*stack_.template Pop(1)); // Add this-> to prevent issue 13. - parseErrorCode_ = kParseErrorNone; - errorOffset_ = 0; - } - else { - parseErrorCode_ = reader.GetParseErrorCode(); - errorOffset_ = reader.GetErrorOffset(); - ClearStack(); } + parseErrorCode_ = reader.GetParseErrorCode(); + errorOffset_ = reader.GetErrorOffset(); return *this; } @@ -1349,6 +1345,14 @@ public: size_t GetStackCapacity() const { return stack_.GetCapacity(); } private: + // clear stack on any exit from ParseStream, e.g. due to exception + struct ClearStackOnExit { + explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} + ~ClearStackOnExit() { d_.ClearStack(); } + private: + GenericDocument& d_; + }; + // callers of the following private Handler functions template friend class GenericReader; // for parsing friend class GenericValue; // for deep copying From 2fcb999749ea793d27effee167de9952375630b7 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Wed, 9 Jul 2014 13:55:54 +0200 Subject: [PATCH 4/7] add ParseResult --- include/rapidjson/document.h | 16 +++++++--------- include/rapidjson/error/error.h | 22 ++++++++++++++++++++++ include/rapidjson/reader.h | 31 ++++++++++++++----------------- 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index e397a487..b8d136df 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1210,7 +1210,7 @@ public: /*! \param allocator Optional allocator for allocating stack memory. \param stackCapacity Initial capacity of stack in bytes. */ - GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseErrorCode_(kParseErrorNone), errorOffset_(0) {} + GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseResult_() {} //!@name Parse from stream //!@{ @@ -1227,12 +1227,11 @@ public: ValueType::SetNull(); // Remove existing root if exist GenericReader reader(&GetAllocator()); ClearStackOnExit scope(*this); - if (reader.template Parse(is, *this)) { + parseResult_ = reader.template Parse(is, *this); + if (parseResult_) { RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object this->RawAssign(*stack_.template Pop(1)); // Add this-> to prevent issue 13. } - parseErrorCode_ = reader.GetParseErrorCode(); - errorOffset_ = reader.GetErrorOffset(); return *this; } @@ -1328,13 +1327,13 @@ public: //!@{ //! Whether a parse error was occured in the last parsing. - bool HasParseError() const { return parseErrorCode_ != kParseErrorNone; } + bool HasParseError() const { return parseResult_.IsError(); } //! Get the message of parsing error. - ParseErrorCode GetParseError() const { return parseErrorCode_; } + ParseErrorCode GetParseError() const { return parseResult_.Code(); } //! Get the offset in character of the parsing error. - size_t GetErrorOffset() const { return errorOffset_; } + size_t GetErrorOffset() const { return parseResult_.Offset(); } //!@} @@ -1401,8 +1400,7 @@ private: static const size_t kDefaultStackCapacity = 1024; internal::Stack stack_; - ParseErrorCode parseErrorCode_; - size_t errorOffset_; + ParseResult parseResult_; }; //! GenericDocument with UTF8 encoding diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h index af597d27..765f1c11 100644 --- a/include/rapidjson/error/error.h +++ b/include/rapidjson/error/error.h @@ -59,6 +59,28 @@ enum ParseErrorCode { kParseErrorNumberMissExponent //!< Miss exponent in number. }; +struct ParseResult { + + ParseResult() : code_(kParseErrorNone), offset_(0) {} + ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} + + ParseErrorCode Code() const { return code_; } + size_t Offset() const { return offset_; } + + operator bool() const { return !IsError(); } + bool IsError() const { return code_ != kParseErrorNone; } + + bool operator==(const ParseResult& that) const { return code_ == that.code_; } + bool operator==(ParseErrorCode code) const { return code_ == code; } + friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } + + void Clear() { Set(kParseErrorNone); } + void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } + +private: + ParseErrorCode code_; + size_t offset_; +}; //! Function pointer type of GetParseError(). /*! This is the prototype for GetParseError_X(), where X is a locale. diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 00ee43ed..72ebad98 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -38,8 +38,7 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ - parseErrorCode_ = parseErrorCode; \ - errorOffset_ = offset; \ + parseResult_.Set(parseErrorCode,offset); \ RAPIDJSON_MULTILINEMACRO_END #endif @@ -51,7 +50,7 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_MULTILINEMACRO_END #endif -#include "error/error.h" // ParseErrorCode +#include "error/error.h" // ParseErrorCode, ParseResult namespace rapidjson { @@ -273,7 +272,7 @@ public: /*! \param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) */ - GenericReader(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseErrorCode_(kParseErrorNone), errorOffset_(0) {} + GenericReader(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseResult_() {} //! Parse JSON text. /*! \tparam parseFlags Combination of \ref ParseFlag. @@ -284,16 +283,15 @@ public: \return Whether the parsing is successful. */ template - bool Parse(InputStream& is, Handler& handler) { - parseErrorCode_ = kParseErrorNone; - errorOffset_ = 0; + ParseResult Parse(InputStream& is, Handler& handler) { + parseResult_.Clear(); ClearStackOnExit scope(*this); SkipWhitespace(is); if (is.Peek() == '\0') { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(false); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } else { switch (is.Peek()) { @@ -301,17 +299,17 @@ public: case '[': ParseArray(is, handler); break; default: RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotObjectOrArray, is.Tell()); } - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(false); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); SkipWhitespace(is); if (is.Peek() != '\0') { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(false); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } } - return true; + return parseResult_; } //! Parse JSON text (with \ref kParseDefaultFlags) @@ -322,15 +320,15 @@ public: \return Whether the parsing is successful. */ template - bool Parse(InputStream& is, Handler& handler) { + ParseResult Parse(InputStream& is, Handler& handler) { return Parse(is, handler); } - bool HasParseError() const { return parseErrorCode_ != kParseErrorNone; } + bool HasParseError() const { return parseResult_.IsError(); } - ParseErrorCode GetParseErrorCode() const { return parseErrorCode_; } + ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } - size_t GetErrorOffset() const { return errorOffset_; } + size_t GetErrorOffset() const { return parseResult_.Offset(); } private: // Prohibit copy constructor & assignment operator. @@ -755,8 +753,7 @@ private: static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. - ParseErrorCode parseErrorCode_; - size_t errorOffset_; + ParseResult parseResult_; }; // class GenericReader //! Reader with UTF8 encoding and default allocator. From 418a5829b311c3a0b1f4dc67ea7c26f240a57b12 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Wed, 9 Jul 2014 21:19:13 +0200 Subject: [PATCH 5/7] update documentation of ParseResult and related functions --- include/rapidjson/document.h | 6 +++--- include/rapidjson/error/error.h | 21 +++++++++++++++++++++ include/rapidjson/reader.h | 3 +++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index b8d136df..042a2a3f 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1326,13 +1326,13 @@ public: //!@name Handling parse errors //!@{ - //! Whether a parse error was occured in the last parsing. + //! Whether a parse error has occured in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } - //! Get the message of parsing error. + //! Get the \ref ParseErrorCode of last parsing. ParseErrorCode GetParseError() const { return parseResult_.Code(); } - //! Get the offset in character of the parsing error. + //! Get the position of last parsing error in input, 0 otherwise. size_t GetErrorOffset() const { return parseResult_.Offset(); } //!@} diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h index 765f1c11..829e2b97 100644 --- a/include/rapidjson/error/error.h +++ b/include/rapidjson/error/error.h @@ -59,22 +59,43 @@ enum ParseErrorCode { kParseErrorNumberMissExponent //!< Miss exponent in number. }; +//! Result of parsing (wraps ParseErrorCode) +/*! + \code + Document doc; + ParseResult ok = doc.Parse("[42]"); + if (!ok) { + fprintf(stderr, "JSON parse error: %s (%u)", + GetParseError_En(ok.Code()), ok.Offset()); + exit(EXIT_FAILURE); + } + \endcode + \see GenericReader::Parse, GenericDocument::Parse +*/ struct ParseResult { + //! Default constructor, no error. ParseResult() : code_(kParseErrorNone), offset_(0) {} + //! Constructor to set an error. ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} + //! Get the error code. ParseErrorCode Code() const { return code_; } + //! Get the error offset, if \ref IsError(), 0 otherwise. size_t Offset() const { return offset_; } + //! Conversion to \c bool, returns \c true, iff !\ref IsError(). operator bool() const { return !IsError(); } + //! Whether the result is an error. bool IsError() const { return code_ != kParseErrorNone; } bool operator==(const ParseResult& that) const { return code_ == that.code_; } bool operator==(ParseErrorCode code) const { return code_ == code; } friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } + //! Reset error code. void Clear() { Set(kParseErrorNone); } + //! Update error code and offset. void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } private: diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 72ebad98..0d773160 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -324,10 +324,13 @@ public: return Parse(is, handler); } + //! Whether a parse error has occured in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } + //! Get the \ref ParseErrorCode of last parsing. ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } + //! Get the position of last parsing error in input, 0 otherwise. size_t GetErrorOffset() const { return parseResult_.Offset(); } private: From c69610239a0ec1cd0e9631dcf297b25b60de9362 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Sat, 12 Jul 2014 18:44:31 +0200 Subject: [PATCH 6/7] error.h: add kParseErrorTermination (from #61) --- include/rapidjson/error/error.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h index 829e2b97..b1839179 100644 --- a/include/rapidjson/error/error.h +++ b/include/rapidjson/error/error.h @@ -52,11 +52,13 @@ enum ParseErrorCode { kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. - kParseErrorStringInvalidEncoding, //!< Invalid encoidng in string. + kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. kParseErrorNumberTooBig, //!< Number too big to be stored in double. kParseErrorNumberMissFraction, //!< Miss fraction part in number. - kParseErrorNumberMissExponent //!< Miss exponent in number. + kParseErrorNumberMissExponent, //!< Miss exponent in number. + + kParseErrorTermination //!< Parsing was terminated. }; //! Result of parsing (wraps ParseErrorCode) From ff5713faf032a6a1210c4d7313f45bfe3254e135 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Sat, 12 Jul 2014 18:45:49 +0200 Subject: [PATCH 7/7] error/en.h: fix typo, add termination string --- include/rapidjson/error/en.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/error/en.h b/include/rapidjson/error/en.h index 81637ee9..6317957b 100644 --- a/include/rapidjson/error/en.h +++ b/include/rapidjson/error/en.h @@ -32,12 +32,14 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); - case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoidng in string."); + case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); + case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); + default: return RAPIDJSON_ERROR_STRING("Unknown error."); }