|
|
@@ -1,5 +1,5 @@
|
|
|
// 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.
|
|
|
//
|
|
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
|
|
@@ -7,9 +7,9 @@
|
|
|
//
|
|
|
// http://opensource.org/licenses/MIT
|
|
|
//
|
|
|
-// Unless required by applicable law or agreed to in writing, software distributed
|
|
|
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
|
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
|
+// Unless required by applicable law or agreed to in writing, software distributed
|
|
|
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
|
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
|
// specific language governing permissions and limitations under the License.
|
|
|
|
|
|
#ifndef RAPIDJSON_READER_H_
|
|
|
@@ -127,7 +127,7 @@ RAPIDJSON_NAMESPACE_BEGIN
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
// ParseFlag
|
|
|
|
|
|
-/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS
|
|
|
+/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS
|
|
|
\ingroup RAPIDJSON_CONFIG
|
|
|
\brief User-defined kParseDefaultFlags definition.
|
|
|
|
|
|
@@ -158,7 +158,7 @@ enum ParseFlag {
|
|
|
|
|
|
/*! \class rapidjson::Handler
|
|
|
\brief Concept for receiving events from GenericReader upon parsing.
|
|
|
- The functions return true if no error occurs. If they return false,
|
|
|
+ The functions return true if no error occurs. If they return false,
|
|
|
the event publisher should terminate the process.
|
|
|
\code
|
|
|
concept Handler {
|
|
|
@@ -425,7 +425,7 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
|
|
|
|
|
|
#ifdef RAPIDJSON_SIMD
|
|
|
//! Template function specialization for InsituStringStream
|
|
|
-template<> inline void SkipWhitespace(InsituStringStream& is) {
|
|
|
+template<> inline void SkipWhitespace(InsituStringStream& is) {
|
|
|
is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_));
|
|
|
}
|
|
|
|
|
|
@@ -443,17 +443,17 @@ template<> inline void SkipWhitespace(EncodedInputStream<UTF8<>, MemoryStream>&
|
|
|
// GenericReader
|
|
|
|
|
|
//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator.
|
|
|
-/*! GenericReader parses JSON text from a stream, and send events synchronously to an
|
|
|
+/*! GenericReader parses JSON text from a stream, and send events synchronously to an
|
|
|
object implementing Handler concept.
|
|
|
|
|
|
- It needs to allocate a stack for storing a single decoded string during
|
|
|
+ It needs to allocate a stack for storing a single decoded string during
|
|
|
non-destructive parsing.
|
|
|
|
|
|
- For in-situ parsing, the decoded string is directly written to the source
|
|
|
+ For in-situ parsing, the decoded string is directly written to the source
|
|
|
text string, no temporary buffer is required.
|
|
|
|
|
|
A GenericReader object can be reused for parsing multiple JSON text.
|
|
|
-
|
|
|
+
|
|
|
\tparam SourceEncoding Encoding of the input stream.
|
|
|
\tparam TargetEncoding Encoding of the parse output.
|
|
|
\tparam StackAllocator Allocator type for stack.
|
|
|
@@ -525,7 +525,7 @@ public:
|
|
|
|
|
|
//! Whether a parse error has occured in the last parsing.
|
|
|
bool HasParseError() const { return parseResult_.IsError(); }
|
|
|
-
|
|
|
+
|
|
|
//! Get the \ref ParseErrorCode of last parsing.
|
|
|
ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); }
|
|
|
|
|
|
@@ -585,7 +585,7 @@ private:
|
|
|
void ParseObject(InputStream& is, Handler& handler) {
|
|
|
RAPIDJSON_ASSERT(is.Peek() == '{');
|
|
|
is.Take(); // Skip '{'
|
|
|
-
|
|
|
+
|
|
|
if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
|
|
|
|
|
@@ -628,12 +628,12 @@ private:
|
|
|
SkipWhitespaceAndComments<parseFlags>(is);
|
|
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
|
|
break;
|
|
|
- case '}':
|
|
|
+ case '}':
|
|
|
is.Take();
|
|
|
if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
|
|
return;
|
|
|
- default:
|
|
|
+ default:
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
|
|
|
break;
|
|
|
}
|
|
|
@@ -654,10 +654,10 @@ private:
|
|
|
void ParseArray(InputStream& is, Handler& handler) {
|
|
|
RAPIDJSON_ASSERT(is.Peek() == '[');
|
|
|
is.Take(); // Skip '['
|
|
|
-
|
|
|
+
|
|
|
if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
|
|
-
|
|
|
+
|
|
|
SkipWhitespaceAndComments<parseFlags>(is);
|
|
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
|
|
|
|
|
@@ -780,7 +780,7 @@ private:
|
|
|
*stack_.template Push<Ch>() = c;
|
|
|
++length_;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
RAPIDJSON_FORCEINLINE void* Push(SizeType count) {
|
|
|
length_ += count;
|
|
|
return stack_.template Push<Ch>(count);
|
|
|
@@ -838,10 +838,10 @@ 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, 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,
|
|
|
+ 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,
|
|
|
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
|
|
|
};
|
|
|
#undef Z16
|
|
|
@@ -893,8 +893,8 @@ private:
|
|
|
}
|
|
|
else {
|
|
|
size_t offset = is.Tell();
|
|
|
- if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ?
|
|
|
- !Transcoder<SEncoding, TEncoding>::Validate(is, os) :
|
|
|
+ if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ?
|
|
|
+ !Transcoder<SEncoding, TEncoding>::Validate(is, os) :
|
|
|
!Transcoder<SEncoding, TEncoding>::Transcode(is, os))))
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset);
|
|
|
}
|
|
|
@@ -954,7 +954,7 @@ private:
|
|
|
}
|
|
|
_mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
is.src_ = p;
|
|
|
}
|
|
|
|
|
|
@@ -977,7 +977,7 @@ private:
|
|
|
if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
|
|
|
is.src_ = p;
|
|
|
is.dst_ = q;
|
|
|
- return;
|
|
|
+ return;
|
|
|
}
|
|
|
else
|
|
|
*q++ = *p++;
|
|
|
@@ -1063,11 +1063,11 @@ private:
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
- template<typename InputStream, bool backup>
|
|
|
+ template<typename InputStream, bool backup, bool pushOnTake>
|
|
|
class NumberStream;
|
|
|
|
|
|
template<typename InputStream>
|
|
|
- class NumberStream<InputStream, false> {
|
|
|
+ class NumberStream<InputStream, false, false> {
|
|
|
public:
|
|
|
typedef typename InputStream::Ch Ch;
|
|
|
|
|
|
@@ -1090,10 +1090,10 @@ private:
|
|
|
};
|
|
|
|
|
|
template<typename InputStream>
|
|
|
- class NumberStream<InputStream, true> : public NumberStream<InputStream, false> {
|
|
|
- typedef NumberStream<InputStream, false> Base;
|
|
|
+ class NumberStream<InputStream, true, false> : public NumberStream<InputStream, false, false> {
|
|
|
+ typedef NumberStream<InputStream, false, false> Base;
|
|
|
public:
|
|
|
- NumberStream(GenericReader& reader, InputStream& is) : NumberStream<InputStream, false>(reader, is), stackStream(reader.stack_) {}
|
|
|
+ NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {}
|
|
|
~NumberStream() {}
|
|
|
|
|
|
RAPIDJSON_FORCEINLINE Ch TakePush() {
|
|
|
@@ -1101,9 +1101,9 @@ private:
|
|
|
return Base::is.Take();
|
|
|
}
|
|
|
|
|
|
- RAPIDJSON_FORCEINLINE void Push(char c) {
|
|
|
- stackStream.Put(c);
|
|
|
- }
|
|
|
+ RAPIDJSON_FORCEINLINE void Push(char c) {
|
|
|
+ stackStream.Put(c);
|
|
|
+ }
|
|
|
|
|
|
size_t Length() { return stackStream.Length(); }
|
|
|
|
|
|
@@ -1116,13 +1116,25 @@ private:
|
|
|
StackStream<char> stackStream;
|
|
|
};
|
|
|
|
|
|
+ template<typename InputStream>
|
|
|
+ class NumberStream<InputStream, true, true> : public NumberStream<InputStream, true, false> {
|
|
|
+ typedef NumberStream<InputStream, true, false> Base;
|
|
|
+ public:
|
|
|
+ NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {}
|
|
|
+ ~NumberStream() {}
|
|
|
+
|
|
|
+ RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); }
|
|
|
+ };
|
|
|
+
|
|
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
|
|
void ParseNumber(InputStream& is, Handler& handler) {
|
|
|
internal::StreamLocalCopy<InputStream> copy(is);
|
|
|
NumberStream<InputStream,
|
|
|
((parseFlags & kParseNumbersAsStringsFlag) != 0) ?
|
|
|
((parseFlags & kParseInsituFlag) == 0) :
|
|
|
- ((parseFlags & kParseFullPrecisionFlag) != 0)> s(*this, copy.s);
|
|
|
+ ((parseFlags & kParseFullPrecisionFlag) != 0),
|
|
|
+ (parseFlags & kParseNumbersAsStringsFlag) != 0 &&
|
|
|
+ (parseFlags & kParseInsituFlag) == 0> s(*this, copy.s);
|
|
|
|
|
|
size_t startOffset = s.Tell();
|
|
|
|
|
|
@@ -1173,7 +1185,7 @@ private:
|
|
|
bool useDouble = false;
|
|
|
double d = 0.0;
|
|
|
if (use64bit) {
|
|
|
- if (minus)
|
|
|
+ if (minus)
|
|
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
|
|
if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808
|
|
|
if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) {
|
|
|
@@ -1210,9 +1222,6 @@ private:
|
|
|
int expFrac = 0;
|
|
|
size_t decimalPosition;
|
|
|
if (Consume(s, '.')) {
|
|
|
- if (((parseFlags & kParseNumbersAsStringsFlag) != 0) && ((parseFlags & kParseInsituFlag) == 0)) {
|
|
|
- s.Push('.');
|
|
|
- }
|
|
|
decimalPosition = s.Length();
|
|
|
|
|
|
if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
|
|
|
@@ -1223,7 +1232,7 @@ private:
|
|
|
// Use i64 to store significand in 64-bit architecture
|
|
|
if (!use64bit)
|
|
|
i64 = i;
|
|
|
-
|
|
|
+
|
|
|
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
|
|
|
if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path
|
|
|
break;
|
|
|
@@ -1260,11 +1269,7 @@ private:
|
|
|
// Parse exp = e [ minus / plus ] 1*DIGIT
|
|
|
int exp = 0;
|
|
|
if (Consume(s, 'e') || Consume(s, 'E')) {
|
|
|
- if ( ((parseFlags & kParseNumbersAsStringsFlag) != 0) && ((parseFlags & kParseInsituFlag) == 0) ) {
|
|
|
- s.Push( 'e' );
|
|
|
- }
|
|
|
-
|
|
|
- if (!useDouble) {
|
|
|
+ if (!useDouble) {
|
|
|
d = static_cast<double>(use64bit ? i64 : i);
|
|
|
useDouble = true;
|
|
|
}
|
|
|
@@ -1316,14 +1321,15 @@ private:
|
|
|
cont = handler.RawNumber(str, SizeType(length), false);
|
|
|
}
|
|
|
else {
|
|
|
- StackStream<typename TargetEncoding::Ch> stackStream(stack_);
|
|
|
SizeType numCharsToCopy = static_cast<SizeType>(s.Length());
|
|
|
+ StringStream srcStream(s.Pop());
|
|
|
+ StackStream<typename TargetEncoding::Ch> dstStream(stack_);
|
|
|
while (numCharsToCopy--) {
|
|
|
- Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, stackStream);
|
|
|
+ Transcoder<UTF8<>, TargetEncoding>::Transcode(srcStream, dstStream);
|
|
|
}
|
|
|
- stackStream.Put('\0');
|
|
|
- const typename TargetEncoding::Ch* str = stackStream.Pop();
|
|
|
- const SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;
|
|
|
+ dstStream.Put('\0');
|
|
|
+ const typename TargetEncoding::Ch* str = dstStream.Pop();
|
|
|
+ const SizeType length = static_cast<SizeType>(dstStream.Length()) - 1;
|
|
|
cont = handler.RawNumber(str, SizeType(length), true);
|
|
|
}
|
|
|
}
|
|
|
@@ -1369,10 +1375,10 @@ private:
|
|
|
case '"': ParseString<parseFlags>(is, handler); break;
|
|
|
case '{': ParseObject<parseFlags>(is, handler); break;
|
|
|
case '[': ParseArray <parseFlags>(is, handler); break;
|
|
|
- default :
|
|
|
+ default :
|
|
|
ParseNumber<parseFlags>(is, handler);
|
|
|
break;
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1444,7 +1450,7 @@ private:
|
|
|
#undef N
|
|
|
#undef N16
|
|
|
//!@endcond
|
|
|
-
|
|
|
+
|
|
|
if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256)
|
|
|
return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]);
|
|
|
else
|
|
|
@@ -1775,7 +1781,7 @@ private:
|
|
|
// Error flag has been set.
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
switch (src) {
|
|
|
case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return;
|
|
|
case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return;
|
|
|
@@ -1788,7 +1794,7 @@ private:
|
|
|
case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return;
|
|
|
case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
|
|
|
default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return;
|
|
|
- }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
template <unsigned parseFlags, typename InputStream, typename Handler>
|