commit
ba50fe7dc8
@ -7,6 +7,7 @@
|
|||||||
#include "rapidjson/writer.h"
|
#include "rapidjson/writer.h"
|
||||||
#include "rapidjson/filereadstream.h"
|
#include "rapidjson/filereadstream.h"
|
||||||
#include "rapidjson/filewritestream.h"
|
#include "rapidjson/filewritestream.h"
|
||||||
|
#include "rapidjson/error/en.h"
|
||||||
|
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ int main(int, char*[]) {
|
|||||||
|
|
||||||
// JSON reader parse from the input stream and let writer generate the output.
|
// JSON reader parse from the input stream and let writer generate the output.
|
||||||
if (!reader.Parse(is, writer)) {
|
if (!reader.Parse(is, writer)) {
|
||||||
fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), reader.GetParseError());
|
fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode()));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "rapidjson/prettywriter.h"
|
#include "rapidjson/prettywriter.h"
|
||||||
#include "rapidjson/filereadstream.h"
|
#include "rapidjson/filereadstream.h"
|
||||||
#include "rapidjson/filewritestream.h"
|
#include "rapidjson/filewritestream.h"
|
||||||
|
#include "rapidjson/error/en.h"
|
||||||
|
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
|
|
||||||
@ -21,7 +22,7 @@ int main(int, char*[]) {
|
|||||||
|
|
||||||
// JSON reader parse from the input stream and let writer generate the output.
|
// JSON reader parse from the input stream and let writer generate the output.
|
||||||
if (!reader.Parse<kParseValidateEncodingFlag>(is, writer)) {
|
if (!reader.Parse<kParseValidateEncodingFlag>(is, writer)) {
|
||||||
fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), reader.GetParseError());
|
fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode()));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "rapidjson/filereadstream.h"
|
#include "rapidjson/filereadstream.h"
|
||||||
#include "rapidjson/filewritestream.h"
|
#include "rapidjson/filewritestream.h"
|
||||||
#include "rapidjson/encodedstream.h" // NEW
|
#include "rapidjson/encodedstream.h" // NEW
|
||||||
|
#include "rapidjson/error/en.h"
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
@ -47,7 +48,7 @@ int main(int, char*[]) {
|
|||||||
// JSON reader parse from the input stream and let writer generate the output.
|
// JSON reader parse from the input stream and let writer generate the output.
|
||||||
//if (!reader.Parse<kParseValidateEncodingFlag>(is, writer)) {
|
//if (!reader.Parse<kParseValidateEncodingFlag>(is, writer)) {
|
||||||
if (!reader.Parse<kParseValidateEncodingFlag>(eis, writer)) { // CHANGED
|
if (!reader.Parse<kParseValidateEncodingFlag>(eis, writer)) { // CHANGED
|
||||||
fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), reader.GetParseError());
|
fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode()));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -788,7 +788,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), parseError_(0), errorOffset_(0) {}
|
GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseErrorCode_(kParseErrorNone), errorOffset_(0) {}
|
||||||
|
|
||||||
//! Parse JSON text from an input stream.
|
//! Parse JSON text from an input stream.
|
||||||
/*! \tparam parseFlags Combination of ParseFlag.
|
/*! \tparam parseFlags Combination of ParseFlag.
|
||||||
@ -802,11 +802,11 @@ public:
|
|||||||
if (reader.template Parse<parseFlags>(is, *this)) {
|
if (reader.template Parse<parseFlags>(is, *this)) {
|
||||||
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.
|
||||||
parseError_ = 0;
|
parseErrorCode_ = kParseErrorNone;
|
||||||
errorOffset_ = 0;
|
errorOffset_ = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
parseError_ = reader.GetParseError();
|
parseErrorCode_ = reader.GetParseErrorCode();
|
||||||
errorOffset_ = reader.GetErrorOffset();
|
errorOffset_ = reader.GetErrorOffset();
|
||||||
ClearStack();
|
ClearStack();
|
||||||
}
|
}
|
||||||
@ -864,10 +864,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Whether a parse error was occured in the last parsing.
|
//! Whether a parse error was occured in the last parsing.
|
||||||
bool HasParseError() const { return parseError_ != 0; }
|
bool HasParseError() const { return parseErrorCode_ != kParseErrorNone; }
|
||||||
|
|
||||||
//! Get the message of parsing error.
|
//! Get the message of parsing error.
|
||||||
const char* GetParseError() const { return parseError_; }
|
ParseErrorCode GetParseError() const { return parseErrorCode_; }
|
||||||
|
|
||||||
//! Get the offset in character of the parsing error.
|
//! Get the offset in character of the parsing error.
|
||||||
size_t GetErrorOffset() const { return errorOffset_; }
|
size_t GetErrorOffset() const { return errorOffset_; }
|
||||||
@ -927,7 +927,7 @@ private:
|
|||||||
|
|
||||||
static const size_t kDefaultStackCapacity = 1024;
|
static const size_t kDefaultStackCapacity = 1024;
|
||||||
internal::Stack<Allocator> stack_;
|
internal::Stack<Allocator> stack_;
|
||||||
const char* parseError_;
|
ParseErrorCode parseErrorCode_;
|
||||||
size_t errorOffset_;
|
size_t errorOffset_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
48
include/rapidjson/error/en.h
Normal file
48
include/rapidjson/error/en.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#ifndef RAPIDJSON_ERROR_EN_H__
|
||||||
|
#define RAPIDJSON_ERROR_EN_H__
|
||||||
|
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
namespace rapidjson {
|
||||||
|
|
||||||
|
//! Maps error code of parsing into error message.
|
||||||
|
/*!
|
||||||
|
\param parseErrorCode Error code obtained in parsing.
|
||||||
|
\return the error message.
|
||||||
|
\note User can make a copy of this function for localization.
|
||||||
|
Using switch-case is safer for future modification of error codes.
|
||||||
|
*/
|
||||||
|
inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
|
||||||
|
switch (parseErrorCode) {
|
||||||
|
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
|
||||||
|
|
||||||
|
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
|
||||||
|
case kParseErrorDocumentRootNotObjectOrArray: return RAPIDJSON_ERROR_STRING("The document root must be either object or array.");
|
||||||
|
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values.");
|
||||||
|
|
||||||
|
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
|
||||||
|
|
||||||
|
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
|
||||||
|
case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
|
||||||
|
case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
|
||||||
|
|
||||||
|
case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
|
||||||
|
|
||||||
|
case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
|
||||||
|
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 kParesErrorNumberTooBig: 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.");
|
||||||
|
|
||||||
|
default:
|
||||||
|
return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace rapidjson
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ERROR_EN_H__
|
46
include/rapidjson/error/error.h
Normal file
46
include/rapidjson/error/error.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#ifndef RAPIDJSON_ERROR_ERROR_H__
|
||||||
|
#define RAPIDJSON_ERROR_ERROR_H__
|
||||||
|
|
||||||
|
#include "../reader.h" // ParseErrorCode
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_ERROR_CHARTYPE
|
||||||
|
|
||||||
|
//! Character type of error messages.
|
||||||
|
/*! The default charater type is char.
|
||||||
|
On Windows, user can define this macro as TCHAR for supporting both
|
||||||
|
unicode/non-unicode settings.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_ERROR_CHARTYPE
|
||||||
|
#define RAPIDJSON_ERROR_CHARTYPE char
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_ERROR_STRING
|
||||||
|
|
||||||
|
//! Macro for converting string literial to RAPIDJSON_ERROR_CHARTYPE[].
|
||||||
|
/*! By default this conversion macro does nothing.
|
||||||
|
On Windows, user can define this macro as _T(x) for supporting both
|
||||||
|
unicode/non-unicode settings.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_ERROR_STRING
|
||||||
|
#define RAPIDJSON_ERROR_STRING(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace rapidjson {
|
||||||
|
|
||||||
|
//! 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.:
|
||||||
|
|
||||||
|
\code
|
||||||
|
GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
|
||||||
|
const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
|
||||||
|
|
||||||
|
} // namespace rapidjson
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ERROR_ERROR_H__
|
@ -21,19 +21,18 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef RAPIDJSON_PARSE_ERROR_NORETURN
|
#ifndef RAPIDJSON_PARSE_ERROR_NORETURN
|
||||||
#define RAPIDJSON_PARSE_ERROR_NORETURN(msg, offset) \
|
#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \
|
||||||
RAPIDJSON_MULTILINEMACRO_BEGIN \
|
RAPIDJSON_MULTILINEMACRO_BEGIN \
|
||||||
if (!HasParseError()) {\
|
RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
|
||||||
parseError_ = msg; \
|
parseErrorCode_ = parseErrorCode; \
|
||||||
errorOffset_ = offset; \
|
errorOffset_ = offset; \
|
||||||
}\
|
RAPIDJSON_MULTILINEMACRO_END
|
||||||
RAPIDJSON_MULTILINEMACRO_END
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef RAPIDJSON_PARSE_ERROR
|
#ifndef RAPIDJSON_PARSE_ERROR
|
||||||
#define RAPIDJSON_PARSE_ERROR(msg, offset) \
|
#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \
|
||||||
RAPIDJSON_MULTILINEMACRO_BEGIN \
|
RAPIDJSON_MULTILINEMACRO_BEGIN \
|
||||||
RAPIDJSON_PARSE_ERROR_NORETURN(msg, offset); \
|
RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
|
||||||
return; \
|
return; \
|
||||||
RAPIDJSON_MULTILINEMACRO_END
|
RAPIDJSON_MULTILINEMACRO_END
|
||||||
#endif
|
#endif
|
||||||
@ -50,6 +49,33 @@ 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.
|
||||||
|
|
||||||
|
kParesErrorNumberTooBig, //!< Number too big to be stored in double.
|
||||||
|
kParseErrorNumberMissFraction, //!< Miss fraction part in number.
|
||||||
|
kParseErrorNumberMissExponent //!< Miss exponent in number.
|
||||||
|
};
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Handler
|
// Handler
|
||||||
|
|
||||||
@ -218,7 +244,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), parseError_(0), errorOffset_(0) {}
|
GenericReader(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseErrorCode_(kParseErrorNone), errorOffset_(0) {}
|
||||||
|
|
||||||
//! Parse JSON text.
|
//! Parse JSON text.
|
||||||
/*! \tparam parseFlags Combination of ParseFlag.
|
/*! \tparam parseFlags Combination of ParseFlag.
|
||||||
@ -230,18 +256,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
template <unsigned parseFlags, typename InputStream, typename Handler>
|
template <unsigned parseFlags, typename InputStream, typename Handler>
|
||||||
bool Parse(InputStream& is, Handler& handler) {
|
bool Parse(InputStream& is, Handler& handler) {
|
||||||
parseError_ = 0;
|
parseErrorCode_ = kParseErrorNone;
|
||||||
errorOffset_ = 0;
|
errorOffset_ = 0;
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespace(is);
|
||||||
|
|
||||||
if (is.Peek() == '\0')
|
if (is.Peek() == '\0')
|
||||||
RAPIDJSON_PARSE_ERROR_NORETURN("Text only contains white space(s)", is.Tell());
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
|
||||||
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("Expect either an object or array at root", is.Tell());
|
default: RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotObjectOrArray, is.Tell());
|
||||||
}
|
}
|
||||||
if (HasParseError())
|
if (HasParseError())
|
||||||
goto out;
|
goto out;
|
||||||
@ -249,7 +275,7 @@ public:
|
|||||||
SkipWhitespace(is);
|
SkipWhitespace(is);
|
||||||
|
|
||||||
if (is.Peek() != '\0')
|
if (is.Peek() != '\0')
|
||||||
RAPIDJSON_PARSE_ERROR_NORETURN("Nothing should follow the root object or array.", is.Tell());
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -262,8 +288,10 @@ public:
|
|||||||
return Parse<0>(is, handler);
|
return Parse<0>(is, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasParseError() const { return parseError_ != 0; }
|
bool HasParseError() const { return parseErrorCode_ != kParseErrorNone; }
|
||||||
const char* GetParseError() const { return parseError_; }
|
|
||||||
|
ParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }
|
||||||
|
|
||||||
size_t GetErrorOffset() const { return errorOffset_; }
|
size_t GetErrorOffset() const { return errorOffset_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -283,7 +311,7 @@ private:
|
|||||||
|
|
||||||
for (SizeType memberCount = 0;;) {
|
for (SizeType memberCount = 0;;) {
|
||||||
if (is.Peek() != '"')
|
if (is.Peek() != '"')
|
||||||
RAPIDJSON_PARSE_ERROR("Name of an object member must be a string", is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
|
||||||
|
|
||||||
ParseString<parseFlags>(is, handler);
|
ParseString<parseFlags>(is, handler);
|
||||||
if (HasParseError())
|
if (HasParseError())
|
||||||
@ -292,7 +320,7 @@ private:
|
|||||||
SkipWhitespace(is);
|
SkipWhitespace(is);
|
||||||
|
|
||||||
if (is.Take() != ':')
|
if (is.Take() != ':')
|
||||||
RAPIDJSON_PARSE_ERROR("There must be a colon after the name of object member", is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
|
||||||
|
|
||||||
SkipWhitespace(is);
|
SkipWhitespace(is);
|
||||||
|
|
||||||
@ -307,7 +335,7 @@ private:
|
|||||||
switch(is.Take()) {
|
switch(is.Take()) {
|
||||||
case ',': SkipWhitespace(is); break;
|
case ',': SkipWhitespace(is); break;
|
||||||
case '}': handler.EndObject(memberCount); return;
|
case '}': handler.EndObject(memberCount); return;
|
||||||
default: RAPIDJSON_PARSE_ERROR("Must be a comma or '}' after an object member", is.Tell());
|
default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -337,7 +365,7 @@ private:
|
|||||||
switch (is.Take()) {
|
switch (is.Take()) {
|
||||||
case ',': SkipWhitespace(is); break;
|
case ',': SkipWhitespace(is); break;
|
||||||
case ']': handler.EndArray(elementCount); return;
|
case ']': handler.EndArray(elementCount); return;
|
||||||
default: RAPIDJSON_PARSE_ERROR("Must be a comma or ']' after an array element.", is.Tell());
|
default: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -350,7 +378,7 @@ private:
|
|||||||
if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l')
|
if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l')
|
||||||
handler.Null();
|
handler.Null();
|
||||||
else
|
else
|
||||||
RAPIDJSON_PARSE_ERROR("Invalid value", is.Tell() - 1);
|
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned parseFlags, typename InputStream, typename Handler>
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
||||||
@ -361,7 +389,7 @@ private:
|
|||||||
if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e')
|
if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e')
|
||||||
handler.Bool(true);
|
handler.Bool(true);
|
||||||
else
|
else
|
||||||
RAPIDJSON_PARSE_ERROR("Invalid value", is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned parseFlags, typename InputStream, typename Handler>
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
||||||
@ -372,7 +400,7 @@ private:
|
|||||||
if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e')
|
if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e')
|
||||||
handler.Bool(false);
|
handler.Bool(false);
|
||||||
else
|
else
|
||||||
RAPIDJSON_PARSE_ERROR("Invalid value", is.Tell() - 1);
|
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
|
// Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
|
||||||
@ -391,7 +419,7 @@ private:
|
|||||||
else if (c >= 'a' && c <= 'f')
|
else if (c >= 'a' && c <= 'f')
|
||||||
codepoint -= 'a' - 10;
|
codepoint -= 'a' - 10;
|
||||||
else {
|
else {
|
||||||
RAPIDJSON_PARSE_ERROR_NORETURN("Incorrect hex digit after \\u escape", s.Tell() - 1);
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, s.Tell() - 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -468,16 +496,16 @@ private:
|
|||||||
if (codepoint >= 0xD800 && codepoint <= 0xDBFF) {
|
if (codepoint >= 0xD800 && codepoint <= 0xDBFF) {
|
||||||
// Handle UTF-16 surrogate pair
|
// Handle UTF-16 surrogate pair
|
||||||
if (is.Take() != '\\' || is.Take() != 'u')
|
if (is.Take() != '\\' || is.Take() != 'u')
|
||||||
RAPIDJSON_PARSE_ERROR("Missing the second \\u in surrogate pair", is.Tell() - 2);
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
|
||||||
unsigned codepoint2 = ParseHex4(is);
|
unsigned codepoint2 = ParseHex4(is);
|
||||||
if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)
|
if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)
|
||||||
RAPIDJSON_PARSE_ERROR("The second \\u in surrogate pair is invalid", is.Tell() - 2);
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
|
||||||
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
|
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
|
||||||
}
|
}
|
||||||
TEncoding::Encode(os, codepoint);
|
TEncoding::Encode(os, codepoint);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
RAPIDJSON_PARSE_ERROR("Unknown escape character", is.Tell() - 1);
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1);
|
||||||
}
|
}
|
||||||
else if (c == '"') { // Closing double quote
|
else if (c == '"') { // Closing double quote
|
||||||
is.Take();
|
is.Take();
|
||||||
@ -485,14 +513,14 @@ private:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (c == '\0')
|
else if (c == '\0')
|
||||||
RAPIDJSON_PARSE_ERROR("lacks ending quotation before the end of string", is.Tell() - 1);
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1);
|
||||||
else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
|
else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
|
||||||
RAPIDJSON_PARSE_ERROR("Incorrect unescaped character in string", is.Tell() - 1);
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1);
|
||||||
else {
|
else {
|
||||||
if (parseFlags & kParseValidateEncodingFlag ?
|
if (parseFlags & kParseValidateEncodingFlag ?
|
||||||
!Transcoder<SEncoding, TEncoding>::Validate(is, os) :
|
!Transcoder<SEncoding, TEncoding>::Validate(is, os) :
|
||||||
!Transcoder<SEncoding, TEncoding>::Transcode(is, os))
|
!Transcoder<SEncoding, TEncoding>::Transcode(is, os))
|
||||||
RAPIDJSON_PARSE_ERROR("Invalid encoding", is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -539,7 +567,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
RAPIDJSON_PARSE_ERROR("Expect a value here.", is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
|
||||||
|
|
||||||
// Parse 64bit int
|
// Parse 64bit int
|
||||||
uint64_t i64 = 0;
|
uint64_t i64 = 0;
|
||||||
@ -572,7 +600,7 @@ private:
|
|||||||
d = (double)i64;
|
d = (double)i64;
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||||
if (d >= 1E307)
|
if (d >= 1E307)
|
||||||
RAPIDJSON_PARSE_ERROR("Number too big to store in double", is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParesErrorNumberTooBig, is.Tell());
|
||||||
d = d * 10 + (s.Take() - '0');
|
d = d * 10 + (s.Take() - '0');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -591,7 +619,7 @@ private:
|
|||||||
--expFrac;
|
--expFrac;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
RAPIDJSON_PARSE_ERROR("At least one digit in fraction part", is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, is.Tell());
|
||||||
|
|
||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||||
if (expFrac > -16) {
|
if (expFrac > -16) {
|
||||||
@ -624,11 +652,11 @@ private:
|
|||||||
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
||||||
exp = exp * 10 + (s.Take() - '0');
|
exp = exp * 10 + (s.Take() - '0');
|
||||||
if (exp > 308)
|
if (exp > 308)
|
||||||
RAPIDJSON_PARSE_ERROR("Number too big to store in double", is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParesErrorNumberTooBig, is.Tell());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
RAPIDJSON_PARSE_ERROR("At least one digit in exponent", s.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell());
|
||||||
|
|
||||||
if (expMinus)
|
if (expMinus)
|
||||||
exp = -exp;
|
exp = -exp;
|
||||||
@ -673,7 +701,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.
|
||||||
const char* parseError_;
|
ParseErrorCode parseErrorCode_;
|
||||||
size_t errorOffset_;
|
size_t errorOffset_;
|
||||||
}; // class GenericReader
|
}; // class GenericReader
|
||||||
|
|
||||||
|
@ -147,8 +147,8 @@ TEST(Reader, ParseNumberHandler) {
|
|||||||
#undef TEST_DOUBLE
|
#undef TEST_DOUBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Reader, ParseNumberHandler_Error) {
|
TEST(Reader, ParseNumber_Error) {
|
||||||
#define TEST_NUMBER_ERROR(str) \
|
#define TEST_NUMBER_ERROR(errorCode, str) \
|
||||||
{ \
|
{ \
|
||||||
char buffer[1001]; \
|
char buffer[1001]; \
|
||||||
sprintf(buffer, "[%s]", str); \
|
sprintf(buffer, "[%s]", str); \
|
||||||
@ -156,23 +156,27 @@ TEST(Reader, ParseNumberHandler_Error) {
|
|||||||
BaseReaderHandler<> h; \
|
BaseReaderHandler<> h; \
|
||||||
Reader reader; \
|
Reader reader; \
|
||||||
EXPECT_FALSE(reader.Parse<0>(s, h)); \
|
EXPECT_FALSE(reader.Parse<0>(s, h)); \
|
||||||
|
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_NUMBER_ERROR("a"); // At least one digit in integer part
|
// Number too big to be stored in double.
|
||||||
TEST_NUMBER_ERROR(".1"); // At least one digit in integer part
|
|
||||||
|
|
||||||
{
|
{
|
||||||
char n1e309[311]; // '1' followed by 309 '0'
|
char n1e309[311]; // '1' followed by 309 '0'
|
||||||
n1e309[0] = '1';
|
n1e309[0] = '1';
|
||||||
for (int i = 1; i < 310; i++)
|
for (int i = 1; i < 310; i++)
|
||||||
n1e309[i] = '0';
|
n1e309[i] = '0';
|
||||||
n1e309[310] = '\0';
|
n1e309[310] = '\0';
|
||||||
TEST_NUMBER_ERROR(n1e309); // Number too big to store in double
|
TEST_NUMBER_ERROR(kParesErrorNumberTooBig, n1e309);
|
||||||
}
|
}
|
||||||
|
TEST_NUMBER_ERROR(kParesErrorNumberTooBig, "1e309");
|
||||||
|
|
||||||
TEST_NUMBER_ERROR("1."); // At least one digit in fraction part
|
// Miss fraction part in number.
|
||||||
TEST_NUMBER_ERROR("1e309"); // Number too big to store in double
|
TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.");
|
||||||
TEST_NUMBER_ERROR("1e_"); // At least one digit in exponent
|
TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.a");
|
||||||
|
|
||||||
|
// Miss exponent in number.
|
||||||
|
TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e");
|
||||||
|
TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e_");
|
||||||
|
|
||||||
#undef TEST_NUMBER_ERROR
|
#undef TEST_NUMBER_ERROR
|
||||||
}
|
}
|
||||||
@ -304,27 +308,38 @@ TEST(Reader, ParseString_NonDestructive) {
|
|||||||
EXPECT_EQ(11u, h.length_);
|
EXPECT_EQ(11u, h.length_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TestString(const char* str) {
|
ParseErrorCode TestString(const char* str) {
|
||||||
StringStream s(str);
|
StringStream s(str);
|
||||||
BaseReaderHandler<> h;
|
BaseReaderHandler<> h;
|
||||||
Reader reader;
|
Reader reader;
|
||||||
return reader.Parse<kParseValidateEncodingFlag>(s, h);
|
reader.Parse<kParseValidateEncodingFlag>(s, h);
|
||||||
|
return reader.GetParseErrorCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Reader, ParseString_Error) {
|
TEST(Reader, ParseString_Error) {
|
||||||
|
#define TEST_STRING_ERROR(errorCode, str)\
|
||||||
|
EXPECT_EQ(errorCode, TestString(str))
|
||||||
|
|
||||||
#define ARRAY(...) { __VA_ARGS__ }
|
#define ARRAY(...) { __VA_ARGS__ }
|
||||||
#define TEST_STRINGARRAY_ERROR(Encoding, utype, array) \
|
#define TEST_STRINGENCODING_ERROR(Encoding, utype, array) \
|
||||||
{ \
|
{ \
|
||||||
static const utype ue[] = array; \
|
static const utype ue[] = array; \
|
||||||
static const Encoding::Ch* e = reinterpret_cast<const Encoding::Ch *>(&ue[0]); \
|
static const Encoding::Ch* e = reinterpret_cast<const Encoding::Ch *>(&ue[0]); \
|
||||||
EXPECT_FALSE(TestString(e)); \
|
EXPECT_EQ(kParseErrorStringInvalidEncoding, TestString(e));\
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_FALSE(TestString("[\"\\a\"]")); // Unknown escape character
|
// Invalid escape character in string.
|
||||||
EXPECT_FALSE(TestString("[\"\\uABCG\"]")); // Incorrect hex digit after \\u escape
|
TEST_STRING_ERROR(kParseErrorStringEscapeInvalid, "[\"\\a\"]");
|
||||||
EXPECT_FALSE(TestString("[\"\\uD800X\"]")); // Missing the second \\u in surrogate pair
|
|
||||||
EXPECT_FALSE(TestString("[\"\\uD800\\uFFFF\"]")); // The second \\u in surrogate pair is invalid
|
// Incorrect hex digit after \\u escape in string.
|
||||||
EXPECT_FALSE(TestString("[\"Test]")); // lacks ending quotation before the end of string
|
TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uABCG\"]");
|
||||||
|
|
||||||
|
// The surrogate pair in string is invalid.
|
||||||
|
TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800X\"]");
|
||||||
|
TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800\\uFFFF\"]");
|
||||||
|
|
||||||
|
// Missing a closing quotation mark in string.
|
||||||
|
TEST_STRING_ERROR(kParseErrorStringMissQuotationMark, "[\"Test]");
|
||||||
|
|
||||||
// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
|
// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
|
||||||
|
|
||||||
@ -335,9 +350,9 @@ TEST(Reader, ParseString_Error) {
|
|||||||
char e[] = { '[', '\"', 0, '\"', ']', '\0' };
|
char e[] = { '[', '\"', 0, '\"', ']', '\0' };
|
||||||
for (unsigned char c = 0x80u; c <= 0xBFu; c++) {
|
for (unsigned char c = 0x80u; c <= 0xBFu; c++) {
|
||||||
e[2] = c;
|
e[2] = c;
|
||||||
bool b = TestString(e);
|
ParseErrorCode error = TestString(e);
|
||||||
EXPECT_FALSE(b);
|
EXPECT_EQ(kParseErrorStringInvalidEncoding, error);
|
||||||
if (b)
|
if (error != kParseErrorStringInvalidEncoding)
|
||||||
std::cout << (unsigned)(unsigned char)c << std::endl;
|
std::cout << (unsigned)(unsigned char)c << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -347,37 +362,37 @@ TEST(Reader, ParseString_Error) {
|
|||||||
char e[] = { '[', '\"', 0, ' ', '\"', ']', '\0' };
|
char e[] = { '[', '\"', 0, ' ', '\"', ']', '\0' };
|
||||||
for (unsigned c = 0xC0u; c <= 0xFFu; c++) {
|
for (unsigned c = 0xC0u; c <= 0xFFu; c++) {
|
||||||
e[2] = (char)c;
|
e[2] = (char)c;
|
||||||
EXPECT_FALSE(TestString(e));
|
TEST_STRING_ERROR(kParseErrorStringInvalidEncoding, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4 Overlong sequences
|
// 4 Overlong sequences
|
||||||
|
|
||||||
// 4.1 Examples of an overlong ASCII character
|
// 4.1 Examples of an overlong ASCII character
|
||||||
TEST_STRINGARRAY_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0xAFu, '\"', ']', '\0'));
|
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0xAFu, '\"', ']', '\0'));
|
||||||
TEST_STRINGARRAY_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0xAFu, '\"', ']', '\0'));
|
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0xAFu, '\"', ']', '\0'));
|
||||||
TEST_STRINGARRAY_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0xAFu, '\"', ']', '\0'));
|
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0xAFu, '\"', ']', '\0'));
|
||||||
|
|
||||||
// 4.2 Maximum overlong sequences
|
// 4.2 Maximum overlong sequences
|
||||||
TEST_STRINGARRAY_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC1u, 0xBFu, '\"', ']', '\0'));
|
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC1u, 0xBFu, '\"', ']', '\0'));
|
||||||
TEST_STRINGARRAY_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x9Fu, 0xBFu, '\"', ']', '\0'));
|
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x9Fu, 0xBFu, '\"', ']', '\0'));
|
||||||
TEST_STRINGARRAY_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x8Fu, 0xBFu, 0xBFu, '\"', ']', '\0'));
|
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x8Fu, 0xBFu, 0xBFu, '\"', ']', '\0'));
|
||||||
|
|
||||||
// 4.3 Overlong representation of the NUL character
|
// 4.3 Overlong representation of the NUL character
|
||||||
TEST_STRINGARRAY_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0x80u, '\"', ']', '\0'));
|
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0x80u, '\"', ']', '\0'));
|
||||||
TEST_STRINGARRAY_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0x80u, '\"', ']', '\0'));
|
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0x80u, '\"', ']', '\0'));
|
||||||
TEST_STRINGARRAY_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0x80u, '\"', ']', '\0'));
|
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0x80u, '\"', ']', '\0'));
|
||||||
|
|
||||||
// 5 Illegal code positions
|
// 5 Illegal code positions
|
||||||
|
|
||||||
// 5.1 Single UTF-16 surrogates
|
// 5.1 Single UTF-16 surrogates
|
||||||
TEST_STRINGARRAY_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xA0u, 0x80u, '\"', ']', '\0'));
|
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xA0u, 0x80u, '\"', ']', '\0'));
|
||||||
TEST_STRINGARRAY_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xADu, 0xBFu, '\"', ']', '\0'));
|
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xADu, 0xBFu, '\"', ']', '\0'));
|
||||||
TEST_STRINGARRAY_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAEu, 0x80u, '\"', ']', '\0'));
|
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAEu, 0x80u, '\"', ']', '\0'));
|
||||||
TEST_STRINGARRAY_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAFu, 0xBFu, '\"', ']', '\0'));
|
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAFu, 0xBFu, '\"', ']', '\0'));
|
||||||
TEST_STRINGARRAY_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xB0u, 0x80u, '\"', ']', '\0'));
|
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xB0u, 0x80u, '\"', ']', '\0'));
|
||||||
TEST_STRINGARRAY_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBEu, 0x80u, '\"', ']', '\0'));
|
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBEu, 0x80u, '\"', ']', '\0'));
|
||||||
TEST_STRINGARRAY_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBFu, 0xBFu, '\"', ']', '\0'));
|
TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBFu, 0xBFu, '\"', ']', '\0'));
|
||||||
|
|
||||||
#undef ARRAY
|
#undef ARRAY
|
||||||
#undef TEST_STRINGARRAY_ERROR
|
#undef TEST_STRINGARRAY_ERROR
|
||||||
@ -416,7 +431,7 @@ TEST(Reader, ParseArray) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(Reader, ParseArray_Error) {
|
TEST(Reader, ParseArray_Error) {
|
||||||
#define TEST_ARRAY_ERROR(str) \
|
#define TEST_ARRAY_ERROR(errorCode, str) \
|
||||||
{ \
|
{ \
|
||||||
char buffer[1001]; \
|
char buffer[1001]; \
|
||||||
strncpy(buffer, str, 1000); \
|
strncpy(buffer, str, 1000); \
|
||||||
@ -424,12 +439,13 @@ TEST(Reader, ParseArray_Error) {
|
|||||||
BaseReaderHandler<> h; \
|
BaseReaderHandler<> h; \
|
||||||
GenericReader<UTF8<>, UTF8<>, CrtAllocator> reader; \
|
GenericReader<UTF8<>, UTF8<>, CrtAllocator> reader; \
|
||||||
EXPECT_FALSE(reader.Parse<0>(s, h)); \
|
EXPECT_FALSE(reader.Parse<0>(s, h)); \
|
||||||
|
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be a comma or ']' after an array element.
|
// Missing a comma or ']' after an array element.
|
||||||
TEST_ARRAY_ERROR("[");
|
TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1");
|
||||||
TEST_ARRAY_ERROR("[}");
|
TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1}");
|
||||||
TEST_ARRAY_ERROR("[1 2]");
|
TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1 2]");
|
||||||
|
|
||||||
#undef TEST_ARRAY_ERROR
|
#undef TEST_ARRAY_ERROR
|
||||||
}
|
}
|
||||||
@ -519,39 +535,7 @@ TEST(Reader, Parse_EmptyObject) {
|
|||||||
EXPECT_EQ(2u, h.step_);
|
EXPECT_EQ(2u, h.step_);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Reader, ParseObject_Error) {
|
#define TEST_ERROR(errorCode, str) \
|
||||||
#define TEST_OBJECT_ERROR(str) \
|
|
||||||
{ \
|
|
||||||
char buffer[1001]; \
|
|
||||||
strncpy(buffer, str, 1000); \
|
|
||||||
InsituStringStream s(buffer); \
|
|
||||||
BaseReaderHandler<> h; \
|
|
||||||
GenericReader<UTF8<>, UTF8<>, CrtAllocator> reader; \
|
|
||||||
EXPECT_FALSE(reader.Parse<0>(s, h)); \
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name of an object member must be a string
|
|
||||||
TEST_OBJECT_ERROR("{null:1}");
|
|
||||||
TEST_OBJECT_ERROR("{true:1}");
|
|
||||||
TEST_OBJECT_ERROR("{false:1}");
|
|
||||||
TEST_OBJECT_ERROR("{1:1}");
|
|
||||||
TEST_OBJECT_ERROR("{[]:1}");
|
|
||||||
TEST_OBJECT_ERROR("{{}:1}");
|
|
||||||
TEST_OBJECT_ERROR("{xyz:1}");
|
|
||||||
|
|
||||||
// There must be a colon after the name of object member
|
|
||||||
TEST_OBJECT_ERROR("{\"a\" 1}");
|
|
||||||
TEST_OBJECT_ERROR("{\"a\",1}");
|
|
||||||
|
|
||||||
// Must be a comma or '}' after an object member
|
|
||||||
TEST_OBJECT_ERROR("{]");
|
|
||||||
TEST_OBJECT_ERROR("{\"a\":1]");
|
|
||||||
|
|
||||||
#undef TEST_OBJECT_ERROR
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(Reader, Parse_Error) {
|
|
||||||
#define TEST_ERROR(str) \
|
|
||||||
{ \
|
{ \
|
||||||
char buffer[1001]; \
|
char buffer[1001]; \
|
||||||
strncpy(buffer, str, 1000); \
|
strncpy(buffer, str, 1000); \
|
||||||
@ -559,31 +543,57 @@ TEST(Reader, Parse_Error) {
|
|||||||
BaseReaderHandler<> h; \
|
BaseReaderHandler<> h; \
|
||||||
Reader reader; \
|
Reader reader; \
|
||||||
EXPECT_FALSE(reader.Parse<0>(s, h)); \
|
EXPECT_FALSE(reader.Parse<0>(s, h)); \
|
||||||
|
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
|
||||||
}
|
}
|
||||||
|
|
||||||
// Text only contains white space(s)
|
TEST(Reader, ParseDocument_Error) {
|
||||||
TEST_ERROR("");
|
// The document is empty.
|
||||||
TEST_ERROR(" ");
|
TEST_ERROR(kParseErrorDocumentEmpty, "");
|
||||||
TEST_ERROR(" \n");
|
TEST_ERROR(kParseErrorDocumentEmpty, " ");
|
||||||
|
TEST_ERROR(kParseErrorDocumentEmpty, " \n");
|
||||||
|
|
||||||
// Expect either an object or array at root
|
// The document root must be either object or array.
|
||||||
TEST_ERROR("null");
|
TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "null");
|
||||||
TEST_ERROR("true");
|
TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "true");
|
||||||
TEST_ERROR("false");
|
TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "false");
|
||||||
TEST_ERROR("\"s\"");
|
TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "\"s\"");
|
||||||
TEST_ERROR("0");
|
TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "0");
|
||||||
|
|
||||||
// Nothing should follow the root object or array
|
// The document root must not follow by other values.
|
||||||
TEST_ERROR("[] 0");
|
TEST_ERROR(kParseErrorDocumentRootNotSingular, "[] 0");
|
||||||
TEST_ERROR("{} 0");
|
TEST_ERROR(kParseErrorDocumentRootNotSingular, "{} 0");
|
||||||
|
}
|
||||||
|
|
||||||
// Invalid value
|
TEST(Reader, ParseValue_Error) {
|
||||||
TEST_ERROR("nulL");
|
// Invalid value.
|
||||||
TEST_ERROR("truE");
|
TEST_ERROR(kParseErrorValueInvalid, "[nulL]");
|
||||||
TEST_ERROR("falsE");
|
TEST_ERROR(kParseErrorValueInvalid, "[truE]");
|
||||||
|
TEST_ERROR(kParseErrorValueInvalid, "[falsE]");
|
||||||
|
TEST_ERROR(kParseErrorValueInvalid, "[a]");
|
||||||
|
TEST_ERROR(kParseErrorValueInvalid, "[.1]");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Reader, ParseObject_Error) {
|
||||||
|
// Missing a name for object member.
|
||||||
|
TEST_ERROR(kParseErrorObjectMissName, "{1}");
|
||||||
|
TEST_ERROR(kParseErrorObjectMissName, "{:1}");
|
||||||
|
TEST_ERROR(kParseErrorObjectMissName, "{null:1}");
|
||||||
|
TEST_ERROR(kParseErrorObjectMissName, "{true:1}");
|
||||||
|
TEST_ERROR(kParseErrorObjectMissName, "{false:1}");
|
||||||
|
TEST_ERROR(kParseErrorObjectMissName, "{1:1}");
|
||||||
|
TEST_ERROR(kParseErrorObjectMissName, "{[]:1}");
|
||||||
|
TEST_ERROR(kParseErrorObjectMissName, "{{}:1}");
|
||||||
|
TEST_ERROR(kParseErrorObjectMissName, "{xyz:1}");
|
||||||
|
|
||||||
|
// Missing a colon after a name of object member.
|
||||||
|
TEST_ERROR(kParseErrorObjectMissColon, "{\"a\" 1}");
|
||||||
|
TEST_ERROR(kParseErrorObjectMissColon, "{\"a\",1}");
|
||||||
|
|
||||||
|
// Must be a comma or '}' after an object member
|
||||||
|
TEST_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, "{\"a\":1]");
|
||||||
|
}
|
||||||
|
|
||||||
#undef TEST_ERROR
|
#undef TEST_ERROR
|
||||||
}
|
|
||||||
|
|
||||||
TEST(Reader, SkipWhitespace) {
|
TEST(Reader, SkipWhitespace) {
|
||||||
StringStream ss(" A \t\tB\n \n\nC\r\r \rD \t\n\r E");
|
StringStream ss(" A \t\tB\n \n\nC\r\r \rD \t\n\r E");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user