• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         explicit 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