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