Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/ext/gason/gason.cpp
5669 views
1
#include "gason.h"
2
#include <stdlib.h>
3
4
#define JSON_ZONE_SIZE 4096
5
#define JSON_STACK_SIZE 32
6
7
const char *jsonStrError(int err) {
8
switch (err) {
9
#define XX(no, str) \
10
case JSON_##no: \
11
return str;
12
JSON_ERRNO_MAP(XX)
13
#undef XX
14
default:
15
return "unknown";
16
}
17
}
18
19
void *JsonAllocator::allocate(size_t size) {
20
size = (size + 7) & ~7;
21
22
if (head && head->used + size <= JSON_ZONE_SIZE) {
23
char *p = (char *)head + head->used;
24
head->used += size;
25
return p;
26
}
27
28
size_t allocSize = sizeof(Zone) + size;
29
Zone *zone = (Zone *)malloc(allocSize <= JSON_ZONE_SIZE ? JSON_ZONE_SIZE : allocSize);
30
if (zone == nullptr)
31
return nullptr;
32
zone->used = allocSize;
33
if (allocSize <= JSON_ZONE_SIZE || head == nullptr) {
34
zone->next = head;
35
head = zone;
36
} else {
37
zone->next = head->next;
38
head->next = zone;
39
}
40
return (char *)zone + sizeof(Zone);
41
}
42
43
void JsonAllocator::deallocate() {
44
while (head) {
45
Zone *next = head->next;
46
free(head);
47
head = next;
48
}
49
}
50
51
static inline bool isspace(char c) {
52
return c == ' ' || (c >= '\t' && c <= '\r');
53
}
54
55
static inline bool isdelim(char c) {
56
return c == ',' || c == ':' || c == ']' || c == '}' || isspace(c) || !c;
57
}
58
59
static inline bool isdigit(char c) {
60
return c >= '0' && c <= '9';
61
}
62
63
static inline bool isxdigit(char c) {
64
return (c >= '0' && c <= '9') || ((c & ~' ') >= 'A' && (c & ~' ') <= 'F');
65
}
66
67
static inline int char2int(char c) {
68
if (c <= '9')
69
return c - '0';
70
return (c & ~' ') - 'A' + 10;
71
}
72
73
static double string2double(char *s, char **endptr) {
74
char ch = *s;
75
if (ch == '-')
76
++s;
77
78
double result = 0;
79
while (isdigit(*s))
80
result = (result * 10) + (*s++ - '0');
81
82
if (*s == '.') {
83
++s;
84
85
double fraction = 1;
86
while (isdigit(*s)) {
87
fraction *= 0.1;
88
result += (*s++ - '0') * fraction;
89
}
90
}
91
92
if (*s == 'e' || *s == 'E') {
93
++s;
94
95
double base = 10;
96
if (*s == '+')
97
++s;
98
else if (*s == '-') {
99
++s;
100
base = 0.1;
101
}
102
103
unsigned int exponent = 0;
104
while (isdigit(*s))
105
exponent = (exponent * 10) + (*s++ - '0');
106
107
double power = 1;
108
for (; exponent; exponent >>= 1, base *= base)
109
if (exponent & 1)
110
power *= base;
111
112
result *= power;
113
}
114
115
*endptr = s;
116
return ch == '-' ? -result : result;
117
}
118
119
static inline JsonNode *insertAfter(JsonNode *tail, JsonNode *node) {
120
if (!tail)
121
return node->next = node;
122
node->next = tail->next;
123
tail->next = node;
124
return node;
125
}
126
127
static inline JsonValue listToValue(JsonTag tag, JsonNode *tail) {
128
if (tail) {
129
auto head = tail->next;
130
tail->next = nullptr;
131
return JsonValue(tag, head);
132
}
133
return JsonValue(tag, nullptr);
134
}
135
136
int jsonParse(char *s, char **endptr, JsonValue *value, JsonAllocator &allocator) {
137
JsonNode *tails[JSON_STACK_SIZE];
138
JsonTag tags[JSON_STACK_SIZE];
139
char *keys[JSON_STACK_SIZE];
140
JsonValue o;
141
int pos = -1;
142
bool separator = true;
143
JsonNode *node;
144
*endptr = s;
145
146
while (*s) {
147
while (isspace(*s)) {
148
++s;
149
if (!*s) break;
150
}
151
*endptr = s++;
152
switch (**endptr) {
153
case '-':
154
if (!isdigit(*s) && *s != '.') {
155
*endptr = s;
156
return JSON_BAD_NUMBER;
157
}
158
[[fallthrough]];
159
case '0': [[fallthrough]];
160
case '1': [[fallthrough]];
161
case '2': [[fallthrough]];
162
case '3': [[fallthrough]];
163
case '4': [[fallthrough]];
164
case '5': [[fallthrough]];
165
case '6': [[fallthrough]];
166
case '7': [[fallthrough]];
167
case '8': [[fallthrough]];
168
case '9':
169
o = JsonValue(string2double(*endptr, &s));
170
if (!isdelim(*s)) {
171
*endptr = s;
172
return JSON_BAD_NUMBER;
173
}
174
break;
175
case '"':
176
o = JsonValue(JSON_STRING, s);
177
for (char *it = s; *s; ++it, ++s) {
178
int c = *it = *s;
179
if (c == '\\') {
180
c = *++s;
181
switch (c) {
182
case '\\':
183
case '"':
184
case '/':
185
*it = c;
186
break;
187
case 'b':
188
*it = '\b';
189
break;
190
case 'f':
191
*it = '\f';
192
break;
193
case 'n':
194
*it = '\n';
195
break;
196
case 'r':
197
*it = '\r';
198
break;
199
case 't':
200
*it = '\t';
201
break;
202
case 'u':
203
c = 0;
204
for (int i = 0; i < 4; ++i) {
205
if (isxdigit(*++s)) {
206
c = c * 16 + char2int(*s);
207
} else {
208
*endptr = s;
209
return JSON_BAD_STRING;
210
}
211
}
212
if (c < 0x80) {
213
*it = c;
214
} else if (c < 0x800) {
215
*it++ = 0xC0 | (c >> 6);
216
*it = 0x80 | (c & 0x3F);
217
} else {
218
*it++ = 0xE0 | (c >> 12);
219
*it++ = 0x80 | ((c >> 6) & 0x3F);
220
*it = 0x80 | (c & 0x3F);
221
}
222
break;
223
default:
224
*endptr = s;
225
return JSON_BAD_STRING;
226
}
227
} else if ((unsigned int)c < ' ' || c == '\x7F') {
228
*endptr = s;
229
return JSON_BAD_STRING;
230
} else if (c == '"') {
231
*it = 0;
232
++s;
233
break;
234
}
235
}
236
if (!isdelim(*s)) {
237
*endptr = s;
238
return JSON_BAD_STRING;
239
}
240
break;
241
case 't':
242
if (!(s[0] == 'r' && s[1] == 'u' && s[2] == 'e' && isdelim(s[3])))
243
return JSON_BAD_IDENTIFIER;
244
o = JsonValue(JSON_TRUE);
245
s += 3;
246
break;
247
case 'f':
248
if (!(s[0] == 'a' && s[1] == 'l' && s[2] == 's' && s[3] == 'e' && isdelim(s[4])))
249
return JSON_BAD_IDENTIFIER;
250
o = JsonValue(JSON_FALSE);
251
s += 4;
252
break;
253
case 'n':
254
if (!(s[0] == 'u' && s[1] == 'l' && s[2] == 'l' && isdelim(s[3])))
255
return JSON_BAD_IDENTIFIER;
256
o = JsonValue(JSON_NULL);
257
s += 3;
258
break;
259
case ']':
260
if (pos == -1)
261
return JSON_STACK_UNDERFLOW;
262
if (tags[pos] != JSON_ARRAY)
263
return JSON_MISMATCH_BRACKET;
264
o = listToValue(JSON_ARRAY, tails[pos--]);
265
break;
266
case '}':
267
if (pos == -1)
268
return JSON_STACK_UNDERFLOW;
269
if (tags[pos] != JSON_OBJECT)
270
return JSON_MISMATCH_BRACKET;
271
if (keys[pos] != nullptr)
272
return JSON_UNEXPECTED_CHARACTER;
273
o = listToValue(JSON_OBJECT, tails[pos--]);
274
break;
275
case '[':
276
if (++pos == JSON_STACK_SIZE)
277
return JSON_STACK_OVERFLOW;
278
tails[pos] = nullptr;
279
tags[pos] = JSON_ARRAY;
280
keys[pos] = nullptr;
281
separator = true;
282
continue;
283
case '{':
284
if (++pos == JSON_STACK_SIZE)
285
return JSON_STACK_OVERFLOW;
286
tails[pos] = nullptr;
287
tags[pos] = JSON_OBJECT;
288
keys[pos] = nullptr;
289
separator = true;
290
continue;
291
case ':':
292
if (separator || keys[pos] == nullptr)
293
return JSON_UNEXPECTED_CHARACTER;
294
separator = true;
295
continue;
296
case ',':
297
if (separator || keys[pos] != nullptr)
298
return JSON_UNEXPECTED_CHARACTER;
299
separator = true;
300
continue;
301
case '\0':
302
continue;
303
default:
304
return JSON_UNEXPECTED_CHARACTER;
305
}
306
307
separator = false;
308
309
if (pos == -1) {
310
*endptr = s;
311
*value = o;
312
return JSON_OK;
313
}
314
315
if (tags[pos] == JSON_OBJECT) {
316
if (!keys[pos]) {
317
if (o.getTag() != JSON_STRING)
318
return JSON_UNQUOTED_KEY;
319
keys[pos] = o.toString();
320
continue;
321
}
322
if ((node = (JsonNode *) allocator.allocate(sizeof(JsonNode))) == nullptr)
323
return JSON_ALLOCATION_FAILURE;
324
tails[pos] = insertAfter(tails[pos], node);
325
tails[pos]->key = keys[pos];
326
keys[pos] = nullptr;
327
} else {
328
if ((node = (JsonNode *) allocator.allocate(sizeof(JsonNode) - sizeof(char *))) == nullptr)
329
return JSON_ALLOCATION_FAILURE;
330
tails[pos] = insertAfter(tails[pos], node);
331
}
332
tails[pos]->value = o;
333
}
334
return JSON_BREAKING_BAD;
335
}
336
337