1 #ifndef RAPIDJSON_WRITER_H_
2 #define RAPIDJSON_WRITER_H_
3 
4 #include "rapidjson.h"
5 #include "internal/stack.h"
6 #include "internal/strfunc.h"
7 #include <cstdio>	// snprintf() or _sprintf_s()
8 #include <new>		// placement new
9 
10 #ifdef _MSC_VER
11 #pragma warning(push)
12 #pragma warning(disable : 4127) // conditional expression is constant
13 #endif
14 
15 namespace rapidjson {
16 
17 //! JSON writer
18 /*! Writer implements the concept Handler.
19 	It generates JSON text by events to an output stream.
20 
21 	User may programmatically calls the functions of a writer to generate JSON text.
22 
23 	On the other side, a writer can also be passed to objects that generates events,
24 
25 	for example Reader::Parse() and Document::Accept().
26 
27 	\tparam Stream Type of ouptut stream.
28 	\tparam Encoding Encoding of both source strings and output.
29 	\implements Handler
30 */
31 template<typename Stream, typename Encoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
32 class Writer {
33 public:
34 	typedef typename Encoding::Ch Ch;
35 
36 	Writer(Stream& stream, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
stream_(stream)37 		stream_(stream), level_stack_(allocator, levelDepth * sizeof(Level)) {}
38 
39 	//@name Implementation of Handler
40 	//@{
Null()41 	Writer& Null()					{ Prefix(kNullType);   WriteNull();			return *this; }
Bool(bool b)42 	Writer& Bool(bool b)			{ Prefix(b ? kTrueType : kFalseType); WriteBool(b); return *this; }
Int(int i)43 	Writer& Int(int i)				{ Prefix(kNumberType); WriteInt(i);			return *this; }
Uint(unsigned u)44 	Writer& Uint(unsigned u)		{ Prefix(kNumberType); WriteUint(u);		return *this; }
Int64(int64_t i64)45 	Writer& Int64(int64_t i64)		{ Prefix(kNumberType); WriteInt64(i64);		return *this; }
Uint64(uint64_t u64)46 	Writer& Uint64(uint64_t u64)	{ Prefix(kNumberType); WriteUint64(u64);	return *this; }
Double(double d)47 	Writer& Double(double d)		{ Prefix(kNumberType); WriteDouble(d);		return *this; }
48 
49 	Writer& String(const Ch* str, SizeType length, bool copy = false) {
50 		(void)copy;
51 		Prefix(kStringType);
52 		WriteString(str, length);
53 		return *this;
54 	}
55 
StartObject()56 	Writer& StartObject() {
57 		Prefix(kObjectType);
58 		new (level_stack_.template Push<Level>()) Level(false);
59 		WriteStartObject();
60 		return *this;
61 	}
62 
63 	Writer& EndObject(SizeType memberCount = 0) {
64 		(void)memberCount;
65 		RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
66 		RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
67 		level_stack_.template Pop<Level>(1);
68 		WriteEndObject();
69 		return *this;
70 	}
71 
StartArray()72 	Writer& StartArray() {
73 		Prefix(kArrayType);
74 		new (level_stack_.template Push<Level>()) Level(true);
75 		WriteStartArray();
76 		return *this;
77 	}
78 
79 	Writer& EndArray(SizeType elementCount = 0) {
80 		(void)elementCount;
81 		RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
82 		RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
83 		level_stack_.template Pop<Level>(1);
84 		WriteEndArray();
85 		return *this;
86 	}
87 	//@}
88 
89 	//! Simpler but slower overload.
String(const Ch * str)90 	Writer& String(const Ch* str) { return String(str, internal::StrLen(str)); }
91 
92 protected:
93 	//! Information for each nested level
94 	struct Level {
LevelLevel95 		Level(bool inArray_) : inArray(inArray_), valueCount(0) {}
96 		bool inArray;		//!< true if in array, otherwise in object
97 		size_t valueCount;	//!< number of values in this level
98 	};
99 
100 	static const size_t kDefaultLevelDepth = 32;
101 
WriteNull()102 	void WriteNull()  {
103 		stream_.Put('n'); stream_.Put('u'); stream_.Put('l'); stream_.Put('l');
104 	}
105 
WriteBool(bool b)106 	void WriteBool(bool b)  {
107 		if (b) {
108 			stream_.Put('t'); stream_.Put('r'); stream_.Put('u'); stream_.Put('e');
109 		}
110 		else {
111 			stream_.Put('f'); stream_.Put('a'); stream_.Put('l'); stream_.Put('s'); stream_.Put('e');
112 		}
113 	}
114 
WriteInt(int i)115 	void WriteInt(int i) {
116 		if (i < 0) {
117 			stream_.Put('-');
118 			i = -i;
119 		}
120 		WriteUint((unsigned)i);
121 	}
122 
WriteUint(unsigned u)123 	void WriteUint(unsigned u) {
124 		char buffer[10];
125 		char *p = buffer;
126 		do {
127 			*p++ = (u % 10) + '0';
128 			u /= 10;
129 		} while (u > 0);
130 
131 		do {
132 			--p;
133 			stream_.Put(*p);
134 		} while (p != buffer);
135 	}
136 
WriteInt64(int64_t i64)137 	void WriteInt64(int64_t i64) {
138 		if (i64 < 0) {
139 			stream_.Put('-');
140 			i64 = -i64;
141 		}
142 		WriteUint64((uint64_t)i64);
143 	}
144 
WriteUint64(uint64_t u64)145 	void WriteUint64(uint64_t u64) {
146 		char buffer[20];
147 		char *p = buffer;
148 		do {
149 			*p++ = char(u64 % 10) + '0';
150 			u64 /= 10;
151 		} while (u64 > 0);
152 
153 		do {
154 			--p;
155 			stream_.Put(*p);
156 		} while (p != buffer);
157 	}
158 
159 	//! \todo Optimization with custom double-to-string converter.
WriteDouble(double d)160 	void WriteDouble(double d) {
161 		char buffer[100];
162 #if _MSC_VER
163 		int ret = sprintf_s(buffer, sizeof(buffer), "%g", d);
164 #else
165 		int ret = snprintf(buffer, sizeof(buffer), "%g", d);
166 #endif
167 		RAPIDJSON_ASSERT(ret >= 1);
168 		for (int i = 0; i < ret; i++)
169 			stream_.Put(buffer[i]);
170 	}
171 
WriteString(const Ch * str,SizeType length)172 	void WriteString(const Ch* str, SizeType length)  {
173 		static const char hexDigits[] = "0123456789ABCDEF";
174 		static const char escape[256] = {
175 #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
176 			//0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
177 			'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
178 			'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
179 			  0,   0, '"',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // 20
180 			Z16, Z16,																		// 30~4F
181 			  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,'\\',   0,   0,   0, // 50
182 			Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16								// 60~FF
183 #undef Z16
184 		};
185 
186 		stream_.Put('\"');
187 		for (const Ch* p = str; p != str + length; ++p) {
188 			if ((sizeof(Ch) == 1 || *p < 256) && escape[(unsigned char)*p])  {
189 				stream_.Put('\\');
190 				stream_.Put(escape[(unsigned char)*p]);
191 				if (escape[(unsigned char)*p] == 'u') {
192 					stream_.Put('0');
193 					stream_.Put('0');
194 					stream_.Put(hexDigits[(*p) >> 4]);
195 					stream_.Put(hexDigits[(*p) & 0xF]);
196 				}
197 			}
198 			else
199 				stream_.Put(*p);
200 		}
201 		stream_.Put('\"');
202 	}
203 
WriteStartObject()204 	void WriteStartObject()	{ stream_.Put('{'); }
WriteEndObject()205 	void WriteEndObject()	{ stream_.Put('}'); }
WriteStartArray()206 	void WriteStartArray()	{ stream_.Put('['); }
WriteEndArray()207 	void WriteEndArray()	{ stream_.Put(']'); }
208 
Prefix(Type type)209 	void Prefix(Type type) {
210 		(void)type;
211 		if (level_stack_.GetSize() != 0) { // this value is not at root
212 			Level* level = level_stack_.template Top<Level>();
213 			if (level->valueCount > 0) {
214 				if (level->inArray)
215 					stream_.Put(','); // add comma if it is not the first element in array
216 				else  // in object
217 					stream_.Put((level->valueCount % 2 == 0) ? ',' : ':');
218 			}
219 			if (!level->inArray && level->valueCount % 2 == 0)
220 				RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name
221 			level->valueCount++;
222 		}
223 		else
224 			RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
225 	}
226 
227 	Stream& stream_;
228 	internal::Stack<Allocator> level_stack_;
229 
230 private:
231 	// Prohibit assignment for VC C4512 warning
232 	Writer& operator=(const Writer& w);
233 };
234 
235 } // namespace rapidjson
236 
237 #ifdef _MSC_VER
238 #pragma warning(pop)
239 #endif
240 
241 #endif // RAPIDJSON_RAPIDJSON_H_
242