// 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 | |
// in compliance with the License. You may obtain a copy of the License at | |
// | |
// 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 | |
// specific language governing permissions and limitations under the License. | |
#ifndef RAPIDJSON_READER_H_ | |
#define RAPIDJSON_READER_H_ | |
/*! \file reader.h */ | |
#include "rapidjson.h" | |
#include "encodings.h" | |
#include "internal/meta.h" | |
#include "internal/stack.h" | |
#include "internal/strtod.h" | |
#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) | |
#include <intrin.h> | |
#pragma intrinsic(_BitScanForward) | |
#endif | |
#ifdef RAPIDJSON_SSE42 | |
#include <nmmintrin.h> | |
#elif defined(RAPIDJSON_SSE2) | |
#include <emmintrin.h> | |
#endif | |
#ifdef _MSC_VER | |
RAPIDJSON_DIAG_PUSH | |
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant | |
RAPIDJSON_DIAG_OFF(4702) // unreachable code | |
#endif | |
#ifdef __GNUC__ | |
RAPIDJSON_DIAG_PUSH | |
RAPIDJSON_DIAG_OFF(effc++) | |
#endif | |
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN | |
#define RAPIDJSON_NOTHING /* deliberately empty */ | |
#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN | |
#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ | |
RAPIDJSON_MULTILINEMACRO_BEGIN \ | |
if (HasParseError()) { return value; } \ | |
RAPIDJSON_MULTILINEMACRO_END | |
#endif | |
#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ | |
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) | |
//!@endcond | |
/*! \def RAPIDJSON_PARSE_ERROR_NORETURN | |
\ingroup RAPIDJSON_ERRORS | |
\brief Macro to indicate a parse error. | |
\param parseErrorCode \ref rapidjson::ParseErrorCode of the error | |
\param offset position of the error in JSON input (\c size_t) | |
This macros can be used as a customization point for the internal | |
error handling mechanism of RapidJSON. | |
A common usage model is to throw an exception instead of requiring the | |
caller to explicitly check the \ref rapidjson::GenericReader::Parse's | |
return value: | |
\code | |
#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \ | |
throw ParseException(parseErrorCode, #parseErrorCode, offset) | |
#include <stdexcept> // std::runtime_error | |
#include "rapidjson/error/error.h" // rapidjson::ParseResult | |
struct ParseException : std::runtime_error, rapidjson::ParseResult { | |
ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset) | |
: std::runtime_error(msg), ParseResult(code, offset) {} | |
}; | |
#include "rapidjson/reader.h" | |
\endcode | |
\see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse | |
*/ | |
#ifndef RAPIDJSON_PARSE_ERROR_NORETURN | |
#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ | |
RAPIDJSON_MULTILINEMACRO_BEGIN \ | |
RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ | |
SetParseError(parseErrorCode, offset); \ | |
RAPIDJSON_MULTILINEMACRO_END | |
#endif | |
/*! \def RAPIDJSON_PARSE_ERROR | |
\ingroup RAPIDJSON_ERRORS | |
\brief (Internal) macro to indicate and handle a parse error. | |
\param parseErrorCode \ref rapidjson::ParseErrorCode of the error | |
\param offset position of the error in JSON input (\c size_t) | |
Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing. | |
\see RAPIDJSON_PARSE_ERROR_NORETURN | |
\hideinitializer | |
*/ | |
#ifndef RAPIDJSON_PARSE_ERROR | |
#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \ | |
RAPIDJSON_MULTILINEMACRO_BEGIN \ | |
RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ | |
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ | |
RAPIDJSON_MULTILINEMACRO_END | |
#endif | |
#include "error/error.h" // ParseErrorCode, ParseResult | |
RAPIDJSON_NAMESPACE_BEGIN | |
/////////////////////////////////////////////////////////////////////////////// | |
// ParseFlag | |
/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS | |
\ingroup RAPIDJSON_CONFIG | |
\brief User-defined kParseDefaultFlags definition. | |
User can define this as any \c ParseFlag combinations. | |
*/ | |
#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS | |
#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags | |
#endif | |
//! Combination of parseFlags | |
/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream | |
*/ | |
enum ParseFlag { | |
kParseNoFlags = 0, //!< No flags are set. | |
kParseInsituFlag = 1, //!< In-situ(destructive) parsing. | |
kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. | |
kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. | |
kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. | |
kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower). | |
kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// Handler | |
/*! \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 event publisher should terminate the process. | |
\code | |
concept Handler { | |
typename Ch; | |
bool Null(); | |
bool Bool(bool b); | |
bool Int(int i); | |
bool Uint(unsigned i); | |
bool Int64(int64_t i); | |
bool Uint64(uint64_t i); | |
bool Double(double d); | |
bool String(const Ch* str, SizeType length, bool copy); | |
bool StartObject(); | |
bool Key(const Ch* str, SizeType length, bool copy); | |
bool EndObject(SizeType memberCount); | |
bool StartArray(); | |
bool EndArray(SizeType elementCount); | |
}; | |
\endcode | |
*/ | |
/////////////////////////////////////////////////////////////////////////////// | |
// BaseReaderHandler | |
//! Default implementation of Handler. | |
/*! This can be used as base class of any reader handler. | |
\note implements Handler concept | |
*/ | |
template<typename Encoding = UTF8<>, typename Derived = void> | |
struct BaseReaderHandler { | |
typedef typename Encoding::Ch Ch; | |
typedef typename internal::SelectIf<internal::IsSame<Derived, void>, BaseReaderHandler, Derived>::Type Override; | |
bool Default() { return true; } | |
bool Null() { return static_cast<Override&>(*this).Default(); } | |
bool Bool(bool) { return static_cast<Override&>(*this).Default(); } | |
bool Int(int) { return static_cast<Override&>(*this).Default(); } | |
bool Uint(unsigned) { return static_cast<Override&>(*this).Default(); } | |
bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); } | |
bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); } | |
bool Double(double) { return static_cast<Override&>(*this).Default(); } | |
bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); } | |
bool StartObject() { return static_cast<Override&>(*this).Default(); } | |
bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); } | |
bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); } | |
bool StartArray() { return static_cast<Override&>(*this).Default(); } | |
bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); } | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// StreamLocalCopy | |
namespace internal { | |
template<typename Stream, int = StreamTraits<Stream>::copyOptimization> | |
class StreamLocalCopy; | |
//! Do copy optimization. | |
template<typename Stream> | |
class StreamLocalCopy<Stream, 1> { | |
public: | |
StreamLocalCopy(Stream& original) : s(original), original_(original) {} | |
~StreamLocalCopy() { original_ = s; } | |
Stream s; | |
private: | |
StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; | |
Stream& original_; | |
}; | |
//! Keep reference. | |
template<typename Stream> | |
class StreamLocalCopy<Stream, 0> { | |
public: | |
StreamLocalCopy(Stream& original) : s(original) {} | |
Stream& s; | |
private: | |
StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; | |
}; | |
} // namespace internal | |
/////////////////////////////////////////////////////////////////////////////// | |
// SkipWhitespace | |
//! Skip the JSON white spaces in a stream. | |
/*! \param is A input stream for skipping white spaces. | |
\note This function has SSE2/SSE4.2 specialization. | |
*/ | |
template<typename InputStream> | |
void SkipWhitespace(InputStream& is) { | |
internal::StreamLocalCopy<InputStream> copy(is); | |
InputStream& s(copy.s); | |
while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t') | |
s.Take(); | |
} | |
#ifdef RAPIDJSON_SSE42 | |
//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. | |
inline const char *SkipWhitespace_SIMD(const char* p) { | |
// Fast return for single non-whitespace | |
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') | |
++p; | |
else | |
return p; | |
// 16-byte align to the next boundary | |
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & ~15); | |
while (p != nextAligned) | |
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') | |
++p; | |
else | |
return p; | |
// The rest of string using SIMD | |
static const char whitespace[16] = " \n\r\t"; | |
const __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]); | |
for (;; p += 16) { | |
const __m128i s = _mm_load_si128((const __m128i *)p); | |
const unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); | |
if (r != 0) { // some of characters is non-whitespace | |
#ifdef _MSC_VER // Find the index of first non-whitespace | |
unsigned long offset; | |
_BitScanForward(&offset, r); | |
return p + offset; | |
#else | |
return p + __builtin_ffs(r) - 1; | |
#endif | |
} | |
} | |
} | |
#elif defined(RAPIDJSON_SSE2) | |
//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. | |
inline const char *SkipWhitespace_SIMD(const char* p) { | |
// Fast return for single non-whitespace | |
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') | |
++p; | |
else | |
return p; | |
// 16-byte align to the next boundary | |
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & ~15); | |
while (p != nextAligned) | |
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') | |
++p; | |
else | |
return p; | |
// The rest of string | |
static const char whitespaces[4][17] = { | |
" ", | |
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", | |
"\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", | |
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; | |
const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]); | |
const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); | |
const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); | |
const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); | |
for (;; p += 16) { | |
const __m128i s = _mm_load_si128((const __m128i *)p); | |
__m128i x = _mm_cmpeq_epi8(s, w0); | |
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); | |
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); | |
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); | |
unsigned short r = (unsigned short)~_mm_movemask_epi8(x); | |
if (r != 0) { // some of characters may be non-whitespace | |
#ifdef _MSC_VER // Find the index of first non-whitespace | |
unsigned long offset; | |
_BitScanForward(&offset, r); | |
return p + offset; | |
#else | |
return p + __builtin_ffs(r) - 1; | |
#endif | |
} | |
} | |
} | |
#endif // RAPIDJSON_SSE2 | |
#ifdef RAPIDJSON_SIMD | |
//! Template function specialization for InsituStringStream | |
template<> inline void SkipWhitespace(InsituStringStream& is) { | |
is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_)); | |
} | |
//! Template function specialization for StringStream | |
template<> inline void SkipWhitespace(StringStream& is) { | |
is.src_ = SkipWhitespace_SIMD(is.src_); | |
} | |
#endif // RAPIDJSON_SIMD | |
/////////////////////////////////////////////////////////////////////////////// | |
// 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 | |
object implementing Handler concept. | |
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 | |
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. | |
*/ | |
template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator = CrtAllocator> | |
class GenericReader { | |
public: | |
typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type | |
//! Constructor. | |
/*! \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_() {} | |
//! Parse JSON text. | |
/*! \tparam parseFlags Combination of \ref ParseFlag. | |
\tparam InputStream Type of input stream, implementing Stream concept. | |
\tparam Handler Type of handler, implementing Handler concept. | |
\param is Input stream to be parsed. | |
\param handler The handler to receive events. | |
\return Whether the parsing is successful. | |
*/ | |
template <unsigned parseFlags, typename InputStream, typename Handler> | |
ParseResult Parse(InputStream& is, Handler& handler) { | |
if (parseFlags & kParseIterativeFlag) | |
return IterativeParse<parseFlags>(is, handler); | |
parseResult_.Clear(); | |
ClearStackOnExit scope(*this); | |
SkipWhitespace(is); | |
if (is.Peek() == '\0') { | |
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); | |
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); | |
} | |
else { | |
ParseValue<parseFlags>(is, handler); | |
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); | |
if (!(parseFlags & kParseStopWhenDoneFlag)) { | |
SkipWhitespace(is); | |
if (is.Peek() != '\0') { | |
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); | |
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); | |
} | |
} | |
} | |
return parseResult_; | |
} | |
//! Parse JSON text (with \ref kParseDefaultFlags) | |
/*! \tparam InputStream Type of input stream, implementing Stream concept | |
\tparam Handler Type of handler, implementing Handler concept. | |
\param is Input stream to be parsed. | |
\param handler The handler to receive events. | |
\return Whether the parsing is successful. | |
*/ | |
template <typename InputStream, typename Handler> | |
ParseResult Parse(InputStream& is, Handler& handler) { | |
return Parse<kParseDefaultFlags>(is, handler); | |
} | |
//! 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(); } | |
//! Get the position of last parsing error in input, 0 otherwise. | |
size_t GetErrorOffset() const { return parseResult_.Offset(); } | |
protected: | |
void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); } | |
private: | |
// Prohibit copy constructor & assignment operator. | |
GenericReader(const GenericReader&); | |
GenericReader& operator=(const GenericReader&); | |
void ClearStack() { stack_.Clear(); } | |
// clear stack on any exit from ParseStream, e.g. due to exception | |
struct ClearStackOnExit { | |
explicit ClearStackOnExit(GenericReader& r) : r_(r) {} | |
~ClearStackOnExit() { r_.ClearStack(); } | |
private: | |
GenericReader& r_; | |
ClearStackOnExit(const ClearStackOnExit&); | |
ClearStackOnExit& operator=(const ClearStackOnExit&); | |
}; | |
// Parse object: { string : value, ... } | |
template<unsigned parseFlags, typename InputStream, typename Handler> | |
void ParseObject(InputStream& is, Handler& handler) { | |
RAPIDJSON_ASSERT(is.Peek() == '{'); | |
is.Take(); // Skip '{' | |
if (!handler.StartObject()) | |
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); | |
SkipWhitespace(is); | |
if (is.Peek() == '}') { | |
is.Take(); | |
if (!handler.EndObject(0)) // empty object | |
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); | |
return; | |
} | |
for (SizeType memberCount = 0;;) { | |
if (is.Peek() != '"') | |
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); | |
ParseString<parseFlags>(is, handler, true); | |
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; | |
SkipWhitespace(is); | |
if (is.Take() != ':') | |
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); | |
SkipWhitespace(is); | |
ParseValue<parseFlags>(is, handler); | |
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; | |
SkipWhitespace(is); | |
++memberCount; | |
switch (is.Take()) { | |
case ',': SkipWhitespace(is); break; | |
case '}': | |
if (!handler.EndObject(memberCount)) | |
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); | |
return; | |
default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); | |
} | |
} | |
} | |
// Parse array: [ value, ... ] | |
template<unsigned parseFlags, typename InputStream, typename Handler> | |
void ParseArray(InputStream& is, Handler& handler) { | |
RAPIDJSON_ASSERT(is.Peek() == '['); | |
is.Take(); // Skip '[' | |
if (!handler.StartArray()) | |
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); | |
SkipWhitespace(is); | |
if (is.Peek() == ']') { | |
is.Take(); | |
if (!handler.EndArray(0)) // empty array | |
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); | |
return; | |
} | |
for (SizeType elementCount = 0;;) { | |
ParseValue<parseFlags>(is, handler); | |
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; | |
++elementCount; | |
SkipWhitespace(is); | |
switch (is.Take()) { | |
case ',': SkipWhitespace(is); break; | |
case ']': | |
if (!handler.EndArray(elementCount)) | |
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); | |
return; | |
default: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); | |
} | |
} | |
} | |
template<unsigned parseFlags, typename InputStream, typename Handler> | |
void ParseNull(InputStream& is, Handler& handler) { | |
RAPIDJSON_ASSERT(is.Peek() == 'n'); | |
is.Take(); | |
if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l') { | |
if (!handler.Null()) | |
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); | |
} | |
else | |
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); | |
} | |
template<unsigned parseFlags, typename InputStream, typename Handler> | |
void ParseTrue(InputStream& is, Handler& handler) { | |
RAPIDJSON_ASSERT(is.Peek() == 't'); | |
is.Take(); | |
if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e') { | |
if (!handler.Bool(true)) | |
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); | |
} | |
else | |
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); | |
} | |
template<unsigned parseFlags, typename InputStream, typename Handler> | |
void ParseFalse(InputStream& is, Handler& handler) { | |
RAPIDJSON_ASSERT(is.Peek() == 'f'); | |
is.Take(); | |
if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e') { | |
if (!handler.Bool(false)) | |
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); | |
} | |
else | |
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); | |
} | |
// Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). | |
template<typename InputStream> | |
unsigned ParseHex4(InputStream& is) { | |
unsigned codepoint = 0; | |
for (int i = 0; i < 4; i++) { | |
Ch c = is.Take(); | |
codepoint <<= 4; | |
codepoint += static_cast<unsigned>(c); | |
if (c >= '0' && c <= '9') | |
codepoint -= '0'; | |
else if (c >= 'A' && c <= 'F') | |
codepoint -= 'A' - 10; | |
else if (c >= 'a' && c <= 'f') | |
codepoint -= 'a' - 10; | |
else { | |
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, is.Tell() - 1); | |
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); | |
} | |
} | |
return codepoint; | |
} | |
template <typename CharType> | |
class StackStream { | |
public: | |
typedef CharType Ch; | |
StackStream(internal::Stack<StackAllocator>& stack) : stack_(stack), length_(0) {} | |
RAPIDJSON_FORCEINLINE void Put(Ch c) { | |
*stack_.template Push<Ch>() = c; | |
++length_; | |
} | |
size_t Length() const { return length_; } | |
Ch* Pop() { | |
return stack_.template Pop<Ch>(length_); | |
} | |
private: | |
StackStream(const StackStream&); | |
StackStream& operator=(const StackStream&); | |
internal::Stack<StackAllocator>& stack_; | |
SizeType length_; | |
}; | |
// Parse string and generate String event. Different code paths for kParseInsituFlag. | |
template<unsigned parseFlags, typename InputStream, typename Handler> | |
void ParseString(InputStream& is, Handler& handler, bool isKey = false) { | |
internal::StreamLocalCopy<InputStream> copy(is); | |
InputStream& s(copy.s); | |
bool success = false; | |
if (parseFlags & kParseInsituFlag) { | |
typename InputStream::Ch *head = s.PutBegin(); | |
ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s); | |
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; | |
size_t length = s.PutEnd(head) - 1; | |
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); | |
const typename TargetEncoding::Ch* const str = (typename TargetEncoding::Ch*)head; | |
success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false)); | |
} | |
else { | |
StackStream<typename TargetEncoding::Ch> stackStream(stack_); | |
ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream); | |
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; | |
SizeType length = static_cast<SizeType>(stackStream.Length()) - 1; | |
const typename TargetEncoding::Ch* const str = stackStream.Pop(); | |
success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true)); | |
} | |
if (!success) | |
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); | |
} | |
// Parse string to an output is | |
// This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. | |
template<unsigned parseFlags, typename SEncoding, typename TEncoding, typename InputStream, typename OutputStream> | |
RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) { | |
//!@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, Z16, Z16, Z16, Z16, Z16, Z16 | |
}; | |
#undef Z16 | |
//!@endcond | |
RAPIDJSON_ASSERT(is.Peek() == '\"'); | |
is.Take(); // Skip '\"' | |
for (;;) { | |
Ch c = is.Peek(); | |
if (c == '\\') { // Escape | |
is.Take(); | |
Ch e = is.Take(); | |
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e]) { | |
os.Put(escape[(unsigned char)e]); | |
} | |
else if (e == 'u') { // Unicode | |
unsigned codepoint = ParseHex4(is); | |
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; | |
if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { | |
// Handle UTF-16 surrogate pair | |
if (is.Take() != '\\' || is.Take() != 'u') | |
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); | |
unsigned codepoint2 = ParseHex4(is); | |
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; | |
if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) | |
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); | |
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; | |
} | |
TEncoding::Encode(os, codepoint); | |
} | |
else | |
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); | |
} | |
else if (c == '"') { // Closing double quote | |
is.Take(); | |
os.Put('\0'); // null-terminate the string | |
return; | |
} | |
else if (c == '\0') | |
RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1); | |
else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF | |
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); | |
else { | |
if (parseFlags & kParseValidateEncodingFlag ? | |
!Transcoder<SEncoding, TEncoding>::Validate(is, os) : | |
!Transcoder<SEncoding, TEncoding>::Transcode(is, os)) | |
RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); | |
} | |
} | |
} | |
template<typename InputStream, bool backup> | |
class NumberStream; | |
template<typename InputStream> | |
class NumberStream<InputStream, false> { | |
public: | |
NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } | |
~NumberStream() {} | |
RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } | |
RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } | |
RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } | |
size_t Tell() { return is.Tell(); } | |
size_t Length() { return 0; } | |
const char* Pop() { return 0; } | |
protected: | |
NumberStream& operator=(const NumberStream&); | |
InputStream& is; | |
}; | |
template<typename InputStream> | |
class NumberStream<InputStream, true> : public NumberStream<InputStream, false> { | |
typedef NumberStream<InputStream, false> Base; | |
public: | |
NumberStream(GenericReader& reader, InputStream& is) : NumberStream<InputStream, false>(reader, is), stackStream(reader.stack_) {} | |
~NumberStream() {} | |
RAPIDJSON_FORCEINLINE Ch TakePush() { | |
stackStream.Put((char)Base::is.Peek()); | |
return Base::is.Take(); | |
} | |
size_t Length() { return stackStream.Length(); } | |
const char* Pop() { | |
stackStream.Put('\0'); | |
return stackStream.Pop(); | |
} | |
private: | |
StackStream<char> stackStream; | |
}; | |
template<unsigned parseFlags, typename InputStream, typename Handler> | |
void ParseNumber(InputStream& is, Handler& handler) { | |
internal::StreamLocalCopy<InputStream> copy(is); | |
NumberStream<InputStream, (parseFlags & kParseFullPrecisionFlag) != 0> s(*this, copy.s); | |
// Parse minus | |
bool minus = false; | |
if (s.Peek() == '-') { | |
minus = true; | |
s.Take(); | |
} | |
// Parse int: zero / ( digit1-9 *DIGIT ) | |
unsigned i = 0; | |
uint64_t i64 = 0; | |
bool use64bit = false; | |
int significandDigit = 0; | |
if (s.Peek() == '0') { | |
i = 0; | |
s.TakePush(); | |
} | |
else if (s.Peek() >= '1' && s.Peek() <= '9') { | |
i = static_cast<unsigned>(s.TakePush() - '0'); | |
if (minus) | |
while (s.Peek() >= '0' && s.Peek() <= '9') { | |
if (i >= 214748364) { // 2^31 = 2147483648 | |
if (i != 214748364 || s.Peek() > '8') { | |
i64 = i; | |
use64bit = true; | |
break; | |
} | |
} | |
i = i * 10 + static_cast<unsigned>(s.TakePush() - '0'); | |
significandDigit++; | |
} | |
else | |
while (s.Peek() >= '0' && s.Peek() <= '9') { | |
if (i >= 429496729) { // 2^32 - 1 = 4294967295 | |
if (i != 429496729 || s.Peek() > '5') { | |
i64 = i; | |
use64bit = true; | |
break; | |
} | |
} | |
i = i * 10 + static_cast<unsigned>(s.TakePush() - '0'); | |
significandDigit++; | |
} | |
} | |
else | |
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); | |
// Parse 64bit int | |
bool useDouble = false; | |
double d = 0.0; | |
if (use64bit) { | |
if (minus) | |
while (s.Peek() >= '0' && s.Peek() <= '9') { | |
if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808 | |
if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') { | |
d = i64; | |
useDouble = true; | |
break; | |
} | |
i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0'); | |
significandDigit++; | |
} | |
else | |
while (s.Peek() >= '0' && s.Peek() <= '9') { | |
if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2^64 - 1 = 18446744073709551615 | |
if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5') { | |
d = i64; | |
useDouble = true; | |
break; | |
} | |
i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0'); | |
significandDigit++; | |
} | |
} | |
// Force double for big integer | |
if (useDouble) { | |
while (s.Peek() >= '0' && s.Peek() <= '9') { | |
if (d >= 1.7976931348623157e307) // DBL_MAX / 10.0 | |
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); | |
d = d * 10 + (s.TakePush() - '0'); | |
} | |
} | |
// Parse frac = decimal-point 1*DIGIT | |
int expFrac = 0; | |
size_t decimalPosition; | |
if (s.Peek() == '.') { | |
s.Take(); | |
decimalPosition = s.Length(); | |
if (!(s.Peek() >= '0' && s.Peek() <= '9')) | |
RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); | |
if (!useDouble) { | |
#if RAPIDJSON_64BIT | |
// Use i64 to store significand in 64-bit architecture | |
if (!use64bit) | |
i64 = i; | |
while (s.Peek() >= '0' && s.Peek() <= '9') { | |
if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path | |
break; | |
else { | |
i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0'); | |
--expFrac; | |
if (i64 != 0) | |
significandDigit++; | |
} | |
} | |
d = (double)i64; | |
#else | |
// Use double to store significand in 32-bit architecture | |
d = use64bit ? (double)i64 : (double)i; | |
#endif | |
useDouble = true; | |
} | |
while (s.Peek() >= '0' && s.Peek() <= '9') { | |
if (significandDigit < 17) { | |
d = d * 10.0 + (s.TakePush() - '0'); | |
--expFrac; | |
if (d > 0.0) | |
significandDigit++; | |
} | |
else | |
s.TakePush(); | |
} | |
} | |
else | |
decimalPosition = s.Length(); // decimal position at the end of integer. | |
// Parse exp = e [ minus / plus ] 1*DIGIT | |
int exp = 0; | |
if (s.Peek() == 'e' || s.Peek() == 'E') { | |
if (!useDouble) { | |
d = use64bit ? i64 : i; | |
useDouble = true; | |
} | |
s.Take(); | |
bool expMinus = false; | |
if (s.Peek() == '+') | |
s.Take(); | |
else if (s.Peek() == '-') { | |
s.Take(); | |
expMinus = true; | |
} | |
if (s.Peek() >= '0' && s.Peek() <= '9') { | |
exp = s.Take() - '0'; | |
if (expMinus) { | |
while (s.Peek() >= '0' && s.Peek() <= '9') { | |
exp = exp * 10 + (s.Take() - '0'); | |
if (exp >= 214748364) { // Issue #313: prevent overflow exponent | |
while (s.Peek() >= '0' && s.Peek() <= '9') // Consume the rest of exponent | |
s.Take(); | |
} | |
} | |
} | |
else { // positive exp | |
int maxExp = 308 - expFrac; | |
while (s.Peek() >= '0' && s.Peek() <= '9') { | |
exp = exp * 10 + (s.Take() - '0'); | |
if (exp > maxExp) | |
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); | |
} | |
} | |
} | |
else | |
RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); | |
if (expMinus) | |
exp = -exp; | |
} | |
// Finish parsing, call event according to the type of number. | |
bool cont = true; | |
size_t length = s.Length(); | |
const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not. | |
if (useDouble) { | |
int p = exp + expFrac; | |
if (parseFlags & kParseFullPrecisionFlag) | |
d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp); | |
else | |
d = internal::StrtodNormalPrecision(d, p); | |
cont = handler.Double(minus ? -d : d); | |
} | |
else { | |
if (use64bit) { | |
if (minus) | |
cont = handler.Int64(static_cast<int64_t>(~i64 + 1)); | |
else | |
cont = handler.Uint64(i64); | |
} | |
else { | |
if (minus) | |
cont = handler.Int(static_cast<int32_t>(~i + 1)); | |
else | |
cont = handler.Uint(i); | |
} | |
} | |
if (!cont) | |
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); | |
} | |
// Parse any JSON value | |
template<unsigned parseFlags, typename InputStream, typename Handler> | |
void ParseValue(InputStream& is, Handler& handler) { | |
switch (is.Peek()) { | |
case 'n': ParseNull <parseFlags>(is, handler); break; | |
case 't': ParseTrue <parseFlags>(is, handler); break; | |
case 'f': ParseFalse <parseFlags>(is, handler); break; | |
case '"': ParseString<parseFlags>(is, handler); break; | |
case '{': ParseObject<parseFlags>(is, handler); break; | |
case '[': ParseArray <parseFlags>(is, handler); break; | |
default : ParseNumber<parseFlags>(is, handler); | |
} | |
} | |
// Iterative Parsing | |
// States | |
enum IterativeParsingState { | |
IterativeParsingStartState = 0, | |
IterativeParsingFinishState, | |
IterativeParsingErrorState, | |
// Object states | |
IterativeParsingObjectInitialState, | |
IterativeParsingMemberKeyState, | |
IterativeParsingKeyValueDelimiterState, | |
IterativeParsingMemberValueState, | |
IterativeParsingMemberDelimiterState, | |
IterativeParsingObjectFinishState, | |
// Array states | |
IterativeParsingArrayInitialState, | |
IterativeParsingElementState, | |
IterativeParsingElementDelimiterState, | |
IterativeParsingArrayFinishState, | |
// Single value state | |
IterativeParsingValueState, | |
cIterativeParsingStateCount | |
}; | |
// Tokens | |
enum Token { | |
LeftBracketToken = 0, | |
RightBracketToken, | |
LeftCurlyBracketToken, | |
RightCurlyBracketToken, | |
CommaToken, | |
ColonToken, | |
StringToken, | |
FalseToken, | |
TrueToken, | |
NullToken, | |
NumberToken, | |
kTokenCount | |
}; | |
RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) { | |
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN | |
#define N NumberToken | |
#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N | |
// Maps from ASCII to Token | |
static const unsigned char tokenMap[256] = { | |
N16, // 00~0F | |
N16, // 10~1F | |
N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F | |
N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F | |
N16, // 40~4F | |
N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F | |
N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F | |
N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F | |
N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF | |
}; | |
#undef N | |
#undef N16 | |
//!@endcond | |
if (sizeof(Ch) == 1 || unsigned(c) < 256) | |
return (Token)tokenMap[(unsigned char)c]; | |
else | |
return NumberToken; | |
} | |
RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { | |
// current state x one lookahead token -> new state | |
static const char G[cIterativeParsingStateCount][kTokenCount] = { | |
// Start | |
{ | |
IterativeParsingArrayInitialState, // Left bracket | |
IterativeParsingErrorState, // Right bracket | |
IterativeParsingObjectInitialState, // Left curly bracket | |
IterativeParsingErrorState, // Right curly bracket | |
IterativeParsingErrorState, // Comma | |
IterativeParsingErrorState, // Colon | |
IterativeParsingValueState, // String | |
IterativeParsingValueState, // False | |
IterativeParsingValueState, // True | |
IterativeParsingValueState, // Null | |
IterativeParsingValueState // Number | |
}, | |
// Finish(sink state) | |
{ | |
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, | |
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, | |
IterativeParsingErrorState | |
}, | |
// Error(sink state) | |
{ | |
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, | |
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, | |
IterativeParsingErrorState | |
}, | |
// ObjectInitial | |
{ | |
IterativeParsingErrorState, // Left bracket | |
IterativeParsingErrorState, // Right bracket | |
IterativeParsingErrorState, // Left curly bracket | |
IterativeParsingObjectFinishState, // Right curly bracket | |
IterativeParsingErrorState, // Comma | |
IterativeParsingErrorState, // Colon | |
IterativeParsingMemberKeyState, // String | |
IterativeParsingErrorState, // False | |
IterativeParsingErrorState, // True | |
IterativeParsingErrorState, // Null | |
IterativeParsingErrorState // Number | |
}, | |
// MemberKey | |
{ | |
IterativeParsingErrorState, // Left bracket | |
IterativeParsingErrorState, // Right bracket | |
IterativeParsingErrorState, // Left curly bracket | |
IterativeParsingErrorState, // Right curly bracket | |
IterativeParsingErrorState, // Comma | |
IterativeParsingKeyValueDelimiterState, // Colon | |
IterativeParsingErrorState, // String | |
IterativeParsingErrorState, // False | |
IterativeParsingErrorState, // True | |
IterativeParsingErrorState, // Null | |
IterativeParsingErrorState // Number | |
}, | |
// KeyValueDelimiter | |
{ | |
IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) | |
IterativeParsingErrorState, // Right bracket | |
IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) | |
IterativeParsingErrorState, // Right curly bracket | |
IterativeParsingErrorState, // Comma | |
IterativeParsingErrorState, // Colon | |
IterativeParsingMemberValueState, // String | |
IterativeParsingMemberValueState, // False | |
IterativeParsingMemberValueState, // True | |
IterativeParsingMemberValueState, // Null | |
IterativeParsingMemberValueState // Number | |
}, | |
// MemberValue | |
{ | |
IterativeParsingErrorState, // Left bracket | |
IterativeParsingErrorState, // Right bracket | |
IterativeParsingErrorState, // Left curly bracket | |
IterativeParsingObjectFinishState, // Right curly bracket | |
IterativeParsingMemberDelimiterState, // Comma | |
IterativeParsingErrorState, // Colon | |
IterativeParsingErrorState, // String | |
IterativeParsingErrorState, // False | |
IterativeParsingErrorState, // True | |
IterativeParsingErrorState, // Null | |
IterativeParsingErrorState // Number | |
}, | |
// MemberDelimiter | |
{ | |
IterativeParsingErrorState, // Left bracket | |
IterativeParsingErrorState, // Right bracket | |
IterativeParsingErrorState, // Left curly bracket | |
IterativeParsingErrorState, // Right curly bracket | |
IterativeParsingErrorState, // Comma | |
IterativeParsingErrorState, // Colon | |
IterativeParsingMemberKeyState, // String | |
IterativeParsingErrorState, // False | |
IterativeParsingErrorState, // True | |
IterativeParsingErrorState, // Null | |
IterativeParsingErrorState // Number | |
}, | |
// ObjectFinish(sink state) | |
{ | |
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, | |
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, | |
IterativeParsingErrorState | |
}, | |
// ArrayInitial | |
{ | |
IterativeParsingArrayInitialState, // Left bracket(push Element state) | |
IterativeParsingArrayFinishState, // Right bracket | |
IterativeParsingObjectInitialState, // Left curly bracket(push Element state) | |
IterativeParsingErrorState, // Right curly bracket | |
IterativeParsingErrorState, // Comma | |
IterativeParsingErrorState, // Colon | |
IterativeParsingElementState, // String | |
IterativeParsingElementState, // False | |
IterativeParsingElementState, // True | |
IterativeParsingElementState, // Null | |
IterativeParsingElementState // Number | |
}, | |
// Element | |
{ | |
IterativeParsingErrorState, // Left bracket | |
IterativeParsingArrayFinishState, // Right bracket | |
IterativeParsingErrorState, // Left curly bracket | |
IterativeParsingErrorState, // Right curly bracket | |
IterativeParsingElementDelimiterState, // Comma | |
IterativeParsingErrorState, // Colon | |
IterativeParsingErrorState, // String | |
IterativeParsingErrorState, // False | |
IterativeParsingErrorState, // True | |
IterativeParsingErrorState, // Null | |
IterativeParsingErrorState // Number | |
}, | |
// ElementDelimiter | |
{ | |
IterativeParsingArrayInitialState, // Left bracket(push Element state) | |
IterativeParsingErrorState, // Right bracket | |
IterativeParsingObjectInitialState, // Left curly bracket(push Element state) | |
IterativeParsingErrorState, // Right curly bracket | |
IterativeParsingErrorState, // Comma | |
IterativeParsingErrorState, // Colon | |
IterativeParsingElementState, // String | |
IterativeParsingElementState, // False | |
IterativeParsingElementState, // True | |
IterativeParsingElementState, // Null | |
IterativeParsingElementState // Number | |
}, | |
// ArrayFinish(sink state) | |
{ | |
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, | |
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, | |
IterativeParsingErrorState | |
}, | |
// Single Value (sink state) | |
{ | |
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, | |
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, | |
IterativeParsingErrorState | |
} | |
}; // End of G | |
return (IterativeParsingState)G[state][token]; | |
} | |
// Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). | |
// May return a new state on state pop. | |
template <unsigned parseFlags, typename InputStream, typename Handler> | |
RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { | |
(void)token; | |
switch (dst) { | |
case IterativeParsingErrorState: | |
return dst; | |
case IterativeParsingObjectInitialState: | |
case IterativeParsingArrayInitialState: | |
{ | |
// Push the state(Element or MemeberValue) if we are nested in another array or value of member. | |
// In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop. | |
IterativeParsingState n = src; | |
if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState) | |
n = IterativeParsingElementState; | |
else if (src == IterativeParsingKeyValueDelimiterState) | |
n = IterativeParsingMemberValueState; | |
// Push current state. | |
*stack_.template Push<SizeType>(1) = n; | |
// Initialize and push the member/element count. | |
*stack_.template Push<SizeType>(1) = 0; | |
// Call handler | |
bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray(); | |
// On handler short circuits the parsing. | |
if (!hr) { | |
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); | |
return IterativeParsingErrorState; | |
} | |
else { | |
is.Take(); | |
return dst; | |
} | |
} | |
case IterativeParsingMemberKeyState: | |
ParseString<parseFlags>(is, handler, true); | |
if (HasParseError()) | |
return IterativeParsingErrorState; | |
else | |
return dst; | |
case IterativeParsingKeyValueDelimiterState: | |
RAPIDJSON_ASSERT(token == ColonToken); | |
is.Take(); | |
return dst; | |
case IterativeParsingMemberValueState: | |
// Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. | |
ParseValue<parseFlags>(is, handler); | |
if (HasParseError()) { | |
return IterativeParsingErrorState; | |
} | |
return dst; | |
case IterativeParsingElementState: | |
// Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. | |
ParseValue<parseFlags>(is, handler); | |
if (HasParseError()) { | |
return IterativeParsingErrorState; | |
} | |
return dst; | |
case IterativeParsingMemberDelimiterState: | |
case IterativeParsingElementDelimiterState: | |
is.Take(); | |
// Update member/element count. | |
*stack_.template Top<SizeType>() = *stack_.template Top<SizeType>() + 1; | |
return dst; | |
case IterativeParsingObjectFinishState: | |
{ | |
// Get member count. | |
SizeType c = *stack_.template Pop<SizeType>(1); | |
// If the object is not empty, count the last member. | |
if (src == IterativeParsingMemberValueState) | |
++c; | |
// Restore the state. | |
IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1)); | |
// Transit to Finish state if this is the topmost scope. | |
if (n == IterativeParsingStartState) | |
n = IterativeParsingFinishState; | |
// Call handler | |
bool hr = handler.EndObject(c); | |
// On handler short circuits the parsing. | |
if (!hr) { | |
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); | |
return IterativeParsingErrorState; | |
} | |
else { | |
is.Take(); | |
return n; | |
} | |
} | |
case IterativeParsingArrayFinishState: | |
{ | |
// Get element count. | |
SizeType c = *stack_.template Pop<SizeType>(1); | |
// If the array is not empty, count the last element. | |
if (src == IterativeParsingElementState) | |
++c; | |
// Restore the state. | |
IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1)); | |
// Transit to Finish state if this is the topmost scope. | |
if (n == IterativeParsingStartState) | |
n = IterativeParsingFinishState; | |
// Call handler | |
bool hr = handler.EndArray(c); | |
// On handler short circuits the parsing. | |
if (!hr) { | |
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); | |
return IterativeParsingErrorState; | |
} | |
else { | |
is.Take(); | |
return n; | |
} | |
} | |
default: | |
// This branch is for IterativeParsingValueState actually. | |
// Use `default:` rather than | |
// `case IterativeParsingValueState:` is for code coverage. | |
// The IterativeParsingStartState is not enumerated in this switch-case. | |
// It is impossible for that case. And it can be caught by following assertion. | |
// The IterativeParsingFinishState is not enumerated in this switch-case either. | |
// It is a "derivative" state which cannot triggered from Predict() directly. | |
// Therefore it cannot happen here. And it can be caught by following assertion. | |
RAPIDJSON_ASSERT(dst == IterativeParsingValueState); | |
// Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. | |
ParseValue<parseFlags>(is, handler); | |
if (HasParseError()) { | |
return IterativeParsingErrorState; | |
} | |
return IterativeParsingFinishState; | |
} | |
} | |
template <typename InputStream> | |
void HandleError(IterativeParsingState src, InputStream& is) { | |
if (HasParseError()) { | |
// 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; | |
case IterativeParsingObjectInitialState: | |
case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return; | |
case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; | |
case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; | |
case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; | |
default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); | |
} | |
} | |
template <unsigned parseFlags, typename InputStream, typename Handler> | |
ParseResult IterativeParse(InputStream& is, Handler& handler) { | |
parseResult_.Clear(); | |
ClearStackOnExit scope(*this); | |
IterativeParsingState state = IterativeParsingStartState; | |
SkipWhitespace(is); | |
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; | |
SkipWhitespace(is); | |
} | |
// Handle the end of file. | |
if (state != IterativeParsingFinishState) | |
HandleError(state, is); | |
return parseResult_; | |
} | |
static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. | |
internal::Stack<StackAllocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. | |
ParseResult parseResult_; | |
}; // class GenericReader | |
//! Reader with UTF8 encoding and default allocator. | |
typedef GenericReader<UTF8<>, UTF8<> > Reader; | |
RAPIDJSON_NAMESPACE_END | |
#ifdef __GNUC__ | |
RAPIDJSON_DIAG_POP | |
#endif | |
#ifdef _MSC_VER | |
RAPIDJSON_DIAG_POP | |
#endif | |
#endif // RAPIDJSON_READER_H_ |