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
31RAPIDJSON_DIAG_PUSH
32RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
33#endif
34
35RAPIDJSON_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*/
53template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator>
54class Writer {
55public:
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
180protected:
181    //! Information for each nested level
182    struct Level {
183        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
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
341private:
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
349template<>
350inline 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
357template<>
358inline 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
365template<>
366inline 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
373template<>
374inline 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
381template<>
382inline 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
389RAPIDJSON_NAMESPACE_END
390
391#ifdef _MSC_VER
392RAPIDJSON_DIAG_POP
393#endif
394
395#endif // RAPIDJSON_RAPIDJSON_H_
396