1 #include <iomanip>
2 #include <cmath>
3 #include <cstring>
4 
5 #include "Common/Data/Format/JSONReader.h"
6 #include "Common/Data/Format/JSONWriter.h"
7 
8 namespace json {
9 
JsonWriter(int flags)10 JsonWriter::JsonWriter(int flags) {
11 	pretty_ = (flags & PRETTY) != 0;
12 	str_.imbue(std::locale::classic());
13 	// Let's maximize precision by default.
14 	str_.precision(53);
15 }
16 
~JsonWriter()17 JsonWriter::~JsonWriter() {
18 }
19 
begin()20 void JsonWriter::begin() {
21 	str_ << "{";
22 	stack_.push_back(StackEntry(DICT));
23 }
24 
beginArray()25 void JsonWriter::beginArray() {
26 	str_ << "[";
27 	stack_.push_back(StackEntry(ARRAY));
28 }
29 
beginRaw()30 void JsonWriter::beginRaw() {
31 	// For the uncommon case of writing a value directly, to avoid duplicated code.
32 	stack_.push_back(StackEntry(RAW));
33 }
34 
end()35 void JsonWriter::end() {
36 	pop();
37 	if (pretty_)
38 		str_ << "\n";
39 }
40 
indent(int n) const41 const char *JsonWriter::indent(int n) const {
42 	if (!pretty_)
43 		return "";
44 	static const char * const whitespace = "                                ";
45 	if (n > 32) {
46 		// Avoid crash.
47 		return whitespace;
48 	}
49 	return whitespace + (32 - n);
50 }
51 
indent() const52 const char *JsonWriter::indent() const {
53 	if (!pretty_)
54 		return "";
55 	int amount = (int)stack_.size() + 1;
56 	amount *= 2;	// 2-space indent.
57 	return indent(amount);
58 }
59 
arrayIndent() const60 const char *JsonWriter::arrayIndent() const {
61 	if (!pretty_)
62 		return "";
63 	int amount = (int)stack_.size() + 1;
64 	amount *= 2;	// 2-space indent.
65 	return stack_.back().first ? indent(amount) : "";
66 }
67 
comma() const68 const char *JsonWriter::comma() const {
69 	if (stack_.back().first) {
70 		return "";
71 	} else {
72 		return pretty_ ? ",\n" : ",";
73 	}
74 }
75 
arrayComma() const76 const char *JsonWriter::arrayComma() const {
77 	if (stack_.back().first) {
78 		return pretty_ ? "\n" : "";
79 	} else {
80 		return pretty_ ? ", " : ",";
81 	}
82 }
83 
pushDict()84 void JsonWriter::pushDict() {
85 	str_ << arrayComma() << arrayIndent() << "{";
86 	stack_.back().first = false;
87 	stack_.push_back(StackEntry(DICT));
88 }
89 
pushDict(const std::string & name)90 void JsonWriter::pushDict(const std::string &name) {
91 	str_ << comma() << indent() << "\"";
92 	writeEscapedString(name);
93 	str_ << (pretty_ ? "\": {" : "\":{");
94 	stack_.back().first = false;
95 	stack_.push_back(StackEntry(DICT));
96 }
97 
pushArray()98 void JsonWriter::pushArray() {
99 	str_ << arrayComma() << arrayIndent() << "[";
100 	stack_.back().first = false;
101 	stack_.push_back(StackEntry(ARRAY));
102 }
103 
pushArray(const std::string & name)104 void JsonWriter::pushArray(const std::string &name) {
105 	str_ << comma() << indent() << "\"";
106 	writeEscapedString(name);
107 	str_ << (pretty_ ? "\": [" : "\":[");
108 	stack_.push_back(StackEntry(ARRAY));
109 }
110 
writeBool(bool value)111 void JsonWriter::writeBool(bool value) {
112 	str_ << arrayComma() << arrayIndent() << (value ? "true" : "false");
113 	stack_.back().first = false;
114 }
115 
writeBool(const std::string & name,bool value)116 void JsonWriter::writeBool(const std::string &name, bool value) {
117 	str_ << comma() << indent() << "\"";
118 	writeEscapedString(name);
119 	str_ << (pretty_ ? "\": " : "\":") << (value ? "true" : "false");
120 	stack_.back().first = false;
121 }
122 
writeInt(int value)123 void JsonWriter::writeInt(int value) {
124 	str_ << arrayComma() << arrayIndent() << value;
125 	stack_.back().first = false;
126 }
127 
writeInt(const std::string & name,int value)128 void JsonWriter::writeInt(const std::string &name, int value) {
129 	str_ << comma() << indent() << "\"";
130 	writeEscapedString(name);
131 	str_ << (pretty_ ? "\": " : "\":") << value;
132 	stack_.back().first = false;
133 }
134 
writeUint(uint32_t value)135 void JsonWriter::writeUint(uint32_t value) {
136 	str_ << arrayComma() << arrayIndent() << value;
137 	stack_.back().first = false;
138 }
139 
writeUint(const std::string & name,uint32_t value)140 void JsonWriter::writeUint(const std::string &name, uint32_t value) {
141 	str_ << comma() << indent() << "\"";
142 	writeEscapedString(name);
143 	str_ << (pretty_ ? "\": " : "\":") << value;
144 	stack_.back().first = false;
145 }
146 
writeFloat(double value)147 void JsonWriter::writeFloat(double value) {
148 	str_ << arrayComma() << arrayIndent();
149 	if (std::isfinite(value))
150 		str_ << value;
151 	else
152 		str_ << "null";
153 	stack_.back().first = false;
154 }
155 
writeFloat(const std::string & name,double value)156 void JsonWriter::writeFloat(const std::string &name, double value) {
157 	str_ << comma() << indent() << "\"";
158 	writeEscapedString(name);
159 	str_ << (pretty_ ? "\": " : "\":");
160 	if (std::isfinite(value))
161 		str_ << value;
162 	else
163 		str_ << "null";
164 	stack_.back().first = false;
165 }
166 
writeString(const std::string & value)167 void JsonWriter::writeString(const std::string &value) {
168 	str_ << arrayComma() << arrayIndent() << "\"";
169 	writeEscapedString(value);
170 	str_ << "\"";
171 	stack_.back().first = false;
172 }
173 
writeString(const std::string & name,const std::string & value)174 void JsonWriter::writeString(const std::string &name, const std::string &value) {
175 	str_ << comma() << indent() << "\"";
176 	writeEscapedString(name);
177 	str_ << (pretty_ ? "\": \"" : "\":\"");
178 	writeEscapedString(value);
179 	str_ << "\"";
180 	stack_.back().first = false;
181 }
182 
writeRaw(const std::string & value)183 void JsonWriter::writeRaw(const std::string &value) {
184 	str_ << arrayComma() << arrayIndent() << value;
185 	stack_.back().first = false;
186 }
187 
writeRaw(const std::string & name,const std::string & value)188 void JsonWriter::writeRaw(const std::string &name, const std::string &value) {
189 	str_ << comma() << indent() << "\"";
190 	writeEscapedString(name);
191 	str_ << (pretty_ ? "\": " : "\":");
192 	str_ << value;
193 	stack_.back().first = false;
194 }
195 
writeNull()196 void JsonWriter::writeNull() {
197 	str_ << arrayComma() << arrayIndent() << "null";
198 	stack_.back().first = false;
199 }
200 
writeNull(const std::string & name)201 void JsonWriter::writeNull(const std::string &name) {
202 	str_ << comma() << indent() << "\"";
203 	writeEscapedString(name);
204 	str_ << (pretty_ ? "\": " : "\":") << "null";
205 	stack_.back().first = false;
206 }
207 
pop()208 void JsonWriter::pop() {
209 	BlockType type = stack_.back().type;
210 	stack_.pop_back();
211 	if (pretty_)
212 		str_ << "\n" << indent();
213 	switch (type) {
214 	case ARRAY:
215 		str_ << "]";
216 		break;
217 	case DICT:
218 		str_ << "}";
219 		break;
220 	case RAW:
221 		break;
222 	}
223 	if (stack_.size() > 0)
224 		stack_.back().first = false;
225 }
226 
writeEscapedString(const std::string & str)227 void JsonWriter::writeEscapedString(const std::string &str) {
228 	size_t pos = 0;
229 	const size_t len = str.size();
230 
231 	auto update = [&](size_t current, size_t skip = 0) {
232 		size_t end = current;
233 		if (pos < end)
234 			str_ << str.substr(pos, end - pos);
235 		pos = end + skip;
236 	};
237 
238 	for (size_t i = 0; i < len; ++i) {
239 		switch (str[i]) {
240 		case '\\':
241 		case '"':
242 		case '/':
243 			update(i);
244 			str_ << '\\';
245 			break;
246 
247 		case '\r':
248 			update(i, 1);
249 			str_ << "\\r";
250 			break;
251 			break;
252 
253 		case '\n':
254 			update(i, 1);
255 			str_ << "\\n";
256 			break;
257 			break;
258 
259 		case '\t':
260 			update(i, 1);
261 			str_ << "\\t";
262 			break;
263 
264 		case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 11:
265 		case 12: case 14: case 15: case 16: case 17: case 18: case 19: case 20:
266 		case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28:
267 		case 29: case 30: case 31:
268 			update(i, 1);
269 			str_ << "\\u" << std::hex << std::setw(4) << std::setfill('0') << (int)str[i] << std::dec << std::setw(0);
270 			break;
271 
272 		default:
273 			break;
274 		}
275 	}
276 
277 	if (pos != 0) {
278 		update(len);
279 	} else {
280 		str_ << str;
281 	}
282 }
283 
284 static void json_stringify_object(JsonWriter &writer, const JsonNode *node);
285 static void json_stringify_array(JsonWriter &writer, const JsonNode *node);
286 
json_stringify(const JsonNode * node)287 std::string json_stringify(const JsonNode *node) {
288 	JsonWriter writer;
289 
290 	// Handle direct values too, not just objects.
291 	switch (node->value.getTag()) {
292 	case JSON_NULL:
293 	case JSON_STRING:
294 	case JSON_NUMBER:
295 	case JSON_TRUE:
296 	case JSON_FALSE:
297 		writer.beginRaw();
298 		// It's the same as a one entry array without brackets, so reuse.
299 		json_stringify_array(writer, node);
300 		break;
301 
302 	case JSON_OBJECT:
303 		writer.begin();
304 		for (const JsonNode *it : node->value) {
305 			json_stringify_object(writer, it);
306 		}
307 		break;
308 	case JSON_ARRAY:
309 		writer.beginArray();
310 		for (const JsonNode *it : node->value) {
311 			json_stringify_array(writer, it);
312 		}
313 		break;
314 	}
315 
316 	writer.end();
317 	return writer.str();
318 }
319 
json_stringify_object(JsonWriter & writer,const JsonNode * node)320 static void json_stringify_object(JsonWriter &writer, const JsonNode *node) {
321 	switch (node->value.getTag()) {
322 	case JSON_NULL:
323 		writer.writeNull(node->key);
324 		break;
325 	case JSON_STRING:
326 		writer.writeString(node->key, node->value.toString());
327 		break;
328 	case JSON_NUMBER:
329 		writer.writeFloat(node->key, node->value.toNumber());
330 		break;
331 	case JSON_TRUE:
332 		writer.writeBool(node->key, true);
333 		break;
334 	case JSON_FALSE:
335 		writer.writeBool(node->key, false);
336 		break;
337 
338 	case JSON_OBJECT:
339 		writer.pushDict(node->key);
340 		for (const JsonNode *it : node->value) {
341 			json_stringify_object(writer, it);
342 		}
343 		writer.pop();
344 		break;
345 	case JSON_ARRAY:
346 		writer.pushArray(node->key);
347 		for (const JsonNode *it : node->value) {
348 			json_stringify_array(writer, it);
349 		}
350 		writer.pop();
351 		break;
352 	}
353 }
354 
json_stringify_array(JsonWriter & writer,const JsonNode * node)355 static void json_stringify_array(JsonWriter &writer, const JsonNode *node) {
356 	switch (node->value.getTag()) {
357 	case JSON_NULL:
358 		writer.writeRaw("null");
359 		break;
360 	case JSON_STRING:
361 		writer.writeString(node->value.toString());
362 		break;
363 	case JSON_NUMBER:
364 		writer.writeFloat(node->value.toNumber());
365 		break;
366 	case JSON_TRUE:
367 		writer.writeBool(true);
368 		break;
369 	case JSON_FALSE:
370 		writer.writeBool(false);
371 		break;
372 
373 	case JSON_OBJECT:
374 		writer.pushDict();
375 		for (const JsonNode *it : node->value) {
376 			json_stringify_object(writer, it);
377 		}
378 		writer.pop();
379 		break;
380 	case JSON_ARRAY:
381 		writer.pushArray();
382 		for (const JsonNode *it : node->value) {
383 			json_stringify_array(writer, it);
384 		}
385 		writer.pop();
386 		break;
387 	}
388 }
389 
390 }  // namespace json
391