278 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			278 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								// Tencent is pleased to support the open source community by making RapidJSON available.
							 | 
						||
| 
								 | 
							
								// 
							 | 
						||
| 
								 | 
							
								// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Licensed under the MIT License (the "License"); you may not use this file except
							 | 
						||
| 
								 | 
							
								// in compliance with the License. You may obtain a copy of the License at
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// http://opensource.org/licenses/MIT
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Unless required by applicable law or agreed to in writing, software distributed 
							 | 
						||
| 
								 | 
							
								// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
							 | 
						||
| 
								 | 
							
								// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
							 | 
						||
| 
								 | 
							
								// specific language governing permissions and limitations under the License.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef RAPIDJSON_PRETTYWRITER_H_
							 | 
						||
| 
								 | 
							
								#define RAPIDJSON_PRETTYWRITER_H_
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "writer.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef __GNUC__
							 | 
						||
| 
								 | 
							
								RAPIDJSON_DIAG_PUSH
							 | 
						||
| 
								 | 
							
								RAPIDJSON_DIAG_OFF(effc++)
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if defined(__clang__)
							 | 
						||
| 
								 | 
							
								RAPIDJSON_DIAG_PUSH
							 | 
						||
| 
								 | 
							
								RAPIDJSON_DIAG_OFF(c++98-compat)
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RAPIDJSON_NAMESPACE_BEGIN
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//! Combination of PrettyWriter format flags.
							 | 
						||
