CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/Data/Format/JSONWriter.cpp
Views: 1401
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
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
17
JsonWriter::~JsonWriter() {
18
}
19
20
void JsonWriter::begin() {
21
str_ << "{";
22
stack_.push_back(StackEntry(DICT));
23
}
24
25
void JsonWriter::beginArray() {
26
str_ << "[";
27
stack_.push_back(StackEntry(ARRAY));
28
}
29
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
35
void JsonWriter::end() {
36
pop();
37
if (pretty_)
38
str_ << "\n";
39
}
40
41
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
52
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
60
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
68
const char *JsonWriter::comma() const {
69
if (stack_.back().first) {
70
return "";
71
} else {
72
return pretty_ ? ",\n" : ",";
73
}
74
}
75
76
const char *JsonWriter::arrayComma() const {
77
if (stack_.back().first) {
78
return pretty_ ? "\n" : "";
79
} else {
80
return pretty_ ? ", " : ",";
81
}
82
}
83
84
void JsonWriter::pushDict() {
85
str_ << arrayComma() << arrayIndent() << "{";
86
stack_.back().first = false;
87
stack_.push_back(StackEntry(DICT));
88
}
89
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
98
void JsonWriter::pushArray() {
99
str_ << arrayComma() << arrayIndent() << "[";
100
stack_.back().first = false;
101
stack_.push_back(StackEntry(ARRAY));
102
}
103
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
111
void JsonWriter::writeBool(bool value) {
112
str_ << arrayComma() << arrayIndent() << (value ? "true" : "false");
113
stack_.back().first = false;
114
}
115
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
123
void JsonWriter::writeInt(int value) {
124
str_ << arrayComma() << arrayIndent() << value;
125
stack_.back().first = false;
126
}
127
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
135
void JsonWriter::writeUint(uint32_t value) {
136
str_ << arrayComma() << arrayIndent() << value;
137
stack_.back().first = false;
138
}
139
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
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
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
167
void JsonWriter::writeString(const std::string &value) {
168
str_ << arrayComma() << arrayIndent() << "\"";
169
writeEscapedString(value);
170
str_ << "\"";
171
stack_.back().first = false;
172
}
173
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
183
void JsonWriter::writeRaw(const std::string &value) {
184
str_ << arrayComma() << arrayIndent() << value;
185
stack_.back().first = false;
186
}
187
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
196
void JsonWriter::writeNull() {
197
str_ << arrayComma() << arrayIndent() << "null";
198
stack_.back().first = false;
199
}
200
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
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
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
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
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
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
392