Branch data Line data Source code
1 : : // Copyright 2014 BitPay Inc.
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or https://opensource.org/licenses/mit-license.php.
4 : :
5 : : #include <univalue.h>
6 : : #include <univalue_utffilter.h>
7 : :
8 : : #include <cstdint>
9 : : #include <cstdio>
10 : : #include <cstring>
11 : : #include <string>
12 : : #include <string_view>
13 : : #include <vector>
14 : :
15 : : /*
16 : : * According to stackexchange, the original json test suite wanted
17 : : * to limit depth to 22. Widely-deployed PHP bails at depth 512,
18 : : * so we will follow PHP's lead, which should be more than sufficient
19 : : * (further stackexchange comments indicate depth > 32 rarely occurs).
20 : : */
21 : : static constexpr size_t MAX_JSON_DEPTH = 512;
22 : :
23 : 30771513 : static bool json_isdigit(int ch)
24 : : {
25 : 30771513 : return ((ch >= '0') && (ch <= '9'));
26 : : }
27 : :
28 : : // convert hexadecimal string to unsigned integer
29 : 31183 : static const char *hatoui(const char *first, const char *last,
30 : : unsigned int& out)
31 : : {
32 : 31183 : unsigned int result = 0;
33 [ + + ]: 155639 : for (; first != last; ++first)
34 : : {
35 : 124561 : int digit;
36 [ + + ]: 124561 : if (json_isdigit(*first))
37 : 65013 : digit = *first - '0';
38 : :
39 [ + + ]: 59548 : else if (*first >= 'a' && *first <= 'f')
40 : 31208 : digit = *first - 'a' + 10;
41 : :
42 [ + + ]: 28340 : else if (*first >= 'A' && *first <= 'F')
43 : 28235 : digit = *first - 'A' + 10;
44 : :
45 : : else
46 : : break;
47 : :
48 : 124456 : result = 16 * result + digit;
49 : : }
50 : 31183 : out = result;
51 : :
52 : 31183 : return first;
53 : : }
54 : :
55 : 8513118 : enum jtokentype getJsonToken(std::string& tokenVal, unsigned int& consumed,
56 : : const char *raw, const char *end)
57 : : {
58 : 8513118 : tokenVal.clear();
59 : 8513118 : consumed = 0;
60 : :
61 : 8513118 : const char *rawStart = raw;
62 : :
63 [ + + + + ]: 9438919 : while (raw < end && (json_isspace(*raw))) // skip whitespace
64 : 925801 : raw++;
65 : :
66 [ + + ]: 8513118 : if (raw >= end)
67 : : return JTOK_NONE;
68 : :
69 [ + + + + : 8499912 : switch (*raw) {
+ + + + +
+ ]
70 : :
71 : 40506 : case '{':
72 : 40506 : raw++;
73 : 40506 : consumed = (raw - rawStart);
74 : 40506 : return JTOK_OBJ_OPEN;
75 : 35203 : case '}':
76 : 35203 : raw++;
77 : 35203 : consumed = (raw - rawStart);
78 : 35203 : return JTOK_OBJ_CLOSE;
79 : 197002 : case '[':
80 : 197002 : raw++;
81 : 197002 : consumed = (raw - rawStart);
82 : 197002 : return JTOK_ARR_OPEN;
83 : 179699 : case ']':
84 : 179699 : raw++;
85 : 179699 : consumed = (raw - rawStart);
86 : 179699 : return JTOK_ARR_CLOSE;
87 : :
88 : 509503 : case ':':
89 : 509503 : raw++;
90 : 509503 : consumed = (raw - rawStart);
91 : 509503 : return JTOK_COLON;
92 : 1473975 : case ',':
93 : 1473975 : raw++;
94 : 1473975 : consumed = (raw - rawStart);
95 : 1473975 : return JTOK_COMMA;
96 : :
97 : 17799 : case 'n':
98 : 17799 : case 't':
99 : 17799 : case 'f':
100 [ + + ]: 17799 : if (!strncmp(raw, "null", 4)) {
101 : 13961 : raw += 4;
102 : 13961 : consumed = (raw - rawStart);
103 : 13961 : return JTOK_KW_NULL;
104 [ + + ]: 3838 : } else if (!strncmp(raw, "true", 4)) {
105 : 1360 : raw += 4;
106 : 1360 : consumed = (raw - rawStart);
107 : 1360 : return JTOK_KW_TRUE;
108 [ + + ]: 2478 : } else if (!strncmp(raw, "false", 5)) {
109 : 2423 : raw += 5;
110 : 2423 : consumed = (raw - rawStart);
111 : 2423 : return JTOK_KW_FALSE;
112 : : } else
113 : : return JTOK_ERR;
114 : :
115 : 5397134 : case '-':
116 : 5397134 : case '0':
117 : 5397134 : case '1':
118 : 5397134 : case '2':
119 : 5397134 : case '3':
120 : 5397134 : case '4':
121 : 5397134 : case '5':
122 : 5397134 : case '6':
123 : 5397134 : case '7':
124 : 5397134 : case '8':
125 : 5397134 : case '9': {
126 : : // part 1: int
127 [ + + ]: 5397134 : std::string numStr;
128 : :
129 : 5397134 : const char *first = raw;
130 : :
131 : 5397134 : const char *firstDigit = first;
132 [ + + ]: 5397134 : if (!json_isdigit(*firstDigit))
133 : 55940 : firstDigit++;
134 [ + + + + ]: 5397134 : if ((*firstDigit == '0') && json_isdigit(firstDigit[1]))
135 : : return JTOK_ERR;
136 : :
137 [ + - ]: 5397095 : numStr += *raw; // copy first char
138 : 5397095 : raw++;
139 : :
140 [ + + + + : 5397095 : if ((*first == '-') && (raw < end) && (!json_isdigit(*raw)))
+ + ]
141 : : return JTOK_ERR;
142 : :
143 [ + + + + ]: 28457015 : while (raw < end && json_isdigit(*raw)) { // copy digits
144 [ + - ]: 23059961 : numStr += *raw;
145 : 23059961 : raw++;
146 : : }
147 : :
148 : : // part 2: frac
149 [ + + + + ]: 5397054 : if (raw < end && *raw == '.') {
150 [ + - ]: 26050 : numStr += *raw; // copy .
151 : 26050 : raw++;
152 : :
153 [ + + + + ]: 26050 : if (raw >= end || !json_isdigit(*raw))
154 : : return JTOK_ERR;
155 [ + + + + ]: 440402 : while (raw < end && json_isdigit(*raw)) { // copy digits
156 [ + - ]: 414414 : numStr += *raw;
157 : 414414 : raw++;
158 : : }
159 : : }
160 : :
161 : : // part 3: exp
162 [ + + + + : 5396992 : if (raw < end && (*raw == 'e' || *raw == 'E')) {
+ + ]
163 [ + - ]: 14090 : numStr += *raw; // copy E
164 : 14090 : raw++;
165 : :
166 [ + + + + : 14090 : if (raw < end && (*raw == '-' || *raw == '+')) { // copy +/-
+ + ]
167 [ + - ]: 7973 : numStr += *raw;
168 : 7973 : raw++;
169 : : }
170 : :
171 [ + + + + ]: 14090 : if (raw >= end || !json_isdigit(*raw))
172 : : return JTOK_ERR;
173 [ + + + + ]: 110862 : while (raw < end && json_isdigit(*raw)) { // copy digits
174 [ + - ]: 96892 : numStr += *raw;
175 : 96892 : raw++;
176 : : }
177 : : }
178 : :
179 [ + - ]: 5396872 : tokenVal = numStr;
180 : 5396872 : consumed = (raw - rawStart);
181 : 5396872 : return JTOK_NUMBER;
182 : 5397134 : }
183 : :
184 : 648498 : case '"': {
185 : 648498 : raw++; // skip "
186 : :
187 : 648498 : std::string valStr;
188 : 648498 : JSONUTF8StringFilter writer(valStr);
189 : :
190 : 78977203 : while (true) {
191 [ + + + + ]: 78977203 : if (raw >= end || (unsigned char)*raw < 0x20)
192 : : return JTOK_ERR;
193 : :
194 [ + + ]: 78976530 : else if (*raw == '\\') {
195 : 44964 : raw++; // skip backslash
196 : :
197 [ + + ]: 44964 : if (raw >= end)
198 : : return JTOK_ERR;
199 : :
200 [ + + + + : 44928 : switch (*raw) {
+ + + + +
+ ]
201 [ + - ]: 2679 : case '"': writer.push_back('\"'); break;
202 [ + - ]: 2942 : case '\\': writer.push_back('\\'); break;
203 [ + - ]: 1229 : case '/': writer.push_back('/'); break;
204 [ + - ]: 1605 : case 'b': writer.push_back('\b'); break;
205 [ + - ]: 1239 : case 'f': writer.push_back('\f'); break;
206 [ + - ]: 1288 : case 'n': writer.push_back('\n'); break;
207 [ + - ]: 1128 : case 'r': writer.push_back('\r'); break;
208 [ + - ]: 1565 : case 't': writer.push_back('\t'); break;
209 : :
210 : 31213 : case 'u': {
211 : 31213 : unsigned int codepoint;
212 [ + + + + ]: 62396 : if (raw + 1 + 4 >= end ||
213 : 31183 : hatoui(raw + 1, raw + 1 + 4, codepoint) !=
214 : : raw + 1 + 4)
215 : 135 : return JTOK_ERR;
216 [ + - ]: 31078 : writer.push_back_u(codepoint);
217 : 31078 : raw += 4;
218 : 31078 : break;
219 : : }
220 : : default:
221 : : return JTOK_ERR;
222 : :
223 : : }
224 : :
225 : 44753 : raw++; // skip esc'd char
226 : : }
227 : :
228 [ + + ]: 78931566 : else if (*raw == '"') {
229 : 647614 : raw++; // skip "
230 : 647614 : break; // stop scanning
231 : : }
232 : :
233 : : else {
234 [ + - ]: 78283952 : writer.push_back(static_cast<unsigned char>(*raw));
235 : 78283952 : raw++;
236 : : }
237 : : }
238 : :
239 [ + + + + ]: 1295228 : if (!writer.finalize())
240 : : return JTOK_ERR;
241 [ + - ]: 647435 : tokenVal = valStr;
242 : 647435 : consumed = (raw - rawStart);
243 : 647435 : return JTOK_STRING;
244 : 648498 : }
245 : :
246 : : default:
247 : : return JTOK_ERR;
248 : : }
249 : : }
250 : :
251 : : enum expect_bits : unsigned {
252 : : EXP_OBJ_NAME = (1U << 0),
253 : : EXP_COLON = (1U << 1),
254 : : EXP_ARR_VALUE = (1U << 2),
255 : : EXP_VALUE = (1U << 3),
256 : : EXP_NOT_VALUE = (1U << 4),
257 : : };
258 : :
259 : : #define expect(bit) (expectMask & (EXP_##bit))
260 : : #define setExpect(bit) (expectMask |= EXP_##bit)
261 : : #define clearExpect(bit) (expectMask &= ~EXP_##bit)
262 : :
263 : 15492 : bool UniValue::read(std::string_view str_in)
264 : : {
265 : 15492 : clear();
266 : :
267 : 15492 : uint32_t expectMask = 0;
268 : 15492 : std::vector<UniValue*> stack;
269 : :
270 : 15492 : std::string tokenVal;
271 : 15492 : unsigned int consumed;
272 : 15492 : enum jtokentype tok = JTOK_NONE;
273 : 15492 : enum jtokentype last_tok = JTOK_NONE;
274 : 15492 : const char* raw{str_in.data()};
275 : 15492 : const char* end{raw + str_in.size()};
276 : 4280648 : do {
277 : 4280648 : last_tok = tok;
278 : :
279 [ + - ]: 4280648 : tok = getJsonToken(tokenVal, consumed, raw, end);
280 [ + + ]: 4280648 : if (tok == JTOK_NONE || tok == JTOK_ERR)
281 : : return false;
282 : 4278168 : raw += consumed;
283 : :
284 [ + + ]: 4278168 : bool isValueOpen = jsonTokenIsValue(tok) ||
285 [ + + ]: 2435874 : tok == JTOK_OBJ_OPEN || tok == JTOK_ARR_OPEN;
286 : :
287 [ + + ]: 4278168 : if (expect(VALUE)) {
288 [ + + ]: 509430 : if (!isValueOpen)
289 : : return false;
290 : 509412 : clearExpect(VALUE);
291 : :
292 [ + + ]: 3768738 : } else if (expect(ARR_VALUE)) {
293 : 1197384 : bool isArrValue = isValueOpen || (tok == JTOK_ARR_CLOSE);
294 [ + + ]: 1197384 : if (!isArrValue)
295 : : return false;
296 : :
297 : 1197359 : clearExpect(ARR_VALUE);
298 : :
299 [ + + ]: 2571354 : } else if (expect(OBJ_NAME)) {
300 : 513476 : bool isObjName = (tok == JTOK_OBJ_CLOSE || tok == JTOK_STRING);
301 [ + + ]: 513476 : if (!isObjName)
302 : : return false;
303 : :
304 [ + + ]: 2057878 : } else if (expect(COLON)) {
305 [ + + ]: 509472 : if (tok != JTOK_COLON)
306 : : return false;
307 : 509445 : clearExpect(COLON);
308 : :
309 [ + + ]: 1548406 : } else if (!expect(COLON) && (tok == JTOK_COLON)) {
310 : : return false;
311 : : }
312 : :
313 [ + + ]: 4278035 : if (expect(NOT_VALUE)) {
314 [ + + ]: 2043949 : if (isValueOpen)
315 : : return false;
316 : 2043885 : clearExpect(NOT_VALUE);
317 : : }
318 : :
319 [ + + + + : 4277971 : switch (tok) {
+ + + - ]
320 : :
321 : 237478 : case JTOK_OBJ_OPEN:
322 : 237478 : case JTOK_ARR_OPEN: {
323 [ + + ]: 237478 : VType utyp = (tok == JTOK_OBJ_OPEN ? VOBJ : VARR);
324 [ - + + + ]: 237478 : if (!stack.size()) {
325 [ + + ]: 8484 : if (utyp == VOBJ)
326 [ + - ]: 2516 : setObject();
327 : : else
328 [ + - ]: 5968 : setArray();
329 [ + - ]: 8484 : stack.push_back(this);
330 : : } else {
331 : 228994 : UniValue tmpVal(utyp);
332 : 228994 : UniValue *top = stack.back();
333 [ + - ]: 228994 : top->values.push_back(tmpVal);
334 : :
335 : 228994 : UniValue *newTop = &(top->values.back());
336 [ + - ]: 228994 : stack.push_back(newTop);
337 : 228994 : }
338 : :
339 [ - + + + ]: 237478 : if (stack.size() > MAX_JSON_DEPTH)
340 : : return false;
341 : :
342 [ + + ]: 237473 : if (utyp == VOBJ)
343 : 40493 : setExpect(OBJ_NAME);
344 : : else
345 : 196980 : setExpect(ARR_VALUE);
346 : : break;
347 : : }
348 : :
349 : 214870 : case JTOK_OBJ_CLOSE:
350 : 214870 : case JTOK_ARR_CLOSE: {
351 [ - + + + : 214870 : if (!stack.size() || (last_tok == JTOK_COMMA))
+ + ]
352 : : return false;
353 : :
354 [ + + ]: 214837 : VType utyp = (tok == JTOK_OBJ_CLOSE ? VOBJ : VARR);
355 : 214837 : UniValue *top = stack.back();
356 [ + + ]: 214837 : if (utyp != top->getType())
357 : : return false;
358 : :
359 : 214823 : stack.pop_back();
360 : 214823 : clearExpect(OBJ_NAME);
361 : 214823 : setExpect(NOT_VALUE);
362 : 214823 : break;
363 : : }
364 : :
365 : 509445 : case JTOK_COLON: {
366 [ - + + - ]: 509445 : if (!stack.size())
367 : : return false;
368 : :
369 : 509445 : UniValue *top = stack.back();
370 [ + - ]: 509445 : if (top->getType() != VOBJ)
371 : : return false;
372 : :
373 : 509445 : setExpect(VALUE);
374 : 509445 : break;
375 : : }
376 : :
377 : 1473954 : case JTOK_COMMA: {
378 [ - + ]: 1473954 : if (!stack.size() ||
379 [ + + + - ]: 1473954 : (last_tok == JTOK_COMMA) || (last_tok == JTOK_ARR_OPEN))
380 : : return false;
381 : :
382 : 1473932 : UniValue *top = stack.back();
383 [ + + ]: 1473932 : if (top->getType() == VOBJ)
384 : 473144 : setExpect(OBJ_NAME);
385 : : else
386 : 1000788 : setExpect(ARR_VALUE);
387 : : break;
388 : : }
389 : :
390 : 17742 : case JTOK_KW_NULL:
391 : 17742 : case JTOK_KW_TRUE:
392 : 17742 : case JTOK_KW_FALSE: {
393 [ + + + ]: 17742 : UniValue tmpVal;
394 [ + + + ]: 17742 : switch (tok) {
395 : : case JTOK_KW_NULL:
396 : : // do nothing more
397 : : break;
398 : 1359 : case JTOK_KW_TRUE:
399 [ + - ]: 1359 : tmpVal.setBool(true);
400 : : break;
401 : 2423 : case JTOK_KW_FALSE:
402 [ + - ]: 2423 : tmpVal.setBool(false);
403 : : break;
404 : : default: /* impossible */ break;
405 : : }
406 : :
407 [ - + + + ]: 17742 : if (!stack.size()) {
408 [ + - ]: 435 : *this = tmpVal;
409 : : break;
410 : : }
411 : :
412 : 17307 : UniValue *top = stack.back();
413 [ + - ]: 17307 : top->values.push_back(tmpVal);
414 : :
415 : 17307 : setExpect(NOT_VALUE);
416 : 17307 : break;
417 : 17742 : }
418 : :
419 : 1177069 : case JTOK_NUMBER: {
420 [ - + ]: 2354138 : UniValue tmpVal(VNUM, tokenVal);
421 [ - + + + ]: 1177069 : if (!stack.size()) {
422 [ + - ]: 1807 : *this = tmpVal;
423 : : break;
424 : : }
425 : :
426 : 1175262 : UniValue *top = stack.back();
427 [ + - ]: 1175262 : top->values.push_back(tmpVal);
428 : :
429 : 1175262 : setExpect(NOT_VALUE);
430 : 1175262 : break;
431 : 1177069 : }
432 : :
433 : 647413 : case JTOK_STRING: {
434 [ + + ]: 647413 : if (expect(OBJ_NAME)) {
435 : 509508 : UniValue *top = stack.back();
436 [ + - ]: 509508 : top->keys.push_back(tokenVal);
437 : 509508 : clearExpect(OBJ_NAME);
438 : 509508 : setExpect(COLON);
439 : : } else {
440 [ - + ]: 275810 : UniValue tmpVal(VSTR, tokenVal);
441 [ - + + + ]: 137905 : if (!stack.size()) {
442 [ + - ]: 3093 : *this = tmpVal;
443 : 3093 : break;
444 : : }
445 : 134812 : UniValue *top = stack.back();
446 [ + - ]: 134812 : top->values.push_back(tmpVal);
447 : 137905 : }
448 : :
449 : 644320 : setExpect(NOT_VALUE);
450 : 644320 : break;
451 : : }
452 : :
453 : : default:
454 : : return false;
455 : : }
456 [ + + ]: 4277897 : } while (!stack.empty ());
457 : :
458 : : /* Check that nothing follows the initial construct (parsed above). */
459 [ + - ]: 12741 : tok = getJsonToken(tokenVal, consumed, raw, end);
460 [ + + ]: 12741 : if (tok != JTOK_NONE)
461 : 167 : return false;
462 : :
463 : : return true;
464 : 15492 : }
465 : :
|