| 
								 | 
							
								/*! \see PrettyWriter::SetFormatOptions
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								enum PrettyFormatOptions {
							 | 
						||
| 
								 | 
							
								    kFormatDefault = 0,         //!< Default pretty formatting.
							 | 
						||
| 
								 | 
							
								    kFormatSingleLineArray = 1  //!< Format arrays on a single line.
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//! Writer with indentation and spacing.
							 | 
						||
| 
								 | 
							
								/*!
							 | 
						||
| 
								 | 
							
								    \tparam OutputStream Type of output os.
							 | 
						||
| 
								 | 
							
								    \tparam SourceEncoding Encoding of source string.
							 | 
						||
| 
								 | 
							
								    \tparam TargetEncoding Encoding of output stream.
							 | 
						||
| 
								 | 
							
								    \tparam StackAllocator Type of allocator for allocating memory of stack.
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
							 | 
						||
| 
								 | 
							
								class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
							 | 
						||
| 
								 | 
							
								public:
							 | 
						||
| 
								 | 
							
								    typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> Base;
							 | 
						||
| 
								 | 
							
								    typedef typename Base::Ch Ch;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Constructor
							 | 
						||
| 
								 | 
							
								    /*! \param os Output stream.
							 | 
						||
| 
								 | 
							
								        \param allocator User supplied allocator. If it is null, it will create a private one.
							 | 
						||
| 
								 | 
							
								        \param levelDepth Initial capacity of stack.
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : 
							 | 
						||
| 
								 | 
							
								        Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : 
							 | 
						||
| 
								 | 
							
								        Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
							 | 
						||
| 
								 | 
							
								    PrettyWriter(PrettyWriter&& rhs) :
							 | 
						||
| 
								 | 
							
								        Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {}
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! 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;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Set pretty writer formatting options.
							 | 
						||
| 
								 | 
							
								    /*! \param options Formatting options.
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    PrettyWriter& SetFormatOptions(PrettyFormatOptions options) {
							 | 
						||
| 
								 | 
							
								        formatOptions_ = options;
							 | 
						||
| 
								 | 
							
								        return *this;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /*! @name Implementation of Handler
							 | 
						||
| 
								 | 
							
								        \see Handler
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    //@{
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool Null()                 { PrettyPrefix(kNullType);   return Base::EndValue(Base::WriteNull()); }
							 | 
						||
| 
								 | 
							
								    bool Bool(bool b)           { PrettyPrefix(b ? kTrueType : kFalseType); return Base::EndValue(Base::WriteBool(b)); }
							 | 
						||
| 
								 | 
							
								    bool Int(int i)             { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt(i)); }
							 | 
						||
| 
								 | 
							
								    bool Uint(unsigned u)       { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint(u)); }
							 | 
						||
| 
								 | 
							
								    bool Int64(int64_t i64)     { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt64(i64)); }
							 | 
						||
| 
								 | 
							
								    bool Uint64(uint64_t u64)   { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint64(u64));  }
							 | 
						||
| 
								 | 
							
								    bool Double(double d)       { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteDouble(d)); }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
							 | 
						||
| 
								 | 
							
								        RAPIDJSON_ASSERT(str != 0);
							 | 
						||
| 
								 | 
							
								        (void)copy;
							 | 
						||
| 
								 | 
							
								        PrettyPrefix(kNumberType);
							 | 
						||
| 
								 | 
							
								        return Base::EndValue(Base::WriteString(str, length));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool String(const Ch* str, SizeType length, bool copy = false) {
							 | 
						||
| 
								 | 
							
								        RAPIDJSON_ASSERT(str != 0);
							 | 
						||
| 
								 | 
							
								        (void)copy;
							 | 
						||
| 
								 | 
							
								        PrettyPrefix(kStringType);
							 | 
						||
| 
								 | 
							
								        return Base::EndValue(Base::WriteString(str, length));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if RAPIDJSON_HAS_STDSTRING
							 | 
						||
| 
								 | 
							
								    bool String(const std::basic_string<Ch>& str) {
							 | 
						||
| 
								 | 
							
								        return String(str.data(), SizeType(str.size()));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool StartObject() {
							 | 
						||
| 
								 | 
							
								        PrettyPrefix(kObjectType);
							 | 
						||
| 
								 | 
							
								        new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
							 | 
						||
| 
								 | 
							
								        return Base::WriteStartObject();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if RAPIDJSON_HAS_STDSTRING
							 | 
						||
| 
								 | 
							
								    bool Key(const std::basic_string<Ch>& str) {
							 | 
						||
| 
								 | 
							
								        return Key(str.data(), SizeType(str.size()));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
								    bool EndObject(SizeType memberCount = 0) {
							 | 
						||
| 
								 | 
							
								        (void)memberCount;
							 | 
						||
| 
								 | 
							
								        RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object
							 | 
						||
| 
								 | 
							
								        RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); // currently inside an Array, not Object
							 | 
						||
| 
								 | 
							
								        RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top<typename Base::Level>()->valueCount % 2); // Object has a Key without a Value
							 | 
						||
| 
								 | 
							
								       
							 | 
						||
| 
								 | 
							
								        bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (!empty) {
							 | 
						||
| 
								 | 
							
								            Base::os_->Put('\n');
							 | 
						||
| 
								 | 
							
								            WriteIndent();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        bool ret = Base::EndValue(Base::WriteEndObject());
							 | 
						||
| 
								 | 
							
								        (void)ret;
							 | 
						||
| 
								 | 
							
								        RAPIDJSON_ASSERT(ret == true);
							 | 
						||
| 
								 | 
							
								        if (Base::level_stack_.Empty()) // end of json text
							 | 
						||
| 
								 | 
							
								            Base::Flush();
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool StartArray() {
							 | 
						||
| 
								 | 
							
								        PrettyPrefix(kArrayType);
							 | 
						||
| 
								 | 
							
								        new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
							 | 
						||
| 
								 | 
							
								        return Base::WriteStartArray();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool EndArray(SizeType memberCount = 0) {
							 | 
						||
| 
								 | 
							
								        (void)memberCount;
							 | 
						||
| 
								 | 
							
								        RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
							 | 
						||
| 
								 | 
							
								        RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
							 | 
						||
| 
								 | 
							
								        bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {
							 | 
						||
| 
								 | 
							
								            Base::os_->Put('\n');
							 | 
						||
| 
								 | 
							
								            WriteIndent();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        bool ret = Base::EndValue(Base::WriteEndArray());
							 | 
						||
| 
								 | 
							
								        (void)ret;
							 | 
						||
| 
								 | 
							
								        RAPIDJSON_ASSERT(ret == true);
							 | 
						||
| 
								 | 
							
								        if (Base::level_stack_.Empty()) // end of json text
							 | 
						||
| 
								 | 
							
								            Base::Flush();
							 | 
						||
| 
								 | 
							
								        return true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //@}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /*! @name Convenience extensions */
							 | 
						||
