#ifndef RAPIDJSON_PRETTYWRITER_H_ #define RAPIDJSON_PRETTYWRITER_H_ #include "writer.h" namespace rapidjson { //! Writer with indentation and spacing. /*! \tparam Stream Type of ouptut stream. \tparam Encoding Encoding of both source strings and output. \tparam Allocator Type of allocator for allocating memory of stack. */ template, typename Allocator = MemoryPoolAllocator<> > class PrettyWriter : public Writer { public: typedef Writer Base; typedef typename Base::Ch Ch; //! Constructor /*! \param stream Output stream. \param allocator User supplied allocator. If it is null, it will create a private one. \param levelDepth Initial capacity of */ PrettyWriter(Stream& stream, int precision = 20, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : Base(stream, precision, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} //! Set custom indentation. /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\t', '\n', '\r'). \param indentCharCount Number of indent characters for each indentation level. \note The default indentation is 4 spaces. */ PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); indentChar_ = indentChar; indentCharCount_ = indentCharCount; return *this; } //@name Implementation of Handler. //@{ PrettyWriter& Null_() { PrettyPrefix(kNull_Type); Base::WriteNull_(); return *this; } PrettyWriter& Bool_(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); Base::WriteBool_(b); return *this; } PrettyWriter& Int(int i) { PrettyPrefix(kNumberType); Base::WriteInt(i); return *this; } PrettyWriter& Uint(unsigned u) { PrettyPrefix(kNumberType); Base::WriteUint(u); return *this; } PrettyWriter& Int64(int64_t i64) { PrettyPrefix(kNumberType); Base::WriteInt64(i64); return *this; } PrettyWriter& Uint64(uint64_t u64) { PrettyPrefix(kNumberType); Base::WriteUint64(u64); return *this; } PrettyWriter& Double(double d) { PrettyPrefix(kNumberType); Base::WriteDouble(d); return *this; } PrettyWriter& String(const Ch* str, SizeType length, bool copy = false) { (void)copy; PrettyPrefix(kStringType); Base::WriteString(str, length); return *this; } PrettyWriter& StartObject() { PrettyPrefix(kObjectType); new (Base::level_stack_.template Push()) typename Base::Level(false); Base::WriteStartObject(); return *this; } PrettyWriter& EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; if (!empty) { Base::stream_.Put('\n'); WriteIndent(); } Base::WriteEndObject(); return *this; } PrettyWriter& StartArray() { PrettyPrefix(kArrayType); new (Base::level_stack_.template Push()) typename Base::Level(true); Base::WriteStartArray(); return *this; } PrettyWriter& EndArray(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; if (!empty) { Base::stream_.Put('\n'); WriteIndent(); } Base::WriteEndArray(); return *this; } //@} //! Simpler but slower overload. PrettyWriter& String(const Ch* str) { return String(str, internal::StrLen(str)); } protected: void PrettyPrefix(Type type) { (void)type; if (Base::level_stack_.GetSize() != 0) { // this value is not at root typename Base::Level* level = Base::level_stack_.template Top(); if (level->inArray) { if (level->valueCount > 0) { Base::stream_.Put(','); // add comma if it is not the first element in array Base::stream_.Put('\n'); } else Base::stream_.Put('\n'); WriteIndent(); } else { // in object if (level->valueCount > 0) { if (level->valueCount % 2 == 0) { Base::stream_.Put(','); Base::stream_.Put('\n'); } else { Base::stream_.Put(':'); Base::stream_.Put(' '); } } else Base::stream_.Put('\n'); if (level->valueCount % 2 == 0) WriteIndent(); } if (!level->inArray && level->valueCount % 2 == 0) RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name level->valueCount++; } else RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType); } void WriteIndent() { size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; PutN(Base::stream_, indentChar_, count); } Ch indentChar_; unsigned indentCharCount_; }; } // namespace rapidjson #endif // RAPIDJSON_RAPIDJSON_H_