123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- // 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) {}
- #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_
|