2011-11-18 17:01:23 +00:00
|
|
|
#ifndef RAPIDJSON_READER_H_
|
|
|
|
#define RAPIDJSON_READER_H_
|
|
|
|
|
|
|
|
// Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
|
|
|
|
// Version 0.1
|
|
|
|
|
|
|
|
#include "rapidjson.h"
|
2011-11-29 18:39:03 +00:00
|
|
|
#include "encodings.h"
|
2011-11-18 17:01:23 +00:00
|
|
|
#include "internal/pow10.h"
|
|
|
|
#include "internal/stack.h"
|
|
|
|
|
2014-07-10 13:09:15 +02:00
|
|
|
#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
|
|
|
|
#include <intrin.h>
|
|
|
|
#pragma intrinsic(_BitScanForward)
|
|
|
|
#endif
|
2011-11-18 17:01:23 +00:00
|
|
|
#ifdef RAPIDJSON_SSE42
|
|
|
|
#include <nmmintrin.h>
|
|
|
|
#elif defined(RAPIDJSON_SSE2)
|
|
|
|
#include <emmintrin.h>
|
|
|
|
#endif
|
|
|
|
|
2012-11-13 08:02:22 +00:00
|
|
|
#ifdef _MSC_VER
|
2014-07-10 13:09:15 +02:00
|
|
|
RAPIDJSON_DIAG_PUSH
|
|
|
|
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
2012-11-13 08:02:22 +00:00
|
|
|
#endif
|
|
|
|
|
2014-07-02 01:04:33 +02:00
|
|
|
#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)
|
|
|
|
|
2014-06-26 22:31:54 +08:00
|
|
|
#ifndef RAPIDJSON_PARSE_ERROR_NORETURN
|
2014-06-27 01:53:56 +08:00
|
|
|
#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \
|
2014-06-26 22:31:54 +08:00
|
|
|
RAPIDJSON_MULTILINEMACRO_BEGIN \
|
2014-06-27 22:13:02 +08:00
|
|
|
RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
|
2014-07-09 13:55:54 +02:00
|
|
|
parseResult_.Set(parseErrorCode,offset); \
|
2014-06-27 22:13:02 +08:00
|
|
|
RAPIDJSON_MULTILINEMACRO_END
|
2014-06-26 22:31:54 +08:00
|
|
|
#endif
|
|
|
|
|
2011-11-18 17:01:23 +00:00
|
|
|
#ifndef RAPIDJSON_PARSE_ERROR
|
2014-06-27 01:53:56 +08:00
|
|
|
#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \
|
2012-11-13 08:02:22 +00:00
|
|
|
RAPIDJSON_MULTILINEMACRO_BEGIN \
|
2014-06-27 01:53:56 +08:00
|
|
|
RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
|
2014-07-02 01:04:33 +02:00
|
|
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
|
2012-11-13 08:02:22 +00:00
|
|
|
RAPIDJSON_MULTILINEMACRO_END
|
2011-11-18 17:01:23 +00:00
|
|
|
#endif
|
|
|
|
|
2014-07-09 13:55:54 +02:00
|
|
|
#include "error/error.h" // ParseErrorCode, ParseResult
|
2014-07-03 17:58:59 +02:00
|
|
|
|
2011-11-18 17:01:23 +00:00
|
|
|
namespace rapidjson {
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ParseFlag
|
|
|
|
|
|
|
|
//! Combination of parseFlags
|
2014-07-05 17:07:13 +02:00
|
|
|
/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream
|
|
|
|
*/
|
2011-11-18 17:01:23 +00:00
|
|
|
enum ParseFlag {
|
|
|
|
kParseDefaultFlags = 0, //!< Default parse flags. Non-destructive parsing. Text strings are decoded into allocated buffer.
|
2011-11-22 19:29:43 +00:00
|
|
|
kParseInsituFlag = 1, //!< In-situ(destructive) parsing.
|
2014-07-06 21:15:38 +08:00
|
|
|
kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings.
|
2014-07-07 21:46:57 +08:00
|
|
|
kParseIterativeFlag = 4 //!< Iterative(constant complexity in terms of function call stack size) parsing.
|
2011-11-18 17:01:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Handler
|
|
|
|
|
|
|
|
/*! \class rapidjson::Handler
|
|
|
|
\brief Concept for receiving events from GenericReader upon parsing.
|
2014-07-10 19:33:01 +08:00
|
|
|
The functions return true if no error occurs. If they return false,
|
|
|
|
the event publisher should terminate the process.
|
2011-11-18 17:01:23 +00:00
|
|
|
\code
|
|
|
|
concept Handler {
|
|
|
|
typename Ch;
|
|
|
|
|
2014-07-10 19:33:01 +08:00
|
|
|
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 EndObject(SizeType memberCount);
|
|
|
|
bool StartArray();
|
|
|
|
bool EndArray(SizeType elementCount);
|
2011-11-18 17:01:23 +00:00
|
|
|
};
|
|
|
|
\endcode
|
|
|
|
*/
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// BaseReaderHandler
|
|
|
|
|
|
|
|
//! Default implementation of Handler.
|
|
|
|
/*! This can be used as base class of any reader handler.
|
2014-06-25 19:21:17 +08:00
|
|
|
\note implements Handler concept
|
2011-11-18 17:01:23 +00:00
|
|
|
*/
|
|
|
|
template<typename Encoding = UTF8<> >
|
|
|
|
struct BaseReaderHandler {
|
|
|
|
typedef typename Encoding::Ch Ch;
|
|
|
|
|
2014-07-10 19:33:01 +08:00
|
|
|
bool Default() { return true; }
|
|
|
|
bool Null() { return Default(); }
|
|
|
|
bool Bool(bool) { return Default(); }
|
|
|
|
bool Int(int) { return Default(); }
|
|
|
|
bool Uint(unsigned) { return Default(); }
|
|
|
|
bool Int64(int64_t) { return Default(); }
|
|
|
|
bool Uint64(uint64_t) { return Default(); }
|
|
|
|
bool Double(double) { return Default(); }
|
|
|
|
bool String(const Ch*, SizeType, bool) { return Default(); }
|
|
|
|
bool StartObject() { return Default(); }
|
|
|
|
bool EndObject(SizeType) { return Default(); }
|
|
|
|
bool StartArray() { return Default(); }
|
|
|
|
bool EndArray(SizeType) { return Default(); }
|
2011-11-18 17:01:23 +00:00
|
|
|
};
|
|
|
|
|
2014-07-02 21:26:44 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// StreamLocalCopy
|
|
|
|
|
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
template<typename Stream, int = StreamTraits<Stream>::copyOptimization>
|
|
|
|
class StreamLocalCopy;
|
|
|
|
|
2014-07-06 21:15:38 +08:00
|
|
|
//! Do copy optimization.
|
2014-07-02 21:26:44 +02:00
|
|
|
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
|
|
|
|
|
2011-11-18 17:01:23 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// SkipWhitespace
|
|
|
|
|
|
|
|
//! Skip the JSON white spaces in a stream.
|
2014-06-25 19:21:17 +08:00
|
|
|
/*! \param is A input stream for skipping white spaces.
|
2011-11-18 17:01:23 +00:00
|
|
|
\note This function has SSE2/SSE4.2 specialization.
|
|
|
|
*/
|
2011-12-03 09:57:17 +00:00
|
|
|
template<typename InputStream>
|
|
|
|
void SkipWhitespace(InputStream& is) {
|
2014-07-02 21:26:44 +02:00
|
|
|
internal::StreamLocalCopy<InputStream> copy(is);
|
2014-07-02 20:51:10 +02:00
|
|
|
InputStream& s(copy.s);
|
|
|
|
|
|
|
|
while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
|
|
|
|
s.Take();
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#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) {
|
|
|
|
static const char whitespace[16] = " \n\r\t";
|
|
|
|
__m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]);
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
__m128i s = _mm_loadu_si128((const __m128i *)p);
|
|
|
|
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) // all 16 characters are whitespace
|
|
|
|
p += 16;
|
|
|
|
else { // some of characters may be non-whitespace
|
|
|
|
#ifdef _MSC_VER // Find the index of first non-whitespace
|
|
|
|
unsigned long offset;
|
|
|
|
if (_BitScanForward(&offset, r))
|
|
|
|
return p + offset;
|
|
|
|
#else
|
|
|
|
if (r != 0)
|
|
|
|
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) {
|
|
|
|
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"};
|
|
|
|
|
|
|
|
__m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]);
|
|
|
|
__m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]);
|
|
|
|
__m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]);
|
|
|
|
__m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]);
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
__m128i s = _mm_loadu_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));
|
2014-07-03 16:52:49 +02:00
|
|
|
unsigned short r = (unsigned short)~_mm_movemask_epi8(x);
|
2011-11-18 17:01:23 +00:00
|
|
|
if (r == 0) // all 16 characters are whitespace
|
|
|
|
p += 16;
|
|
|
|
else { // some of characters may be non-whitespace
|
|
|
|
#ifdef _MSC_VER // Find the index of first non-whitespace
|
|
|
|
unsigned long offset;
|
|
|
|
if (_BitScanForward(&offset, r))
|
|
|
|
return p + offset;
|
|
|
|
#else
|
|
|
|
if (r != 0)
|
|
|
|
return p + __builtin_ffs(r) - 1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // RAPIDJSON_SSE2
|
|
|
|
|
|
|
|
#ifdef RAPIDJSON_SIMD
|
|
|
|
//! Template function specialization for InsituStringStream
|
2011-12-03 09:57:17 +00:00
|
|
|
template<> inline void SkipWhitespace(InsituStringStream& is) {
|
|
|
|
is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_));
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//! Template function specialization for StringStream
|
2011-12-03 09:57:17 +00:00
|
|
|
template<> inline void SkipWhitespace(StringStream& is) {
|
|
|
|
is.src_ = SkipWhitespace_SIMD(is.src_);
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
#endif // RAPIDJSON_SIMD
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// GenericReader
|
|
|
|
|
2014-07-05 17:07:13 +02:00
|
|
|
//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator.
|
2011-11-18 17:01:23 +00:00
|
|
|
/*! 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.
|
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
\tparam SourceEncoding Encoding of the input stream.
|
|
|
|
\tparam TargetEncoding Encoding of the parse output.
|
2011-11-18 17:01:23 +00:00
|
|
|
\tparam Allocator Allocator type for stack.
|
|
|
|
*/
|
2011-11-28 09:30:32 +00:00
|
|
|
template <typename SourceEncoding, typename TargetEncoding, typename Allocator = MemoryPoolAllocator<> >
|
2011-11-18 17:01:23 +00:00
|
|
|
class GenericReader {
|
|
|
|
public:
|
2014-07-05 17:07:13 +02:00
|
|
|
typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type
|
2011-11-18 17:01:23 +00:00
|
|
|
|
|
|
|
//! Constructor.
|
2014-07-15 14:16:06 +08:00
|
|
|
/*! \param limit Parsing stack size limit(in bytes). Pass 0 means no limit.
|
|
|
|
\param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
|
2011-11-18 17:01:23 +00:00
|
|
|
\param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
|
|
|
|
*/
|
2014-07-15 14:16:06 +08:00
|
|
|
GenericReader(size_t limit = 0, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), kStackSizeLimit(limit), parseResult_() {}
|
2011-11-18 17:01:23 +00:00
|
|
|
|
|
|
|
//! Parse JSON text.
|
2014-07-05 17:07:13 +02:00
|
|
|
/*! \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.
|
2011-11-18 17:01:23 +00:00
|
|
|
*/
|
2011-12-03 09:57:17 +00:00
|
|
|
template <unsigned parseFlags, typename InputStream, typename Handler>
|
2014-07-09 13:55:54 +02:00
|
|
|
ParseResult Parse(InputStream& is, Handler& handler) {
|
2014-07-07 21:46:57 +08:00
|
|
|
if (parseFlags & kParseIterativeFlag)
|
|
|
|
return IterativeParse<parseFlags>(is, handler);
|
2014-07-06 21:15:38 +08:00
|
|
|
|
2014-07-09 13:55:54 +02:00
|
|
|
parseResult_.Clear();
|
2011-11-18 17:01:23 +00:00
|
|
|
|
2014-07-02 01:04:33 +02:00
|
|
|
ClearStackOnExit scope(*this);
|
2014-07-14 23:49:57 +08:00
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
SkipWhitespace(is);
|
2011-11-18 17:01:23 +00:00
|
|
|
|
2014-07-02 01:04:33 +02:00
|
|
|
if (is.Peek() == '\0') {
|
2014-06-27 01:53:56 +08:00
|
|
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
|
2014-07-09 13:55:54 +02:00
|
|
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
2014-07-02 01:04:33 +02:00
|
|
|
}
|
2011-11-18 17:01:23 +00:00
|
|
|
else {
|
2011-12-03 09:57:17 +00:00
|
|
|
switch (is.Peek()) {
|
2014-06-26 23:14:05 +08:00
|
|
|
case '{': ParseObject<parseFlags>(is, handler); break;
|
|
|
|
case '[': ParseArray<parseFlags>(is, handler); break;
|
2014-06-27 01:53:56 +08:00
|
|
|
default: RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotObjectOrArray, is.Tell());
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
2014-07-09 13:55:54 +02:00
|
|
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
2014-06-27 22:27:18 +08:00
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
SkipWhitespace(is);
|
2011-11-18 17:01:23 +00:00
|
|
|
|
2014-07-02 01:04:33 +02:00
|
|
|
if (is.Peek() != '\0') {
|
2014-06-27 01:53:56 +08:00
|
|
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
|
2014-07-09 13:55:54 +02:00
|
|
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
|
2014-07-02 01:04:33 +02:00
|
|
|
}
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
|
2014-07-09 13:55:54 +02:00
|
|
|
return parseResult_;
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
|
2014-07-05 17:07:13 +02:00
|
|
|
//! 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.
|
|
|
|
*/
|
2014-06-29 15:03:38 +08:00
|
|
|
template <typename InputStream, typename Handler>
|
2014-07-09 13:55:54 +02:00
|
|
|
ParseResult Parse(InputStream& is, Handler& handler) {
|
2014-07-02 01:08:46 +02:00
|
|
|
return Parse<kParseDefaultFlags>(is, handler);
|
2014-06-29 15:03:38 +08:00
|
|
|
}
|
|
|
|
|
2014-07-09 21:19:13 +02:00
|
|
|
//! Whether a parse error has occured in the last parsing.
|
2014-07-09 13:55:54 +02:00
|
|
|
bool HasParseError() const { return parseResult_.IsError(); }
|
2014-06-30 09:44:24 +08:00
|
|
|
|
2014-07-09 21:19:13 +02:00
|
|
|
//! Get the \ref ParseErrorCode of last parsing.
|
2014-07-09 13:55:54 +02:00
|
|
|
ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); }
|
2014-06-30 09:44:24 +08:00
|
|
|
|
2014-07-09 21:19:13 +02:00
|
|
|
//! Get the position of last parsing error in input, 0 otherwise.
|
2014-07-09 13:55:54 +02:00
|
|
|
size_t GetErrorOffset() const { return parseResult_.Offset(); }
|
2011-11-18 17:01:23 +00:00
|
|
|
|
|
|
|
private:
|
2014-07-02 23:49:47 +08:00
|
|
|
// Prohibit copy constructor & assignment operator.
|
|
|
|
GenericReader(const GenericReader&);
|
|
|
|
GenericReader& operator=(const GenericReader&);
|
|
|
|
|
2014-07-02 01:04:33 +02:00
|
|
|
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_;
|
2014-07-13 01:10:25 +08:00
|
|
|
ClearStackOnExit(const ClearStackOnExit&);
|
|
|
|
ClearStackOnExit& operator=(const ClearStackOnExit&);
|
2014-07-02 01:04:33 +02:00
|
|
|
};
|
|
|
|
|
2011-11-18 17:01:23 +00:00
|
|
|
// Parse object: { string : value, ... }
|
2011-12-03 09:57:17 +00:00
|
|
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
|
|
|
void ParseObject(InputStream& is, Handler& handler) {
|
|
|
|
RAPIDJSON_ASSERT(is.Peek() == '{');
|
|
|
|
is.Take(); // Skip '{'
|
2014-07-10 19:33:01 +08:00
|
|
|
|
|
|
|
if (!handler.StartObject())
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
SkipWhitespace(is);
|
2011-11-18 17:01:23 +00:00
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
if (is.Peek() == '}') {
|
|
|
|
is.Take();
|
2014-07-10 19:33:01 +08:00
|
|
|
if (!handler.EndObject(0)) // empty object
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
2011-11-18 17:01:23 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (SizeType memberCount = 0;;) {
|
2011-12-03 09:57:17 +00:00
|
|
|
if (is.Peek() != '"')
|
2014-06-27 01:53:56 +08:00
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
|
2011-11-18 17:01:23 +00:00
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
ParseString<parseFlags>(is, handler);
|
2014-07-02 01:04:33 +02:00
|
|
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
2014-06-26 23:35:13 +08:00
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
SkipWhitespace(is);
|
2011-11-18 17:01:23 +00:00
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
if (is.Take() != ':')
|
2014-06-27 01:53:56 +08:00
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
|
2011-11-23 16:32:15 +00:00
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
SkipWhitespace(is);
|
2011-11-18 17:01:23 +00:00
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
ParseValue<parseFlags>(is, handler);
|
2014-07-02 01:04:33 +02:00
|
|
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
2014-06-26 23:35:13 +08:00
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
SkipWhitespace(is);
|
2011-11-18 17:01:23 +00:00
|
|
|
|
|
|
|
++memberCount;
|
|
|
|
|
2014-07-10 19:33:01 +08:00
|
|
|
switch (is.Take()) {
|
2011-12-03 09:57:17 +00:00
|
|
|
case ',': SkipWhitespace(is); break;
|
2014-07-10 19:33:01 +08:00
|
|
|
case '}':
|
|
|
|
if (!handler.EndObject(memberCount))
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
|
|
|
else
|
|
|
|
return;
|
2014-06-27 01:53:56 +08:00
|
|
|
default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse array: [ value, ... ]
|
2011-12-03 09:57:17 +00:00
|
|
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
|
|
|
void ParseArray(InputStream& is, Handler& handler) {
|
|
|
|
RAPIDJSON_ASSERT(is.Peek() == '[');
|
|
|
|
is.Take(); // Skip '['
|
2014-07-10 19:33:01 +08:00
|
|
|
|
|
|
|
if (!handler.StartArray())
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
SkipWhitespace(is);
|
2011-11-18 17:01:23 +00:00
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
if (is.Peek() == ']') {
|
|
|
|
is.Take();
|
2014-07-10 19:33:01 +08:00
|
|
|
if (!handler.EndArray(0)) // empty array
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
2011-11-18 17:01:23 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (SizeType elementCount = 0;;) {
|
2011-12-03 09:57:17 +00:00
|
|
|
ParseValue<parseFlags>(is, handler);
|
2014-07-02 01:04:33 +02:00
|
|
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
2014-06-26 23:35:13 +08:00
|
|
|
|
2011-11-18 17:01:23 +00:00
|
|
|
++elementCount;
|
2011-12-03 09:57:17 +00:00
|
|
|
SkipWhitespace(is);
|
2011-11-18 17:01:23 +00:00
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
switch (is.Take()) {
|
|
|
|
case ',': SkipWhitespace(is); break;
|
2014-07-10 19:33:01 +08:00
|
|
|
case ']':
|
|
|
|
if (!handler.EndArray(elementCount))
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
|
|
|
else
|
|
|
|
return;
|
2014-06-27 01:53:56 +08:00
|
|
|
default: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
|
|
|
void ParseNull(InputStream& is, Handler& handler) {
|
|
|
|
RAPIDJSON_ASSERT(is.Peek() == 'n');
|
|
|
|
is.Take();
|
2011-11-18 17:01:23 +00:00
|
|
|
|
2014-07-10 19:33:01 +08:00
|
|
|
if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l') {
|
|
|
|
if (!handler.Null())
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
|
|
|
}
|
2011-11-18 17:01:23 +00:00
|
|
|
else
|
2014-06-27 01:53:56 +08:00
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1);
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
|
|
|
void ParseTrue(InputStream& is, Handler& handler) {
|
|
|
|
RAPIDJSON_ASSERT(is.Peek() == 't');
|
|
|
|
is.Take();
|
2011-11-18 17:01:23 +00:00
|
|
|
|
2014-07-10 19:33:01 +08:00
|
|
|
if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e') {
|
|
|
|
if (!handler.Bool(true))
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
|
|
|
}
|
2011-11-18 17:01:23 +00:00
|
|
|
else
|
2014-07-10 19:33:01 +08:00
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1);
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
|
|
|
void ParseFalse(InputStream& is, Handler& handler) {
|
|
|
|
RAPIDJSON_ASSERT(is.Peek() == 'f');
|
|
|
|
is.Take();
|
2011-11-18 17:01:23 +00:00
|
|
|
|
2014-07-10 19:33:01 +08:00
|
|
|
if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e') {
|
|
|
|
if (!handler.Bool(false))
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
|
|
|
|
}
|
2011-11-18 17:01:23 +00:00
|
|
|
else
|
2014-06-27 01:53:56 +08:00
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1);
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
|
2011-12-03 09:57:17 +00:00
|
|
|
template<typename InputStream>
|
|
|
|
unsigned ParseHex4(InputStream& is) {
|
2011-11-18 17:01:23 +00:00
|
|
|
unsigned codepoint = 0;
|
|
|
|
for (int i = 0; i < 4; i++) {
|
2014-07-02 23:49:47 +08:00
|
|
|
Ch c = is.Take();
|
2011-11-18 17:01:23 +00:00
|
|
|
codepoint <<= 4;
|
2014-06-25 19:21:17 +08:00
|
|
|
codepoint += static_cast<unsigned>(c);
|
2011-11-18 17:01:23 +00:00
|
|
|
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;
|
2014-06-26 22:31:54 +08:00
|
|
|
else {
|
2014-07-02 23:49:47 +08:00
|
|
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, is.Tell() - 1);
|
2014-07-02 01:04:33 +02:00
|
|
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0);
|
2014-06-26 22:31:54 +08:00
|
|
|
}
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
return codepoint;
|
|
|
|
}
|
|
|
|
|
2012-11-13 08:02:22 +00:00
|
|
|
class StackStream {
|
|
|
|
public:
|
2011-12-03 09:57:17 +00:00
|
|
|
typedef typename TargetEncoding::Ch Ch;
|
|
|
|
|
2011-11-23 09:46:14 +00:00
|
|
|
StackStream(internal::Stack<Allocator>& stack) : stack_(stack), length_(0) {}
|
2011-12-03 09:57:17 +00:00
|
|
|
void Put(Ch c) {
|
|
|
|
*stack_.template Push<Ch>() = c;
|
2011-11-23 09:46:14 +00:00
|
|
|
++length_;
|
|
|
|
}
|
|
|
|
internal::Stack<Allocator>& stack_;
|
|
|
|
SizeType length_;
|
2012-11-13 08:02:22 +00:00
|
|
|
|
|
|
|
private:
|
2014-07-04 20:19:15 +08:00
|
|
|
StackStream(const StackStream&);
|
2012-11-13 08:02:22 +00:00
|
|
|
StackStream& operator=(const StackStream&);
|
2011-11-23 09:46:14 +00:00
|
|
|
};
|
|
|
|
|
2011-11-27 15:18:12 +00:00
|
|
|
// Parse string and generate String event. Different code paths for kParseInsituFlag.
|
2011-12-03 09:57:17 +00:00
|
|
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
|
|
|
void ParseString(InputStream& is, Handler& handler) {
|
2014-07-02 21:26:44 +02:00
|
|
|
internal::StreamLocalCopy<InputStream> copy(is);
|
2014-07-02 20:51:10 +02:00
|
|
|
InputStream& s(copy.s);
|
|
|
|
|
2011-11-27 15:18:12 +00:00
|
|
|
if (parseFlags & kParseInsituFlag) {
|
2014-07-04 14:32:44 +08:00
|
|
|
typename InputStream::Ch *head = s.PutBegin();
|
2014-07-02 20:51:10 +02:00
|
|
|
ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
|
2014-07-02 01:04:33 +02:00
|
|
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
2014-07-02 20:51:10 +02:00
|
|
|
size_t length = s.PutEnd(head) - 1;
|
2011-11-27 15:18:12 +00:00
|
|
|
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
|
2014-07-10 19:33:01 +08:00
|
|
|
if (!handler.String((typename TargetEncoding::Ch*)head, SizeType(length), false))
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
|
2011-11-27 15:18:12 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
StackStream stackStream(stack_);
|
2014-07-02 20:51:10 +02:00
|
|
|
ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
|
2014-07-02 01:04:33 +02:00
|
|
|
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
|
2014-07-10 19:33:01 +08:00
|
|
|
if (!handler.String(stack_.template Pop<typename TargetEncoding::Ch>(stackStream.length_), stackStream.length_ - 1, true))
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
|
2011-11-27 15:18:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
// Parse string to an output is
|
2011-11-27 15:18:12 +00:00
|
|
|
// This function handles the prefix/suffix double quotes, escaping, and optional encoding validation.
|
2011-12-03 09:57:17 +00:00
|
|
|
template<unsigned parseFlags, typename SEncoding, typename TEncoding, typename InputStream, typename OutputStream>
|
|
|
|
RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) {
|
2011-11-18 17:01:23 +00:00
|
|
|
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
2011-11-23 16:32:15 +00:00
|
|
|
static const char escape[256] = {
|
2011-11-18 17:01:23 +00:00
|
|
|
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
|
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
RAPIDJSON_ASSERT(is.Peek() == '\"');
|
|
|
|
is.Take(); // Skip '\"'
|
2011-11-18 17:01:23 +00:00
|
|
|
|
|
|
|
for (;;) {
|
2011-12-03 09:57:17 +00:00
|
|
|
Ch c = is.Peek();
|
2011-11-18 17:01:23 +00:00
|
|
|
if (c == '\\') { // Escape
|
2011-12-03 09:57:17 +00:00
|
|
|
is.Take();
|
|
|
|
Ch e = is.Take();
|
2014-07-15 14:16:06 +08:00
|
|
|
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e]) {
|
|
|
|
if (!(parseFlags & kParseInsituFlag)) {
|
|
|
|
if (!IsStackSpaceSufficient<Ch>(1)) {
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorStackSizeLimitExceeded, is.Tell() - 1);
|
|
|
|
}
|
|
|
|
}
|
2011-12-03 09:57:17 +00:00
|
|
|
os.Put(escape[(unsigned char)e]);
|
2014-07-15 14:16:06 +08:00
|
|
|
}
|
2011-11-18 17:01:23 +00:00
|
|
|
else if (e == 'u') { // Unicode
|
2011-12-03 09:57:17 +00:00
|
|
|
unsigned codepoint = ParseHex4(is);
|
2011-11-23 16:32:15 +00:00
|
|
|
if (codepoint >= 0xD800 && codepoint <= 0xDBFF) {
|
|
|
|
// Handle UTF-16 surrogate pair
|
2011-12-03 09:57:17 +00:00
|
|
|
if (is.Take() != '\\' || is.Take() != 'u')
|
2014-06-27 01:53:56 +08:00
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
|
2011-12-03 09:57:17 +00:00
|
|
|
unsigned codepoint2 = ParseHex4(is);
|
2011-11-23 16:32:15 +00:00
|
|
|
if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)
|
2014-06-27 01:53:56 +08:00
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
|
2011-11-18 17:01:23 +00:00
|
|
|
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
|
|
|
|
}
|
2011-12-03 09:57:17 +00:00
|
|
|
TEncoding::Encode(os, codepoint);
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
2011-11-23 16:32:15 +00:00
|
|
|
else
|
2014-06-27 01:53:56 +08:00
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1);
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
else if (c == '"') { // Closing double quote
|
2011-12-03 09:57:17 +00:00
|
|
|
is.Take();
|
2014-07-15 14:16:06 +08:00
|
|
|
if (!(parseFlags & kParseInsituFlag)) {
|
|
|
|
if (!IsStackSpaceSufficient<Ch>(1)) {
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorStackSizeLimitExceeded, is.Tell() - 1);
|
|
|
|
}
|
|
|
|
}
|
2011-12-03 09:57:17 +00:00
|
|
|
os.Put('\0'); // null-terminate the string
|
2011-11-18 17:01:23 +00:00
|
|
|
return;
|
|
|
|
}
|
2011-11-23 16:32:15 +00:00
|
|
|
else if (c == '\0')
|
2014-06-27 01:53:56 +08:00
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1);
|
2011-11-23 16:32:15 +00:00
|
|
|
else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
|
2014-06-27 01:53:56 +08:00
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1);
|
2011-11-28 09:30:32 +00:00
|
|
|
else {
|
|
|
|
if (parseFlags & kParseValidateEncodingFlag ?
|
2011-12-03 09:57:17 +00:00
|
|
|
!Transcoder<SEncoding, TEncoding>::Validate(is, os) :
|
|
|
|
!Transcoder<SEncoding, TEncoding>::Transcode(is, os))
|
2014-06-27 01:53:56 +08:00
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell());
|
2011-11-22 19:29:43 +00:00
|
|
|
}
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-03 09:57:17 +00:00
|
|
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
|
|
|
void ParseNumber(InputStream& is, Handler& handler) {
|
2014-07-02 21:26:44 +02:00
|
|
|
internal::StreamLocalCopy<InputStream> copy(is);
|
2014-07-02 20:51:10 +02:00
|
|
|
InputStream& s(copy.s);
|
|
|
|
|
2011-11-18 17:01:23 +00:00
|
|
|
// Parse minus
|
|
|
|
bool minus = false;
|
2014-07-02 20:51:10 +02:00
|
|
|
if (s.Peek() == '-') {
|
2011-11-18 17:01:23 +00:00
|
|
|
minus = true;
|
2014-07-02 20:51:10 +02:00
|
|
|
s.Take();
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse int: zero / ( digit1-9 *DIGIT )
|
2014-07-13 01:10:25 +08:00
|
|
|
unsigned i = 0;
|
2011-11-18 17:01:23 +00:00
|
|
|
bool try64bit = false;
|
2014-07-02 20:51:10 +02:00
|
|
|
if (s.Peek() == '0') {
|
2011-11-18 17:01:23 +00:00
|
|
|
i = 0;
|
2014-07-02 20:51:10 +02:00
|
|
|
s.Take();
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
2014-07-02 20:51:10 +02:00
|
|
|
else if (s.Peek() >= '1' && s.Peek() <= '9') {
|
|
|
|
i = static_cast<unsigned>(s.Take() - '0');
|
2011-11-18 17:01:23 +00:00
|
|
|
|
|
|
|
if (minus)
|
2014-07-02 20:51:10 +02:00
|
|
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
2011-11-18 17:01:23 +00:00
|
|
|
if (i >= 214748364) { // 2^31 = 2147483648
|
2014-07-02 20:51:10 +02:00
|
|
|
if (i != 214748364 || s.Peek() > '8') {
|
2011-11-18 17:01:23 +00:00
|
|
|
try64bit = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-07-02 20:51:10 +02:00
|
|
|
i = i * 10 + static_cast<unsigned>(s.Take() - '0');
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
else
|
2014-07-02 20:51:10 +02:00
|
|
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
2011-11-18 17:01:23 +00:00
|
|
|
if (i >= 429496729) { // 2^32 - 1 = 4294967295
|
2014-07-02 20:51:10 +02:00
|
|
|
if (i != 429496729 || s.Peek() > '5') {
|
2011-11-18 17:01:23 +00:00
|
|
|
try64bit = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-07-02 20:51:10 +02:00
|
|
|
i = i * 10 + static_cast<unsigned>(s.Take() - '0');
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
}
|
2011-11-23 16:32:15 +00:00
|
|
|
else
|
2014-07-03 17:05:03 +02:00
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
|
2011-11-18 17:01:23 +00:00
|
|
|
|
|
|
|
// Parse 64bit int
|
2012-02-28 06:07:32 +00:00
|
|
|
uint64_t i64 = 0;
|
2011-11-18 17:01:23 +00:00
|
|
|
bool useDouble = false;
|
|
|
|
if (try64bit) {
|
|
|
|
i64 = i;
|
|
|
|
if (minus)
|
2014-07-02 20:51:10 +02:00
|
|
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
2014-06-25 19:21:17 +08:00
|
|
|
if (i64 >= UINT64_C(922337203685477580)) // 2^63 = 9223372036854775808
|
2014-07-02 20:51:10 +02:00
|
|
|
if (i64 != UINT64_C(922337203685477580) || s.Peek() > '8') {
|
2011-11-18 17:01:23 +00:00
|
|
|
useDouble = true;
|
|
|
|
break;
|
|
|
|
}
|
2014-07-02 20:51:10 +02:00
|
|
|
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
else
|
2014-07-02 20:51:10 +02:00
|
|
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
2014-06-25 19:21:17 +08:00
|
|
|
if (i64 >= UINT64_C(1844674407370955161)) // 2^64 - 1 = 18446744073709551615
|
2014-07-02 20:51:10 +02:00
|
|
|
if (i64 != UINT64_C(1844674407370955161) || s.Peek() > '5') {
|
2011-11-18 17:01:23 +00:00
|
|
|
useDouble = true;
|
|
|
|
break;
|
|
|
|
}
|
2014-07-02 20:51:10 +02:00
|
|
|
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Force double for big integer
|
2012-02-28 06:07:32 +00:00
|
|
|
double d = 0.0;
|
2011-11-18 17:01:23 +00:00
|
|
|
if (useDouble) {
|
|
|
|
d = (double)i64;
|
2014-07-02 20:51:10 +02:00
|
|
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
2011-11-23 16:32:15 +00:00
|
|
|
if (d >= 1E307)
|
2014-07-03 17:05:03 +02:00
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
2014-07-02 20:51:10 +02:00
|
|
|
d = d * 10 + (s.Take() - '0');
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse frac = decimal-point 1*DIGIT
|
|
|
|
int expFrac = 0;
|
2014-07-02 20:51:10 +02:00
|
|
|
if (s.Peek() == '.') {
|
2011-11-18 17:01:23 +00:00
|
|
|
if (!useDouble) {
|
|
|
|
d = try64bit ? (double)i64 : (double)i;
|
|
|
|
useDouble = true;
|
|
|
|
}
|
2014-07-02 20:51:10 +02:00
|
|
|
s.Take();
|
2011-11-18 17:01:23 +00:00
|
|
|
|
2014-07-02 20:51:10 +02:00
|
|
|
if (s.Peek() >= '0' && s.Peek() <= '9') {
|
|
|
|
d = d * 10 + (s.Take() - '0');
|
2011-11-18 17:01:23 +00:00
|
|
|
--expFrac;
|
|
|
|
}
|
2011-11-23 16:32:15 +00:00
|
|
|
else
|
2014-07-03 17:05:03 +02:00
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());
|
2011-11-18 17:01:23 +00:00
|
|
|
|
2014-07-02 20:51:10 +02:00
|
|
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
2011-11-18 17:01:23 +00:00
|
|
|
if (expFrac > -16) {
|
2014-07-02 20:51:10 +02:00
|
|
|
d = d * 10 + (s.Peek() - '0');
|
2011-11-18 17:01:23 +00:00
|
|
|
--expFrac;
|
|
|
|
}
|
2014-07-02 20:51:10 +02:00
|
|
|
s.Take();
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse exp = e [ minus / plus ] 1*DIGIT
|
|
|
|
int exp = 0;
|
2014-07-02 20:51:10 +02:00
|
|
|
if (s.Peek() == 'e' || s.Peek() == 'E') {
|
2011-11-18 17:01:23 +00:00
|
|
|
if (!useDouble) {
|
|
|
|
d = try64bit ? (double)i64 : (double)i;
|
|
|
|
useDouble = true;
|
|
|
|
}
|
2014-07-02 20:51:10 +02:00
|
|
|
s.Take();
|
2011-11-18 17:01:23 +00:00
|
|
|
|
|
|
|
bool expMinus = false;
|
2014-07-02 20:51:10 +02:00
|
|
|
if (s.Peek() == '+')
|
|
|
|
s.Take();
|
|
|
|
else if (s.Peek() == '-') {
|
|
|
|
s.Take();
|
2011-11-18 17:01:23 +00:00
|
|
|
expMinus = true;
|
|
|
|
}
|
|
|
|
|
2014-07-02 20:51:10 +02:00
|
|
|
if (s.Peek() >= '0' && s.Peek() <= '9') {
|
|
|
|
exp = s.Take() - '0';
|
|
|
|
while (s.Peek() >= '0' && s.Peek() <= '9') {
|
|
|
|
exp = exp * 10 + (s.Take() - '0');
|
2011-11-23 16:32:15 +00:00
|
|
|
if (exp > 308)
|
2014-07-03 17:05:03 +02:00
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
}
|
2011-11-23 16:32:15 +00:00
|
|
|
else
|
2014-07-03 17:05:03 +02:00
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell());
|
2011-11-18 17:01:23 +00:00
|
|
|
|
|
|
|
if (expMinus)
|
|
|
|
exp = -exp;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finish parsing, call event according to the type of number.
|
2014-07-10 19:33:01 +08:00
|
|
|
bool cont = true;
|
2011-11-18 17:01:23 +00:00
|
|
|
if (useDouble) {
|
2014-06-30 21:26:43 +08:00
|
|
|
int expSum = exp + expFrac;
|
|
|
|
if (expSum < -308) {
|
|
|
|
// Prevent expSum < -308, making Pow10(expSum) = 0
|
|
|
|
d *= internal::Pow10(exp);
|
|
|
|
d *= internal::Pow10(expFrac);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
d *= internal::Pow10(expSum);
|
|
|
|
|
2014-07-10 19:33:01 +08:00
|
|
|
cont = handler.Double(minus ? -d : d);
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (try64bit) {
|
|
|
|
if (minus)
|
2014-07-10 19:33:01 +08:00
|
|
|
cont = handler.Int64(-(int64_t)i64);
|
2011-11-18 17:01:23 +00:00
|
|
|
else
|
2014-07-10 19:33:01 +08:00
|
|
|
cont = handler.Uint64(i64);
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (minus)
|
2014-07-10 19:33:01 +08:00
|
|
|
cont = handler.Int(-(int)i);
|
2011-11-18 17:01:23 +00:00
|
|
|
else
|
2014-07-10 19:33:01 +08:00
|
|
|
cont = handler.Uint(i);
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
}
|
2014-07-10 19:33:01 +08:00
|
|
|
if (!cont)
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse any JSON value
|
2011-12-03 09:57:17 +00:00
|
|
|
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);
|
2011-11-18 17:01:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-08 02:19:35 +08:00
|
|
|
// Iterative Parsing
|
|
|
|
|
|
|
|
// States
|
2014-07-07 21:46:57 +08:00
|
|
|
enum IterativeParsingState {
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingStartState = 0,
|
2014-07-07 21:46:57 +08:00
|
|
|
IterativeParsingFinishState,
|
|
|
|
IterativeParsingErrorState,
|
2014-07-08 02:19:35 +08:00
|
|
|
|
2014-07-06 21:15:38 +08:00
|
|
|
// Object states
|
2014-07-07 21:46:57 +08:00
|
|
|
IterativeParsingObjectInitialState,
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingMemberKeyState,
|
|
|
|
IterativeParsingKeyValueDelimiterState,
|
|
|
|
IterativeParsingMemberValueState,
|
|
|
|
IterativeParsingMemberDelimiterState,
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingObjectFinishState,
|
|
|
|
|
2014-07-06 21:15:38 +08:00
|
|
|
// Array states
|
2014-07-07 21:46:57 +08:00
|
|
|
IterativeParsingArrayInitialState,
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingElementState,
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingElementDelimiterState,
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingArrayFinishState,
|
|
|
|
|
|
|
|
cIterativeParsingStateCount
|
2014-07-06 21:15:38 +08:00
|
|
|
};
|
|
|
|
|
2014-07-08 02:19:35 +08:00
|
|
|
// Tokens
|
|
|
|
enum IterativeParsingToken {
|
|
|
|
IterativeParsingLeftBracketToken = 0,
|
|
|
|
IterativeParsingRightBracketToken,
|
2014-07-06 21:15:38 +08:00
|
|
|
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingLeftCurlyBracketToken,
|
|
|
|
IterativeParsingRightCurlyBracketToken,
|
2014-07-06 21:15:38 +08:00
|
|
|
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingCommaToken,
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingColonToken,
|
2014-07-06 21:15:38 +08:00
|
|
|
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingStringToken,
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingFalseToken,
|
|
|
|
IterativeParsingTrueToken,
|
|
|
|
IterativeParsingNullToken,
|
|
|
|
IterativeParsingNumberToken,
|
|
|
|
|
|
|
|
cIterativeParsingTokenCount
|
|
|
|
};
|
|
|
|
|
2014-07-10 22:27:25 +08:00
|
|
|
IterativeParsingToken Tokenize(Ch c) {
|
2014-07-08 02:19:35 +08:00
|
|
|
switch (c) {
|
|
|
|
case '[': return IterativeParsingLeftBracketToken;
|
|
|
|
case ']': return IterativeParsingRightBracketToken;
|
|
|
|
case '{': return IterativeParsingLeftCurlyBracketToken;
|
|
|
|
case '}': return IterativeParsingRightCurlyBracketToken;
|
|
|
|
case ',': return IterativeParsingCommaToken;
|
2014-07-08 22:54:22 +08:00
|
|
|
case ':': return IterativeParsingColonToken;
|
|
|
|
case '"': return IterativeParsingStringToken;
|
2014-07-08 02:19:35 +08:00
|
|
|
case 'f': return IterativeParsingFalseToken;
|
|
|
|
case 't': return IterativeParsingTrueToken;
|
|
|
|
case 'n': return IterativeParsingNullToken;
|
|
|
|
default: return IterativeParsingNumberToken;
|
2014-07-06 21:15:38 +08:00
|
|
|
}
|
2014-07-08 02:19:35 +08:00
|
|
|
}
|
2014-07-06 21:15:38 +08:00
|
|
|
|
2014-07-10 22:27:25 +08:00
|
|
|
IterativeParsingState Predict(IterativeParsingState state, IterativeParsingToken token) {
|
2014-07-08 02:19:35 +08:00
|
|
|
// current state x one lookahead token -> new state
|
|
|
|
static const IterativeParsingState G[cIterativeParsingStateCount][cIterativeParsingTokenCount] = {
|
|
|
|
// Start
|
|
|
|
{
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingArrayInitialState, // Left bracket
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingErrorState, // Right bracket
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingObjectInitialState, // Left curly bracket
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingErrorState, // Right curly bracket
|
|
|
|
IterativeParsingErrorState, // Comma
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingErrorState, // Colon
|
|
|
|
IterativeParsingErrorState, // String
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingErrorState, // False
|
|
|
|
IterativeParsingErrorState, // True
|
|
|
|
IterativeParsingErrorState, // Null
|
|
|
|
IterativeParsingErrorState // Number
|
|
|
|
},
|
|
|
|
// Finish(sink state)
|
|
|
|
{
|
|
|
|
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
|
|
|
|
IterativeParsingErrorState
|
2014-07-08 02:19:35 +08:00
|
|
|
},
|
|
|
|
// Error(sink state)
|
|
|
|
{
|
|
|
|
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
|
|
|
|
IterativeParsingErrorState
|
2014-07-08 02:19:35 +08:00
|
|
|
},
|
|
|
|
// ObjectInitial
|
|
|
|
{
|
|
|
|
IterativeParsingErrorState, // Left bracket
|
|
|
|
IterativeParsingErrorState, // Right bracket
|
|
|
|
IterativeParsingErrorState, // Left curly bracket
|
|
|
|
IterativeParsingObjectFinishState, // Right curly bracket
|
|
|
|
IterativeParsingErrorState, // Comma
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingErrorState, // Colon
|
|
|
|
IterativeParsingMemberKeyState, // String
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingErrorState, // False
|
|
|
|
IterativeParsingErrorState, // True
|
|
|
|
IterativeParsingErrorState, // Null
|
|
|
|
IterativeParsingErrorState // Number
|
|
|
|
},
|
2014-07-08 22:54:22 +08:00
|
|
|
// 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
|
2014-07-08 02:19:35 +08:00
|
|
|
{
|
|
|
|
IterativeParsingErrorState, // Left bracket
|
|
|
|
IterativeParsingErrorState, // Right bracket
|
|
|
|
IterativeParsingErrorState, // Left curly bracket
|
|
|
|
IterativeParsingObjectFinishState, // Right curly bracket
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingMemberDelimiterState, // Comma
|
|
|
|
IterativeParsingErrorState, // Colon
|
|
|
|
IterativeParsingErrorState, // String
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingErrorState, // False
|
|
|
|
IterativeParsingErrorState, // True
|
|
|
|
IterativeParsingErrorState, // Null
|
|
|
|
IterativeParsingErrorState // Number
|
|
|
|
},
|
2014-07-08 22:54:22 +08:00
|
|
|
// MemberDelimiter
|
2014-07-08 02:19:35 +08:00
|
|
|
{
|
|
|
|
IterativeParsingErrorState, // Left bracket
|
|
|
|
IterativeParsingErrorState, // Right bracket
|
|
|
|
IterativeParsingErrorState, // Left curly bracket
|
|
|
|
IterativeParsingErrorState, // Right curly bracket
|
|
|
|
IterativeParsingErrorState, // Comma
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingErrorState, // Colon
|
|
|
|
IterativeParsingMemberKeyState, // String
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingErrorState, // False
|
|
|
|
IterativeParsingErrorState, // True
|
|
|
|
IterativeParsingErrorState, // Null
|
|
|
|
IterativeParsingErrorState // Number
|
|
|
|
},
|
|
|
|
// ObjectFinish(sink state)
|
|
|
|
{
|
|
|
|
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
|
|
|
|
IterativeParsingErrorState
|
2014-07-08 02:19:35 +08:00
|
|
|
},
|
|
|
|
// ArrayInitial
|
|
|
|
{
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingArrayInitialState, // Left bracket(push Element state)
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingArrayFinishState, // Right bracket
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingObjectInitialState, // Left curly bracket(push Element state)
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingErrorState, // Right curly bracket
|
|
|
|
IterativeParsingErrorState, // Comma
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingErrorState, // Colon
|
|
|
|
IterativeParsingElementState, // String
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingElementState, // False
|
|
|
|
IterativeParsingElementState, // True
|
|
|
|
IterativeParsingElementState, // Null
|
|
|
|
IterativeParsingElementState // Number
|
|
|
|
},
|
|
|
|
// Element
|
|
|
|
{
|
|
|
|
IterativeParsingErrorState, // Left bracket
|
|
|
|
IterativeParsingArrayFinishState, // Right bracket
|
|
|
|
IterativeParsingErrorState, // Left curly bracket
|
|
|
|
IterativeParsingErrorState, // Right curly bracket
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingElementDelimiterState, // Comma
|
|
|
|
IterativeParsingErrorState, // Colon
|
|
|
|
IterativeParsingErrorState, // String
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingErrorState, // False
|
|
|
|
IterativeParsingErrorState, // True
|
|
|
|
IterativeParsingErrorState, // Null
|
|
|
|
IterativeParsingErrorState // Number
|
|
|
|
},
|
2014-07-08 22:54:22 +08:00
|
|
|
// ElementDelimiter
|
2014-07-08 02:19:35 +08:00
|
|
|
{
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingArrayInitialState, // Left bracket(push Element state)
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingErrorState, // Right bracket
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingObjectInitialState, // Left curly bracket(push Element state)
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingErrorState, // Right curly bracket
|
|
|
|
IterativeParsingErrorState, // Comma
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingErrorState, // Colon
|
|
|
|
IterativeParsingElementState, // String
|
2014-07-08 02:19:35 +08:00
|
|
|
IterativeParsingElementState, // False
|
|
|
|
IterativeParsingElementState, // True
|
|
|
|
IterativeParsingElementState, // Null
|
|
|
|
IterativeParsingElementState // Number
|
|
|
|
},
|
|
|
|
// ArrayFinish(sink state)
|
|
|
|
{
|
|
|
|
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
|
2014-07-08 22:54:22 +08:00
|
|
|
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
|
|
|
|
IterativeParsingErrorState
|
2014-07-08 02:19:35 +08:00
|
|
|
}
|
|
|
|
}; // End of G
|
2014-07-06 21:15:38 +08:00
|
|
|
|
2014-07-08 02:19:35 +08:00
|
|
|
return G[state][token];
|
2014-07-06 21:15:38 +08:00
|
|
|
}
|
|
|
|
|
2014-07-08 22:54:22 +08:00
|
|
|
// 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.
|
2014-07-06 21:15:38 +08:00
|
|
|
template <unsigned parseFlags, typename InputStream, typename Handler>
|
2014-07-10 00:00:56 +08:00
|
|
|
IterativeParsingState Transit(IterativeParsingState src, IterativeParsingToken token, IterativeParsingState dst, InputStream& is, Handler& handler) {
|
2014-07-08 02:19:35 +08:00
|
|
|
int c = 0;
|
|
|
|
IterativeParsingState n;
|
2014-07-14 23:49:57 +08:00
|
|
|
bool hr;
|
2014-07-06 21:15:38 +08:00
|
|
|
|
2014-07-08 02:19:35 +08:00
|
|
|
switch (dst) {
|
|
|
|
case IterativeParsingStartState:
|
|
|
|
RAPIDJSON_ASSERT(false);
|
|
|
|
return IterativeParsingErrorState;
|
2014-07-06 21:15:38 +08:00
|
|
|
|
2014-07-08 02:19:35 +08:00
|
|
|
case IterativeParsingFinishState:
|
|
|
|
return dst;
|
2014-07-06 21:15:38 +08:00
|
|
|
|
2014-07-08 02:19:35 +08:00
|
|
|
case IterativeParsingErrorState:
|
|
|
|
return dst;
|
2014-07-06 21:15:38 +08:00
|
|
|
|
2014-07-08 02:19:35 +08:00
|
|
|
case IterativeParsingObjectInitialState:
|
|
|
|
case IterativeParsingArrayInitialState:
|
2014-07-08 22:54:22 +08:00
|
|
|
// 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.
|
|
|
|
n = src;
|
|
|
|
if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState)
|
|
|
|
n = IterativeParsingElementState;
|
|
|
|
else if (src == IterativeParsingKeyValueDelimiterState)
|
|
|
|
n = IterativeParsingMemberValueState;
|
2014-07-08 02:19:35 +08:00
|
|
|
// Push current state.
|
2014-07-15 14:16:06 +08:00
|
|
|
if (!IsStackSpaceSufficient<IterativeParsingState>(1)) {
|
|
|
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStackSizeLimitExceeded, is.Tell());
|
|
|
|
return IterativeParsingErrorState;
|
|
|
|
}
|
2014-07-08 22:54:22 +08:00
|
|
|
*stack_.template Push<IterativeParsingState>(1) = n;
|
2014-07-08 02:19:35 +08:00
|
|
|
// Initialize and push the member/element count.
|
2014-07-15 14:16:06 +08:00
|
|
|
if (!IsStackSpaceSufficient<int>(1)) {
|
|
|
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStackSizeLimitExceeded, is.Tell());
|
|
|
|
return IterativeParsingErrorState;
|
|
|
|
}
|
2014-07-08 02:19:35 +08:00
|
|
|
*stack_.template Push<int>(1) = 0;
|
2014-07-08 22:54:22 +08:00
|
|
|
// Call handler
|
|
|
|
if (dst == IterativeParsingObjectInitialState)
|
2014-07-14 23:49:57 +08:00
|
|
|
hr = handler.StartObject();
|
2014-07-08 22:54:22 +08:00
|
|
|
else
|
2014-07-14 23:49:57 +08:00
|
|
|
hr = handler.StartArray();
|
|
|
|
// On handler short circuits the parsing.
|
|
|
|
if (!hr) {
|
|
|
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
|
|
|
|
return IterativeParsingErrorState;
|
|
|
|
}
|
2014-07-15 00:51:34 +08:00
|
|
|
else {
|
|
|
|
is.Take();
|
2014-07-14 23:49:57 +08:00
|
|
|
return dst;
|
2014-07-15 00:51:34 +08:00
|
|
|
}
|
2014-07-06 21:15:38 +08:00
|
|
|
|
2014-07-08 22:54:22 +08:00
|
|
|
case IterativeParsingMemberKeyState:
|
|
|
|
ParseString<parseFlags>(is, handler);
|
|
|
|
if (HasParseError())
|
|
|
|
return IterativeParsingErrorState;
|
|
|
|
else
|
|
|
|
return dst;
|
2014-07-06 21:15:38 +08:00
|
|
|
|
2014-07-08 22:54:22 +08:00
|
|
|
case IterativeParsingKeyValueDelimiterState:
|
|
|
|
if (token == IterativeParsingColonToken) {
|
|
|
|
is.Take();
|
2014-07-08 02:19:35 +08:00
|
|
|
return dst;
|
|
|
|
}
|
2014-07-08 22:54:22 +08:00
|
|
|
else
|
|
|
|
return IterativeParsingErrorState;
|
2014-07-06 21:15:38 +08:00
|
|
|
|
2014-07-08 22:54:22 +08:00
|
|
|
case IterativeParsingMemberValueState:
|
|
|
|
// Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
|
|
|
|
ParseValue<parseFlags>(is, handler);
|
|
|
|
if (HasParseError()) {
|
|
|
|
return IterativeParsingErrorState;
|
2014-07-08 02:19:35 +08:00
|
|
|
}
|
2014-07-08 22:54:22 +08:00
|
|
|
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;
|
2014-07-06 21:15:38 +08:00
|
|
|
|
2014-07-08 22:54:22 +08:00
|
|
|
case IterativeParsingMemberDelimiterState:
|
|
|
|
case IterativeParsingElementDelimiterState:
|
2014-07-06 21:15:38 +08:00
|
|
|
is.Take();
|
2014-07-08 02:19:35 +08:00
|
|
|
// Update member/element count.
|
2014-07-06 21:15:38 +08:00
|
|
|
*stack_.template Top<int>() = *stack_.template Top<int>() + 1;
|
2014-07-08 02:19:35 +08:00
|
|
|
return dst;
|
2014-07-06 21:15:38 +08:00
|
|
|
|
2014-07-08 02:19:35 +08:00
|
|
|
case IterativeParsingObjectFinishState:
|
|
|
|
// Get member count.
|
|
|
|
c = *stack_.template Pop<int>(1);
|
2014-07-08 22:54:22 +08:00
|
|
|
// If the object is not empty, count the last member.
|
|
|
|
if (src == IterativeParsingMemberValueState)
|
2014-07-08 02:19:35 +08:00
|
|
|
++c;
|
|
|
|
// Restore the state.
|
|
|
|
n = *stack_.template Pop<IterativeParsingState>(1);
|
|
|
|
// Transit to Finish state if this is the topmost scope.
|
|
|
|
if (n == IterativeParsingStartState)
|
|
|
|
n = IterativeParsingFinishState;
|
|
|
|
// Call handler
|
2014-07-14 23:49:57 +08:00
|
|
|
hr = handler.EndObject(c);
|
|
|
|
// On handler short circuits the parsing.
|
|
|
|
if (!hr) {
|
|
|
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
|
|
|
|
return IterativeParsingErrorState;
|
|
|
|
}
|
2014-07-15 00:51:34 +08:00
|
|
|
else {
|
|
|
|
is.Take();
|
2014-07-14 23:49:57 +08:00
|
|
|
return n;
|
2014-07-15 00:51:34 +08:00
|
|
|
}
|
2014-07-08 02:19:35 +08:00
|
|
|
|
|
|
|
case IterativeParsingArrayFinishState:
|
|
|
|
// Get element count.
|
|
|
|
c = *stack_.template Pop<int>(1);
|
2014-07-08 22:54:22 +08:00
|
|
|
// If the array is not empty, count the last element.
|
2014-07-08 02:19:35 +08:00
|
|
|
if (src == IterativeParsingElementState)
|
|
|
|
++c;
|
|
|
|
// Restore the state.
|
|
|
|
n = *stack_.template Pop<IterativeParsingState>(1);
|
|
|
|
// Transit to Finish state if this is the topmost scope.
|
|
|
|
if (n == IterativeParsingStartState)
|
|
|
|
n = IterativeParsingFinishState;
|
|
|
|
// Call handler
|
2014-07-14 23:49:57 +08:00
|
|
|
hr = handler.EndArray(c);
|
|
|
|
// On handler short circuits the parsing.
|
|
|
|
if (!hr) {
|
|
|
|
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
|
|
|
|
return IterativeParsingErrorState;
|
|
|
|
}
|
2014-07-15 00:51:34 +08:00
|
|
|
else {
|
|
|
|
is.Take();
|
2014-07-14 23:49:57 +08:00
|
|
|
return n;
|
2014-07-15 00:51:34 +08:00
|
|
|
}
|
2014-07-06 21:15:38 +08:00
|
|
|
|
2014-07-08 02:19:35 +08:00
|
|
|
default:
|
|
|
|
RAPIDJSON_ASSERT(false);
|
|
|
|
return IterativeParsingErrorState;
|
2014-07-06 21:15:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-10 00:00:56 +08:00
|
|
|
template <typename InputStream>
|
|
|
|
void HandleError(IterativeParsingState src, InputStream& is) {
|
|
|
|
if (HasParseError()) {
|
|
|
|
// Error flag has been set.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (src == IterativeParsingStartState && is.Peek() == '\0')
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell());
|
|
|
|
|
|
|
|
else if (src == IterativeParsingStartState)
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotObjectOrArray, is.Tell());
|
|
|
|
|
|
|
|
else if (src == IterativeParsingFinishState)
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell());
|
|
|
|
|
|
|
|
else if (src == IterativeParsingObjectInitialState || src == IterativeParsingMemberDelimiterState)
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
|
|
|
|
|
|
|
|
else if (src == IterativeParsingMemberKeyState)
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
|
|
|
|
|
|
|
|
else if (src == IterativeParsingMemberValueState)
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
|
|
|
|
|
|
|
|
else if (src == IterativeParsingElementState)
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
|
2014-07-10 19:49:43 +08:00
|
|
|
|
|
|
|
else
|
|
|
|
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
|
2014-07-10 00:00:56 +08:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:15:38 +08:00
|
|
|
template <unsigned parseFlags, typename InputStream, typename Handler>
|
2014-07-14 23:49:57 +08:00
|
|
|
ParseResult IterativeParse(InputStream& is, Handler& handler) {
|
|
|
|
parseResult_.Clear();
|
|
|
|
ClearStackOnExit scope(*this);
|
2014-07-07 21:46:57 +08:00
|
|
|
IterativeParsingState state = IterativeParsingStartState;
|
2014-07-06 21:15:38 +08:00
|
|
|
|
|
|
|
SkipWhitespace(is);
|
2014-07-08 22:54:22 +08:00
|
|
|
while (is.Peek() != '\0') {
|
2014-07-10 22:27:25 +08:00
|
|
|
IterativeParsingToken t = Tokenize(is.Peek());
|
|
|
|
IterativeParsingState n = Predict(state, t);
|
2014-07-10 00:00:56 +08:00
|
|
|
IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handler);
|
2014-07-08 02:19:35 +08:00
|
|
|
|
2014-07-10 00:00:56 +08:00
|
|
|
if (d == IterativeParsingErrorState) {
|
|
|
|
HandleError(state, is);
|
2014-07-08 02:19:35 +08:00
|
|
|
break;
|
2014-07-10 00:00:56 +08:00
|
|
|
}
|
2014-07-08 02:19:35 +08:00
|
|
|
|
2014-07-10 00:00:56 +08:00
|
|
|
state = d;
|
2014-07-06 21:15:38 +08:00
|
|
|
SkipWhitespace(is);
|
|
|
|
}
|
|
|
|
|
2014-07-10 00:00:56 +08:00
|
|
|
// Handle the end of file.
|
|
|
|
if (state != IterativeParsingFinishState)
|
|
|
|
HandleError(state, is);
|
2014-07-14 23:49:57 +08:00
|
|
|
|
|
|
|
return parseResult_;
|
2014-07-06 21:15:38 +08:00
|
|
|
}
|
|
|
|
|
2014-07-15 14:16:06 +08:00
|
|
|
template <typename T>
|
|
|
|
bool IsStackSpaceSufficient(size_t count) const {
|
|
|
|
return kStackSizeLimit == 0 || (stack_.GetSize() + sizeof(T) * count <= kStackSizeLimit);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
|
|
|
|
const size_t kStackSizeLimit; //!< Stack size limit(in bytes). A value of 0 means no limit.
|
2011-11-18 17:01:23 +00:00
|
|
|
internal::Stack<Allocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
|
2014-07-09 13:55:54 +02:00
|
|
|
ParseResult parseResult_;
|
2011-11-18 17:01:23 +00:00
|
|
|
}; // class GenericReader
|
|
|
|
|
|
|
|
//! Reader with UTF8 encoding and default allocator.
|
2011-11-28 09:30:32 +00:00
|
|
|
typedef GenericReader<UTF8<>, UTF8<> > Reader;
|
2011-11-18 17:01:23 +00:00
|
|
|
|
|
|
|
} // namespace rapidjson
|
|
|
|
|
2012-11-13 08:02:22 +00:00
|
|
|
#ifdef _MSC_VER
|
2014-07-10 13:09:15 +02:00
|
|
|
RAPIDJSON_DIAG_POP
|
2012-11-13 08:02:22 +00:00
|
|
|
#endif
|
|
|
|
|
2011-11-18 17:01:23 +00:00
|
|
|
#endif // RAPIDJSON_READER_H_
|