|
|
@@ -1,6 +1,6 @@
|
|
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
|
|
//
|
|
|
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
|
|
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
|
|
|
//
|
|
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
|
|
// in compliance with the License. You may obtain a copy of the License at
|
|
|
@@ -20,6 +20,7 @@
|
|
|
#include "allocators.h"
|
|
|
#include "stream.h"
|
|
|
#include "encodedstream.h"
|
|
|
+#include "internal/clzll.h"
|
|
|
#include "internal/meta.h"
|
|
|
#include "internal/stack.h"
|
|
|
#include "internal/strtod.h"
|
|
|
@@ -37,17 +38,15 @@
|
|
|
#include <arm_neon.h>
|
|
|
#endif
|
|
|
|
|
|
-#ifdef _MSC_VER
|
|
|
-RAPIDJSON_DIAG_PUSH
|
|
|
-RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
|
|
-RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
|
|
-#endif
|
|
|
-
|
|
|
#ifdef __clang__
|
|
|
RAPIDJSON_DIAG_PUSH
|
|
|
RAPIDJSON_DIAG_OFF(old-style-cast)
|
|
|
RAPIDJSON_DIAG_OFF(padded)
|
|
|
RAPIDJSON_DIAG_OFF(switch-enum)
|
|
|
+#elif defined(_MSC_VER)
|
|
|
+RAPIDJSON_DIAG_PUSH
|
|
|
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
|
|
+RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
|
|
#endif
|
|
|
|
|
|
#ifdef __GNUC__
|
|
|
@@ -155,6 +154,7 @@ enum ParseFlag {
|
|
|
kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings.
|
|
|
kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays.
|
|
|
kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles.
|
|
|
+ kParseEscapedApostropheFlag = 512, //!< Allow escaped apostrophe in strings.
|
|
|
kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
|
|
|
};
|
|
|
|
|
|
@@ -445,16 +445,16 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
|
|
|
|
|
|
x = vmvnq_u8(x); // Negate
|
|
|
x = vrev64q_u8(x); // Rev in 64
|
|
|
- uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
|
|
|
- uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
|
|
|
+ uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
|
|
|
+ uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
|
|
|
|
|
|
if (low == 0) {
|
|
|
if (high != 0) {
|
|
|
- int lz =__builtin_clzll(high);;
|
|
|
+ uint32_t lz = internal::clzll(high);
|
|
|
return p + 8 + (lz >> 3);
|
|
|
}
|
|
|
} else {
|
|
|
- int lz = __builtin_clzll(low);;
|
|
|
+ uint32_t lz = internal::clzll(low);
|
|
|
return p + (lz >> 3);
|
|
|
}
|
|
|
}
|
|
|
@@ -481,16 +481,16 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
|
|
|
|
|
|
x = vmvnq_u8(x); // Negate
|
|
|
x = vrev64q_u8(x); // Rev in 64
|
|
|
- uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
|
|
|
- uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
|
|
|
+ uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
|
|
|
+ uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
|
|
|
|
|
|
if (low == 0) {
|
|
|
if (high != 0) {
|
|
|
- int lz = __builtin_clzll(high);
|
|
|
+ uint32_t lz = internal::clzll(high);
|
|
|
return p + 8 + (lz >> 3);
|
|
|
}
|
|
|
} else {
|
|
|
- int lz = __builtin_clzll(low);
|
|
|
+ uint32_t lz = internal::clzll(low);
|
|
|
return p + (lz >> 3);
|
|
|
}
|
|
|
}
|
|
|
@@ -544,7 +544,8 @@ public:
|
|
|
/*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
|
|
|
\param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
|
|
|
*/
|
|
|
- GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {}
|
|
|
+ GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) :
|
|
|
+ stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {}
|
|
|
|
|
|
//! Parse JSON text.
|
|
|
/*! \tparam parseFlags Combination of \ref ParseFlag.
|
|
|
@@ -607,7 +608,7 @@ public:
|
|
|
parseResult_.Clear();
|
|
|
state_ = IterativeParsingStartState;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
//! Parse one token from JSON text
|
|
|
/*! \tparam InputStream Type of input stream, implementing Stream concept
|
|
|
\tparam Handler Type of handler, implementing Handler concept.
|
|
|
@@ -619,11 +620,11 @@ public:
|
|
|
bool IterativeParseNext(InputStream& is, Handler& handler) {
|
|
|
while (RAPIDJSON_LIKELY(is.Peek() != '\0')) {
|
|
|
SkipWhitespaceAndComments<parseFlags>(is);
|
|
|
-
|
|
|
+
|
|
|
Token t = Tokenize(is.Peek());
|
|
|
IterativeParsingState n = Predict(state_, t);
|
|
|
IterativeParsingState d = Transit<parseFlags>(state_, t, n, is, handler);
|
|
|
-
|
|
|
+
|
|
|
// If we've finished or hit an error...
|
|
|
if (RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) {
|
|
|
// Report errors.
|
|
|
@@ -631,11 +632,11 @@ public:
|
|
|
HandleError(state_, is);
|
|
|
return false;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Transition to the finish state.
|
|
|
RAPIDJSON_ASSERT(d == IterativeParsingFinishState);
|
|
|
state_ = d;
|
|
|
-
|
|
|
+
|
|
|
// If StopWhenDone is not set...
|
|
|
if (!(parseFlags & kParseStopWhenDoneFlag)) {
|
|
|
// ... and extra non-whitespace data is found...
|
|
|
@@ -646,11 +647,11 @@ public:
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Success! We are done!
|
|
|
return true;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Transition to the new state.
|
|
|
state_ = d;
|
|
|
|
|
|
@@ -658,7 +659,7 @@ public:
|
|
|
if (!IsIterativeParsingDelimiterState(n))
|
|
|
return true;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// We reached the end of file.
|
|
|
stack_.Clear();
|
|
|
|
|
|
@@ -666,18 +667,18 @@ public:
|
|
|
HandleError(state_, is);
|
|
|
return false;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
//! Check if token-by-token parsing JSON text is complete
|
|
|
/*! \return Whether the JSON has been fully decoded.
|
|
|
*/
|
|
|
- RAPIDJSON_FORCEINLINE bool IterativeParseComplete() {
|
|
|
+ RAPIDJSON_FORCEINLINE bool IterativeParseComplete() const {
|
|
|
return IsIterativeParsingCompleteState(state_);
|
|
|
}
|
|
|
|
|
|
- //! Whether a parse error has occured in the last parsing.
|
|
|
+ //! Whether a parse error has occurred in the last parsing.
|
|
|
bool HasParseError() const { return parseResult_.IsError(); }
|
|
|
|
|
|
//! Get the \ref ParseErrorCode of last parsing.
|
|
|
@@ -900,7 +901,7 @@ private:
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
|
|
|
+ // Helper function to parse four hexadecimal digits in \uXXXX in ParseString().
|
|
|
template<typename InputStream>
|
|
|
unsigned ParseHex4(InputStream& is, size_t escapeOffset) {
|
|
|
unsigned codepoint = 0;
|
|
|
@@ -991,7 +992,7 @@ private:
|
|
|
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
|
|
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
|
static const char escape[256] = {
|
|
|
- Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
|
|
|
+ Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/',
|
|
|
Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
|
|
|
0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
|
|
|
0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
@@ -1007,26 +1008,38 @@ private:
|
|
|
|
|
|
Ch c = is.Peek();
|
|
|
if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape
|
|
|
- size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset
|
|
|
+ size_t escapeOffset = is.Tell(); // For invalid escaping, report the initial '\\' as error offset
|
|
|
is.Take();
|
|
|
Ch e = is.Peek();
|
|
|
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)]));
|
|
|
}
|
|
|
+ else if ((parseFlags & kParseEscapedApostropheFlag) && RAPIDJSON_LIKELY(e == '\'')) { // Allow escaped apostrophe
|
|
|
+ is.Take();
|
|
|
+ os.Put('\'');
|
|
|
+ }
|
|
|
else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode
|
|
|
is.Take();
|
|
|
unsigned codepoint = ParseHex4(is, escapeOffset);
|
|
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
|
|
- if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {
|
|
|
- // Handle UTF-16 surrogate pair
|
|
|
- if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
|
|
|
- RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
|
|
|
- unsigned codepoint2 = ParseHex4(is, escapeOffset);
|
|
|
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
|
|
- if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
|
|
|
+ if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDFFF)) {
|
|
|
+ // high surrogate, check if followed by valid low surrogate
|
|
|
+ if (RAPIDJSON_LIKELY(codepoint <= 0xDBFF)) {
|
|
|
+ // Handle UTF-16 surrogate pair
|
|
|
+ if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
|
|
|
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
|
|
|
+ unsigned codepoint2 = ParseHex4(is, escapeOffset);
|
|
|
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
|
|
+ if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
|
|
|
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
|
|
|
+ codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
|
|
|
+ }
|
|
|
+ // single low surrogate
|
|
|
+ else
|
|
|
+ {
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
|
|
|
- codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
|
|
|
+ }
|
|
|
}
|
|
|
TEncoding::Encode(os, codepoint);
|
|
|
}
|
|
|
@@ -1245,19 +1258,19 @@ private:
|
|
|
x = vorrq_u8(x, vcltq_u8(s, s3));
|
|
|
|
|
|
x = vrev64q_u8(x); // Rev in 64
|
|
|
- uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
|
|
|
- uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
|
|
|
+ uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
|
|
|
+ uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
|
|
|
|
|
|
SizeType length = 0;
|
|
|
bool escaped = false;
|
|
|
if (low == 0) {
|
|
|
if (high != 0) {
|
|
|
- unsigned lz = (unsigned)__builtin_clzll(high);;
|
|
|
+ uint32_t lz = internal::clzll(high);
|
|
|
length = 8 + (lz >> 3);
|
|
|
escaped = true;
|
|
|
}
|
|
|
} else {
|
|
|
- unsigned lz = (unsigned)__builtin_clzll(low);;
|
|
|
+ uint32_t lz = internal::clzll(low);
|
|
|
length = lz >> 3;
|
|
|
escaped = true;
|
|
|
}
|
|
|
@@ -1315,19 +1328,19 @@ private:
|
|
|
x = vorrq_u8(x, vcltq_u8(s, s3));
|
|
|
|
|
|
x = vrev64q_u8(x); // Rev in 64
|
|
|
- uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
|
|
|
- uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
|
|
|
+ uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
|
|
|
+ uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
|
|
|
|
|
|
SizeType length = 0;
|
|
|
bool escaped = false;
|
|
|
if (low == 0) {
|
|
|
if (high != 0) {
|
|
|
- unsigned lz = (unsigned)__builtin_clzll(high);
|
|
|
+ uint32_t lz = internal::clzll(high);
|
|
|
length = 8 + (lz >> 3);
|
|
|
escaped = true;
|
|
|
}
|
|
|
} else {
|
|
|
- unsigned lz = (unsigned)__builtin_clzll(low);
|
|
|
+ uint32_t lz = internal::clzll(low);
|
|
|
length = lz >> 3;
|
|
|
escaped = true;
|
|
|
}
|
|
|
@@ -1371,17 +1384,17 @@ private:
|
|
|
x = vorrq_u8(x, vcltq_u8(s, s3));
|
|
|
|
|
|
x = vrev64q_u8(x); // Rev in 64
|
|
|
- uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
|
|
|
- uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
|
|
|
+ uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
|
|
|
+ uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
|
|
|
|
|
|
if (low == 0) {
|
|
|
if (high != 0) {
|
|
|
- int lz = __builtin_clzll(high);
|
|
|
+ uint32_t lz = internal::clzll(high);
|
|
|
p += 8 + (lz >> 3);
|
|
|
break;
|
|
|
}
|
|
|
} else {
|
|
|
- int lz = __builtin_clzll(low);
|
|
|
+ uint32_t lz = internal::clzll(low);
|
|
|
p += lz >> 3;
|
|
|
break;
|
|
|
}
|
|
|
@@ -1391,11 +1404,11 @@ private:
|
|
|
}
|
|
|
#endif // RAPIDJSON_NEON
|
|
|
|
|
|
- template<typename InputStream, bool backup, bool pushOnTake>
|
|
|
+ template<typename InputStream, typename StackCharacter, bool backup, bool pushOnTake>
|
|
|
class NumberStream;
|
|
|
|
|
|
- template<typename InputStream>
|
|
|
- class NumberStream<InputStream, false, false> {
|
|
|
+ template<typename InputStream, typename StackCharacter>
|
|
|
+ class NumberStream<InputStream, StackCharacter, false, false> {
|
|
|
public:
|
|
|
typedef typename InputStream::Ch Ch;
|
|
|
|
|
|
@@ -1404,11 +1417,11 @@ private:
|
|
|
RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
|
|
|
RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
|
|
|
RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
|
|
|
- RAPIDJSON_FORCEINLINE void Push(char) {}
|
|
|
+ RAPIDJSON_FORCEINLINE void Push(char) {}
|
|
|
|
|
|
size_t Tell() { return is.Tell(); }
|
|
|
size_t Length() { return 0; }
|
|
|
- const char* Pop() { return 0; }
|
|
|
+ const StackCharacter* Pop() { return 0; }
|
|
|
|
|
|
protected:
|
|
|
NumberStream& operator=(const NumberStream&);
|
|
|
@@ -1416,45 +1429,47 @@ private:
|
|
|
InputStream& is;
|
|
|
};
|
|
|
|
|
|
- template<typename InputStream>
|
|
|
- class NumberStream<InputStream, true, false> : public NumberStream<InputStream, false, false> {
|
|
|
- typedef NumberStream<InputStream, false, false> Base;
|
|
|
+ template<typename InputStream, typename StackCharacter>
|
|
|
+ class NumberStream<InputStream, StackCharacter, true, false> : public NumberStream<InputStream, StackCharacter, false, false> {
|
|
|
+ typedef NumberStream<InputStream, StackCharacter, false, false> Base;
|
|
|
public:
|
|
|
- NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {}
|
|
|
+ NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s), stackStream(reader.stack_) {}
|
|
|
|
|
|
RAPIDJSON_FORCEINLINE Ch TakePush() {
|
|
|
- stackStream.Put(static_cast<char>(Base::is.Peek()));
|
|
|
+ stackStream.Put(static_cast<StackCharacter>(Base::is.Peek()));
|
|
|
return Base::is.Take();
|
|
|
}
|
|
|
|
|
|
- RAPIDJSON_FORCEINLINE void Push(char c) {
|
|
|
+ RAPIDJSON_FORCEINLINE void Push(StackCharacter c) {
|
|
|
stackStream.Put(c);
|
|
|
}
|
|
|
|
|
|
size_t Length() { return stackStream.Length(); }
|
|
|
|
|
|
- const char* Pop() {
|
|
|
+ const StackCharacter* Pop() {
|
|
|
stackStream.Put('\0');
|
|
|
return stackStream.Pop();
|
|
|
}
|
|
|
|
|
|
private:
|
|
|
- StackStream<char> stackStream;
|
|
|
+ StackStream<StackCharacter> stackStream;
|
|
|
};
|
|
|
|
|
|
- template<typename InputStream>
|
|
|
- class NumberStream<InputStream, true, true> : public NumberStream<InputStream, true, false> {
|
|
|
- typedef NumberStream<InputStream, true, false> Base;
|
|
|
+ template<typename InputStream, typename StackCharacter>
|
|
|
+ class NumberStream<InputStream, StackCharacter, true, true> : public NumberStream<InputStream, StackCharacter, true, false> {
|
|
|
+ typedef NumberStream<InputStream, StackCharacter, true, false> Base;
|
|
|
public:
|
|
|
- NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {}
|
|
|
+ NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s) {}
|
|
|
|
|
|
RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); }
|
|
|
};
|
|
|
|
|
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
|
|
void ParseNumber(InputStream& is, Handler& handler) {
|
|
|
+ typedef typename internal::SelectIf<internal::BoolType<(parseFlags & kParseNumbersAsStringsFlag) != 0>, typename TargetEncoding::Ch, char>::Type NumberCharacter;
|
|
|
+
|
|
|
internal::StreamLocalCopy<InputStream> copy(is);
|
|
|
- NumberStream<InputStream,
|
|
|
+ NumberStream<InputStream, NumberCharacter,
|
|
|
((parseFlags & kParseNumbersAsStringsFlag) != 0) ?
|
|
|
((parseFlags & kParseInsituFlag) == 0) :
|
|
|
((parseFlags & kParseFullPrecisionFlag) != 0),
|
|
|
@@ -1524,7 +1539,7 @@ private:
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (RAPIDJSON_UNLIKELY(!useNanOrInf)) {
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
|
|
|
}
|
|
|
@@ -1562,8 +1577,6 @@ private:
|
|
|
// Force double for big integer
|
|
|
if (useDouble) {
|
|
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
|
|
- if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0
|
|
|
- RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
|
|
|
d = d * 10 + (s.TakePush() - '0');
|
|
|
}
|
|
|
}
|
|
|
@@ -1633,9 +1646,18 @@ private:
|
|
|
if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
|
|
exp = static_cast<int>(s.Take() - '0');
|
|
|
if (expMinus) {
|
|
|
+ // (exp + expFrac) must not underflow int => we're detecting when -exp gets
|
|
|
+ // dangerously close to INT_MIN (a pessimistic next digit 9 would push it into
|
|
|
+ // underflow territory):
|
|
|
+ //
|
|
|
+ // -(exp * 10 + 9) + expFrac >= INT_MIN
|
|
|
+ // <=> exp <= (expFrac - INT_MIN - 9) / 10
|
|
|
+ RAPIDJSON_ASSERT(expFrac <= 0);
|
|
|
+ int maxExp = (expFrac + 2147483639) / 10;
|
|
|
+
|
|
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
|
|
exp = exp * 10 + static_cast<int>(s.Take() - '0');
|
|
|
- if (exp >= 214748364) { // Issue #313: prevent overflow exponent
|
|
|
+ if (RAPIDJSON_UNLIKELY(exp > maxExp)) {
|
|
|
while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent
|
|
|
s.Take();
|
|
|
}
|
|
|
@@ -1672,10 +1694,10 @@ private:
|
|
|
}
|
|
|
else {
|
|
|
SizeType numCharsToCopy = static_cast<SizeType>(s.Length());
|
|
|
- StringStream srcStream(s.Pop());
|
|
|
+ GenericStringStream<UTF8<NumberCharacter> > srcStream(s.Pop());
|
|
|
StackStream<typename TargetEncoding::Ch> dstStream(stack_);
|
|
|
while (numCharsToCopy--) {
|
|
|
- Transcoder<UTF8<>, TargetEncoding>::Transcode(srcStream, dstStream);
|
|
|
+ Transcoder<UTF8<typename TargetEncoding::Ch>, TargetEncoding>::Transcode(srcStream, dstStream);
|
|
|
}
|
|
|
dstStream.Put('\0');
|
|
|
const typename TargetEncoding::Ch* str = dstStream.Pop();
|
|
|
@@ -1685,7 +1707,7 @@ private:
|
|
|
}
|
|
|
else {
|
|
|
size_t length = s.Length();
|
|
|
- const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
|
|
|
+ const NumberCharacter* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
|
|
|
|
|
|
if (useDouble) {
|
|
|
int p = exp + expFrac;
|
|
|
@@ -1694,6 +1716,13 @@ private:
|
|
|
else
|
|
|
d = internal::StrtodNormalPrecision(d, p);
|
|
|
|
|
|
+ // Use > max, instead of == inf, to fix bogus warning -Wfloat-equal
|
|
|
+ if (d > (std::numeric_limits<double>::max)()) {
|
|
|
+ // Overflow
|
|
|
+ // TODO: internal::StrtodX should report overflow (or underflow)
|
|
|
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
|
|
|
+ }
|
|
|
+
|
|
|
cont = handler.Double(minus ? -d : d);
|
|
|
}
|
|
|
else if (useNanOrInf) {
|
|
|
@@ -1756,12 +1785,12 @@ private:
|
|
|
|
|
|
// Single value state
|
|
|
IterativeParsingValueState,
|
|
|
-
|
|
|
+
|
|
|
// Delimiter states (at bottom)
|
|
|
IterativeParsingElementDelimiterState,
|
|
|
IterativeParsingMemberDelimiterState,
|
|
|
IterativeParsingKeyValueDelimiterState,
|
|
|
-
|
|
|
+
|
|
|
cIterativeParsingStateCount
|
|
|
};
|
|
|
|
|
|
@@ -1785,7 +1814,7 @@ private:
|
|
|
kTokenCount
|
|
|
};
|
|
|
|
|
|
- RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) {
|
|
|
+ RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) const {
|
|
|
|
|
|
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
|
|
#define N NumberToken
|
|
|
@@ -1812,7 +1841,7 @@ private:
|
|
|
return NumberToken;
|
|
|
}
|
|
|
|
|
|
- RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) {
|
|
|
+ RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) const {
|
|
|
// current state x one lookahead token -> new state
|
|
|
static const char G[cIterativeParsingStateCount][kTokenCount] = {
|
|
|
// Finish(sink state)
|
|
|
@@ -2151,46 +2180,46 @@ private:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) {
|
|
|
+ RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) const {
|
|
|
return s >= IterativeParsingElementDelimiterState;
|
|
|
}
|
|
|
-
|
|
|
- RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) {
|
|
|
+
|
|
|
+ RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) const {
|
|
|
return s <= IterativeParsingErrorState;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
template <unsigned parseFlags, typename InputStream, typename Handler>
|
|
|
ParseResult IterativeParse(InputStream& is, Handler& handler) {
|
|
|
parseResult_.Clear();
|
|
|
ClearStackOnExit scope(*this);
|
|
|
IterativeParsingState state = IterativeParsingStartState;
|
|
|
-
|
|
|
+
|
|
|
SkipWhitespaceAndComments<parseFlags>(is);
|
|
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
|
|
while (is.Peek() != '\0') {
|
|
|
Token t = Tokenize(is.Peek());
|
|
|
IterativeParsingState n = Predict(state, t);
|
|
|
IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handler);
|
|
|
-
|
|
|
+
|
|
|
if (d == IterativeParsingErrorState) {
|
|
|
HandleError(state, is);
|
|
|
break;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
state = d;
|
|
|
-
|
|
|
+
|
|
|
// Do not further consume streams if a root JSON has been parsed.
|
|
|
if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
|
|
|
break;
|
|
|
-
|
|
|
+
|
|
|
SkipWhitespaceAndComments<parseFlags>(is);
|
|
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Handle the end of file.
|
|
|
if (state != IterativeParsingFinishState)
|
|
|
HandleError(state, is);
|
|
|
-
|
|
|
+
|
|
|
return parseResult_;
|
|
|
}
|
|
|
|
|
|
@@ -2205,7 +2234,7 @@ typedef GenericReader<UTF8<>, UTF8<> > Reader;
|
|
|
|
|
|
RAPIDJSON_NAMESPACE_END
|
|
|
|
|
|
-#ifdef __clang__
|
|
|
+#if defined(__clang__) || defined(_MSC_VER)
|
|
|
RAPIDJSON_DIAG_POP
|
|
|
#endif
|
|
|
|
|
|
@@ -2214,8 +2243,4 @@ RAPIDJSON_DIAG_POP
|
|
|
RAPIDJSON_DIAG_POP
|
|
|
#endif
|
|
|
|
|
|
-#ifdef _MSC_VER
|
|
|
-RAPIDJSON_DIAG_POP
|
|
|
-#endif
|
|
|
-
|
|
|
#endif // RAPIDJSON_READER_H_
|