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
......
This diff is collapsed.
...@@ -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"
......
This diff is collapsed.
...@@ -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