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_PRETTYWRITER_H_
16 #define RAPIDJSON_PRETTYWRITER_H_
17 
18 #include "writer.h"
19 
20 #ifdef __GNUC__
21 RAPIDJSON_DIAG_PUSH
22 RAPIDJSON_DIAG_OFF(effc++)
23 #endif
24 
25 RAPIDJSON_NAMESPACE_BEGIN
26 
27 //! Combination of PrettyWriter format flags.
28 /*! \see PrettyWriter::SetFormatOptions
29  */
30 enum PrettyFormatOptions {
31     kFormatDefault = 0,         //!< Default pretty formatting.
32     kFormatSingleLineArray = 1  //!< Format arrays on a single line.
33 };
34 
35 //! Writer with indentation and spacing.
36 /*!
37     \tparam OutputStream Type of ouptut os.
38     \tparam SourceEncoding Encoding of source string.
39     \tparam TargetEncoding Encoding of output stream.
40     \tparam StackAllocator Type of allocator for allocating memory of stack.
41 */
42 template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
43 class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
44 public:
45     typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
46     typedef typename Base::Ch Ch;
47 
48     //! Constructor
49     /*! \param os Output stream.
50         \param allocator User supplied allocator. If it is null, it will create a private one.
51         \param levelDepth Initial capacity of stack.
52     */
53     explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
Base(os,allocator,levelDepth)54         Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
55 
56 
57     explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
Base(allocator,levelDepth)58         Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
59 
60     //! Set custom indentation.
61     /*! \param indentChar       Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
62         \param indentCharCount  Number of indent characters for each indentation level.
63         \note The default indentation is 4 spaces.
64     */
SetIndent(Ch indentChar,unsigned indentCharCount)65     PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
66         RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
67         indentChar_ = indentChar;
68         indentCharCount_ = indentCharCount;
69         return *this;
70     }
71 
72     //! Set pretty writer formatting options.
73     /*! \param options Formatting options.
74     */
SetFormatOptions(PrettyFormatOptions options)75     PrettyWriter& SetFormatOptions(PrettyFormatOptions options) {
76         formatOptions_ = options;
77         return *this;
78     }
79 
80     /*! @name Implementation of Handler
81         \see Handler
82     */
83     //@{
84 
Null()85     bool Null()                 { PrettyPrefix(kNullType);   return Base::WriteNull(); }
Bool(bool b)86     bool Bool(bool b)           { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
Int(int i)87     bool Int(int i)             { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
Uint(unsigned u)88     bool Uint(unsigned u)       { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
Int64(int64_t i64)89     bool Int64(int64_t i64)     { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
Uint64(uint64_t u64)90     bool Uint64(uint64_t u64)   { PrettyPrefix(kNumberType); return Base::WriteUint64(u64);  }
Double(double d)91     bool Double(double d)       { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
92 
93     bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
94         (void)copy;
95         PrettyPrefix(kNumberType);
96         return Base::WriteString(str, length);
97     }
98 
99     bool String(const Ch* str, SizeType length, bool copy = false) {
100         (void)copy;
101         PrettyPrefix(kStringType);
102         return Base::WriteString(str, length);
103     }
104 
105 #if RAPIDJSON_HAS_STDSTRING
String(const std::basic_string<Ch> & str)106     bool String(const std::basic_string<Ch>& str) {
107         return String(str.data(), SizeType(str.size()));
108     }
109 #endif
110 
StartObject()111     bool StartObject() {
112         PrettyPrefix(kObjectType);
113         new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
114         return Base::WriteStartObject();
115     }
116 
117     bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
118 
119     bool EndObject(SizeType memberCount = 0) {
120         (void)memberCount;
121         RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
122         RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
123         bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
124 
125         if (!empty) {
126             Base::os_->Put('\n');
127             WriteIndent();
128         }
129         bool ret = Base::WriteEndObject();
130         (void)ret;
131         RAPIDJSON_ASSERT(ret == true);
132         if (Base::level_stack_.Empty()) // end of json text
133             Base::os_->Flush();
134         return true;
135     }
136 
StartArray()137     bool StartArray() {
138         PrettyPrefix(kArrayType);
139         new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
140         return Base::WriteStartArray();
141     }
142 
143     bool EndArray(SizeType memberCount = 0) {
144         (void)memberCount;
145         RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
146         RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
147         bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
148 
149         if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {
150             Base::os_->Put('\n');
151             WriteIndent();
152         }
153         bool ret = Base::WriteEndArray();
154         (void)ret;
155         RAPIDJSON_ASSERT(ret == true);
156         if (Base::level_stack_.Empty()) // end of json text
157             Base::os_->Flush();
158         return true;
159     }
160 
161     //@}
162 
163     /*! @name Convenience extensions */
164     //@{
165 
166     //! Simpler but slower overload.
String(const Ch * str)167     bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
Key(const Ch * str)168     bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
169 
170     //@}
171 
172     //! Write a raw JSON value.
173     /*!
174         For user to write a stringified JSON as a value.
175 
176         \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
177         \param length Length of the json.
178         \param type Type of the root of json.
179         \note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
180     */
RawValue(const Ch * json,size_t length,Type type)181     bool RawValue(const Ch* json, size_t length, Type type) { PrettyPrefix(type); return Base::WriteRawValue(json, length); }
182 
183 protected:
PrettyPrefix(Type type)184     void PrettyPrefix(Type type) {
185         (void)type;
186         if (Base::level_stack_.GetSize() != 0) { // this value is not at root
187             typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
188 
189             if (level->inArray) {
190                 if (level->valueCount > 0) {
191                     Base::os_->Put(','); // add comma if it is not the first element in array
192                     if (formatOptions_ & kFormatSingleLineArray)
193                         Base::os_->Put(' ');
194                 }
195 
196                 if (!(formatOptions_ & kFormatSingleLineArray)) {
197                     Base::os_->Put('\n');
198                     WriteIndent();
199                 }
200             }
201             else {  // in object
202                 if (level->valueCount > 0) {
203                     if (level->valueCount % 2 == 0) {
204                         Base::os_->Put(',');
205                         Base::os_->Put('\n');
206                     }
207                     else {
208                         Base::os_->Put(':');
209                         Base::os_->Put(' ');
210                     }
211                 }
212                 else
213                     Base::os_->Put('\n');
214 
215                 if (level->valueCount % 2 == 0)
216                     WriteIndent();
217             }
218             if (!level->inArray && level->valueCount % 2 == 0)
219                 RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name
220             level->valueCount++;
221         }
222         else {
223             RAPIDJSON_ASSERT(!Base::hasRoot_);  // Should only has one and only one root.
224             Base::hasRoot_ = true;
225         }
226     }
227 
WriteIndent()228     void WriteIndent()  {
229         size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
230         PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count);
231     }
232 
233     Ch indentChar_;
234     unsigned indentCharCount_;
235     PrettyFormatOptions formatOptions_;
236 
237 private:
238     // Prohibit copy constructor & assignment operator.
239     PrettyWriter(const PrettyWriter&);
240     PrettyWriter& operator=(const PrettyWriter&);
241 };
242 
243 RAPIDJSON_NAMESPACE_END
244 
245 #ifdef __GNUC__
246 RAPIDJSON_DIAG_POP
247 #endif
248 
249 #endif // RAPIDJSON_RAPIDJSON_H_
250