2015-12-30 10:25:29 +00:00
// 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.
2014-10-17 20:51:37 +00:00
//
2015-12-30 10:25:29 +00:00
// 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
2014-10-17 20:51:37 +00:00
//
2015-12-30 10:25:29 +00:00
// http://opensource.org/licenses/MIT
2014-10-17 20:51:37 +00:00
//
2015-12-30 10:25:29 +00:00
// 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.
2014-10-17 20:51:37 +00:00
# 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"
2015-12-30 10:25:29 +00:00
# include "internal/strtod.h"
2014-10-17 20:51:37 +00:00
# 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
2015-12-30 10:25:29 +00:00
# ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF ( padded )
RAPIDJSON_DIAG_OFF ( switch - enum )
# endif
# ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF ( effc + + )
# endif
2014-10-17 20:51:37 +00:00
//!@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
2015-12-30 10:25:29 +00:00
RAPIDJSON_NAMESPACE_BEGIN
2014-10-17 20:51:37 +00:00
///////////////////////////////////////////////////////////////////////////////
// ParseFlag
2015-12-30 10:25:29 +00:00
/*! \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
2014-10-17 20:51:37 +00:00
//! Combination of parseFlags
/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream
*/
enum ParseFlag {
2015-12-30 10:25:29 +00:00
kParseNoFlags = 0 , //!< No flags are set.
2014-10-17 20:51:37 +00:00
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.
2015-12-30 10:25:29 +00:00
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).
kParseCommentsFlag = 32 , //!< Allow one-line (//) and multi-line (/**/) comments.
kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
2014-10-17 20:51:37 +00:00
} ;
///////////////////////////////////////////////////////////////////////////////
// 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 ) {
2015-12-30 10:25:29 +00:00
// 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 ) & static_cast < size_t > ( ~ 15 ) ) ;
while ( p ! = nextAligned )
if ( * p = = ' ' | | * p = = ' \n ' | | * p = = ' \r ' | | * p = = ' \t ' )
+ + p ;
else
return p ;
2014-10-17 20:51:37 +00:00
// The rest of string using SIMD
2015-12-30 10:25:29 +00:00
static const char whitespace [ 16 ] = " \n \r \t " ;
const __m128i w = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & whitespace [ 0 ] ) ) ;
2014-10-17 20:51:37 +00:00
for ( ; ; p + = 16 ) {
2015-12-30 10:25:29 +00:00
const __m128i s = _mm_load_si128 ( reinterpret_cast < const __m128i * > ( p ) ) ;
const int r = _mm_cvtsi128_si32 ( _mm_cmpistrm ( w , s , _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY ) ) ;
2014-10-17 20:51:37 +00:00
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 ) {
2015-12-30 10:25:29 +00:00
// Fast return for single non-whitespace
if ( * p = = ' ' | | * p = = ' \n ' | | * p = = ' \r ' | | * p = = ' \t ' )
+ + p ;
else
return p ;
2014-10-17 20:51:37 +00:00
// 16-byte align to the next boundary
2015-12-30 10:25:29 +00:00
const char * nextAligned = reinterpret_cast < const char * > ( ( reinterpret_cast < size_t > ( p ) + 15 ) & static_cast < size_t > ( ~ 15 ) ) ;
while ( p ! = nextAligned )
if ( * p = = ' ' | | * p = = ' \n ' | | * p = = ' \r ' | | * p = = ' \t ' )
+ + p ;
else
return p ;
2014-10-17 20:51:37 +00:00
// The rest of string
2015-12-30 10:25:29 +00:00
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 " } ;
2014-10-17 20:51:37 +00:00
2015-12-30 10:25:29 +00:00
const __m128i w0 = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & whitespaces [ 0 ] [ 0 ] ) ) ;
const __m128i w1 = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & whitespaces [ 1 ] [ 0 ] ) ) ;
const __m128i w2 = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & whitespaces [ 2 ] [ 0 ] ) ) ;
const __m128i w3 = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( & whitespaces [ 3 ] [ 0 ] ) ) ;
2014-10-17 20:51:37 +00:00
for ( ; ; p + = 16 ) {
2015-12-30 10:25:29 +00:00
const __m128i s = _mm_load_si128 ( reinterpret_cast < const __m128i * > ( p ) ) ;
2014-10-17 20:51:37 +00:00
__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 ) ) ;
2015-12-30 10:25:29 +00:00
unsigned short r = static_cast < unsigned short > ( ~ _mm_movemask_epi8 ( x ) ) ;
2014-10-17 20:51:37 +00:00
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.
2015-12-30 10:25:29 +00:00
/*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
2014-10-17 20:51:37 +00:00
\ 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 ) ;
2015-12-30 10:25:29 +00:00
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN ( parseResult_ ) ;
2014-10-17 20:51:37 +00:00
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 ) ) {
2015-12-30 10:25:29 +00:00
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN ( parseResult_ ) ;
2014-10-17 20:51:37 +00:00
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 & ) ;
} ;
2015-12-30 10:25:29 +00:00
template < unsigned parseFlags , typename InputStream >
void SkipWhitespaceAndComments ( InputStream & is ) {
SkipWhitespace ( is ) ;
if ( parseFlags & kParseCommentsFlag ) {
while ( is . Peek ( ) = = ' / ' ) {
is . Take ( ) ;
if ( is . Peek ( ) = = ' * ' ) {
is . Take ( ) ;
while ( true ) {
if ( is . Peek ( ) = = ' \0 ' )
RAPIDJSON_PARSE_ERROR ( kParseErrorUnspecificSyntaxError , is . Tell ( ) ) ;
if ( is . Take ( ) = = ' * ' ) {
if ( is . Peek ( ) = = ' \0 ' )
RAPIDJSON_PARSE_ERROR ( kParseErrorUnspecificSyntaxError , is . Tell ( ) ) ;
if ( is . Take ( ) = = ' / ' )
break ;
}
}
} else if ( is . Peek ( ) = = ' / ' ) {
is . Take ( ) ;
while ( is . Peek ( ) ! = ' \0 ' & & is . Take ( ) ! = ' \n ' ) { }
} else {
RAPIDJSON_PARSE_ERROR ( kParseErrorUnspecificSyntaxError , is . Tell ( ) ) ;
}
SkipWhitespace ( is ) ;
}
}
}
2014-10-17 20:51:37 +00:00
// 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 ( ) ) ;
2015-12-30 10:25:29 +00:00
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
2014-10-17 20:51:37 +00:00
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 ;
2015-12-30 10:25:29 +00:00
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
2014-10-17 20:51:37 +00:00
if ( is . Take ( ) ! = ' : ' )
RAPIDJSON_PARSE_ERROR ( kParseErrorObjectMissColon , is . Tell ( ) ) ;
2015-12-30 10:25:29 +00:00
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
2014-10-17 20:51:37 +00:00
ParseValue < parseFlags > ( is , handler ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
2015-12-30 10:25:29 +00:00
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
2014-10-17 20:51:37 +00:00
+ + memberCount ;
switch ( is . Take ( ) ) {
2015-12-30 10:25:29 +00:00
case ' , ' :
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
break ;
2014-10-17 20:51:37 +00:00
case ' } ' :
if ( ! handler . EndObject ( memberCount ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorTermination , is . Tell ( ) ) ;
2015-12-30 10:25:29 +00:00
return ;
default :
RAPIDJSON_PARSE_ERROR ( kParseErrorObjectMissCommaOrCurlyBracket , is . Tell ( ) ) ;
break ;
2014-10-17 20:51:37 +00:00
}
}
}
// 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 ( ) ) ;
2015-12-30 10:25:29 +00:00
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
2014-10-17 20:51:37 +00:00
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 ;
2015-12-30 10:25:29 +00:00
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
2014-10-17 20:51:37 +00:00
switch ( is . Take ( ) ) {
2015-12-30 10:25:29 +00:00
case ' , ' :
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
break ;
2014-10-17 20:51:37 +00:00
case ' ] ' :
if ( ! handler . EndArray ( elementCount ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorTermination , is . Tell ( ) ) ;
2015-12-30 10:25:29 +00:00
return ;
default :
RAPIDJSON_PARSE_ERROR ( kParseErrorArrayMissCommaOrSquareBracket , is . Tell ( ) ) ;
break ;
2014-10-17 20:51:37 +00:00
}
}
}
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 ;
}
2015-12-30 10:25:29 +00:00
template < typename CharType >
2014-10-17 20:51:37 +00:00
class StackStream {
public :
2015-12-30 10:25:29 +00:00
typedef CharType Ch ;
2014-10-17 20:51:37 +00:00
StackStream ( internal : : Stack < StackAllocator > & stack ) : stack_ ( stack ) , length_ ( 0 ) { }
RAPIDJSON_FORCEINLINE void Put ( Ch c ) {
* stack_ . template Push < Ch > ( ) = c ;
+ + length_ ;
}
2015-12-30 10:25:29 +00:00
size_t Length ( ) const { return length_ ; }
Ch * Pop ( ) {
return stack_ . template Pop < Ch > ( length_ ) ;
}
2014-10-17 20:51:37 +00:00
private :
StackStream ( const StackStream & ) ;
StackStream & operator = ( const StackStream & ) ;
2015-12-30 10:25:29 +00:00
internal : : Stack < StackAllocator > & stack_ ;
SizeType length_ ;
2014-10-17 20:51:37 +00:00
} ;
// 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 ) ;
2015-12-30 10:25:29 +00:00
const typename TargetEncoding : : Ch * const str = reinterpret_cast < typename TargetEncoding : : Ch * > ( head ) ;
2014-10-17 20:51:37 +00:00
success = ( isKey ? handler . Key ( str , SizeType ( length ) , false ) : handler . String ( str , SizeType ( length ) , false ) ) ;
}
else {
2015-12-30 10:25:29 +00:00
StackStream < typename TargetEncoding : : Ch > stackStream ( stack_ ) ;
2014-10-17 20:51:37 +00:00
ParseStringToStream < parseFlags , SourceEncoding , TargetEncoding > ( s , stackStream ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
2015-12-30 10:25:29 +00:00
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 ) ) ;
2014-10-17 20:51:37 +00:00
}
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 ( ) ;
2015-12-30 10:25:29 +00:00
if ( ( sizeof ( Ch ) = = 1 | | unsigned ( e ) < 256 ) & & escape [ static_cast < unsigned char > ( e ) ] )
os . Put ( static_cast < typename TEncoding : : Ch > ( escape [ static_cast < unsigned char > ( e ) ] ) ) ;
2014-10-17 20:51:37 +00:00
else if ( e = = ' u ' ) { // Unicode
unsigned codepoint = ParseHex4 ( is ) ;
2015-12-30 10:25:29 +00:00
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
2014-10-17 20:51:37 +00:00
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 ) ;
2015-12-30 10:25:29 +00:00
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID ;
2014-10-17 20:51:37 +00:00
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 ) ;
2015-12-30 10:25:29 +00:00
else if ( static_cast < unsigned > ( c ) < 0x20 ) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
2014-10-17 20:51:37 +00:00
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 ( ) ) ;
}
}
}
2015-12-30 10:25:29 +00:00
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 ( static_cast < 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 ;
} ;
2014-10-17 20:51:37 +00:00
template < unsigned parseFlags , typename InputStream , typename Handler >
void ParseNumber ( InputStream & is , Handler & handler ) {
internal : : StreamLocalCopy < InputStream > copy ( is ) ;
2015-12-30 10:25:29 +00:00
NumberStream < InputStream , ( parseFlags & kParseFullPrecisionFlag ) ! = 0 > s ( * this , copy . s ) ;
2014-10-17 20:51:37 +00:00
// 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 ;
2015-12-30 10:25:29 +00:00
int significandDigit = 0 ;
2014-10-17 20:51:37 +00:00
if ( s . Peek ( ) = = ' 0 ' ) {
i = 0 ;
2015-12-30 10:25:29 +00:00
s . TakePush ( ) ;
2014-10-17 20:51:37 +00:00
}
else if ( s . Peek ( ) > = ' 1 ' & & s . Peek ( ) < = ' 9 ' ) {
2015-12-30 10:25:29 +00:00
i = static_cast < unsigned > ( s . TakePush ( ) - ' 0 ' ) ;
2014-10-17 20:51:37 +00:00
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 ;
}
}
2015-12-30 10:25:29 +00:00
i = i * 10 + static_cast < unsigned > ( s . TakePush ( ) - ' 0 ' ) ;
significandDigit + + ;
2014-10-17 20:51:37 +00:00
}
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 ;
}
}
2015-12-30 10:25:29 +00:00
i = i * 10 + static_cast < unsigned > ( s . TakePush ( ) - ' 0 ' ) ;
significandDigit + + ;
2014-10-17 20:51:37 +00:00
}
}
else
RAPIDJSON_PARSE_ERROR ( kParseErrorValueInvalid , s . Tell ( ) ) ;
// Parse 64bit int
bool useDouble = false ;
2015-12-30 10:25:29 +00:00
double d = 0.0 ;
2014-10-17 20:51:37 +00:00
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 ' ) {
2015-12-30 10:25:29 +00:00
d = i64 ;
2014-10-17 20:51:37 +00:00
useDouble = true ;
break ;
}
2015-12-30 10:25:29 +00:00
i64 = i64 * 10 + static_cast < unsigned > ( s . TakePush ( ) - ' 0 ' ) ;
significandDigit + + ;
2014-10-17 20:51:37 +00:00
}
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 ' ) {
2015-12-30 10:25:29 +00:00
d = i64 ;
2014-10-17 20:51:37 +00:00
useDouble = true ;
break ;
}
2015-12-30 10:25:29 +00:00
i64 = i64 * 10 + static_cast < unsigned > ( s . TakePush ( ) - ' 0 ' ) ;
significandDigit + + ;
2014-10-17 20:51:37 +00:00
}
}
// 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 ( ) ) ;
2015-12-30 10:25:29 +00:00
d = d * 10 + ( s . TakePush ( ) - ' 0 ' ) ;
2014-10-17 20:51:37 +00:00
}
}
// Parse frac = decimal-point 1*DIGIT
int expFrac = 0 ;
2015-12-30 10:25:29 +00:00
size_t decimalPosition ;
2014-10-17 20:51:37 +00:00
if ( s . Peek ( ) = = ' . ' ) {
s . Take ( ) ;
2015-12-30 10:25:29 +00:00
decimalPosition = s . Length ( ) ;
if ( ! ( s . Peek ( ) > = ' 0 ' & & s . Peek ( ) < = ' 9 ' ) )
RAPIDJSON_PARSE_ERROR ( kParseErrorNumberMissFraction , s . Tell ( ) ) ;
2014-10-17 20:51:37 +00:00
if ( ! useDouble ) {
2015-12-30 10:25:29 +00:00
# if RAPIDJSON_64BIT
// Use i64 to store significand in 64-bit architecture
2014-10-17 20:51:37 +00:00
if ( ! use64bit )
i64 = i ;
while ( s . Peek ( ) > = ' 0 ' & & s . Peek ( ) < = ' 9 ' ) {
2015-12-30 10:25:29 +00:00
if ( i64 > RAPIDJSON_UINT64_C2 ( 0x1FFFFF , 0xFFFFFFFF ) ) // 2^53 - 1 for fast path
2014-10-17 20:51:37 +00:00
break ;
else {
2015-12-30 10:25:29 +00:00
i64 = i64 * 10 + static_cast < unsigned > ( s . TakePush ( ) - ' 0 ' ) ;
2014-10-17 20:51:37 +00:00
- - expFrac ;
2015-12-30 10:25:29 +00:00
if ( i64 ! = 0 )
significandDigit + + ;
2014-10-17 20:51:37 +00:00
}
}
2015-12-30 10:25:29 +00:00
d = static_cast < double > ( i64 ) ;
2014-10-17 20:51:37 +00:00
# else
2015-12-30 10:25:29 +00:00
// Use double to store significand in 32-bit architecture
d = static_cast < double > ( use64bit ? i64 : i ) ;
2014-10-17 20:51:37 +00:00
# endif
2015-12-30 10:25:29 +00:00
useDouble = true ;
}
2014-10-17 20:51:37 +00:00
while ( s . Peek ( ) > = ' 0 ' & & s . Peek ( ) < = ' 9 ' ) {
2015-12-30 10:25:29 +00:00
if ( significandDigit < 17 ) {
d = d * 10.0 + ( s . TakePush ( ) - ' 0 ' ) ;
- - expFrac ;
if ( d > 0.0 )
significandDigit + + ;
}
else
s . TakePush ( ) ;
2014-10-17 20:51:37 +00:00
}
}
2015-12-30 10:25:29 +00:00
else
decimalPosition = s . Length ( ) ; // decimal position at the end of integer.
2014-10-17 20:51:37 +00:00
// Parse exp = e [ minus / plus ] 1*DIGIT
int exp = 0 ;
if ( s . Peek ( ) = = ' e ' | | s . Peek ( ) = = ' E ' ) {
if ( ! useDouble ) {
2015-12-30 10:25:29 +00:00
d = use64bit ? i64 : i ;
2014-10-17 20:51:37 +00:00
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 ' ) {
2015-12-30 10:25:29 +00:00
exp = static_cast < int > ( s . Take ( ) - ' 0 ' ) ;
if ( expMinus ) {
while ( s . Peek ( ) > = ' 0 ' & & s . Peek ( ) < = ' 9 ' ) {
exp = exp * 10 + static_cast < int > ( 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 + static_cast < int > ( s . Take ( ) - ' 0 ' ) ;
if ( exp > maxExp )
RAPIDJSON_PARSE_ERROR ( kParseErrorNumberTooBig , s . Tell ( ) ) ;
}
2014-10-17 20:51:37 +00:00
}
}
else
RAPIDJSON_PARSE_ERROR ( kParseErrorNumberMissExponent , s . Tell ( ) ) ;
if ( expMinus )
exp = - exp ;
}
// Finish parsing, call event according to the type of number.
bool cont = true ;
2015-12-30 10:25:29 +00:00
size_t length = s . Length ( ) ;
const char * decimal = s . Pop ( ) ; // Pop stack no matter if it will be used or not.
2014-10-17 20:51:37 +00:00
if ( useDouble ) {
2015-12-30 10:25:29 +00:00
int p = exp + expFrac ;
if ( parseFlags & kParseFullPrecisionFlag )
d = internal : : StrtodFullPrecision ( d , p , decimal , length , decimalPosition , exp ) ;
2014-10-17 20:51:37 +00:00
else
2015-12-30 10:25:29 +00:00
d = internal : : StrtodNormalPrecision ( d , p ) ;
2014-10-17 20:51:37 +00:00
cont = handler . Double ( minus ? - d : d ) ;
}
else {
if ( use64bit ) {
if ( minus )
2015-12-30 10:25:29 +00:00
cont = handler . Int64 ( static_cast < int64_t > ( ~ i64 + 1 ) ) ;
2014-10-17 20:51:37 +00:00
else
cont = handler . Uint64 ( i64 ) ;
}
else {
if ( minus )
2015-12-30 10:25:29 +00:00
cont = handler . Int ( static_cast < int32_t > ( ~ i + 1 ) ) ;
2014-10-17 20:51:37 +00:00
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 ;
2015-12-30 10:25:29 +00:00
default :
ParseNumber < parseFlags > ( is , handler ) ;
break ;
2014-10-17 20:51:37 +00:00
}
}
// 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
2015-12-30 10:25:29 +00:00
IterativeParsingValueState
2014-10-17 20:51:37 +00:00
} ;
2015-12-30 10:25:29 +00:00
enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 } ;
2014-10-17 20:51:37 +00:00
// 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
2015-12-30 10:25:29 +00:00
if ( sizeof ( Ch ) = = 1 | | static_cast < unsigned > ( c ) < 256 )
return static_cast < Token > ( tokenMap [ static_cast < unsigned char > ( c ) ] ) ;
2014-10-17 20:51:37 +00:00
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
2015-12-30 10:25:29 +00:00
return static_cast < IterativeParsingState > ( G [ state ] [ token ] ) ;
2014-10-17 20:51:37 +00: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.
template < unsigned parseFlags , typename InputStream , typename Handler >
RAPIDJSON_FORCEINLINE IterativeParsingState Transit ( IterativeParsingState src , Token token , IterativeParsingState dst , InputStream & is , Handler & handler ) {
2015-12-30 10:25:29 +00:00
( void ) token ;
2014-10-17 20:51:37 +00:00
2015-12-30 10:25:29 +00:00
switch ( dst ) {
2014-10-17 20:51:37 +00:00
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 :
2015-12-30 10:25:29 +00:00
RAPIDJSON_ASSERT ( token = = ColonToken ) ;
is . Take ( ) ;
return dst ;
2014-10-17 20:51:37 +00:00
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 ;
}
}
2015-12-30 10:25:29 +00:00
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 ) ;
2014-10-17 20:51:37 +00:00
// 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 ) {
2015-12-30 10:25:29 +00:00
case IterativeParsingStartState : RAPIDJSON_PARSE_ERROR ( kParseErrorDocumentEmpty , is . Tell ( ) ) ; return ;
case IterativeParsingFinishState : RAPIDJSON_PARSE_ERROR ( kParseErrorDocumentRootNotSingular , is . Tell ( ) ) ; return ;
2014-10-17 20:51:37 +00:00
case IterativeParsingObjectInitialState :
2015-12-30 10:25:29 +00:00
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 ( ) ) ; return ;
2014-10-17 20:51:37 +00:00
}
}
template < unsigned parseFlags , typename InputStream , typename Handler >
ParseResult IterativeParse ( InputStream & is , Handler & handler ) {
parseResult_ . Clear ( ) ;
ClearStackOnExit scope ( * this ) ;
IterativeParsingState state = IterativeParsingStartState ;
2015-12-30 10:25:29 +00:00
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN ( parseResult_ ) ;
2014-10-17 20:51:37 +00:00
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 ;
2015-12-30 10:25:29 +00:00
SkipWhitespaceAndComments < parseFlags > ( is ) ;
RAPIDJSON_PARSE_ERROR_EARLY_RETURN ( parseResult_ ) ;
2014-10-17 20:51:37 +00:00
}
// 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 ;
2015-12-30 10:25:29 +00:00
RAPIDJSON_NAMESPACE_END
# ifdef __clang__
RAPIDJSON_DIAG_POP
# endif
# ifdef __GNUC__
RAPIDJSON_DIAG_POP
# endif
2014-10-17 20:51:37 +00:00
# ifdef _MSC_VER
RAPIDJSON_DIAG_POP
# endif
# endif // RAPIDJSON_READER_H_