All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
writer.h
1 // Tencent is pleased to support the open source community by making RapidJSON available.
2 //
3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 //
5 // Licensed under the MIT License (the "License"); you may not use this file except
6 // in compliance with the License. You may obtain a copy of the License at
7 //
8 // http://opensource.org/licenses/MIT
9 //
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 // specific language governing permissions and limitations under the License.
14 
15 #ifndef RAPIDJSON_WRITER_H_
16 #define RAPIDJSON_WRITER_H_
17 
18 #include "rapidjson.h"
19 #include "internal/stack.h"
20 #include "internal/strfunc.h"
21 #include "internal/dtoa.h"
22 #include "internal/itoa.h"
23 #include "stringbuffer.h"
24 #include <new> // placement new
25 
26 #if RAPIDJSON_HAS_STDSTRING
27 #include <string>
28 #endif
29 
30 #ifdef _MSC_VER
31 RAPIDJSON_DIAG_PUSH
32 RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
33 #endif
34 
35 RAPIDJSON_NAMESPACE_BEGIN
36 
37 //! JSON writer
38 /*! Writer implements the concept Handler.
39  It generates JSON text by events to an output os.
40 
41  User may programmatically calls the functions of a writer to generate JSON text.
42 
43  On the other side, a writer can also be passed to objects that generates events,
44 
45  for example Reader::Parse() and Document::Accept().
46 
47  \tparam OutputStream Type of output stream.
48  \tparam SourceEncoding Encoding of source string.
49  \tparam TargetEncoding Encoding of output stream.
50  \tparam StackAllocator Type of allocator for allocating memory of stack.
51  \note implements Handler concept
52 */
53 template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator>
54 class Writer {
55 public:
56  typedef typename SourceEncoding::Ch Ch;
57 
58  //! Constructor
59  /*! \param os Output stream.
60  \param stackAllocator User supplied allocator. If it is null, it will create a private one.
61  \param levelDepth Initial capacity of stack.
62  */
63  explicit
64  Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
65  os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), hasRoot_(false) {}
66 
67  explicit
68  Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
69  os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {}
70 
71  //! Reset the writer with a new stream.
72  /*!
73  This function reset the writer with a new stream and default settings,
74  in order to make a Writer object reusable for output multiple JSONs.
75 
76  \param os New output stream.
77  \code
78  Writer<OutputStream> writer(os1);
79  writer.StartObject();
80  // ...
81  writer.EndObject();
82 
83  writer.Reset(os2);
84  writer.StartObject();
85  // ...
86  writer.EndObject();
87  \endcode
88  */
89  void Reset(OutputStream& os) {
90  os_ = &os;
91  hasRoot_ = false;
92  level_stack_.Clear();
93  }
94 
95  //! Checks whether the output is a complete JSON.
96  /*!
97  A complete JSON has a complete root object or array.
98  */
99  bool IsComplete() const {
100  return hasRoot_ && level_stack_.Empty();
101  }
102 
103  /*!@name Implementation of Handler
104  \see Handler
105  */
106  //@{
107 
108  bool Null() { Prefix(kNullType); return WriteNull(); }
109  bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); }
110  bool Int(int i) { Prefix(kNumberType); return WriteInt(i); }
111  bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); }
112  bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); }
113  bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); }
114 
115  //! Writes the given \c double value to the stream
116  /*!
117  \param d The value to be written.
118  \return Whether it is succeed.
119  */
120  bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); }
121 
122  bool String(const Ch* str, SizeType length, bool copy = false) {
123  (void)copy;
124  Prefix(kStringType);
125  return WriteString(str, length);
126  }
127 
128 #if RAPIDJSON_HAS_STDSTRING
129  bool String(const std::basic_string<Ch>& str) {
130  return String(str.data(), SizeType(str.size()));
131  }
132 #endif
133 
134  bool StartObject() {
135  Prefix(kObjectType);
136  new (level_stack_.template Push<Level>()) Level(false);
137  return WriteStartObject();
138  }
139 
140  bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
141 
142  bool EndObject(SizeType memberCount = 0) {
143  (void)memberCount;
144  RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
145  RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
146  level_stack_.template Pop<Level>(1);
147  bool ret = WriteEndObject();
148  if (level_stack_.Empty()) // end of json text
149  os_->Flush();
150  return ret;
151  }
152 
153  bool StartArray() {
154  Prefix(kArrayType);
155  new (level_stack_.template Push<Level>()) Level(true);
156  return WriteStartArray();
157  }
158 
159  bool EndArray(SizeType elementCount = 0) {
160  (void)elementCount;
161  RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
162  RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
163  level_stack_.template Pop<Level>(1);
164  bool ret = WriteEndArray();
165  if (level_stack_.Empty()) // end of json text
166  os_->Flush();
167  return ret;
168  }
169  //@}
170 
171  /*! @name Convenience extensions */
172  //@{
173 
174  //! Simpler but slower overload.
175  bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
176  bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
177 
178  //@}
179 
180 protected:
181  //! Information for each nested level
182  struct Level {
183  Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
184  size_t valueCount; //!< number of values in this level
185  bool inArray; //!< true if in array, otherwise in object
186  };
187 
188  static const size_t kDefaultLevelDepth = 32;
189 
190  bool WriteNull() {
191  os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true;
192  }
193 
194  bool WriteBool(bool b) {
195  if (b) {
196  os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e');
197  }
198  else {
199  os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e');
200  }
201  return true;
202  }
203 
204  bool WriteInt(int i) {
205  char buffer[11];
206  const char* end = internal::i32toa(i, buffer);
207  for (const char* p = buffer; p != end; ++p)
208  os_->Put(*p);
209  return true;
210  }
211 
212  bool WriteUint(unsigned u) {
213  char buffer[10];
214  const char* end = internal::u32toa(u, buffer);
215  for (const char* p = buffer; p != end; ++p)
216  os_->Put(*p);
217  return true;
218  }
219 
220  bool WriteInt64(int64_t i64) {
221  char buffer[21];
222  const char* end = internal::i64toa(i64, buffer);
223  for (const char* p = buffer; p != end; ++p)
224  os_->Put(*p);
225  return true;
226  }
227 
228  bool WriteUint64(uint64_t u64) {
229  char buffer[20];
230  char* end = internal::u64toa(u64, buffer);
231  for (char* p = buffer; p != end; ++p)
232  os_->Put(*p);
233  return true;
234  }
235 
236  bool WriteDouble(double d) {
237  char buffer[25];
238  char* end = internal::dtoa(d, buffer);
239  for (char* p = buffer; p != end; ++p)
240  os_->Put(*p);
241  return true;
242  }
243 
244  bool WriteString(const Ch* str, SizeType length) {
245  static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
246  static const char escape[256] = {
247 #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
248  //0 1 2 3 4 5 6 7 8 9 A B C D E F
249  'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
250  'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
251  0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
252  Z16, Z16, // 30~4F
253  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
254  Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
255 #undef Z16
256  };
257 
258  os_->Put('\"');
259  GenericStringStream<SourceEncoding> is(str);
260  while (is.Tell() < length) {
261  const Ch c = is.Peek();
262  if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) {
263  // Unicode escaping
264  unsigned codepoint;
265  if (!SourceEncoding::Decode(is, &codepoint))
266  return false;
267  os_->Put('\\');
268  os_->Put('u');
269  if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
270  os_->Put(hexDigits[(codepoint >> 12) & 15]);
271  os_->Put(hexDigits[(codepoint >> 8) & 15]);
272  os_->Put(hexDigits[(codepoint >> 4) & 15]);
273  os_->Put(hexDigits[(codepoint ) & 15]);
274  }
275  else {
276  RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
277  // Surrogate pair
278  unsigned s = codepoint - 0x010000;
279  unsigned lead = (s >> 10) + 0xD800;
280  unsigned trail = (s & 0x3FF) + 0xDC00;
281  os_->Put(hexDigits[(lead >> 12) & 15]);
282  os_->Put(hexDigits[(lead >> 8) & 15]);
283  os_->Put(hexDigits[(lead >> 4) & 15]);
284  os_->Put(hexDigits[(lead ) & 15]);
285  os_->Put('\\');
286  os_->Put('u');
287  os_->Put(hexDigits[(trail >> 12) & 15]);
288  os_->Put(hexDigits[(trail >> 8) & 15]);
289  os_->Put(hexDigits[(trail >> 4) & 15]);
290  os_->Put(hexDigits[(trail ) & 15]);
291  }
292  }
293  else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) {
294  is.Take();
295  os_->Put('\\');
296  os_->Put(escape[(unsigned char)c]);
297  if (escape[(unsigned char)c] == 'u') {
298  os_->Put('0');
299  os_->Put('0');
300  os_->Put(hexDigits[(unsigned char)c >> 4]);
301  os_->Put(hexDigits[(unsigned char)c & 0xF]);
302  }
303  }
304  else
305  if (!Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, *os_))
306  return false;
307  }
308  os_->Put('\"');
309  return true;
310  }
311 
312  bool WriteStartObject() { os_->Put('{'); return true; }
313  bool WriteEndObject() { os_->Put('}'); return true; }
314  bool WriteStartArray() { os_->Put('['); return true; }
315  bool WriteEndArray() { os_->Put(']'); return true; }
316 
317  void Prefix(Type type) {
318  (void)type;
319  if (level_stack_.GetSize() != 0) { // this value is not at root
320  Level* level = level_stack_.template Top<Level>();
321  if (level->valueCount > 0) {
322  if (level->inArray)
323  os_->Put(','); // add comma if it is not the first element in array
324  else // in object
325  os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
326  }
327  if (!level->inArray && level->valueCount % 2 == 0)
328  RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
329  level->valueCount++;
330  }
331  else {
332  RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
333  hasRoot_ = true;
334  }
335  }
336 
337  OutputStream* os_;
338  internal::Stack<StackAllocator> level_stack_;
339  bool hasRoot_;
340 
341 private:
342  // Prohibit copy constructor & assignment operator.
343  Writer(const Writer&);
344  Writer& operator=(const Writer&);
345 };
346 
347 // Full specialization for StringStream to prevent memory copying
348 
349 template<>
350 inline bool Writer<StringBuffer>::WriteInt(int i) {
351  char *buffer = os_->Push(11);
352  const char* end = internal::i32toa(i, buffer);
353  os_->Pop(static_cast<size_t>(11 - (end - buffer)));
354  return true;
355 }
356 
357 template<>
358 inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
359  char *buffer = os_->Push(10);
360  const char* end = internal::u32toa(u, buffer);
361  os_->Pop(static_cast<size_t>(10 - (end - buffer)));
362  return true;
363 }
364 
365 template<>
366 inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
367  char *buffer = os_->Push(21);
368  const char* end = internal::i64toa(i64, buffer);
369  os_->Pop(static_cast<size_t>(21 - (end - buffer)));
370  return true;
371 }
372 
373 template<>
374 inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
375  char *buffer = os_->Push(20);
376  const char* end = internal::u64toa(u, buffer);
377  os_->Pop(static_cast<size_t>(20 - (end - buffer)));
378  return true;
379 }
380 
381 template<>
382 inline bool Writer<StringBuffer>::WriteDouble(double d) {
383  char *buffer = os_->Push(25);
384  char* end = internal::dtoa(d, buffer);
385  os_->Pop(static_cast<size_t>(25 - (end - buffer)));
386  return true;
387 }
388 
389 RAPIDJSON_NAMESPACE_END
390 
391 #ifdef _MSC_VER
392 RAPIDJSON_DIAG_POP
393 #endif
394 
395 #endif // RAPIDJSON_RAPIDJSON_H_
true
Definition: rapidjson.h:645
bool Double(double d)
Writes the given double value to the stream.
Definition: writer.h:120
unsigned SizeType
Size type (for string lengths, array sizes, etc.)
Definition: rapidjson.h:322
false
Definition: rapidjson.h:644
bool inArray
true if in array, otherwise in object
Definition: writer.h:185
Information for each nested level.
Definition: writer.h:182
bool String(const Ch *str)
Simpler but slower overload.
Definition: writer.h:175
Type
Type of JSON value.
Definition: rapidjson.h:642
object
Definition: rapidjson.h:646
Writer(OutputStream &os, StackAllocator *stackAllocator=0, size_t levelDepth=kDefaultLevelDepth)
Constructor.
Definition: writer.h:64
size_t valueCount
number of values in this level
Definition: writer.h:184
array
Definition: rapidjson.h:647
JSON writer.
Definition: writer.h:54
bool IsComplete() const
Checks whether the output is a complete JSON.
Definition: writer.h:99
null
Definition: rapidjson.h:643
string
Definition: rapidjson.h:648
common definitions and configuration
void Reset(OutputStream &os)
Reset the writer with a new stream.
Definition: writer.h:89
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:344
number
Definition: rapidjson.h:649