Commit 7c914a9d authored by miloyip@gmail.com's avatar miloyip@gmail.com

Added RAPIDJSON_STATIC_ASSERT() and applied it to check size of character types in encodings.

Modified API documentation to previous changes.
Rename Stream to InputStream/OutputStream/InputByteStream/OutputByteStream, and stream to is/os according to the context.


git-svn-id: https://rapidjson.googlecode.com/svn/trunk@49 c5894555-1306-4e8d-425f-1f6f381ee07c
parent f516a017
...@@ -5,13 +5,18 @@ ...@@ -5,13 +5,18 @@
namespace rapidjson { namespace rapidjson {
//! Adapts an input byte stream with an specified encoding. //! Input byte stream wrapper with a statically bound encoding.
template <typename Encoding, typename InputStream> /*!
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
\tparam InputByteStream Type of input byte stream. For example, FileReadStream.
*/
template <typename Encoding, typename InputByteStream>
class EncodedInputStream { class EncodedInputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
public: public:
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
EncodedInputStream(InputStream& is) : is_(is) { EncodedInputStream(InputByteStream& is) : is_(is) {
current_ = Encoding::TakeBOM(is_); current_ = Encoding::TakeBOM(is_);
} }
...@@ -26,17 +31,22 @@ public: ...@@ -26,17 +31,22 @@ public:
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private: private:
InputStream& is_; InputByteStream& is_;
Ch current_; Ch current_;
}; };
//! Adapts an output byte stream with an specified encoding. //! Output byte stream wrapper with statically bound encoding.
template <typename Encoding, typename OutputStream> /*!
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
\tparam InputByteStream Type of input byte stream. For example, FileWriteStream.
*/
template <typename Encoding, typename OutputByteStream>
class EncodedOutputStream { class EncodedOutputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
public: public:
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
EncodedOutputStream(OutputStream& os, bool putBOM = true) : os_(os) { EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
if (putBOM) if (putBOM)
Encoding::PutBOM(os_); Encoding::PutBOM(os_);
} }
...@@ -52,24 +62,36 @@ public: ...@@ -52,24 +62,36 @@ public:
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private: private:
OutputStream& os_; OutputByteStream& os_;
}; };
#define ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
template <typename CharType, typename InputStream> //! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
/*!
\tparam CharType Type of character for reading.
\tparam InputByteStream type of input byte stream to be wrapped.
*/
template <typename CharType, typename InputByteStream>
class AutoUTFInputStream { class AutoUTFInputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
public: public:
typedef CharType Ch; typedef CharType Ch;
AutoUTFInputStream(InputStream& is, UTFType type = kUTF8) : is_(is), type_(type) { //! Constructor.
/*!
\param is input stream to be wrapped.
\param type UTF encoding type if it is not detected from the stream.
*/
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(is), type_(type), hasBOM_(false) {
DetectType(is); DetectType(is);
static const TakeFunc f[] = { ENCODINGS_FUNC(Take) }; static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
takeFunc_ = f[type_]; takeFunc_ = f[type_];
current_ = takeFunc_(is_); current_ = takeFunc_(is_);
} }
UTFType GetType() const { return type_; } UTFType GetType() const { return type_; }
bool HasBOM() const { return hasBOM_; }
Ch Peek() const { return current_; } Ch Peek() const { return current_; }
Ch Take() { Ch c = current_; current_ = takeFunc_(is_); return c; } Ch Take() { Ch c = current_; current_ = takeFunc_(is_); return c; }
...@@ -83,7 +105,7 @@ public: ...@@ -83,7 +105,7 @@ public:
private: private:
// Detect encoding type with BOM or RFC 4627 // Detect encoding type with BOM or RFC 4627
void DetectType(InputStream& is) { void DetectType(InputByteStream& is) {
// BOM (Byte Order Mark): // BOM (Byte Order Mark):
// 00 00 FE FF UTF-32BE // 00 00 FE FF UTF-32BE
// FF FE 00 00 UTF-32LE // FF FE 00 00 UTF-32LE
...@@ -96,11 +118,12 @@ private: ...@@ -96,11 +118,12 @@ private:
return; return;
unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
if (bom == 0xFFFE0000) { type_ = kUTF32BE; is.Take(); is.Take(); is.Take(); is.Take(); goto sizecheck; } hasBOM_ = false;
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; is.Take(); is.Take(); is.Take(); is.Take(); goto sizecheck; } if (bom == 0xFFFE0000) { type_ = kUTF32BE; is.Take(); is.Take(); is.Take(); is.Take(); hasBOM_ = true; }
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; is.Take(); is.Take(); goto sizecheck; } else if (bom == 0x0000FEFF) { type_ = kUTF32LE; is.Take(); is.Take(); is.Take(); is.Take(); hasBOM_ = true; }
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; is.Take(); is.Take(); goto sizecheck; } else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; is.Take(); is.Take(); hasBOM_ = true; }
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; is.Take(); is.Take(); is.Take(); goto sizecheck; } else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; is.Take(); is.Take(); hasBOM_ = true; }
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; is.Take(); is.Take(); is.Take(); hasBOM_ = true; }
// RFC 4627: Section 3 // RFC 4627: Section 3
// "Since the first two characters of a JSON text will always be ASCII // "Since the first two characters of a JSON text will always be ASCII
...@@ -113,16 +136,17 @@ private: ...@@ -113,16 +136,17 @@ private:
// xx 00 xx 00 UTF-16LE // xx 00 xx 00 UTF-16LE
// xx xx xx xx UTF-8 // xx xx xx xx UTF-8
unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); if (!hasBOM_) {
switch (pattern) { unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
case 0x08: type_ = kUTF32BE; break; switch (pattern) {
case 0x0A: type_ = kUTF16BE; break; case 0x08: type_ = kUTF32BE; break;
case 0x01: type_ = kUTF32LE; break; case 0x0A: type_ = kUTF16BE; break;
case 0x05: type_ = kUTF16LE; break; case 0x01: type_ = kUTF32LE; break;
case 0x0F: type_ = kUTF8; break; case 0x05: type_ = kUTF16LE; break;
case 0x0F: type_ = kUTF8; break;
}
} }
sizecheck:
// RUntime check whether the size of character type is sufficient. It only perform checks with assertion. // RUntime check whether the size of character type is sufficient. It only perform checks with assertion.
switch (type_) { switch (type_) {
case kUTF16LE: case kUTF16LE:
...@@ -136,19 +160,32 @@ private: ...@@ -136,19 +160,32 @@ private:
} }
} }
typedef Ch (*TakeFunc)(InputStream& is); typedef Ch (*TakeFunc)(InputByteStream& is);
InputStream& is_; InputByteStream& is_;
UTFType type_; UTFType type_;
Ch current_; Ch current_;
TakeFunc takeFunc_; TakeFunc takeFunc_;
bool hasBOM_;
}; };
template <typename CharType, typename OutputStream> //! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
/*!
\tparam CharType Type of character for writing.
\tparam InputByteStream type of output byte stream to be wrapped.
*/
template <typename CharType, typename OutputByteStream>
class AutoUTFOutputStream { class AutoUTFOutputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
public: public:
typedef CharType Ch; typedef CharType Ch;
AutoUTFOutputStream(OutputStream& os, UTFType type, bool putBOM) : os_(os), type_(type) { //! Constructor.
/*!
\param os output stream to be wrapped.
\param type UTF encoding type.
\param putBOM Whether to write BOM at the beginning of the stream.
*/
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(os), type_(type) {
// RUntime check whether the size of character type is sufficient. It only perform checks with assertion. // RUntime check whether the size of character type is sufficient. It only perform checks with assertion.
switch (type_) { switch (type_) {
case kUTF16LE: case kUTF16LE:
...@@ -161,7 +198,7 @@ public: ...@@ -161,7 +198,7 @@ public:
break; break;
} }
static const PutFunc f[] = { ENCODINGS_FUNC(Put) }; static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
putFunc_ = f[type_]; putFunc_ = f[type_];
if (putBOM) if (putBOM)
...@@ -170,10 +207,7 @@ public: ...@@ -170,10 +207,7 @@ public:
UTFType GetType() const { return type_; } UTFType GetType() const { return type_; }
void Put(Ch c) { void Put(Ch c) { putFunc_(os_, c); }
putFunc_(os_, c);
}
void Flush() { os_.Flush(); } void Flush() { os_.Flush(); }
// Not implemented // Not implemented
...@@ -185,19 +219,19 @@ public: ...@@ -185,19 +219,19 @@ public:
private: private:
void PutBOM() { void PutBOM() {
typedef void (*PutBOMFunc)(OutputStream&); typedef void (*PutBOMFunc)(OutputByteStream&);
static const PutBOMFunc f[] = { ENCODINGS_FUNC(PutBOM) }; static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
f[type_](os_); f[type_](os_);
} }
typedef void (*PutFunc)(OutputStream&, Ch); typedef void (*PutFunc)(OutputByteStream&, Ch);
OutputStream& os_; OutputByteStream& os_;
UTFType type_; UTFType type_;
PutFunc putFunc_; PutFunc putFunc_;
}; };
#undef ENCODINGS_FUNC #undef RAPIDJSON_ENCODINGS_FUNC
} // namespace rapidjson } // namespace rapidjson
......
...@@ -13,13 +13,20 @@ namespace rapidjson { ...@@ -13,13 +13,20 @@ namespace rapidjson {
\code \code
concept Encoding { concept Encoding {
typename Ch; //! Type of character. typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
//! \brief Encode a Unicode codepoint to a stream. //! \brief Encode a Unicode codepoint to an output stream.
//! \param os Output stream. //! \param os Output stream.
//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
template<typename OutputStream> template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) { static void Encode(OutputStream& os, unsigned codepoint);
//! \brief Decode a Unicode codepoint from an input stream.
//! \param is Input stream.
//! \param codepoint Output of the unicode codepoint.
//! \return true if a valid codepoint can be decoded from the stream.
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint);
//! \brief Validate one Unicode codepoint from an encoded stream. //! \brief Validate one Unicode codepoint from an encoded stream.
//! \param is Input stream to obtain codepoint. //! \param is Input stream to obtain codepoint.
...@@ -27,7 +34,25 @@ concept Encoding { ...@@ -27,7 +34,25 @@ concept Encoding {
//! \return true if it is valid. //! \return true if it is valid.
//! \note This function just validating and copying the codepoint without actually decode it. //! \note This function just validating and copying the codepoint without actually decode it.
template <typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { static bool Validate(InputStream& is, OutputStream& os);
// The following functions are deal with byte streams.
//! Take a character from input byte stream, skip BOM if exist.
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is);
//! Take a character from input byte stream.
template <typename InputByteStream>
static Ch Take(InputByteStream& is);
//! Put BOM to output byte stream.
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os);
//! Put a character to output byte stream.
template <typename OutputByteStream>
static void Put(OutputByteStream& os, Ch c);
}; };
\endcode \endcode
*/ */
...@@ -38,7 +63,7 @@ concept Encoding { ...@@ -38,7 +63,7 @@ concept Encoding {
//! UTF-8 encoding. //! UTF-8 encoding.
/*! http://en.wikipedia.org/wiki/UTF-8 /*! http://en.wikipedia.org/wiki/UTF-8
http://tools.ietf.org/html/rfc3629 http://tools.ietf.org/html/rfc3629
\tparam CharType Type for storing 8-bit UTF-8 data. Default is char. \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
\implements Encoding \implements Encoding
*/ */
template<typename CharType = char> template<typename CharType = char>
...@@ -68,7 +93,7 @@ struct UTF8 { ...@@ -68,7 +93,7 @@ struct UTF8 {
} }
template <typename InputStream> template <typename InputStream>
RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { static bool Decode(InputStream& is, unsigned* codepoint) {
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu) #define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu)
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) #define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
#define TAIL() COPY(); TRANS(0x70) #define TAIL() COPY(); TRANS(0x70)
...@@ -97,7 +122,7 @@ struct UTF8 { ...@@ -97,7 +122,7 @@ struct UTF8 {
} }
template <typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { static bool Validate(InputStream& is, OutputStream& os) {
#define COPY() os.Put(c = is.Take()) #define COPY() os.Put(c = is.Take())
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) #define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
#define TAIL() COPY(); TRANS(0x70) #define TAIL() COPY(); TRANS(0x70)
...@@ -122,7 +147,7 @@ struct UTF8 { ...@@ -122,7 +147,7 @@ struct UTF8 {
#undef TAIL #undef TAIL
} }
RAPIDJSON_FORCEINLINE static unsigned char GetRange(unsigned char c) { static unsigned char GetRange(unsigned char c) {
// Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
// With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
static const unsigned char type[] = { static const unsigned char type[] = {
...@@ -140,8 +165,9 @@ struct UTF8 { ...@@ -140,8 +165,9 @@ struct UTF8 {
return type[c]; return type[c];
} }
template <typename InputStream> template <typename InputByteStream>
static CharType TakeBOM(InputStream& is) { static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
Ch c = Take(is); Ch c = Take(is);
if ((unsigned char)c != 0xEFu) return c; if ((unsigned char)c != 0xEFu) return c;
c = is.Take(); c = is.Take();
...@@ -152,18 +178,21 @@ struct UTF8 { ...@@ -152,18 +178,21 @@ struct UTF8 {
return c; return c;
} }
template <typename InputStream> template <typename InputByteStream>
RAPIDJSON_FORCEINLINE static Ch Take(InputStream& is) { static Ch Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
return is.Take(); return is.Take();
} }
template <typename OutputStream> template <typename OutputByteStream>
static void PutBOM(OutputStream& os) { static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu); os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu);
} }
template <typename OutputStream> template <typename OutputByteStream>
static void Put(OutputStream& os, Ch c) { static void Put(OutputByteStream& os, Ch c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(c); os.Put(c);
} }
}; };
...@@ -176,13 +205,18 @@ struct UTF8 { ...@@ -176,13 +205,18 @@ struct UTF8 {
http://tools.ietf.org/html/rfc2781 http://tools.ietf.org/html/rfc2781
\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
\implements Encoding \implements Encoding
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
For streaming, use UTF16LE and UTF16BE, which handle endianness.
*/ */
template<typename CharType = wchar_t> template<typename CharType = wchar_t>
struct UTF16 { struct UTF16 {
typedef CharType Ch; typedef CharType Ch;
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
template<typename OutputStream> template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) { static void Encode(OutputStream& os, unsigned codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
if (codepoint <= 0xFFFF) { if (codepoint <= 0xFFFF) {
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
os.Put(codepoint); os.Put(codepoint);
...@@ -196,7 +230,8 @@ struct UTF16 { ...@@ -196,7 +230,8 @@ struct UTF16 {
} }
template <typename InputStream> template <typename InputStream>
RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { static bool Decode(InputStream& is, unsigned* codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
Ch c = is.Take(); Ch c = is.Take();
if (c < 0xD800 || c > 0xDFFF) { if (c < 0xD800 || c > 0xDFFF) {
*codepoint = c; *codepoint = c;
...@@ -213,7 +248,9 @@ struct UTF16 { ...@@ -213,7 +248,9 @@ struct UTF16 {
} }
template <typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { static bool Validate(InputStream& is, OutputStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
Ch c; Ch c;
os.Put(c = is.Take()); os.Put(c = is.Take());
if (c < 0xD800 || c > 0xDFFF) if (c < 0xD800 || c > 0xDFFF)
...@@ -226,55 +263,65 @@ struct UTF16 { ...@@ -226,55 +263,65 @@ struct UTF16 {
} }
}; };
//! UTF-16 little endian encoding.
template<typename CharType = wchar_t> template<typename CharType = wchar_t>
struct UTF16LE : UTF16<CharType> { struct UTF16LE : UTF16<CharType> {
template <typename InputStream> template <typename InputByteStream>
static CharType TakeBOM(InputStream& is) { static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is); CharType c = Take(is);
return (unsigned short)c == 0xFEFFu ? Take(is) : c; return (unsigned short)c == 0xFEFFu ? Take(is) : c;
} }
template <typename InputStream> template <typename InputByteStream>
RAPIDJSON_FORCEINLINE static CharType Take(InputStream& is) { static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take(); CharType c = (unsigned char)is.Take();
c |= (unsigned char)is.Take() << 8; c |= (unsigned char)is.Take() << 8;
return c; return c;
} }
template <typename OutputStream> template <typename OutputByteStream>
static void PutBOM(OutputStream& os) { static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0xFFu); os.Put(0xFEu); os.Put(0xFFu); os.Put(0xFEu);
} }
template <typename OutputStream> template <typename OutputByteStream>
static void Put(OutputStream& os, CharType c) { static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(c & 0xFFu); os.Put(c & 0xFFu);
os.Put((c >> 8) & 0xFFu); os.Put((c >> 8) & 0xFFu);
} }
}; };
//! UTF-16 big endian encoding.
template<typename CharType = wchar_t> template<typename CharType = wchar_t>
struct UTF16BE : UTF16<CharType> { struct UTF16BE : UTF16<CharType> {
template <typename InputStream> template <typename InputByteStream>
static CharType TakeBOM(InputStream& is) { static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is); CharType c = Take(is);
return (unsigned short)c == 0xFEFFu ? Take(is) : c; return (unsigned short)c == 0xFEFFu ? Take(is) : c;
} }
template <typename InputStream> template <typename InputByteStream>
RAPIDJSON_FORCEINLINE static CharType Take(InputStream& is) { static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take() << 8; CharType c = (unsigned char)is.Take() << 8;
c |= (unsigned char)is.Take(); c |= (unsigned char)is.Take();
return c; return c;
} }
template <typename OutputStream> template <typename OutputByteStream>
static void PutBOM(OutputStream& os) { static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0xFEu); os.Put(0xFFu); os.Put(0xFEu); os.Put(0xFFu);
} }
template <typename OutputStream> template <typename OutputByteStream>
static void Put(OutputStream& os, CharType c) { static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put((c >> 8) & 0xFFu); os.Put((c >> 8) & 0xFFu);
os.Put(c & 0xFFu); os.Put(c & 0xFFu);
} }
...@@ -287,42 +334,52 @@ struct UTF16BE : UTF16<CharType> { ...@@ -287,42 +334,52 @@ struct UTF16BE : UTF16<CharType> {
/*! http://en.wikipedia.org/wiki/UTF-32 /*! http://en.wikipedia.org/wiki/UTF-32
\tparam Ch Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. \tparam Ch Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
\implements Encoding \implements Encoding
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
For streaming, use UTF32LE and UTF32BE, which handle endianness.
*/ */
template<typename CharType = unsigned> template<typename CharType = unsigned>
struct UTF32 { struct UTF32 {
typedef CharType Ch; typedef CharType Ch;
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
template<typename OutputStream> template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) { static void Encode(OutputStream& os, unsigned codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
os.Put(codepoint); os.Put(codepoint);
} }
template <typename InputStream> template <typename InputStream>
RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { static bool Decode(InputStream& is, unsigned* codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
Ch c = is.Take(); Ch c = is.Take();
*codepoint = c; *codepoint = c;
return c <= 0x10FFFF; return c <= 0x10FFFF;
} }
template <typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { static bool Validate(InputStream& is, OutputStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
Ch c; Ch c;
os.Put(c = is.Take()); os.Put(c = is.Take());
return c <= 0x10FFFF; return c <= 0x10FFFF;
} }
}; };
//! UTF-32 little endian enocoding.
template<typename CharType = unsigned> template<typename CharType = unsigned>
struct UTF32LE : UTF32<CharType> { struct UTF32LE : UTF32<CharType> {
template <typename InputStream> template <typename InputByteStream>
static CharType TakeBOM(InputStream& is) { static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is); CharType c = Take(is);
return (unsigned)c == 0x0000FEFFu ? Take(is) : c; return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
} }
template <typename InputStream> template <typename InputByteStream>
RAPIDJSON_FORCEINLINE static CharType Take(InputStream& is) { static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take(); CharType c = (unsigned char)is.Take();
c |= (unsigned char)is.Take() << 8; c |= (unsigned char)is.Take() << 8;
c |= (unsigned char)is.Take() << 16; c |= (unsigned char)is.Take() << 16;
...@@ -330,13 +387,15 @@ struct UTF32LE : UTF32<CharType> { ...@@ -330,13 +387,15 @@ struct UTF32LE : UTF32<CharType> {
return c; return c;
} }
template <typename OutputStream> template <typename OutputByteStream>
static void PutBOM(OutputStream& os) { static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u); os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u);
} }
template <typename OutputStream> template <typename OutputByteStream>
static void Put(OutputStream& os, CharType c) { static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(c & 0xFFu); os.Put(c & 0xFFu);
os.Put((c >> 8) & 0xFFu); os.Put((c >> 8) & 0xFFu);
os.Put((c >> 16) & 0xFFu); os.Put((c >> 16) & 0xFFu);
...@@ -344,16 +403,19 @@ struct UTF32LE : UTF32<CharType> { ...@@ -344,16 +403,19 @@ struct UTF32LE : UTF32<CharType> {
} }
}; };
//! UTF-32 big endian encoding.
template<typename CharType = unsigned> template<typename CharType = unsigned>
struct UTF32BE : UTF32<CharType> { struct UTF32BE : UTF32<CharType> {
template <typename InputStream> template <typename InputByteStream>
static CharType TakeBOM(InputStream& is) { static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is); CharType c = Take(is);
return (unsigned)c == 0x0000FEFFu ? Take(is) : c; return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
} }
template <typename InputStream> template <typename InputByteStream>
RAPIDJSON_FORCEINLINE static CharType Take(InputStream& is) { static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take() << 24; CharType c = (unsigned char)is.Take() << 24;
c |= (unsigned char)is.Take() << 16; c |= (unsigned char)is.Take() << 16;
c |= (unsigned char)is.Take() << 8; c |= (unsigned char)is.Take() << 8;
...@@ -361,13 +423,15 @@ struct UTF32BE : UTF32<CharType> { ...@@ -361,13 +423,15 @@ struct UTF32BE : UTF32<CharType> {
return c; return c;
} }
template <typename OutputStream> template <typename OutputByteStream>
static void PutBOM(OutputStream& os) { static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu); os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu);
} }
template <typename OutputStream> template <typename OutputByteStream>
static void Put(OutputStream& os, CharType c) { static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put((c >> 24) & 0xFFu); os.Put((c >> 24) & 0xFFu);
os.Put((c >> 16) & 0xFFu); os.Put((c >> 16) & 0xFFu);
os.Put((c >> 8) & 0xFFu); os.Put((c >> 8) & 0xFFu);
...@@ -378,52 +442,57 @@ struct UTF32BE : UTF32<CharType> { ...@@ -378,52 +442,57 @@ struct UTF32BE : UTF32<CharType> {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// AutoUTF // AutoUTF
//! Runtime-specified UTF encoding type of a stream.
enum UTFType { enum UTFType {
kUTF8 = 0, kUTF8 = 0, //!< UTF-8.
kUTF16LE = 1, kUTF16LE = 1, //!< UTF-16 little endian.
kUTF16BE = 2, kUTF16BE = 2, //!< UTF-16 big endian.
kUTF32LE = 3, kUTF32LE = 3, //!< UTF-32 little endian.
kUTF32BE = 4, kUTF32BE = 4, //!< UTF-32 big endian.
}; };
// Dynamically select encoding according to BOM or user setting. //! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
*/
template<typename CharType> template<typename CharType>
struct AutoUTF { struct AutoUTF {
typedef CharType Ch; typedef CharType Ch;
#define ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
template<typename OutputStream> template<typename OutputStream>
RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) { RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
typedef void (*EncodeFunc)(OutputStream&, unsigned); typedef void (*EncodeFunc)(OutputStream&, unsigned);
static const EncodeFunc f[] = { ENCODINGS_FUNC(Encode) }; static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
(*f[os.GetType()])(os, codepoint); (*f[os.GetType()])(os, codepoint);
} }
template <typename InputStream> template <typename InputStream>
RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
typedef bool (*DecodeFunc)(InputStream&, unsigned*); typedef bool (*DecodeFunc)(InputStream&, unsigned*);
static const DecodeFunc f[] = { ENCODINGS_FUNC(Decode) }; static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
return (*f[is.GetType()])(is, codepoint); return (*f[is.GetType()])(is, codepoint);
} }
template <typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
typedef bool (*ValidateFunc)(InputStream&, unsigned*); typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
static const ValidateFunc f[] = { ENCODINGS_FUNC(Validate) }; static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
return (*f[is.GetType()])(is, os); return (*f[is.GetType()])(is, os);
} }
#undef ENCODINGS_FUNC #undef RAPIDJSON_ENCODINGS_FUNC
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Transcoder // Transcoder
//! Encoding conversion.
template<typename SourceEncoding, typename TargetEncoding> template<typename SourceEncoding, typename TargetEncoding>
struct Transcoder { struct Transcoder {
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
template<typename InputStream, typename OutputStream> template<typename InputStream, typename OutputStream>
static bool Transcode(InputStream& is, OutputStream& os) { RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
unsigned codepoint; unsigned codepoint;
if (!SourceEncoding::Decode(is, &codepoint)) if (!SourceEncoding::Decode(is, &codepoint))
return false; return false;
...@@ -431,9 +500,10 @@ struct Transcoder { ...@@ -431,9 +500,10 @@ struct Transcoder {
return true; return true;
} }
//! Validate one Unicode codepoint from an encoded stream.
template<typename InputStream, typename OutputStream> template<typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) { RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
return Transcode(is, os); return Transcode(is, os); // Since source/target encoding is different, must transcode.
} }
}; };
...@@ -441,14 +511,14 @@ struct Transcoder { ...@@ -441,14 +511,14 @@ struct Transcoder {
template<typename Encoding> template<typename Encoding>
struct Transcoder<Encoding, Encoding> { struct Transcoder<Encoding, Encoding> {
template<typename InputStream, typename OutputStream> template<typename InputStream, typename OutputStream>
static bool Transcode(InputStream& is, OutputStream& os) { RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
os.Put(is.Take()); os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
return true; return true;
} }
template<typename InputStream, typename OutputStream> template<typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) { RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
return Encoding::Validate(is, os); return Encoding::Validate(is, os); // source/target encoding are the same
} }
}; };
......
...@@ -6,32 +6,38 @@ ...@@ -6,32 +6,38 @@
namespace rapidjson { namespace rapidjson {
//! Wrapper of C file stream for input using fread(). //! File byte stream for input using fread().
/*! /*!
\implements Stream \implements Stream
*/ */
class FileReadStream { class FileReadStream {
public: public:
typedef char Ch; //!< Character type. Only support char. typedef char Ch; //!< Character type (byte).
//! Constructor.
/*!
\param fp File pointer opened for read.
\param buffer user-supplied buffer.
\param bufferSize size of buffer in bytes. Must >=4 bytes.
*/
FileReadStream(FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { FileReadStream(FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
RAPIDJSON_ASSERT(fp_ != 0); RAPIDJSON_ASSERT(fp_ != 0);
RAPIDJSON_ASSERT(bufferSize >= 4); RAPIDJSON_ASSERT(bufferSize >= 4);
Read(); Read();
} }
char Peek() const { return *current_; } Ch Peek() const { return *current_; }
char Take() { char c = *current_; Read(); return c; } Ch Take() { Ch c = *current_; Read(); return c; }
size_t Tell() const { return count_ + (current_ - buffer_); } size_t Tell() const { return count_ + (current_ - buffer_); }
// Not implemented // Not implemented
void Put(char c) { RAPIDJSON_ASSERT(false); } void Put(Ch c) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); }
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
// For encoding detection only. // For encoding detection only.
const char* Peek4() const { const Ch* Peek4() const {
return (current_ + 4 <= bufferLast_) ? current_ : 0; return (current_ + 4 <= bufferLast_) ? current_ : 0;
} }
...@@ -39,12 +45,7 @@ private: ...@@ -39,12 +45,7 @@ private:
void Read() { void Read() {
if (current_ < bufferLast_) if (current_ < bufferLast_)
++current_; ++current_;
else else if (!eof_) {
FillBuffer();
}
void FillBuffer() {
if (!eof_) {
count_ += readCount_; count_ += readCount_;
readCount_ = fread(buffer_, 1, bufferSize_, fp_); readCount_ = fread(buffer_, 1, bufferSize_, fp_);
bufferLast_ = buffer_ + readCount_ - 1; bufferLast_ = buffer_ + readCount_ - 1;
...@@ -59,10 +60,10 @@ private: ...@@ -59,10 +60,10 @@ private:
} }
FILE* fp_; FILE* fp_;
char *buffer_; Ch *buffer_;
size_t bufferSize_; size_t bufferSize_;
char *bufferLast_; Ch *bufferLast_;
char *current_; Ch *current_;
size_t readCount_; size_t readCount_;
size_t count_; //!< Number of characters read size_t count_; //!< Number of characters read
bool eof_; bool eof_;
......
...@@ -7,23 +7,23 @@ namespace rapidjson { ...@@ -7,23 +7,23 @@ namespace rapidjson {
//! Writer with indentation and spacing. //! Writer with indentation and spacing.
/*! /*!
\tparam Stream Type of ouptut stream. \tparam OutputStream Type of ouptut os.
\tparam Encoding Encoding of both source strings and output. \tparam Encoding Encoding of both source strings and output.
\tparam Allocator Type of allocator for allocating memory of stack. \tparam Allocator Type of allocator for allocating memory of stack.
*/ */
template<typename Stream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> > template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
class PrettyWriter : public Writer<Stream, SourceEncoding, TargetEncoding, Allocator> { class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, Allocator> {
public: public:
typedef Writer<Stream, SourceEncoding, TargetEncoding, Allocator> Base; typedef Writer<OutputStream, SourceEncoding, TargetEncoding, Allocator> Base;
typedef typename Base::Ch Ch; typedef typename Base::Ch Ch;
//! Constructor //! Constructor
/*! \param stream Output stream. /*! \param os Output os.
\param allocator User supplied allocator. If it is null, it will create a private one. \param allocator User supplied allocator. If it is null, it will create a private one.
\param levelDepth Initial capacity of \param levelDepth Initial capacity of
*/ */
PrettyWriter(Stream& stream, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : PrettyWriter(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
Base(stream, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
//! Set custom indentation. //! Set custom indentation.
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\t', '\n', '\r'). /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\t', '\n', '\r').
...@@ -67,12 +67,12 @@ public: ...@@ -67,12 +67,12 @@ public:
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0; bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
if (!empty) { if (!empty) {
Base::stream_.Put('\n'); Base::os_.Put('\n');
WriteIndent(); WriteIndent();
} }
Base::WriteEndObject(); Base::WriteEndObject();
if (Base::level_stack_.Empty()) // end of json text if (Base::level_stack_.Empty()) // end of json text
Base::stream_.Flush(); Base::os_.Flush();
return *this; return *this;
} }
...@@ -89,12 +89,12 @@ public: ...@@ -89,12 +89,12 @@ public:
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0; bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
if (!empty) { if (!empty) {
Base::stream_.Put('\n'); Base::os_.Put('\n');
WriteIndent(); WriteIndent();
} }
Base::WriteEndArray(); Base::WriteEndArray();
if (Base::level_stack_.Empty()) // end of json text if (Base::level_stack_.Empty()) // end of json text
Base::stream_.Flush(); Base::os_.Flush();
return *this; return *this;
} }
...@@ -110,26 +110,26 @@ protected: ...@@ -110,26 +110,26 @@ protected:
if (level->inArray) { if (level->inArray) {
if (level->valueCount > 0) { if (level->valueCount > 0) {
Base::stream_.Put(','); // add comma if it is not the first element in array Base::os_.Put(','); // add comma if it is not the first element in array
Base::stream_.Put('\n'); Base::os_.Put('\n');
} }
else else
Base::stream_.Put('\n'); Base::os_.Put('\n');
WriteIndent(); WriteIndent();
} }
else { // in object else { // in object
if (level->valueCount > 0) { if (level->valueCount > 0) {
if (level->valueCount % 2 == 0) { if (level->valueCount % 2 == 0) {
Base::stream_.Put(','); Base::os_.Put(',');
Base::stream_.Put('\n'); Base::os_.Put('\n');
} }
else { else {
Base::stream_.Put(':'); Base::os_.Put(':');
Base::stream_.Put(' '); Base::os_.Put(' ');
} }
} }
else else
Base::stream_.Put('\n'); Base::os_.Put('\n');
if (level->valueCount % 2 == 0) if (level->valueCount % 2 == 0)
WriteIndent(); WriteIndent();
...@@ -144,7 +144,7 @@ protected: ...@@ -144,7 +144,7 @@ protected:
void WriteIndent() { void WriteIndent() {
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
PutN(Base::stream_, indentChar_, count); PutN(Base::os_, indentChar_, count);
} }
Ch indentChar_; Ch indentChar_;
......
...@@ -82,6 +82,29 @@ typedef unsigned SizeType; ...@@ -82,6 +82,29 @@ typedef unsigned SizeType;
#define RAPIDJSON_ASSERT(x) assert(x) #define RAPIDJSON_ASSERT(x) assert(x)
#endif // RAPIDJSON_ASSERT #endif // RAPIDJSON_ASSERT
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_STATIC_ASSERT
// Adopt from boost
#ifndef RAPIDJSON_STATIC_ASSERT
namespace rapidjson {
template <bool x> struct STATIC_ASSERTION_FAILURE;
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
template<int x> struct StaticAssertTest {};
} // namespace rapidjson
#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
#define RAPIDJSON_STATIC_ASSERT(x) typedef ::rapidjson::StaticAssertTest<\
sizeof(::rapidjson::STATIC_ASSERTION_FAILURE<bool(x) >)>\
RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__)
#endif
///////////////////////////////////////////////////////////////////////////////
// Allocators and Encodings
#include "allocators.h" #include "allocators.h"
#include "encodings.h" #include "encodings.h"
......
...@@ -89,12 +89,12 @@ struct BaseReaderHandler { ...@@ -89,12 +89,12 @@ struct BaseReaderHandler {
/*! \param stream A input stream for skipping white spaces. /*! \param stream A input stream for skipping white spaces.
\note This function has SSE2/SSE4.2 specialization. \note This function has SSE2/SSE4.2 specialization.
*/ */
template<typename Stream> template<typename InputStream>
void SkipWhitespace(Stream& stream) { void SkipWhitespace(InputStream& is) {
Stream s = stream; // Use a local copy for optimization InputStream s = is; // Use a local copy for optimization
while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t') while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
s.Take(); s.Take();
stream = s; is = s;
} }
#ifdef RAPIDJSON_SSE42 #ifdef RAPIDJSON_SSE42
...@@ -162,13 +162,13 @@ inline const char *SkipWhitespace_SIMD(const char* p) { ...@@ -162,13 +162,13 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
#ifdef RAPIDJSON_SIMD #ifdef RAPIDJSON_SIMD
//! Template function specialization for InsituStringStream //! Template function specialization for InsituStringStream
template<> inline void SkipWhitespace(InsituStringStream& stream) { template<> inline void SkipWhitespace(InsituStringStream& is) {
stream.src_ = const_cast<char*>(SkipWhitespace_SIMD(stream.src_)); is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_));
} }
//! Template function specialization for StringStream //! Template function specialization for StringStream
template<> inline void SkipWhitespace(StringStream& stream) { template<> inline void SkipWhitespace(StringStream& is) {
stream.src_ = SkipWhitespace_SIMD(stream.src_); is.src_ = SkipWhitespace_SIMD(is.src_);
} }
#endif // RAPIDJSON_SIMD #endif // RAPIDJSON_SIMD
...@@ -187,7 +187,8 @@ template<> inline void SkipWhitespace(StringStream& stream) { ...@@ -187,7 +187,8 @@ template<> inline void SkipWhitespace(StringStream& stream) {
A GenericReader object can be reused for parsing multiple JSON text. A GenericReader object can be reused for parsing multiple JSON text.
\tparam Encoding Encoding of both the stream and the parse output. \tparam SourceEncoding Encoding of the input stream.
\tparam TargetEncoding Encoding of the parse output.
\tparam Allocator Allocator type for stack. \tparam Allocator Allocator type for stack.
*/ */
template <typename SourceEncoding, typename TargetEncoding, typename Allocator = MemoryPoolAllocator<> > template <typename SourceEncoding, typename TargetEncoding, typename Allocator = MemoryPoolAllocator<> >
...@@ -203,14 +204,14 @@ public: ...@@ -203,14 +204,14 @@ public:
//! Parse JSON text. //! Parse JSON text.
/*! \tparam parseFlags Combination of ParseFlag. /*! \tparam parseFlags Combination of ParseFlag.
\tparam Stream Type of input stream. \tparam InputStream Type of input stream.
\tparam Handler Type of handler which must implement Handler concept. \tparam Handler Type of handler which must implement Handler concept.
\param stream Input stream to be parsed. \param stream Input stream to be parsed.
\param handler The handler to receive events. \param handler The handler to receive events.
\return Whether the parsing is successful. \return Whether the parsing is successful.
*/ */
template <unsigned parseFlags, typename Stream, typename Handler> template <unsigned parseFlags, typename InputStream, typename Handler>
bool Parse(Stream& stream, Handler& handler) { bool Parse(InputStream& is, Handler& handler) {
parseError_ = 0; parseError_ = 0;
errorOffset_ = 0; errorOffset_ = 0;
...@@ -219,20 +220,20 @@ public: ...@@ -219,20 +220,20 @@ public:
return false; return false;
} }
SkipWhitespace(stream); SkipWhitespace(is);
if (stream.Peek() == '\0') if (is.Peek() == '\0')
RAPIDJSON_PARSE_ERROR("Text only contains white space(s)", stream.Tell()); RAPIDJSON_PARSE_ERROR("Text only contains white space(s)", is.Tell());
else { else {
switch (stream.Peek()) { switch (is.Peek()) {
case '{': ParseObject<parseFlags>(stream, handler); break; case '{': ParseObject<parseFlags>(is, handler); break;
case '[': ParseArray<parseFlags>(stream, handler); break; case '[': ParseArray<parseFlags>(is, handler); break;
default: RAPIDJSON_PARSE_ERROR("Expect either an object or array at root", stream.Tell()); default: RAPIDJSON_PARSE_ERROR("Expect either an object or array at root", is.Tell());
} }
SkipWhitespace(stream); SkipWhitespace(is);
if (stream.Peek() != '\0') if (is.Peek() != '\0')
RAPIDJSON_PARSE_ERROR("Nothing should follow the root object or array.", stream.Tell()); RAPIDJSON_PARSE_ERROR("Nothing should follow the root object or array.", is.Tell());
} }
return true; return true;
...@@ -244,108 +245,108 @@ public: ...@@ -244,108 +245,108 @@ public:
private: private:
// Parse object: { string : value, ... } // Parse object: { string : value, ... }
template<unsigned parseFlags, typename Stream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseObject(Stream& stream, Handler& handler) { void ParseObject(InputStream& is, Handler& handler) {
RAPIDJSON_ASSERT(stream.Peek() == '{'); RAPIDJSON_ASSERT(is.Peek() == '{');
stream.Take(); // Skip '{' is.Take(); // Skip '{'
handler.StartObject(); handler.StartObject();
SkipWhitespace(stream); SkipWhitespace(is);
if (stream.Peek() == '}') { if (is.Peek() == '}') {
stream.Take(); is.Take();
handler.EndObject(0); // empty object handler.EndObject(0); // empty object
return; return;
} }
for (SizeType memberCount = 0;;) { for (SizeType memberCount = 0;;) {
if (stream.Peek() != '"') if (is.Peek() != '"')
RAPIDJSON_PARSE_ERROR("Name of an object member must be a string", stream.Tell()); RAPIDJSON_PARSE_ERROR("Name of an object member must be a string", is.Tell());
ParseString<parseFlags>(stream, handler); ParseString<parseFlags>(is, handler);
SkipWhitespace(stream); SkipWhitespace(is);
if (stream.Take() != ':') if (is.Take() != ':')
RAPIDJSON_PARSE_ERROR("There must be a colon after the name of object member", stream.Tell()); RAPIDJSON_PARSE_ERROR("There must be a colon after the name of object member", is.Tell());
SkipWhitespace(stream); SkipWhitespace(is);
ParseValue<parseFlags>(stream, handler); ParseValue<parseFlags>(is, handler);
SkipWhitespace(stream); SkipWhitespace(is);
++memberCount; ++memberCount;
switch(stream.Take()) { switch(is.Take()) {
case ',': SkipWhitespace(stream); break; case ',': SkipWhitespace(is); break;
case '}': handler.EndObject(memberCount); return; case '}': handler.EndObject(memberCount); return;
default: RAPIDJSON_PARSE_ERROR("Must be a comma or '}' after an object member", stream.Tell()); default: RAPIDJSON_PARSE_ERROR("Must be a comma or '}' after an object member", is.Tell());
} }
} }
} }
// Parse array: [ value, ... ] // Parse array: [ value, ... ]
template<unsigned parseFlags, typename Stream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseArray(Stream& stream, Handler& handler) { void ParseArray(InputStream& is, Handler& handler) {
RAPIDJSON_ASSERT(stream.Peek() == '['); RAPIDJSON_ASSERT(is.Peek() == '[');
stream.Take(); // Skip '[' is.Take(); // Skip '['
handler.StartArray(); handler.StartArray();
SkipWhitespace(stream); SkipWhitespace(is);
if (stream.Peek() == ']') { if (is.Peek() == ']') {
stream.Take(); is.Take();
handler.EndArray(0); // empty array handler.EndArray(0); // empty array
return; return;
} }
for (SizeType elementCount = 0;;) { for (SizeType elementCount = 0;;) {
ParseValue<parseFlags>(stream, handler); ParseValue<parseFlags>(is, handler);
++elementCount; ++elementCount;
SkipWhitespace(stream); SkipWhitespace(is);
switch (stream.Take()) { switch (is.Take()) {
case ',': SkipWhitespace(stream); break; case ',': SkipWhitespace(is); break;
case ']': handler.EndArray(elementCount); return; case ']': handler.EndArray(elementCount); return;
default: RAPIDJSON_PARSE_ERROR("Must be a comma or ']' after an array element.", stream.Tell()); default: RAPIDJSON_PARSE_ERROR("Must be a comma or ']' after an array element.", is.Tell());
} }
} }
} }
template<unsigned parseFlags, typename Stream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseNull(Stream& stream, Handler& handler) { void ParseNull(InputStream& is, Handler& handler) {
RAPIDJSON_ASSERT(stream.Peek() == 'n'); RAPIDJSON_ASSERT(is.Peek() == 'n');
stream.Take(); is.Take();
if (stream.Take() == 'u' && stream.Take() == 'l' && stream.Take() == 'l') if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l')
handler.Null(); handler.Null();
else else
RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1); RAPIDJSON_PARSE_ERROR("Invalid value", is.Tell() - 1);
} }
template<unsigned parseFlags, typename Stream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseTrue(Stream& stream, Handler& handler) { void ParseTrue(InputStream& is, Handler& handler) {
RAPIDJSON_ASSERT(stream.Peek() == 't'); RAPIDJSON_ASSERT(is.Peek() == 't');
stream.Take(); is.Take();
if (stream.Take() == 'r' && stream.Take() == 'u' && stream.Take() == 'e') if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e')
handler.Bool(true); handler.Bool(true);
else else
RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell()); RAPIDJSON_PARSE_ERROR("Invalid value", is.Tell());
} }
template<unsigned parseFlags, typename Stream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseFalse(Stream& stream, Handler& handler) { void ParseFalse(InputStream& is, Handler& handler) {
RAPIDJSON_ASSERT(stream.Peek() == 'f'); RAPIDJSON_ASSERT(is.Peek() == 'f');
stream.Take(); is.Take();
if (stream.Take() == 'a' && stream.Take() == 'l' && stream.Take() == 's' && stream.Take() == 'e') if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e')
handler.Bool(false); handler.Bool(false);
else else
RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1); RAPIDJSON_PARSE_ERROR("Invalid value", is.Tell() - 1);
} }
// Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
template<typename Stream> template<typename InputStream>
unsigned ParseHex4(Stream& stream) { unsigned ParseHex4(InputStream& is) {
Stream s = stream; // Use a local copy for optimization InputStream s = is; // Use a local copy for optimization
unsigned codepoint = 0; unsigned codepoint = 0;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
Ch c = s.Take(); Ch c = s.Take();
...@@ -360,14 +361,16 @@ private: ...@@ -360,14 +361,16 @@ private:
else else
RAPIDJSON_PARSE_ERROR("Incorrect hex digit after \\u escape", s.Tell() - 1); RAPIDJSON_PARSE_ERROR("Incorrect hex digit after \\u escape", s.Tell() - 1);
} }
stream = s; // Restore stream is = s; // Restore is
return codepoint; return codepoint;
} }
struct StackStream { struct StackStream {
typedef typename TargetEncoding::Ch Ch;
StackStream(internal::Stack<Allocator>& stack) : stack_(stack), length_(0) {} StackStream(internal::Stack<Allocator>& stack) : stack_(stack), length_(0) {}
void Put(typename TargetEncoding::Ch c) { void Put(Ch c) {
*stack_.template Push<typename TargetEncoding::Ch>() = c; *stack_.template Push<Ch>() = c;
++length_; ++length_;
} }
internal::Stack<Allocator>& stack_; internal::Stack<Allocator>& stack_;
...@@ -375,28 +378,28 @@ private: ...@@ -375,28 +378,28 @@ private:
}; };
// Parse string and generate String event. Different code paths for kParseInsituFlag. // Parse string and generate String event. Different code paths for kParseInsituFlag.
template<unsigned parseFlags, typename Stream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseString(Stream& stream, Handler& handler) { void ParseString(InputStream& is, Handler& handler) {
Stream s = stream; // Local copy for optimization InputStream s = is; // Local copy for optimization
if (parseFlags & kParseInsituFlag) { if (parseFlags & kParseInsituFlag) {
Ch *head = s.PutBegin(); Ch *head = s.PutBegin();
ParseStringToStream<parseFlags>(s, s); ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
size_t length = s.PutEnd(head) - 1; size_t length = s.PutEnd(head) - 1;
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
handler.String((typename TargetEncoding::Ch*)head, SizeType(length), false); handler.String((typename TargetEncoding::Ch*)head, SizeType(length), false);
} }
else { else {
StackStream stackStream(stack_); StackStream stackStream(stack_);
ParseStringToStream<parseFlags>(s, stackStream); ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
handler.String(stack_.template Pop<typename TargetEncoding::Ch>(stackStream.length_), stackStream.length_ - 1, true); handler.String(stack_.template Pop<typename TargetEncoding::Ch>(stackStream.length_), stackStream.length_ - 1, true);
} }
stream = s; // Restore stream is = s; // Restore is
} }
// Parse string to an output stream // Parse string to an output is
// This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation.
template<unsigned parseFlags, typename InputStream, typename OutputStream> template<unsigned parseFlags, typename SEncoding, typename TEncoding, typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& input, OutputStream& output) { RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) {
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
static const char escape[256] = { 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,'/',
...@@ -407,53 +410,53 @@ private: ...@@ -407,53 +410,53 @@ private:
}; };
#undef Z16 #undef Z16
RAPIDJSON_ASSERT(input.Peek() == '\"'); RAPIDJSON_ASSERT(is.Peek() == '\"');
input.Take(); // Skip '\"' is.Take(); // Skip '\"'
for (;;) { for (;;) {
Ch c = input.Peek(); Ch c = is.Peek();
if (c == '\\') { // Escape if (c == '\\') { // Escape
input.Take(); is.Take();
Ch e = input.Take(); Ch e = is.Take();
if ((sizeof(Ch) == 1 || e < 256) && escape[(unsigned char)e]) if ((sizeof(Ch) == 1 || e < 256) && escape[(unsigned char)e])
output.Put(escape[(unsigned char)e]); os.Put(escape[(unsigned char)e]);
else if (e == 'u') { // Unicode else if (e == 'u') { // Unicode
unsigned codepoint = ParseHex4(input); unsigned codepoint = ParseHex4(is);
if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { if (codepoint >= 0xD800 && codepoint <= 0xDBFF) {
// Handle UTF-16 surrogate pair // Handle UTF-16 surrogate pair
if (input.Take() != '\\' || input.Take() != 'u') if (is.Take() != '\\' || is.Take() != 'u')
RAPIDJSON_PARSE_ERROR("Missing the second \\u in surrogate pair", input.Tell() - 2); RAPIDJSON_PARSE_ERROR("Missing the second \\u in surrogate pair", is.Tell() - 2);
unsigned codepoint2 = ParseHex4(input); unsigned codepoint2 = ParseHex4(is);
if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)
RAPIDJSON_PARSE_ERROR("The second \\u in surrogate pair is invalid", input.Tell() - 2); RAPIDJSON_PARSE_ERROR("The second \\u in surrogate pair is invalid", is.Tell() - 2);
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
} }
TargetEncoding::Encode(output, codepoint); TEncoding::Encode(os, codepoint);
} }
else else
RAPIDJSON_PARSE_ERROR("Unknown escape character", input.Tell() - 1); RAPIDJSON_PARSE_ERROR("Unknown escape character", is.Tell() - 1);
} }
else if (c == '"') { // Closing double quote else if (c == '"') { // Closing double quote
input.Take(); is.Take();
output.Put('\0'); // null-terminate the string os.Put('\0'); // null-terminate the string
return; return;
} }
else if (c == '\0') else if (c == '\0')
RAPIDJSON_PARSE_ERROR("lacks ending quotation before the end of string", input.Tell() - 1); RAPIDJSON_PARSE_ERROR("lacks ending quotation before the end of string", is.Tell() - 1);
else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
RAPIDJSON_PARSE_ERROR("Incorrect unescaped character in string", input.Tell() - 1); RAPIDJSON_PARSE_ERROR("Incorrect unescaped character in string", is.Tell() - 1);
else { else {
if (parseFlags & kParseValidateEncodingFlag ? if (parseFlags & kParseValidateEncodingFlag ?
!Transcoder<SourceEncoding, TargetEncoding>::Validate(input, output) : !Transcoder<SEncoding, TEncoding>::Validate(is, os) :
!Transcoder<SourceEncoding, TargetEncoding>::Transcode(input, output)) !Transcoder<SEncoding, TEncoding>::Transcode(is, os))
RAPIDJSON_PARSE_ERROR("Invalid encoding", input.Tell()); RAPIDJSON_PARSE_ERROR("Invalid encoding", is.Tell());
} }
} }
} }
template<unsigned parseFlags, typename Stream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseNumber(Stream& stream, Handler& handler) { void ParseNumber(InputStream& is, Handler& handler) {
Stream s = stream; // Local copy for optimization InputStream s = is; // Local copy for optimization
// Parse minus // Parse minus
bool minus = false; bool minus = false;
if (s.Peek() == '-') { if (s.Peek() == '-') {
...@@ -493,7 +496,7 @@ private: ...@@ -493,7 +496,7 @@ private:
} }
} }
else else
RAPIDJSON_PARSE_ERROR("Expect a value here.", stream.Tell()); RAPIDJSON_PARSE_ERROR("Expect a value here.", is.Tell());
// Parse 64bit int // Parse 64bit int
uint64_t i64; uint64_t i64;
...@@ -526,7 +529,7 @@ private: ...@@ -526,7 +529,7 @@ private:
d = (double)i64; d = (double)i64;
while (s.Peek() >= '0' && s.Peek() <= '9') { while (s.Peek() >= '0' && s.Peek() <= '9') {
if (d >= 1E307) if (d >= 1E307)
RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell()); RAPIDJSON_PARSE_ERROR("Number too big to store in double", is.Tell());
d = d * 10 + (s.Take() - '0'); d = d * 10 + (s.Take() - '0');
} }
} }
...@@ -545,7 +548,7 @@ private: ...@@ -545,7 +548,7 @@ private:
--expFrac; --expFrac;
} }
else else
RAPIDJSON_PARSE_ERROR("At least one digit in fraction part", stream.Tell()); RAPIDJSON_PARSE_ERROR("At least one digit in fraction part", is.Tell());
while (s.Peek() >= '0' && s.Peek() <= '9') { while (s.Peek() >= '0' && s.Peek() <= '9') {
if (expFrac > -16) { if (expFrac > -16) {
...@@ -578,7 +581,7 @@ private: ...@@ -578,7 +581,7 @@ private:
while (s.Peek() >= '0' && s.Peek() <= '9') { while (s.Peek() >= '0' && s.Peek() <= '9') {
exp = exp * 10 + (s.Take() - '0'); exp = exp * 10 + (s.Take() - '0');
if (exp > 308) if (exp > 308)
RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell()); RAPIDJSON_PARSE_ERROR("Number too big to store in double", is.Tell());
} }
} }
else else
...@@ -608,20 +611,20 @@ private: ...@@ -608,20 +611,20 @@ private:
} }
} }
stream = s; // restore stream is = s; // restore is
} }
// Parse any JSON value // Parse any JSON value
template<unsigned parseFlags, typename Stream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseValue(Stream& stream, Handler& handler) { void ParseValue(InputStream& is, Handler& handler) {
switch (stream.Peek()) { switch (is.Peek()) {
case 'n': ParseNull <parseFlags>(stream, handler); break; case 'n': ParseNull <parseFlags>(is, handler); break;
case 't': ParseTrue <parseFlags>(stream, handler); break; case 't': ParseTrue <parseFlags>(is, handler); break;
case 'f': ParseFalse <parseFlags>(stream, handler); break; case 'f': ParseFalse <parseFlags>(is, handler); break;
case '"': ParseString<parseFlags>(stream, handler); break; case '"': ParseString<parseFlags>(is, handler); break;
case '{': ParseObject<parseFlags>(stream, handler); break; case '{': ParseObject<parseFlags>(is, handler); break;
case '[': ParseArray <parseFlags>(stream, handler); break; case '[': ParseArray <parseFlags>(is, handler); break;
default : ParseNumber<parseFlags>(stream, handler); default : ParseNumber<parseFlags>(is, handler);
} }
} }
......
...@@ -11,7 +11,7 @@ namespace rapidjson { ...@@ -11,7 +11,7 @@ namespace rapidjson {
//! JSON writer //! JSON writer
/*! Writer implements the concept Handler. /*! Writer implements the concept Handler.
It generates JSON text by events to an output stream. It generates JSON text by events to an output os.
User may programmatically calls the functions of a writer to generate JSON text. User may programmatically calls the functions of a writer to generate JSON text.
...@@ -19,17 +19,18 @@ namespace rapidjson { ...@@ -19,17 +19,18 @@ namespace rapidjson {
for example Reader::Parse() and Document::Accept(). for example Reader::Parse() and Document::Accept().
\tparam Stream Type of ouptut stream. \tparam OutputStream Type of output stream.
\tparam Encoding Encoding of both source strings and output. \tparam SourceEncoding Encoding of both source strings.
\tparam TargetEncoding Encoding of and output stream.
\implements Handler \implements Handler
*/ */
template<typename Stream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> > template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
class Writer { class Writer {
public: public:
typedef typename SourceEncoding::Ch Ch; typedef typename SourceEncoding::Ch Ch;
Writer(Stream& stream, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : Writer(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
stream_(stream), level_stack_(allocator, levelDepth * sizeof(Level)) {} os_(os), level_stack_(allocator, levelDepth * sizeof(Level)) {}
//@name Implementation of Handler //@name Implementation of Handler
//@{ //@{
...@@ -60,7 +61,7 @@ public: ...@@ -60,7 +61,7 @@ public:
level_stack_.template Pop<Level>(1); level_stack_.template Pop<Level>(1);
WriteEndObject(); WriteEndObject();
if (level_stack_.Empty()) // end of json text if (level_stack_.Empty()) // end of json text
stream_.Flush(); os_.Flush();
return *this; return *this;
} }
...@@ -77,7 +78,7 @@ public: ...@@ -77,7 +78,7 @@ public:
level_stack_.template Pop<Level>(1); level_stack_.template Pop<Level>(1);
WriteEndArray(); WriteEndArray();
if (level_stack_.Empty()) // end of json text if (level_stack_.Empty()) // end of json text
stream_.Flush(); os_.Flush();
return *this; return *this;
} }
//@} //@}
...@@ -96,21 +97,21 @@ protected: ...@@ -96,21 +97,21 @@ protected:
static const size_t kDefaultLevelDepth = 32; static const size_t kDefaultLevelDepth = 32;
void WriteNull() { void WriteNull() {
stream_.Put('n'); stream_.Put('u'); stream_.Put('l'); stream_.Put('l'); os_.Put('n'); os_.Put('u'); os_.Put('l'); os_.Put('l');
} }
void WriteBool(bool b) { void WriteBool(bool b) {
if (b) { if (b) {
stream_.Put('t'); stream_.Put('r'); stream_.Put('u'); stream_.Put('e'); os_.Put('t'); os_.Put('r'); os_.Put('u'); os_.Put('e');
} }
else { else {
stream_.Put('f'); stream_.Put('a'); stream_.Put('l'); stream_.Put('s'); stream_.Put('e'); os_.Put('f'); os_.Put('a'); os_.Put('l'); os_.Put('s'); os_.Put('e');
} }
} }
void WriteInt(int i) { void WriteInt(int i) {
if (i < 0) { if (i < 0) {
stream_.Put('-'); os_.Put('-');
i = -i; i = -i;
} }
WriteUint((unsigned)i); WriteUint((unsigned)i);
...@@ -126,13 +127,13 @@ protected: ...@@ -126,13 +127,13 @@ protected:
do { do {
--p; --p;
stream_.Put(*p); os_.Put(*p);
} while (p != buffer); } while (p != buffer);
} }
void WriteInt64(int64_t i64) { void WriteInt64(int64_t i64) {
if (i64 < 0) { if (i64 < 0) {
stream_.Put('-'); os_.Put('-');
i64 = -i64; i64 = -i64;
} }
WriteUint64((uint64_t)i64); WriteUint64((uint64_t)i64);
...@@ -148,7 +149,7 @@ protected: ...@@ -148,7 +149,7 @@ protected:
do { do {
--p; --p;
stream_.Put(*p); os_.Put(*p);
} while (p != buffer); } while (p != buffer);
} }
...@@ -162,7 +163,7 @@ protected: ...@@ -162,7 +163,7 @@ protected:
#endif #endif
RAPIDJSON_ASSERT(ret >= 1); RAPIDJSON_ASSERT(ret >= 1);
for (int i = 0; i < ret; i++) for (int i = 0; i < ret; i++)
stream_.Put(buffer[i]); os_.Put(buffer[i]);
} }
void WriteString(const Ch* str, SizeType length) { void WriteString(const Ch* str, SizeType length) {
...@@ -179,40 +180,40 @@ protected: ...@@ -179,40 +180,40 @@ protected:
#undef Z16 #undef Z16
}; };
stream_.Put('\"'); os_.Put('\"');
GenericStringStream<SourceEncoding> is(str); GenericStringStream<SourceEncoding> is(str);
while (is.Tell() < length) { while (is.Tell() < length) {
const Ch c = is.Peek(); const Ch c = is.Peek();
if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) { if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) {
is.Take(); is.Take();
stream_.Put('\\'); os_.Put('\\');
stream_.Put(escape[(unsigned char)c]); os_.Put(escape[(unsigned char)c]);
if (escape[(unsigned char)c] == 'u') { if (escape[(unsigned char)c] == 'u') {
stream_.Put('0'); os_.Put('0');
stream_.Put('0'); os_.Put('0');
stream_.Put(hexDigits[(unsigned char)c >> 4]); os_.Put(hexDigits[(unsigned char)c >> 4]);
stream_.Put(hexDigits[(unsigned char)c & 0xF]); os_.Put(hexDigits[(unsigned char)c & 0xF]);
} }
} }
else else
Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, stream_); Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, os_);
} }
stream_.Put('\"'); os_.Put('\"');
} }
void WriteStartObject() { stream_.Put('{'); } void WriteStartObject() { os_.Put('{'); }
void WriteEndObject() { stream_.Put('}'); } void WriteEndObject() { os_.Put('}'); }
void WriteStartArray() { stream_.Put('['); } void WriteStartArray() { os_.Put('['); }
void WriteEndArray() { stream_.Put(']'); } void WriteEndArray() { os_.Put(']'); }
void Prefix(Type type) { void Prefix(Type type) {
if (level_stack_.GetSize() != 0) { // this value is not at root if (level_stack_.GetSize() != 0) { // this value is not at root
Level* level = level_stack_.template Top<Level>(); Level* level = level_stack_.template Top<Level>();
if (level->valueCount > 0) { if (level->valueCount > 0) {
if (level->inArray) if (level->inArray)
stream_.Put(','); // add comma if it is not the first element in array os_.Put(','); // add comma if it is not the first element in array
else // in object else // in object
stream_.Put((level->valueCount % 2 == 0) ? ',' : ':'); os_.Put((level->valueCount % 2 == 0) ? ',' : ':');
} }
if (!level->inArray && level->valueCount % 2 == 0) if (!level->inArray && level->valueCount % 2 == 0)
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
...@@ -222,7 +223,7 @@ protected: ...@@ -222,7 +223,7 @@ protected:
RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType); RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
} }
Stream& stream_; OutputStream& os_;
internal::Stack<Allocator> level_stack_; internal::Stack<Allocator> level_stack_;
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment