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 */
Reset(OutputStream & os)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 */
IsComplete()99 bool IsComplete() const {
100 return hasRoot_ && level_stack_.Empty();
101 }
102
103 /*!@name Implementation of Handler
104 \see Handler
105 */
106 //@{
107
Null()108 bool Null() { Prefix(kNullType); return WriteNull(); }
Bool(bool b)109 bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); }
Int(int i)110 bool Int(int i) { Prefix(kNumberType); return WriteInt(i); }
Uint(unsigned u)111 bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); }
Int64(int64_t i64)112 bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); }
Uint64(uint64_t u64)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 */
Double(double d)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
String(const std::basic_string<Ch> & str)129 bool String(const std::basic_string<Ch>& str) {
130 return String(str.data(), SizeType(str.size()));
131 }
132 #endif
133
StartObject()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
StartArray()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.
String(const Ch * str)175 bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
Key(const Ch * 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 {
LevelLevel183 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
WriteNull()190 bool WriteNull() {
191 os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true;
192 }
193
WriteBool(bool b)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
WriteInt(int i)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
WriteUint(unsigned u)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
WriteInt64(int64_t i64)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
WriteUint64(uint64_t u64)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
WriteDouble(double d)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
WriteString(const Ch * str,SizeType length)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
WriteStartObject()312 bool WriteStartObject() { os_->Put('{'); return true; }
WriteEndObject()313 bool WriteEndObject() { os_->Put('}'); return true; }
WriteStartArray()314 bool WriteStartArray() { os_->Put('['); return true; }
WriteEndArray()315 bool WriteEndArray() { os_->Put(']'); return true; }
316
Prefix(Type type)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<>
WriteInt(int i)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<>
WriteUint(unsigned u)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<>
WriteInt64(int64_t i64)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<>
WriteUint64(uint64_t u)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<>
WriteDouble(double d)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_
396