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 #if RAPIDJSON_HAS_STDSTRING
Key(const std::basic_string<Ch> & str)120     bool Key(const std::basic_string<Ch>& str) {
121         return Key(str.data(), SizeType(str.size()));
122     }
123 #endif
124 
125     bool EndObject(SizeType memberCount = 0) {
126         (void)memberCount;
127         RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
128         RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
129         bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
130 
131         if (!empty) {
132             Base::os_->Put('\n');
133             WriteIndent();
134         }
135         bool ret = Base::WriteEndObject();
136         (void)ret;
137         RAPIDJSON_ASSERT(ret == true);
138         if (Base::level_stack_.Empty()) // end of json text
139             Base::os_->Flush();
140         return true;
141     }
142 
StartArray()143     bool StartArray() {
144         PrettyPrefix(kArrayType);
145         new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
146         return Base::WriteStartArray();
147     }
148 
149     bool EndArray(SizeType memberCount = 0) {
150         (void)memberCount;
151         RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
152         RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
153         bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
154 
155         if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {
156             Base::os_->Put('\n');
157             WriteIndent();
158         }
159         bool ret = Base::WriteEndArray();
160         (void)ret;
161         RAPIDJSON_ASSERT(ret == true);
162         if (Base::level_stack_.Empty()) // end of json text
163             Base::os_->Flush();
164         return true;
165     }
166 
167     //@}
168 
169     /*! @name Convenience extensions */
170     //@{
171 
172     //! Simpler but slower overload.
String(const Ch * str)173     bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
Key(const Ch * str)174     bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
175 
176     //@}
177 
178     //! Write a raw JSON value.
179     /*!
180         For user to write a stringified JSON as a value.
181 
182         \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
183         \param length Length of the json.
184         \param type Type of the root of json.
185         \note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
186     */
RawValue(const Ch * json,size_t length,Type type)187     bool RawValue(const Ch* json, size_t length, Type type) { PrettyPrefix(type); return Base::WriteRawValue(json, length); }
188 
189 protected:
PrettyPrefix(Type type)190     void PrettyPrefix(Type type) {
191         (void)type;
192         if (Base::level_stack_.GetSize() != 0) { // this value is not at root
193             typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
194 
195             if (level->inArray) {
196                 if (level->valueCount > 0) {
197                     Base::os_->Put(','); // add comma if it is not the first element in array
198                     if (formatOptions_ & kFormatSingleLineArray)
199                         Base::os_->Put(' ');
200                 }
201 
202                 if (!(formatOptions_ & kFormatSingleLineArray)) {
203                     Base::os_->Put('\n');
204                     WriteIndent();
205                 }
206             }
207             else {  // in object
208                 if (level->valueCount > 0) {
209                     if (level->valueCount % 2 == 0) {
210                         Base::os_->Put(',');
211                         Base::os_->Put('\n');
212                     }
213                     else {
214                         Base::os_->Put(':');
215                         Base::os_->Put(' ');
216                     }
217                 }
218                 else
219                     Base::os_->Put('\n');
220 
221                 if (level->valueCount % 2 == 0)
222                     WriteIndent();
223             }
224             if (!level->inArray && level->valueCount % 2 == 0)
225                 RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name
226             level->valueCount++;
227         }
228         else {
229             RAPIDJSON_ASSERT(!Base::hasRoot_);  // Should only has one and only one root.
230             Base::hasRoot_ = true;
231         }
232     }
233 
WriteIndent()234     void WriteIndent()  {
235         size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
236         PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count);
237     }
238 
239     Ch indentChar_;
240     unsigned indentCharCount_;
241     PrettyFormatOptions formatOptions_;
242 
243 private:
244     // Prohibit copy constructor & assignment operator.
245     PrettyWriter(const PrettyWriter&);
246     PrettyWriter& operator=(const PrettyWriter&);
247 };
248 
249 RAPIDJSON_NAMESPACE_END
250 
251 #ifdef __GNUC__
252 RAPIDJSON_DIAG_POP
253 #endif
254 
255 #endif // RAPIDJSON_RAPIDJSON_H_
256