| 
								 | 
							
								    //@{
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Simpler but slower overload.
							 | 
						||
| 
								 | 
							
								    bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
							 | 
						||
| 
								 | 
							
								    bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //@}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //! Write a raw JSON value.
							 | 
						||
| 
								 | 
							
								    /*!
							 | 
						||
| 
								 | 
							
								        For user to write a stringified JSON as a value.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
							 | 
						||
| 
								 | 
							
								        \param length Length of the json.
							 | 
						||
| 
								 | 
							
								        \param type Type of the root of json.
							 | 
						||
| 
								 | 
							
								        \note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
							 | 
						||
| 
								 | 
							
								    */
							 | 
						||
| 
								 | 
							
								    bool RawValue(const Ch* json, size_t length, Type type) {
							 | 
						||
| 
								 | 
							
								        RAPIDJSON_ASSERT(json != 0);
							 | 
						||
| 
								 | 
							
								        PrettyPrefix(type);
							 | 
						||
| 
								 | 
							
								        return Base::EndValue(Base::WriteRawValue(json, length));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								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<typename Base::Level>();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (level->inArray) {
							 | 
						||
| 
								 | 
							
								                if (level->valueCount > 0) {
							 | 
						||
| 
								 | 
							
								                    Base::os_->Put(','); // add comma if it is not the first element in array
							 | 
						||
| 
								 | 
							
								                    if (formatOptions_ & kFormatSingleLineArray)
							 | 
						||
| 
								 | 
							
								                        Base::os_->Put(' ');
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (!(formatOptions_ & kFormatSingleLineArray)) {
							 | 
						||
| 
								 | 
							
								                    Base::os_->Put('\n');
							 | 
						||
| 
								 | 
							
								                    WriteIndent();
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else {  // in object
							 | 
						||
| 
								 | 
							
								                if (level->valueCount > 0) {
							 | 
						||
| 
								 | 
							
								                    if (level->valueCount % 2 == 0) {
							 | 
						||
| 
								 | 
							
								                        Base::os_->Put(',');
							 | 
						||
| 
								 | 
							
								                        Base::os_->Put('\n');
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    else {
							 | 
						||
| 
								 | 
							
								                        Base::os_->Put(':');
							 | 
						||
| 
								 | 
							
								                        Base::os_->Put(' ');
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                    Base::os_->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(!Base::hasRoot_);  // Should only has one and only one root.
							 | 
						||
| 
								 | 
							
								            Base::hasRoot_ = true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    void WriteIndent()  {
							 | 
						||
| 
								 | 
							
								        size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
							 | 
						||
| 
								 | 
							
								        PutN(*Base::os_, static_cast<typename OutputStream::Ch>(indentChar_), count);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Ch indentChar_;
							 | 
						||
| 
								 | 
							
								    unsigned indentCharCount_;
							 | 
						||
| 
								 | 
							
								    PrettyFormatOptions formatOptions_;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								private:
							 | 
						||
| 
								 | 
							
								    // Prohibit copy constructor & assignment operator.
							 | 
						||
| 
								 | 
							
								    PrettyWriter(const PrettyWriter&);
							 | 
						||
| 
								 | 
							
								    PrettyWriter& operator=(const PrettyWriter&);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RAPIDJSON_NAMESPACE_END
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if defined(__clang__)
							 | 
						||
| 
								 | 
							
								RAPIDJSON_DIAG_POP
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef __GNUC__
							 | 
						||
| 
								 | 
							
								RAPIDJSON_DIAG_POP
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif // RAPIDJSON_RAPIDJSON_H_
							 |