256 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			C
		
	
	
	
		
		
			
		
	
	
			256 lines
		
	
	
		
			9.4 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
 | ||
|  | 
 | ||
|  | 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 ouptut 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> 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) {} | ||
|  | 
 | ||
|  |     //! 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::WriteNull(); } | ||
|  |     bool Bool(bool b)           { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); } | ||
|  |     bool Int(int i)             { PrettyPrefix(kNumberType); return Base::WriteInt(i); } | ||
|  |     bool Uint(unsigned u)       { PrettyPrefix(kNumberType); return Base::WriteUint(u); } | ||
|  |     bool Int64(int64_t i64)     { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); } | ||
|  |     bool Uint64(uint64_t u64)   { PrettyPrefix(kNumberType); return Base::WriteUint64(u64);  } | ||
|  |     bool Double(double d)       { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } | ||
|  | 
 | ||
|  |     bool RawNumber(const Ch* str, SizeType length, bool copy = false) { | ||
|  |         (void)copy; | ||
|  |         PrettyPrefix(kNumberType); | ||
|  |         return Base::WriteString(str, length); | ||
|  |     } | ||
|  | 
 | ||
|  |     bool String(const Ch* str, SizeType length, bool copy = false) { | ||
|  |         (void)copy; | ||
|  |         PrettyPrefix(kStringType); | ||
|  |         return 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)); | ||
|  |         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) { | ||
|  |             Base::os_->Put('\n'); | ||
|  |             WriteIndent(); | ||
|  |         } | ||
|  |         bool ret = Base::WriteEndObject(); | ||
|  |         (void)ret; | ||
|  |         RAPIDJSON_ASSERT(ret == true); | ||
|  |         if (Base::level_stack_.Empty()) // end of json text
 | ||
|  |             Base::os_->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::WriteEndArray(); | ||
|  |         (void)ret; | ||
|  |         RAPIDJSON_ASSERT(ret == true); | ||
|  |         if (Base::level_stack_.Empty()) // end of json text
 | ||
|  |             Base::os_->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) { PrettyPrefix(type); return 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 TargetEncoding::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 | ||
|  | 
 | ||
|  | #ifdef __GNUC__
 | ||
|  | RAPIDJSON_DIAG_POP | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #endif // RAPIDJSON_RAPIDJSON_H_
 |