#ifndef RAPIDJSON_WRITER_H_
#define RAPIDJSON_WRITER_H_
#include "rapidjson.h"
#include "internal/stack.h"
#include "internal/strfunc.h"
#include <cstdio> // snprintf() or _sprintf_s()
#include <new> // placement new
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4127) // conditional expression is constant
#endif
namespace
rapidjson {
template
<
typename
Stream,
typename
Encoding = UTF8<>,
typename
Allocator = MemoryPoolAllocator<> >
class
Writer {
public
:
typedef
typename
Encoding::Ch Ch;
Writer(Stream& stream, Allocator* allocator = 0,
size_t
levelDepth = kDefaultLevelDepth) :
stream_(stream), level_stack_(allocator, levelDepth *
sizeof
(Level)) {}
Writer& Null() { Prefix(kNullType); WriteNull();
return
*
this
; }
Writer& Bool(
bool
b) { Prefix(b ? kTrueType : kFalseType); WriteBool(b);
return
*
this
; }
Writer& Int(
int
i) { Prefix(kNumberType); WriteInt(i);
return
*
this
; }
Writer& Uint(unsigned u) { Prefix(kNumberType); WriteUint(u);
return
*
this
; }
Writer& Int64(int64_t i64) { Prefix(kNumberType); WriteInt64(i64);
return
*
this
; }
Writer& Uint64(uint64_t u64) { Prefix(kNumberType); WriteUint64(u64);
return
*
this
; }
Writer& Double(
double
d) { Prefix(kNumberType); WriteDouble(d);
return
*
this
; }
Writer& String(
const
Ch* str, SizeType length,
bool
copy =
false
) {
(
void
)copy;
Prefix(kStringType);
WriteString(str, length);
return
*
this
;
}
Writer& StartObject() {
Prefix(kObjectType);
new
(level_stack_.
template
Push<Level>()) Level(
false
);
WriteStartObject();
return
*
this
;
}
Writer& 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);
WriteEndObject();
return
*
this
;
}
Writer& StartArray() {
Prefix(kArrayType);
new
(level_stack_.
template
Push<Level>()) Level(
true
);
WriteStartArray();
return
*
this
;
}
Writer& 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);
WriteEndArray();
return
*
this
;
}
Writer& String(
const
Ch* str) {
return
String(str, internal::StrLen(str)); }
protected
:
struct
Level {
Level(
bool
inArray_) : inArray(inArray_), valueCount(0) {}
bool
inArray;
size_t
valueCount;
};
static
const
size_t
kDefaultLevelDepth = 32;
void
WriteNull() {
stream_.Put(
'n'
); stream_.Put(
'u'
); stream_.Put(
'l'
); stream_.Put(
'l'
);
}
void
WriteBool(
bool
b) {
if
(b) {
stream_.Put(
't'
); stream_.Put(
'r'
); stream_.Put(
'u'
); stream_.Put(
'e'
);
}
else
{
stream_.Put(
'f'
); stream_.Put(
'a'
); stream_.Put(
'l'
); stream_.Put(
's'
); stream_.Put(
'e'
);
}
}
void
WriteInt(
int
i) {
if
(i < 0) {
stream_.Put(
'-'
);
i = -i;
}
WriteUint((unsigned)i);
}
void
WriteUint(unsigned u) {
char
buffer[10];
char
*p = buffer;
do
{
*p++ = (u % 10) +
'0'
;
u /= 10;
}
while
(u > 0);
do
{
--p;
stream_.Put(*p);
}
while
(p != buffer);
}
void
WriteInt64(int64_t i64) {
if
(i64 < 0) {
stream_.Put(
'-'
);
i64 = -i64;
}
WriteUint64((uint64_t)i64);
}
void
WriteUint64(uint64_t u64) {
char
buffer[20];
char
*p = buffer;
do
{
*p++ =
char
(u64 % 10) +
'0'
;
u64 /= 10;
}
while
(u64 > 0);
do
{
--p;
stream_.Put(*p);
}
while
(p != buffer);
}
void
WriteDouble(
double
d) {
char
buffer[100];
#if _MSC_VER
int
ret = sprintf_s(buffer,
sizeof
(buffer),
"%g"
, d);
#else
int
ret = snprintf(buffer,
sizeof
(buffer),
"%g"
, d);
#endif
RAPIDJSON_ASSERT(ret >= 1);
for
(
int
i = 0; i < ret; i++)
stream_.Put(buffer[i]);
}
void
WriteString(
const
Ch* str, SizeType length) {
static
const
char
hexDigits[] =
"0123456789ABCDEF"
;
static
const
char
escape[256] = {
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'b'
,
't'
,
'n'
,
'u'
,
'f'
,
'r'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
'u'
,
0, 0,
'"'
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Z16, Z16,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
'\\'
, 0, 0, 0,
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
#undef Z16
};
stream_.Put(
'\"'
);
for
(
const
Ch* p = str; p != str + length; ++p) {
if
((
sizeof
(Ch) == 1 || *p < 256) && escape[(unsigned
char
)*p]) {
stream_.Put(
'\\'
);
stream_.Put(escape[(unsigned
char
)*p]);
if
(escape[(unsigned
char
)*p] ==
'u'
) {
stream_.Put(
'0'
);
stream_.Put(
'0'
);
stream_.Put(hexDigits[(*p) >> 4]);
stream_.Put(hexDigits[(*p) & 0xF]);
}
}
else
stream_.Put(*p);
}
stream_.Put(
'\"'
);
}
void
WriteStartObject() { stream_.Put(
'{'
); }
void
WriteEndObject() { stream_.Put(
'}'
); }
void
WriteStartArray() { stream_.Put(
'['
); }
void
WriteEndArray() { stream_.Put(
']'
); }
void
Prefix(Type type) {
(
void
)type;
if
(level_stack_.GetSize() != 0) {
Level* level = level_stack_.
template
Top<Level>();
if
(level->valueCount > 0) {
if
(level->inArray)
stream_.Put(
','
);
else
stream_.Put((level->valueCount % 2 == 0) ?
','
:
':'
);
}
if
(!level->inArray && level->valueCount % 2 == 0)
RAPIDJSON_ASSERT(type == kStringType);
level->valueCount++;
}
else
RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
}
Stream& stream_;
internal::Stack<Allocator> level_stack_;
private
:
Writer& operator=(
const
Writer& w);
};
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // RAPIDJSON_RAPIDJSON_H_