Rectify parsing error offsets
This commit is contained in:
parent
3771188701
commit
ab250d21bc
@ -474,28 +474,21 @@ private:
|
|||||||
SkipWhitespace(is);
|
SkipWhitespace(is);
|
||||||
|
|
||||||
if (parseFlags & kParseCommentsFlag) {
|
if (parseFlags & kParseCommentsFlag) {
|
||||||
while (RAPIDJSON_UNLIKELY(is.Peek() == '/')) {
|
while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) {
|
||||||
is.Take();
|
if (Consume(is, '*')) {
|
||||||
|
|
||||||
if (is.Peek() == '*') {
|
|
||||||
is.Take();
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (RAPIDJSON_UNLIKELY(is.Peek() == '\0'))
|
if (RAPIDJSON_UNLIKELY(is.Peek() == '\0'))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
||||||
|
else if (Consume(is, '*')) {
|
||||||
if (is.Take() == '*') {
|
if (Consume(is, '/'))
|
||||||
if (RAPIDJSON_UNLIKELY(is.Peek() == '\0'))
|
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
|
||||||
|
|
||||||
if (is.Take() == '/')
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
is.Take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (RAPIDJSON_LIKELY(is.Peek() == '/')) {
|
else if (RAPIDJSON_LIKELY(Consume(is, '/')))
|
||||||
is.Take();
|
while (is.Peek() != '\0' && is.Take() != '\n');
|
||||||
while (is.Peek() != '\0' && is.Take() != '\n') { }
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
||||||
|
|
||||||
@ -516,8 +509,7 @@ private:
|
|||||||
SkipWhitespaceAndComments<parseFlags>(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
if (is.Peek() == '}') {
|
if (Consume(is, '}')) {
|
||||||
is.Take();
|
|
||||||
if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object
|
if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
return;
|
return;
|
||||||
@ -533,7 +525,7 @@ private:
|
|||||||
SkipWhitespaceAndComments<parseFlags>(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
if (RAPIDJSON_UNLIKELY(is.Take() != ':'))
|
if (RAPIDJSON_UNLIKELY(!Consume(is, ':')))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
|
||||||
|
|
||||||
SkipWhitespaceAndComments<parseFlags>(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
@ -547,12 +539,14 @@ private:
|
|||||||
|
|
||||||
++memberCount;
|
++memberCount;
|
||||||
|
|
||||||
switch (is.Take()) {
|
switch (is.Peek()) {
|
||||||
case ',':
|
case ',':
|
||||||
|
is.Take();
|
||||||
SkipWhitespaceAndComments<parseFlags>(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
break;
|
break;
|
||||||
case '}':
|
case '}':
|
||||||
|
is.Take();
|
||||||
if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
|
if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
return;
|
return;
|
||||||
@ -575,8 +569,7 @@ private:
|
|||||||
SkipWhitespaceAndComments<parseFlags>(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
if (is.Peek() == ']') {
|
if (Consume(is, ']')) {
|
||||||
is.Take();
|
|
||||||
if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array
|
if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
return;
|
return;
|
||||||
@ -590,19 +583,17 @@ private:
|
|||||||
SkipWhitespaceAndComments<parseFlags>(is);
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
|
|
||||||
switch (is.Take()) {
|
if (Consume(is, ',')) {
|
||||||
case ',':
|
SkipWhitespaceAndComments<parseFlags>(is);
|
||||||
SkipWhitespaceAndComments<parseFlags>(is);
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
|
||||||
break;
|
|
||||||
case ']':
|
|
||||||
if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
|
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else if (Consume(is, ']')) {
|
||||||
|
if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
|
||||||
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -611,12 +602,12 @@ private:
|
|||||||
RAPIDJSON_ASSERT(is.Peek() == 'n');
|
RAPIDJSON_ASSERT(is.Peek() == 'n');
|
||||||
is.Take();
|
is.Take();
|
||||||
|
|
||||||
if (RAPIDJSON_LIKELY(is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l')) {
|
if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) {
|
||||||
if (RAPIDJSON_UNLIKELY(!handler.Null()))
|
if (RAPIDJSON_UNLIKELY(!handler.Null()))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1);
|
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned parseFlags, typename InputStream, typename Handler>
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
||||||
@ -624,12 +615,12 @@ private:
|
|||||||
RAPIDJSON_ASSERT(is.Peek() == 't');
|
RAPIDJSON_ASSERT(is.Peek() == 't');
|
||||||
is.Take();
|
is.Take();
|
||||||
|
|
||||||
if (RAPIDJSON_LIKELY(is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e')) {
|
if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) {
|
||||||
if (RAPIDJSON_UNLIKELY(!handler.Bool(true)))
|
if (RAPIDJSON_UNLIKELY(!handler.Bool(true)))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1);
|
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned parseFlags, typename InputStream, typename Handler>
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
||||||
@ -637,20 +628,30 @@ private:
|
|||||||
RAPIDJSON_ASSERT(is.Peek() == 'f');
|
RAPIDJSON_ASSERT(is.Peek() == 'f');
|
||||||
is.Take();
|
is.Take();
|
||||||
|
|
||||||
if (RAPIDJSON_LIKELY(is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e')) {
|
if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) {
|
||||||
if (RAPIDJSON_UNLIKELY(!handler.Bool(false)))
|
if (RAPIDJSON_UNLIKELY(!handler.Bool(false)))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1);
|
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename InputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) {
|
||||||
|
if (RAPIDJSON_LIKELY(is.Peek() == expect)) {
|
||||||
|
is.Take();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
|
// Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
|
||||||
template<typename InputStream>
|
template<typename InputStream>
|
||||||
unsigned ParseHex4(InputStream& is) {
|
unsigned ParseHex4(InputStream& is, size_t escapeOffset) {
|
||||||
unsigned codepoint = 0;
|
unsigned codepoint = 0;
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
Ch c = is.Take();
|
Ch c = is.Peek();
|
||||||
codepoint <<= 4;
|
codepoint <<= 4;
|
||||||
codepoint += static_cast<unsigned>(c);
|
codepoint += static_cast<unsigned>(c);
|
||||||
if (c >= '0' && c <= '9')
|
if (c >= '0' && c <= '9')
|
||||||
@ -660,9 +661,10 @@ 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(kParseErrorStringUnicodeEscapeInvalidHex, is.Tell() - 1);
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0);
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0);
|
||||||
}
|
}
|
||||||
|
is.Take();
|
||||||
}
|
}
|
||||||
return codepoint;
|
return codepoint;
|
||||||
}
|
}
|
||||||
@ -751,27 +753,31 @@ private:
|
|||||||
|
|
||||||
Ch c = is.Peek();
|
Ch c = is.Peek();
|
||||||
if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape
|
if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape
|
||||||
|
size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset
|
||||||
is.Take();
|
is.Take();
|
||||||
Ch e = is.Take();
|
Ch e = is.Peek();
|
||||||
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)]))
|
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)])) {
|
||||||
|
is.Take();
|
||||||
os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
|
os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
|
||||||
|
}
|
||||||
else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode
|
else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode
|
||||||
unsigned codepoint = ParseHex4(is);
|
is.Take();
|
||||||
|
unsigned codepoint = ParseHex4(is, escapeOffset);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {
|
if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {
|
||||||
// Handle UTF-16 surrogate pair
|
// Handle UTF-16 surrogate pair
|
||||||
if (RAPIDJSON_UNLIKELY(is.Take() != '\\' || is.Take() != 'u'))
|
if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
|
||||||
unsigned codepoint2 = ParseHex4(is);
|
unsigned codepoint2 = ParseHex4(is, escapeOffset);
|
||||||
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
||||||
if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
|
if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
|
||||||
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(kParseErrorStringEscapeInvalid, is.Tell() - 1);
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset);
|
||||||
}
|
}
|
||||||
else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote
|
else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote
|
||||||
is.Take();
|
is.Take();
|
||||||
@ -780,15 +786,16 @@ private:
|
|||||||
}
|
}
|
||||||
else if (RAPIDJSON_UNLIKELY(static_cast<unsigned>(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
|
else if (RAPIDJSON_UNLIKELY(static_cast<unsigned>(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
|
||||||
if (c == '\0')
|
if (c == '\0')
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1);
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell());
|
||||||
else
|
else
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1);
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
size_t offset = is.Tell();
|
||||||
if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ?
|
if (RAPIDJSON_UNLIKELY((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(kParseErrorStringInvalidEncoding, is.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -961,6 +968,8 @@ private:
|
|||||||
template<typename InputStream>
|
template<typename InputStream>
|
||||||
class NumberStream<InputStream, false> {
|
class NumberStream<InputStream, false> {
|
||||||
public:
|
public:
|
||||||
|
typedef typename InputStream::Ch Ch;
|
||||||
|
|
||||||
NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; }
|
NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; }
|
||||||
~NumberStream() {}
|
~NumberStream() {}
|
||||||
|
|
||||||
@ -1004,13 +1013,10 @@ private:
|
|||||||
void ParseNumber(InputStream& is, Handler& handler) {
|
void ParseNumber(InputStream& is, Handler& handler) {
|
||||||
internal::StreamLocalCopy<InputStream> copy(is);
|
internal::StreamLocalCopy<InputStream> copy(is);
|
||||||
NumberStream<InputStream, (parseFlags & kParseFullPrecisionFlag) != 0> s(*this, copy.s);
|
NumberStream<InputStream, (parseFlags & kParseFullPrecisionFlag) != 0> s(*this, copy.s);
|
||||||
|
size_t startOffset = s.Tell();
|
||||||
|
|
||||||
// Parse minus
|
// Parse minus
|
||||||
bool minus = false;
|
bool minus = Consume(s, '-');
|
||||||
if (s.Peek() == '-') {
|
|
||||||
minus = true;
|
|
||||||
s.Take();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse int: zero / ( digit1-9 *DIGIT )
|
// Parse int: zero / ( digit1-9 *DIGIT )
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
@ -1084,7 +1090,7 @@ private:
|
|||||||
if (useDouble) {
|
if (useDouble) {
|
||||||
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
||||||
if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0
|
if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
|
||||||
d = d * 10 + (s.TakePush() - '0');
|
d = d * 10 + (s.TakePush() - '0');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1092,8 +1098,7 @@ private:
|
|||||||
// Parse frac = decimal-point 1*DIGIT
|
// Parse frac = decimal-point 1*DIGIT
|
||||||
int expFrac = 0;
|
int expFrac = 0;
|
||||||
size_t decimalPosition;
|
size_t decimalPosition;
|
||||||
if (s.Peek() == '.') {
|
if (Consume(s, '.')) {
|
||||||
s.Take();
|
|
||||||
decimalPosition = s.Length();
|
decimalPosition = s.Length();
|
||||||
|
|
||||||
if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
|
if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
|
||||||
@ -1140,20 +1145,17 @@ private:
|
|||||||
|
|
||||||
// Parse exp = e [ minus / plus ] 1*DIGIT
|
// Parse exp = e [ minus / plus ] 1*DIGIT
|
||||||
int exp = 0;
|
int exp = 0;
|
||||||
if (s.Peek() == 'e' || s.Peek() == 'E') {
|
if (Consume(s, 'e') || Consume(s, 'E')) {
|
||||||
if (!useDouble) {
|
if (!useDouble) {
|
||||||
d = static_cast<double>(use64bit ? i64 : i);
|
d = static_cast<double>(use64bit ? i64 : i);
|
||||||
useDouble = true;
|
useDouble = true;
|
||||||
}
|
}
|
||||||
s.Take();
|
|
||||||
|
|
||||||
bool expMinus = false;
|
bool expMinus = false;
|
||||||
if (s.Peek() == '+')
|
if (Consume(s, '+'))
|
||||||
s.Take();
|
;
|
||||||
else if (s.Peek() == '-') {
|
else if (Consume(s, '-'))
|
||||||
s.Take();
|
|
||||||
expMinus = true;
|
expMinus = true;
|
||||||
}
|
|
||||||
|
|
||||||
if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
||||||
exp = static_cast<int>(s.Take() - '0');
|
exp = static_cast<int>(s.Take() - '0');
|
||||||
@ -1171,7 +1173,7 @@ private:
|
|||||||
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
||||||
exp = exp * 10 + static_cast<int>(s.Take() - '0');
|
exp = exp * 10 + static_cast<int>(s.Take() - '0');
|
||||||
if (RAPIDJSON_UNLIKELY(exp > maxExp))
|
if (RAPIDJSON_UNLIKELY(exp > maxExp))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1211,7 +1213,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (RAPIDJSON_UNLIKELY(!cont))
|
if (RAPIDJSON_UNLIKELY(!cont))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse any JSON value
|
// Parse any JSON value
|
||||||
|
@ -418,7 +418,7 @@ TEST(Reader, ParseNumber_NormalPrecisionError) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(Reader, ParseNumber_Error) {
|
TEST(Reader, ParseNumber_Error) {
|
||||||
#define TEST_NUMBER_ERROR(errorCode, str) \
|
#define TEST_NUMBER_ERROR(errorCode, str, errorOffset) \
|
||||||
{ \
|
{ \
|
||||||
char buffer[1001]; \
|
char buffer[1001]; \
|
||||||
sprintf(buffer, "%s", str); \
|
sprintf(buffer, "%s", str); \
|
||||||
@ -427,6 +427,7 @@ TEST(Reader, ParseNumber_Error) {
|
|||||||
Reader reader; \
|
Reader reader; \
|
||||||
EXPECT_FALSE(reader.Parse(s, h)); \
|
EXPECT_FALSE(reader.Parse(s, h)); \
|
||||||
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
|
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
|
||||||
|
EXPECT_EQ(errorOffset, reader.GetErrorOffset());\
|
||||||
}
|
}
|
||||||
|
|
||||||
// Number too big to be stored in double.
|
// Number too big to be stored in double.
|
||||||
@ -436,17 +437,17 @@ TEST(Reader, ParseNumber_Error) {
|
|||||||
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(kParseErrorNumberTooBig, n1e309);
|
TEST_NUMBER_ERROR(kParseErrorNumberTooBig, n1e309, 0);
|
||||||
}
|
}
|
||||||
TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1e309");
|
TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1e309", 0);
|
||||||
|
|
||||||
// Miss fraction part in number.
|
// Miss fraction part in number.
|
||||||
TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.");
|
TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.", 2);
|
||||||
TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.a");
|
TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.a", 2);
|
||||||
|
|
||||||
// Miss exponent in number.
|
// Miss exponent in number.
|
||||||
TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e");
|
TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e", 2);
|
||||||
TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e_");
|
TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e_", 2);
|
||||||
|
|
||||||
#undef TEST_NUMBER_ERROR
|
#undef TEST_NUMBER_ERROR
|
||||||
}
|
}
|
||||||
@ -604,8 +605,15 @@ ParseErrorCode TestString(const typename Encoding::Ch* str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(Reader, ParseString_Error) {
|
TEST(Reader, ParseString_Error) {
|
||||||
#define TEST_STRING_ERROR(errorCode, str)\
|
#define TEST_STRING_ERROR(errorCode, str, errorOffset)\
|
||||||
EXPECT_EQ(errorCode, TestString<UTF8<> >(str))
|
{\
|
||||||
|
GenericStringStream<UTF8<> > s(str);\
|
||||||
|
BaseReaderHandler<UTF8<> > h;\
|
||||||
|
GenericReader<UTF8<> , UTF8<> > reader;\
|
||||||
|
reader.template Parse<kParseValidateEncodingFlag>(s, h);\
|
||||||
|
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
|
||||||
|
EXPECT_EQ(errorOffset, reader.GetErrorOffset());\
|
||||||
|
}
|
||||||
|
|
||||||
#define ARRAY(...) { __VA_ARGS__ }
|
#define ARRAY(...) { __VA_ARGS__ }
|
||||||
#define TEST_STRINGENCODING_ERROR(Encoding, TargetEncoding, utype, array) \
|
#define TEST_STRINGENCODING_ERROR(Encoding, TargetEncoding, utype, array) \
|
||||||
@ -622,21 +630,21 @@ TEST(Reader, ParseString_Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invalid escape character in string.
|
// Invalid escape character in string.
|
||||||
TEST_STRING_ERROR(kParseErrorStringEscapeInvalid, "[\"\\a\"]");
|
TEST_STRING_ERROR(kParseErrorStringEscapeInvalid, "[\"\\a\"]", 2);
|
||||||
|
|
||||||
// Incorrect hex digit after \\u escape in string.
|
// Incorrect hex digit after \\u escape in string.
|
||||||
TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uABCG\"]");
|
TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uABCG\"]", 2);
|
||||||
|
|
||||||
// Quotation in \\u escape in string (Issue #288)
|
// Quotation in \\u escape in string (Issue #288)
|
||||||
TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uaaa\"]");
|
TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uaaa\"]", 2);
|
||||||
TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uD800\\uFFF\"]");
|
TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uD800\\uFFF\"]", 2);
|
||||||
|
|
||||||
// The surrogate pair in string is invalid.
|
// The surrogate pair in string is invalid.
|
||||||
TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800X\"]");
|
TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800X\"]", 2);
|
||||||
TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800\\uFFFF\"]");
|
TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800\\uFFFF\"]", 2);
|
||||||
|
|
||||||
// Missing a closing quotation mark in string.
|
// Missing a closing quotation mark in string.
|
||||||
TEST_STRING_ERROR(kParseErrorStringMissQuotationMark, "[\"Test]");
|
TEST_STRING_ERROR(kParseErrorStringMissQuotationMark, "[\"Test]", 7);
|
||||||
|
|
||||||
// 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
|
||||||
|
|
||||||
@ -659,7 +667,7 @@ 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] = static_cast<char>(c);
|
e[2] = static_cast<char>(c);
|
||||||
TEST_STRING_ERROR(kParseErrorStringInvalidEncoding, e);
|
TEST_STRING_ERROR(kParseErrorStringInvalidEncoding, e, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -738,7 +746,7 @@ TEST(Reader, ParseArray) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(Reader, ParseArray_Error) {
|
TEST(Reader, ParseArray_Error) {
|
||||||
#define TEST_ARRAY_ERROR(errorCode, str) \
|
#define TEST_ARRAY_ERROR(errorCode, str, errorOffset) \
|
||||||
{ \
|
{ \
|
||||||
char buffer[1001]; \
|
char buffer[1001]; \
|
||||||
strncpy(buffer, str, 1000); \
|
strncpy(buffer, str, 1000); \
|
||||||
@ -747,12 +755,13 @@ TEST(Reader, ParseArray_Error) {
|
|||||||
GenericReader<UTF8<>, UTF8<>, CrtAllocator> reader; \
|
GenericReader<UTF8<>, UTF8<>, CrtAllocator> reader; \
|
||||||
EXPECT_FALSE(reader.Parse(s, h)); \
|
EXPECT_FALSE(reader.Parse(s, h)); \
|
||||||
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
|
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
|
||||||
|
EXPECT_EQ(errorOffset, reader.GetErrorOffset());\
|
||||||
}
|
}
|
||||||
|
|
||||||
// Missing a comma or ']' after an array element.
|
// Missing a comma or ']' after an array element.
|
||||||
TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1");
|
TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1", 2);
|
||||||
TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1}");
|
TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1}", 2);
|
||||||
TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1 2]");
|
TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1 2]", 3);
|
||||||
|
|
||||||
#undef TEST_ARRAY_ERROR
|
#undef TEST_ARRAY_ERROR
|
||||||
}
|
}
|
||||||
@ -899,7 +908,7 @@ TEST(Reader, ParseInsituIterative_MultipleRoot) {
|
|||||||
TestInsituMultipleRoot<kParseIterativeFlag | kParseStopWhenDoneFlag>();
|
TestInsituMultipleRoot<kParseIterativeFlag | kParseStopWhenDoneFlag>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TEST_ERROR(errorCode, str) \
|
#define TEST_ERROR(errorCode, str, errorOffset) \
|
||||||
{ \
|
{ \
|
||||||
char buffer[1001]; \
|
char buffer[1001]; \
|
||||||
strncpy(buffer, str, 1000); \
|
strncpy(buffer, str, 1000); \
|
||||||
@ -908,48 +917,49 @@ TEST(Reader, ParseInsituIterative_MultipleRoot) {
|
|||||||
Reader reader; \
|
Reader reader; \
|
||||||
EXPECT_FALSE(reader.Parse(s, h)); \
|
EXPECT_FALSE(reader.Parse(s, h)); \
|
||||||
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
|
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
|
||||||
|
EXPECT_EQ(errorOffset, reader.GetErrorOffset());\
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Reader, ParseDocument_Error) {
|
TEST(Reader, ParseDocument_Error) {
|
||||||
// The document is empty.
|
// The document is empty.
|
||||||
TEST_ERROR(kParseErrorDocumentEmpty, "");
|
TEST_ERROR(kParseErrorDocumentEmpty, "", 0);
|
||||||
TEST_ERROR(kParseErrorDocumentEmpty, " ");
|
TEST_ERROR(kParseErrorDocumentEmpty, " ", 1);
|
||||||
TEST_ERROR(kParseErrorDocumentEmpty, " \n");
|
TEST_ERROR(kParseErrorDocumentEmpty, " \n", 2);
|
||||||
|
|
||||||
// The document root must not follow by other values.
|
// The document root must not follow by other values.
|
||||||
TEST_ERROR(kParseErrorDocumentRootNotSingular, "[] 0");
|
TEST_ERROR(kParseErrorDocumentRootNotSingular, "[] 0", 3);
|
||||||
TEST_ERROR(kParseErrorDocumentRootNotSingular, "{} 0");
|
TEST_ERROR(kParseErrorDocumentRootNotSingular, "{} 0", 3);
|
||||||
TEST_ERROR(kParseErrorDocumentRootNotSingular, "null []");
|
TEST_ERROR(kParseErrorDocumentRootNotSingular, "null []", 5);
|
||||||
TEST_ERROR(kParseErrorDocumentRootNotSingular, "0 {}");
|
TEST_ERROR(kParseErrorDocumentRootNotSingular, "0 {}", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Reader, ParseValue_Error) {
|
TEST(Reader, ParseValue_Error) {
|
||||||
// Invalid value.
|
// Invalid value.
|
||||||
TEST_ERROR(kParseErrorValueInvalid, "nulL");
|
TEST_ERROR(kParseErrorValueInvalid, "nulL", 3);
|
||||||
TEST_ERROR(kParseErrorValueInvalid, "truE");
|
TEST_ERROR(kParseErrorValueInvalid, "truE", 3);
|
||||||
TEST_ERROR(kParseErrorValueInvalid, "falsE");
|
TEST_ERROR(kParseErrorValueInvalid, "falsE", 4);
|
||||||
TEST_ERROR(kParseErrorValueInvalid, "a]");
|
TEST_ERROR(kParseErrorValueInvalid, "a]", 0);
|
||||||
TEST_ERROR(kParseErrorValueInvalid, ".1");
|
TEST_ERROR(kParseErrorValueInvalid, ".1", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Reader, ParseObject_Error) {
|
TEST(Reader, ParseObject_Error) {
|
||||||
// Missing a name for object member.
|
// Missing a name for object member.
|
||||||
TEST_ERROR(kParseErrorObjectMissName, "{1}");
|
TEST_ERROR(kParseErrorObjectMissName, "{1}", 1);
|
||||||
TEST_ERROR(kParseErrorObjectMissName, "{:1}");
|
TEST_ERROR(kParseErrorObjectMissName, "{:1}", 1);
|
||||||
TEST_ERROR(kParseErrorObjectMissName, "{null:1}");
|
TEST_ERROR(kParseErrorObjectMissName, "{null:1}", 1);
|
||||||
TEST_ERROR(kParseErrorObjectMissName, "{true:1}");
|
TEST_ERROR(kParseErrorObjectMissName, "{true:1}", 1);
|
||||||
TEST_ERROR(kParseErrorObjectMissName, "{false:1}");
|
TEST_ERROR(kParseErrorObjectMissName, "{false:1}", 1);
|
||||||
TEST_ERROR(kParseErrorObjectMissName, "{1:1}");
|
TEST_ERROR(kParseErrorObjectMissName, "{1:1}", 1);
|
||||||
TEST_ERROR(kParseErrorObjectMissName, "{[]:1}");
|
TEST_ERROR(kParseErrorObjectMissName, "{[]:1}", 1);
|
||||||
TEST_ERROR(kParseErrorObjectMissName, "{{}:1}");
|
TEST_ERROR(kParseErrorObjectMissName, "{{}:1}", 1);
|
||||||
TEST_ERROR(kParseErrorObjectMissName, "{xyz:1}");
|
TEST_ERROR(kParseErrorObjectMissName, "{xyz:1}", 1);
|
||||||
|
|
||||||
// Missing a colon after a name of object member.
|
// Missing a colon after a name of object member.
|
||||||
TEST_ERROR(kParseErrorObjectMissColon, "{\"a\" 1}");
|
TEST_ERROR(kParseErrorObjectMissColon, "{\"a\" 1}", 5);
|
||||||
TEST_ERROR(kParseErrorObjectMissColon, "{\"a\",1}");
|
TEST_ERROR(kParseErrorObjectMissColon, "{\"a\",1}", 4);
|
||||||
|
|
||||||
// Must be a comma or '}' after an object member
|
// Must be a comma or '}' after an object member
|
||||||
TEST_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, "{\"a\":1]");
|
TEST_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, "{\"a\":1]", 6);
|
||||||
|
|
||||||
// This tests that MemoryStream is checking the length in Peek().
|
// This tests that MemoryStream is checking the length in Peek().
|
||||||
{
|
{
|
||||||
@ -1089,10 +1099,10 @@ TEST(Reader, IterativeParsing_ErrorHandling) {
|
|||||||
TESTERRORHANDLING("{\"a\"}", kParseErrorObjectMissColon, 4u);
|
TESTERRORHANDLING("{\"a\"}", kParseErrorObjectMissColon, 4u);
|
||||||
TESTERRORHANDLING("{\"a\": 1", kParseErrorObjectMissCommaOrCurlyBracket, 7u);
|
TESTERRORHANDLING("{\"a\": 1", kParseErrorObjectMissCommaOrCurlyBracket, 7u);
|
||||||
TESTERRORHANDLING("[1 2 3]", kParseErrorArrayMissCommaOrSquareBracket, 3u);
|
TESTERRORHANDLING("[1 2 3]", kParseErrorArrayMissCommaOrSquareBracket, 3u);
|
||||||
TESTERRORHANDLING("{\"a: 1", kParseErrorStringMissQuotationMark, 5u);
|
TESTERRORHANDLING("{\"a: 1", kParseErrorStringMissQuotationMark, 6u);
|
||||||
|
|
||||||
// Any JSON value can be a valid root element in RFC7159.
|
// Any JSON value can be a valid root element in RFC7159.
|
||||||
TESTERRORHANDLING("\"ab", kParseErrorStringMissQuotationMark, 2u);
|
TESTERRORHANDLING("\"ab", kParseErrorStringMissQuotationMark, 3u);
|
||||||
TESTERRORHANDLING("truE", kParseErrorValueInvalid, 3u);
|
TESTERRORHANDLING("truE", kParseErrorValueInvalid, 3u);
|
||||||
TESTERRORHANDLING("False", kParseErrorValueInvalid, 0u);
|
TESTERRORHANDLING("False", kParseErrorValueInvalid, 0u);
|
||||||
TESTERRORHANDLING("true, false", kParseErrorDocumentRootNotSingular, 4u);
|
TESTERRORHANDLING("true, false", kParseErrorDocumentRootNotSingular, 4u);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user