Merge pull request #64 from pah/feature/exception-support
Improve exception safety and add support for swtiching error handling to exceptions
This commit is contained in:
commit
cb3f213186
@ -1211,7 +1211,7 @@ public:
|
|||||||
/*! \param allocator Optional allocator for allocating stack memory.
|
/*! \param allocator Optional allocator for allocating stack memory.
|
||||||
\param stackCapacity Initial capacity of stack in bytes.
|
\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
|
//!@name Parse from stream
|
||||||
//!@{
|
//!@{
|
||||||
@ -1227,16 +1227,11 @@ public:
|
|||||||
GenericDocument& ParseStream(InputStream& is) {
|
GenericDocument& ParseStream(InputStream& is) {
|
||||||
ValueType::SetNull(); // Remove existing root if exist
|
ValueType::SetNull(); // Remove existing root if exist
|
||||||
GenericReader<SourceEncoding, Encoding, Allocator> reader(&GetAllocator());
|
GenericReader<SourceEncoding, Encoding, Allocator> reader(&GetAllocator());
|
||||||
if (reader.template Parse<parseFlags>(is, *this)) {
|
ClearStackOnExit scope(*this);
|
||||||
|
parseResult_ = reader.template Parse<parseFlags>(is, *this);
|
||||||
|
if (parseResult_) {
|
||||||
RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
|
RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
|
||||||
this->RawAssign(*stack_.template Pop<ValueType>(1)); // Add this-> to prevent issue 13.
|
this->RawAssign(*stack_.template Pop<ValueType>(1)); // Add this-> to prevent issue 13.
|
||||||
parseErrorCode_ = kParseErrorNone;
|
|
||||||
errorOffset_ = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
parseErrorCode_ = reader.GetParseErrorCode();
|
|
||||||
errorOffset_ = reader.GetErrorOffset();
|
|
||||||
ClearStack();
|
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -1332,14 +1327,14 @@ public:
|
|||||||
//!@name Handling parse errors
|
//!@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 parseErrorCode_ != kParseErrorNone; }
|
bool HasParseError() const { return parseResult_.IsError(); }
|
||||||
|
|
||||||
//! Get the message of parsing error.
|
//! Get the \ref ParseErrorCode of last parsing.
|
||||||
ParseErrorCode GetParseError() const { return parseErrorCode_; }
|
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 errorOffset_; }
|
size_t GetErrorOffset() const { return parseResult_.Offset(); }
|
||||||
|
|
||||||
//!@}
|
//!@}
|
||||||
|
|
||||||
@ -1350,6 +1345,14 @@ public:
|
|||||||
size_t GetStackCapacity() const { return stack_.GetCapacity(); }
|
size_t GetStackCapacity() const { return stack_.GetCapacity(); }
|
||||||
|
|
||||||
private:
|
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
|
// callers of the following private Handler functions
|
||||||
template <typename,typename,typename> friend class GenericReader; // for parsing
|
template <typename,typename,typename> friend class GenericReader; // for parsing
|
||||||
friend class GenericValue<Encoding,Allocator>; // for deep copying
|
friend class GenericValue<Encoding,Allocator>; // for deep copying
|
||||||
@ -1401,8 +1404,7 @@ private:
|
|||||||
|
|
||||||
static const size_t kDefaultStackCapacity = 1024;
|
static const size_t kDefaultStackCapacity = 1024;
|
||||||
internal::Stack<Allocator> stack_;
|
internal::Stack<Allocator> stack_;
|
||||||
ParseErrorCode parseErrorCode_;
|
ParseResult parseResult_;
|
||||||
size_t errorOffset_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! GenericDocument with UTF8 encoding
|
//! GenericDocument with UTF8 encoding
|
||||||
|
@ -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 kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
|
||||||
case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
|
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 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 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 kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
|
||||||
case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent 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:
|
default:
|
||||||
return RAPIDJSON_ERROR_STRING("Unknown error.");
|
return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
#ifndef RAPIDJSON_ERROR_ERROR_H__
|
#ifndef RAPIDJSON_ERROR_ERROR_H__
|
||||||
#define RAPIDJSON_ERROR_ERROR_H__
|
#define RAPIDJSON_ERROR_ERROR_H__
|
||||||
|
|
||||||
#include "../reader.h" // ParseErrorCode
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// RAPIDJSON_ERROR_CHARTYPE
|
// RAPIDJSON_ERROR_CHARTYPE
|
||||||
|
|
||||||
@ -29,6 +27,84 @@
|
|||||||
|
|
||||||
namespace rapidjson {
|
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 encoding in string.
|
||||||
|
|
||||||
|
kParseErrorNumberTooBig, //!< Number too big to be stored in double.
|
||||||
|
kParseErrorNumberMissFraction, //!< Miss fraction part in number.
|
||||||
|
kParseErrorNumberMissExponent, //!< Miss exponent in number.
|
||||||
|
|
||||||
|
kParseErrorTermination //!< Parsing was terminated.
|
||||||
|
};
|
||||||
|
|
||||||
|
//! 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:
|
||||||
|
ParseErrorCode code_;
|
||||||
|
size_t offset_;
|
||||||
|
};
|
||||||
|
|
||||||
//! Function pointer type of GetParseError().
|
//! Function pointer type of GetParseError().
|
||||||
/*! This is the prototype for GetParseError_X(), where X is a locale.
|
/*! This is the prototype for GetParseError_X(), where X is a locale.
|
||||||
User can dynamically change locale in runtime, e.g.:
|
User can dynamically change locale in runtime, e.g.:
|
||||||
|
@ -24,12 +24,21 @@ RAPIDJSON_DIAG_PUSH
|
|||||||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||||
#endif
|
#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
|
#ifndef RAPIDJSON_PARSE_ERROR_NORETURN
|
||||||
#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \
|
#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \
|
||||||
RAPIDJSON_MULTILINEMACRO_BEGIN \
|
RAPIDJSON_MULTILINEMACRO_BEGIN \
|
||||||
RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
|
RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
|
||||||
parseErrorCode_ = parseErrorCode; \
|
parseResult_.Set(parseErrorCode,offset); \
|
||||||
errorOffset_ = offset; \
|
|
||||||
RAPIDJSON_MULTILINEMACRO_END
|
RAPIDJSON_MULTILINEMACRO_END
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -37,10 +46,12 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
|||||||
#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \
|
#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \
|
||||||
RAPIDJSON_MULTILINEMACRO_BEGIN \
|
RAPIDJSON_MULTILINEMACRO_BEGIN \
|
||||||
RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
|
RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
|
||||||
return; \
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
|
||||||
RAPIDJSON_MULTILINEMACRO_END
|
RAPIDJSON_MULTILINEMACRO_END
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "error/error.h" // ParseErrorCode, ParseResult
|
||||||
|
|
||||||
namespace rapidjson {
|
namespace rapidjson {
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -55,35 +66,6 @@ enum ParseFlag {
|
|||||||
kParseValidateEncodingFlag = 2 //!< Validate encoding of JSON strings.
|
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.
|
|
||||||
|
|
||||||
kParseErrorTermination //!< Parsing was terminated.
|
|
||||||
};
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Handler
|
// Handler
|
||||||
|
|
||||||
@ -292,7 +274,7 @@ public:
|
|||||||
/*! \param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
|
/*! \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)
|
\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.
|
//! Parse JSON text.
|
||||||
/*! \tparam parseFlags Combination of \ref ParseFlag.
|
/*! \tparam parseFlags Combination of \ref ParseFlag.
|
||||||
@ -303,32 +285,33 @@ public:
|
|||||||
\return Whether the parsing is successful.
|
\return Whether the parsing is successful.
|
||||||
*/
|
*/
|
||||||
template <unsigned parseFlags, typename InputStream, typename Handler>
|
template <unsigned parseFlags, typename InputStream, typename Handler>
|
||||||
bool Parse(InputStream& is, Handler& handler) {
|
ParseResult Parse(InputStream& is, Handler& handler) {
|
||||||
parseErrorCode_ = kParseErrorNone;
|
parseResult_.Clear();
|
||||||
errorOffset_ = 0;
|
|
||||||
|
|
||||||
|
ClearStackOnExit scope(*this);
|
||||||
SkipWhitespace(is);
|
SkipWhitespace(is);
|
||||||
|
|
||||||
if (is.Peek() == '\0')
|
if (is.Peek() == '\0') {
|
||||||
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
switch (is.Peek()) {
|
switch (is.Peek()) {
|
||||||
case '{': ParseObject<parseFlags>(is, handler); break;
|
case '{': ParseObject<parseFlags>(is, handler); break;
|
||||||
case '[': ParseArray<parseFlags>(is, handler); break;
|
case '[': ParseArray<parseFlags>(is, handler); break;
|
||||||
default: RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotObjectOrArray, is.Tell());
|
default: RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotObjectOrArray, is.Tell());
|
||||||
}
|
}
|
||||||
if (HasParseError())
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||||
goto out;
|
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespace(is);
|
||||||
|
|
||||||
if (is.Peek() != '\0')
|
if (is.Peek() != '\0') {
|
||||||
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
|
||||||
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
return parseResult_;
|
||||||
stack_.Clear();
|
|
||||||
return !HasParseError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Parse JSON text (with \ref kParseDefaultFlags)
|
//! Parse JSON text (with \ref kParseDefaultFlags)
|
||||||
@ -339,21 +322,34 @@ public:
|
|||||||
\return Whether the parsing is successful.
|
\return Whether the parsing is successful.
|
||||||
*/
|
*/
|
||||||
template <typename InputStream, typename Handler>
|
template <typename InputStream, typename Handler>
|
||||||
bool Parse(InputStream& is, Handler& handler) {
|
ParseResult Parse(InputStream& is, Handler& handler) {
|
||||||
return Parse<kParseDefaultFlags>(is, handler);
|
return Parse<kParseDefaultFlags>(is, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasParseError() const { return parseErrorCode_ != kParseErrorNone; }
|
//! Whether a parse error has occured in the last parsing.
|
||||||
|
bool HasParseError() const { return parseResult_.IsError(); }
|
||||||
|
|
||||||
ParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }
|
//! Get the \ref ParseErrorCode of last parsing.
|
||||||
|
ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); }
|
||||||
|
|
||||||
size_t GetErrorOffset() const { return errorOffset_; }
|
//! Get the position of last parsing error in input, 0 otherwise.
|
||||||
|
size_t GetErrorOffset() const { return parseResult_.Offset(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Prohibit copy constructor & assignment operator.
|
// Prohibit copy constructor & assignment operator.
|
||||||
GenericReader(const GenericReader&);
|
GenericReader(const GenericReader&);
|
||||||
GenericReader& operator=(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, ... }
|
// Parse object: { string : value, ... }
|
||||||
template<unsigned parseFlags, typename InputStream, typename Handler>
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
||||||
void ParseObject(InputStream& is, Handler& handler) {
|
void ParseObject(InputStream& is, Handler& handler) {
|
||||||
@ -377,8 +373,7 @@ private:
|
|||||||
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
|
||||||
|
|
||||||
ParseString<parseFlags>(is, handler);
|
ParseString<parseFlags>(is, handler);
|
||||||
if (HasParseError())
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
return;
|
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespace(is);
|
||||||
|
|
||||||
@ -388,8 +383,7 @@ private:
|
|||||||
SkipWhitespace(is);
|
SkipWhitespace(is);
|
||||||
|
|
||||||
ParseValue<parseFlags>(is, handler);
|
ParseValue<parseFlags>(is, handler);
|
||||||
if (HasParseError())
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
return;
|
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespace(is);
|
||||||
|
|
||||||
@ -427,8 +421,7 @@ private:
|
|||||||
|
|
||||||
for (SizeType elementCount = 0;;) {
|
for (SizeType elementCount = 0;;) {
|
||||||
ParseValue<parseFlags>(is, handler);
|
ParseValue<parseFlags>(is, handler);
|
||||||
if (HasParseError())
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
return;
|
|
||||||
|
|
||||||
++elementCount;
|
++elementCount;
|
||||||
SkipWhitespace(is);
|
SkipWhitespace(is);
|
||||||
@ -500,7 +493,7 @@ private:
|
|||||||
codepoint -= 'a' - 10;
|
codepoint -= 'a' - 10;
|
||||||
else {
|
else {
|
||||||
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, is.Tell() - 1);
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, is.Tell() - 1);
|
||||||
return 0;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return codepoint;
|
return codepoint;
|
||||||
@ -532,8 +525,7 @@ private:
|
|||||||
if (parseFlags & kParseInsituFlag) {
|
if (parseFlags & kParseInsituFlag) {
|
||||||
typename InputStream::Ch *head = s.PutBegin();
|
typename InputStream::Ch *head = s.PutBegin();
|
||||||
ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
|
ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
|
||||||
if (HasParseError())
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
return;
|
|
||||||
size_t length = s.PutEnd(head) - 1;
|
size_t length = s.PutEnd(head) - 1;
|
||||||
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
|
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
|
||||||
if (!handler.String((typename TargetEncoding::Ch*)head, SizeType(length), false))
|
if (!handler.String((typename TargetEncoding::Ch*)head, SizeType(length), false))
|
||||||
@ -542,8 +534,7 @@ private:
|
|||||||
else {
|
else {
|
||||||
StackStream stackStream(stack_);
|
StackStream stackStream(stack_);
|
||||||
ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
|
ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
|
||||||
if (HasParseError())
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
return;
|
|
||||||
if (!handler.String(stack_.template Pop<typename TargetEncoding::Ch>(stackStream.length_), stackStream.length_ - 1, true))
|
if (!handler.String(stack_.template Pop<typename TargetEncoding::Ch>(stackStream.length_), stackStream.length_ - 1, true))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
|
||||||
}
|
}
|
||||||
@ -794,8 +785,7 @@ private:
|
|||||||
|
|
||||||
static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
|
static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
|
||||||
internal::Stack<Allocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
|
internal::Stack<Allocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
|
||||||
ParseErrorCode parseErrorCode_;
|
ParseResult parseResult_;
|
||||||
size_t errorOffset_;
|
|
||||||
}; // class GenericReader
|
}; // class GenericReader
|
||||||
|
|
||||||
//! Reader with UTF8 encoding and default allocator.
|
//! Reader with UTF8 encoding and default allocator.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user