writer.h

Engine/source/persistence/rapidjson/writer.h

More...

Classes:

class

JSON writer.

class

Information for each nested level.

Namespaces:

namespace

Public Defines

define
Z16() 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

Detailed Description

Public Defines

Z16() 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1
  2#ifndef RAPIDJSON_WRITER_H_
  3#define RAPIDJSON_WRITER_H_
  4
  5#include "rapidjson.h"
  6#include "internal/stack.h"
  7#include "internal/strfunc.h"
  8#include <cstdio> // snprintf() or _sprintf_s()
  9#include <new>    // placement new
 10
 11#ifdef _MSC_VER
 12#pragma warning(push)
 13#pragma warning(disable : 4127) // conditional expression is constant
 14#endif
 15
 16namespace rapidjson {
 17
 18//! JSON writer
 19/*! Writer implements the concept Handler.
 20   It generates JSON text by events to an output os.
 21
 22   User may programmatically calls the functions of a writer to generate JSON text.
 23
 24   On the other side, a writer can also be passed to objects that generates events, 
 25
 26   for example Reader::Parse() and Document::Accept().
 27
 28   \tparam OutputStream Type of output stream.
 29   \tparam SourceEncoding Encoding of both source strings.
 30   \tparam TargetEncoding Encoding of and output stream.
 31   \implements Handler
 32*/
 33template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
 34class Writer {
 35public:
 36   typedef typename SourceEncoding::Ch Ch;
 37
 38   Writer(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : 
 39      os_(os), level_stack_(allocator, levelDepth * sizeof(Level)) {}
 40
 41   //@name Implementation of Handler
 42   //@{
 43   Writer& Null()             { Prefix(kNullType);   WriteNull();       return *this; }
 44   Writer& Bool(bool b)       { Prefix(b ? kTrueType : kFalseType); WriteBool(b); return *this; }
 45   Writer& Int(int i)            { Prefix(kNumberType); WriteInt(i);       return *this; }
 46   Writer& Uint(unsigned u)      { Prefix(kNumberType); WriteUint(u);      return *this; }
 47   Writer& Int64(int64_t i64)    { Prefix(kNumberType); WriteInt64(i64);      return *this; }
 48   Writer& Uint64(uint64_t u64)  { Prefix(kNumberType); WriteUint64(u64);  return *this; }
 49   Writer& Double(double d)      { Prefix(kNumberType); WriteDouble(d);    return *this; }
 50
 51   Writer& String(const Ch* str, SizeType length, bool copy = false) {
 52      (void)copy;
 53      Prefix(kStringType);
 54      WriteString(str, length);
 55      return *this;
 56   }
 57
 58   Writer& StartObject() {
 59      Prefix(kObjectType);
 60      new (level_stack_.template Push<Level>()) Level(false);
 61      WriteStartObject();
 62      return *this;
 63   }
 64
 65   Writer& EndObject(SizeType memberCount = 0) {
 66      (void)memberCount;
 67      RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
 68      RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
 69      level_stack_.template Pop<Level>(1);
 70      WriteEndObject();
 71      if (level_stack_.Empty())  // end of json text
 72         os_.Flush();
 73      return *this;
 74   }
 75
 76   Writer& StartArray() {
 77      Prefix(kArrayType);
 78      new (level_stack_.template Push<Level>()) Level(true);
 79      WriteStartArray();
 80      return *this;
 81   }
 82
 83   Writer& EndArray(SizeType elementCount = 0) {
 84      (void)elementCount;
 85      RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
 86      RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
 87      level_stack_.template Pop<Level>(1);
 88      WriteEndArray();
 89      if (level_stack_.Empty())  // end of json text
 90         os_.Flush();
 91      return *this;
 92   }
 93   //@}
 94
 95   //! Simpler but slower overload.
 96   Writer& String(const Ch* str) { return String(str, internal::StrLen(str)); }
 97
 98protected:
 99   //! Information for each nested level
100   struct Level {
101      Level(bool inArray_) : inArray(inArray_), valueCount(0) {}
102      bool inArray;     //!< true if in array, otherwise in object
103      size_t valueCount;   //!< number of values in this level
104   };
105
106   static const size_t kDefaultLevelDepth = 32;
107
108   void WriteNull()  {
109      os_.Put('n'); os_.Put('u'); os_.Put('l'); os_.Put('l');
110   }
111
112   void WriteBool(bool b)  {
113      if (b) {
114         os_.Put('t'); os_.Put('r'); os_.Put('u'); os_.Put('e');
115      }
116      else {
117         os_.Put('f'); os_.Put('a'); os_.Put('l'); os_.Put('s'); os_.Put('e');
118      }
119   }
120
121   void WriteInt(int i) {
122      if (i < 0) {
123         os_.Put('-');
124         i = -i;
125      }
126      WriteUint((unsigned)i);
127   }
128
129   void WriteUint(unsigned u) {
130      char buffer[10];
131      char *p = buffer;
132      do {
133         *p++ = (u % 10) + '0';
134         u /= 10;
135      } while (u > 0);
136
137      do {
138         --p;
139         os_.Put(*p);
140      } while (p != buffer);
141   }
142
143   void WriteInt64(int64_t i64) {
144      if (i64 < 0) {
145         os_.Put('-');
146         i64 = -i64;
147      }
148      WriteUint64((uint64_t)i64);
149   }
150
151   void WriteUint64(uint64_t u64) {
152      char buffer[20];
153      char *p = buffer;
154      do {
155         *p++ = char(u64 % 10) + '0';
156         u64 /= 10;
157      } while (u64 > 0);
158
159      do {
160         --p;
161         os_.Put(*p);
162      } while (p != buffer);
163   }
164
165   //! \todo Optimization with custom double-to-string converter.
166   void WriteDouble(double d) {
167      char buffer[100];
168#if _MSC_VER
169      int ret = sprintf_s(buffer, sizeof(buffer), "%g", d);
170#else
171      int ret = snprintf(buffer, sizeof(buffer), "%g", d);
172#endif
173      RAPIDJSON_ASSERT(ret >= 1);
174      for (int i = 0; i < ret; i++)
175         os_.Put(buffer[i]);
176   }
177
178   void WriteString(const Ch* str, SizeType length)  {
179      static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
180      static const char escape[256] = {
181#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
182         //0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
183         'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
184         'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
185           0,   0, '"',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // 20
186         Z16, Z16,                                                      // 30~4F
187           0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,'\\',   0,   0,   0, // 50
188         Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16                        // 60~FF
189#undef Z16
190      };
191
192      os_.Put('\"');
193      GenericStringStream<SourceEncoding> is(str);
194      while (is.Tell() < length) {
195         const Ch c = is.Peek();
196         if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c])  {
197            is.Take();
198            os_.Put('\\');
199            os_.Put(escape[(unsigned char)c]);
200            if (escape[(unsigned char)c] == 'u') {
201               os_.Put('0');
202               os_.Put('0');
203               os_.Put(hexDigits[(unsigned char)c >> 4]);
204               os_.Put(hexDigits[(unsigned char)c & 0xF]);
205            }
206         }
207         else
208            Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, os_);
209      }
210      os_.Put('\"');
211   }
212
213   void WriteStartObject() { os_.Put('{'); }
214   void WriteEndObject()   { os_.Put('}'); }
215   void WriteStartArray()  { os_.Put('['); }
216   void WriteEndArray() { os_.Put(']'); }
217
218   void Prefix(Type type) {
219      (void)type;
220      if (level_stack_.GetSize() != 0) { // this value is not at root
221         Level* level = level_stack_.template Top<Level>();
222         if (level->valueCount > 0) {
223            if (level->inArray) 
224               os_.Put(','); // add comma if it is not the first element in array
225            else  // in object
226               os_.Put((level->valueCount % 2 == 0) ? ',' : ':');
227         }
228         if (!level->inArray && level->valueCount % 2 == 0)
229            RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name
230         level->valueCount++;
231      }
232      else
233         RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
234   }
235
236   OutputStream& os_;
237   internal::Stack<Allocator> level_stack_;
238
239private:
240   // Prohibit assignment for VC C4512 warning
241   Writer& operator=(const Writer& w);
242};
243
244} // namespace rapidjson
245
246#ifdef _MSC_VER
247#pragma warning(pop)
248#endif
249
250#endif // RAPIDJSON_RAPIDJSON_H_
251