// 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_WRITER_H_
#define RAPIDJSON_WRITER_H_
#include "rapidjson.h"
#include "internal/stack.h"
#include "internal/strfunc.h"
#include "internal/dtoa.h"
#include "internal/itoa.h"
#include "stringbuffer.h"
#include <
new >
// placement new
#if RAPIDJSON_HAS_STDSTRING
#include <string>
#endif
#ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(
4127 )
// conditional expression is constant
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! JSON writer
/*! Writer implements the concept Handler.
It generates JSON text by events to an output os .
User may programmatically calls the functions of a writer to generate JSON text .
On the other side , a writer can also be passed to objects that generates events ,
for example Reader : : Parse ( ) and Document : : Accept ( ) .
\ tparam OutputStream Type of output stream .
\ tparam SourceEncoding Encoding of source string .
\ tparam TargetEncoding Encoding of output stream .
\ tparam StackAllocator Type of allocator for allocating memory of stack .
\ note implements Handler concept
*/
template <
typename OutputStream,
typename SourceEncoding = UTF8<>,
typename TargetEncoding =
UTF8<>, typename StackAllocator = CrtAllocator>
class Writer {
public :
typedef typename SourceEncoding::Ch Ch;
//! Constructor
/*! \param os Output stream.
\ param stackAllocator User supplied allocator . If it is null , it will create a private one .
\ param levelDepth Initial capacity of stack .
*/
explicit
Writer(OutputStream& os, StackAllocator* stackAllocator = 0 , size_t levelDepth = kDefaultLevelDepth) :
os_(&os), level_stack_(stackAllocator, levelDepth * sizeof (Level)), hasRoot_(false ) {}
explicit
Writer(StackAllocator* allocator = 0 , size_t levelDepth = kDefaultLevelDepth) :
os_(0 ), level_stack_(allocator, levelDepth * sizeof (Level)), hasRoot_(false ) {}
//! Reset the writer with a new stream.
/*!
This function reset the writer with a new stream and default settings ,
in order to make a Writer object reusable for output multiple JSONs .
\ param os New output stream .
\ code
Writer < OutputStream > writer ( os1 ) ;
writer . StartObject ( ) ;
// ...
writer . EndObject ( ) ;
writer . Reset ( os2 ) ;
writer . StartObject ( ) ;
// ...
writer . EndObject ( ) ;
\ endcode
*/
void Reset(OutputStream& os) {
os_ = &os;
hasRoot_ = false ;
level_stack_.Clear();
}
//! Checks whether the output is a complete JSON.
/*!
A complete JSON has a complete root object or array .
*/
bool IsComplete() const {
return hasRoot_ && level_stack_.Empty();
}
/*!@name Implementation of Handler
\ see Handler
*/
//@{
bool Null() { Prefix(kNullType); return WriteNull(); }
bool Bool (bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); }
bool Int (int i) { Prefix(kNumberType); return WriteInt(i); }
bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); }
bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); }
bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); }
//! Writes the given \c double value to the stream
/*!
\ param d The value to be written .
\ return Whether it is succeed .
*/
bool Double (double d) { Prefix(kNumberType); return WriteDouble(d); }
bool String(const Ch* str, SizeType length, bool copy = false ) {
(void )copy;
Prefix(kStringType);
return 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() {
Prefix(kObjectType);
new (level_stack_.template Push<Level>()) Level(false );
return WriteStartObject();
}
bool Key(const Ch* str, SizeType length, bool copy = false ) { return String(str, length, copy); }
bool EndObject(SizeType memberCount = 0 ) {
(void )memberCount;
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof (Level));
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
level_stack_.template Pop<Level>(1 );
bool ret = WriteEndObject();
if (level_stack_.Empty()) // end of json text
os_->Flush();
return ret;
}
bool StartArray() {
Prefix(kArrayType);
new (level_stack_.template Push<Level>()) Level(true );
return WriteStartArray();
}
bool EndArray(SizeType elementCount = 0 ) {
(void )elementCount;
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof (Level));
RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
level_stack_.template Pop<Level>(1 );
bool ret = WriteEndArray();
if (level_stack_.Empty()) // end of json text
os_->Flush();
return ret;
}
//@}
/*! @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)); }
//@}
protected :
//! Information for each nested level
struct Level {
Level(bool inArray_) : valueCount(0 ), inArray(inArray_) {}
size_t valueCount; //!< number of values in this level
bool inArray; //!< true if in array, otherwise in object
};
static const size_t kDefaultLevelDepth = 32 ;
bool WriteNull() {
os_->Put('n' ); os_->Put('u' ); os_->Put('l' ); os_->Put('l' ); return true ;
}
bool WriteBool(bool b) {
if (b) {
os_->Put('t' ); os_->Put('r' ); os_->Put('u' ); os_->Put('e' );
}
else {
os_->Put('f' ); os_->Put('a' ); os_->Put('l' ); os_->Put('s' ); os_->Put('e' );
}
return true ;
}
bool WriteInt(int i) {
char buffer[11 ];
const char * end = internal::i32toa(i, buffer);
for (const char * p = buffer; p != end; ++p)
os_->Put(*p);
return true ;
}
bool WriteUint(unsigned u) {
char buffer[10 ];
const char * end = internal::u32toa(u, buffer);
for (const char * p = buffer; p != end; ++p)
os_->Put(*p);
return true ;
}
bool WriteInt64(int64_t i64) {
char buffer[21 ];
const char * end = internal::i64toa(i64, buffer);
for (const char * p = buffer; p != end; ++p)
os_->Put(*p);
return true ;
}
bool WriteUint64(uint64_t u64) {
char buffer[20 ];
char * end = internal::u64toa(u64, buffer);
for (char * p = buffer; p != end; ++p)
os_->Put(*p);
return true ;
}
bool WriteDouble(double d) {
char buffer[25 ];
char * end = internal::dtoa(d, buffer);
for (char * p = buffer; p != end; ++p)
os_->Put(*p);
return true ;
}
bool WriteString(const Ch* str, SizeType length) {
static const char hexDigits[16 ] = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' };
static const char escape[256 ] = {
#define Z16 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0
//0 1 2 3 4 5 6 7 8 9 A B C D E F
'u' , 'u' , 'u' , 'u' , 'u' , 'u' , 'u' , 'u' , 'b' , 't' , 'n' , 'u' , 'f' , 'r' , 'u' , 'u' , // 00
'u' , 'u' , 'u' , 'u' , 'u' , 'u' , 'u' , 'u' , 'u' , 'u' , 'u' , 'u' , 'u' , 'u' , 'u' , 'u' , // 10
0 , 0 , '"' , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // 20
Z16, Z16, // 30~4F
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,'\\' , 0 , 0 , 0 , // 50
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
#undef Z16
};
os_->Put('\"' );
GenericStringStream<SourceEncoding> is(str);
while (is.Tell() < length) {
const Ch c = is.Peek();
if (!TargetEncoding::supportUnicode && (unsigned )c >= 0 x80) {
// Unicode escaping
unsigned codepoint;
if (!SourceEncoding::Decode(is, &codepoint))
return false ;
os_->Put('\\' );
os_->Put('u' );
if (codepoint <= 0 xD7FF || (codepoint >= 0 xE000 && codepoint <= 0 xFFFF)) {
os_->Put(hexDigits[(codepoint >> 12 ) & 15 ]);
os_->Put(hexDigits[(codepoint >> 8 ) & 15 ]);
os_->Put(hexDigits[(codepoint >> 4 ) & 15 ]);
os_->Put(hexDigits[(codepoint ) & 15 ]);
}
else {
RAPIDJSON_ASSERT(codepoint >= 0 x010000 && codepoint <= 0 x10FFFF);
// Surrogate pair
unsigned s = codepoint - 0 x010000;
unsigned lead = (s >> 10 ) + 0 xD800;
unsigned trail = (s & 0 x3FF) + 0 xDC00;
os_->Put(hexDigits[(lead >> 12 ) & 15 ]);
os_->Put(hexDigits[(lead >> 8 ) & 15 ]);
os_->Put(hexDigits[(lead >> 4 ) & 15 ]);
os_->Put(hexDigits[(lead ) & 15 ]);
os_->Put('\\' );
os_->Put('u' );
os_->Put(hexDigits[(trail >> 12 ) & 15 ]);
os_->Put(hexDigits[(trail >> 8 ) & 15 ]);
os_->Put(hexDigits[(trail >> 4 ) & 15 ]);
os_->Put(hexDigits[(trail ) & 15 ]);
}
}
else if ((sizeof (Ch) == 1 || (unsigned )c < 256 ) && escape[(unsigned char )c]) {
is.Take();
os_->Put('\\' );
os_->Put(escape[(unsigned char )c]);
if (escape[(unsigned char )c] == 'u' ) {
os_->Put('0' );
os_->Put('0' );
os_->Put(hexDigits[(unsigned char )c >> 4 ]);
os_->Put(hexDigits[(unsigned char )c & 0 xF]);
}
}
else
if (!Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, *os_))
return false ;
}
os_->Put('\"' );
return true ;
}
bool WriteStartObject() { os_->Put('{' ); return true ; }
bool WriteEndObject() { os_->Put('}' ); return true ; }
bool WriteStartArray() { os_->Put('[' ); return true ; }
bool WriteEndArray() { os_->Put(']' ); return true ; }
void Prefix(Type type) {
(void )type;
if (level_stack_.GetSize() != 0 ) { // this value is not at root
Level* level = level_stack_.template Top<Level>();
if (level->valueCount > 0 ) {
if (level->inArray)
os_->Put(',' ); // add comma if it is not the first element in array
else // in object
os_->Put((level->valueCount % 2 == 0 ) ? ',' : ':' );
}
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(!hasRoot_); // Should only has one and only one root.
hasRoot_ = true ;
}
}
OutputStream* os_;
internal::Stack<StackAllocator> level_stack_;
bool hasRoot_;
private :
// Prohibit copy constructor & assignment operator.
Writer(const Writer&);
Writer& operator =(const Writer&);
};
// Full specialization for StringStream to prevent memory copying
template <>
inline bool Writer<StringBuffer>::WriteInt(int i) {
char *buffer = os_->Push(11 );
const char * end = internal::i32toa(i, buffer);
os_->Pop(static_cast <size_t>(11 - (end - buffer)));
return true ;
}
template <>
inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
char *buffer = os_->Push(10 );
const char * end = internal::u32toa(u, buffer);
os_->Pop(static_cast <size_t>(10 - (end - buffer)));
return true ;
}
template <>
inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
char *buffer = os_->Push(21 );
const char * end = internal::i64toa(i64, buffer);
os_->Pop(static_cast <size_t>(21 - (end - buffer)));
return true ;
}
template <>
inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
char *buffer = os_->Push(20 );
const char * end = internal::u64toa(u, buffer);
os_->Pop(static_cast <size_t>(20 - (end - buffer)));
return true ;
}
template <>
inline bool Writer<StringBuffer>::WriteDouble(double d) {
char *buffer = os_->Push(25 );
char * end = internal::dtoa(d, buffer);
os_->Pop(static_cast <size_t>(25 - (end - buffer)));
return true ;
}
RAPIDJSON_NAMESPACE_END
#ifdef _MSC_VER
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_RAPIDJSON_H_
Messung V0.5 in Prozent C=81 H=96 G=88
¤ Dauer der Verarbeitung: 0.19 Sekunden
(vorverarbeitet am 2026-06-17)
¤
*© Formatika GbR, Deutschland