Bitcoin Core
32.1.0
P2P Digital Currency
Toggle main menu visibility
Loading...
Searching...
No Matches
src
univalue
lib
univalue_read.cpp
Go to the documentation of this file.
1
// Copyright 2014 BitPay Inc.
2
// Copyright (c) 2015-present The Bitcoin Core developers
3
// Distributed under the MIT software license, see the accompanying
4
// file COPYING or https://opensource.org/licenses/mit-license.php.
5
6
#include <
univalue.h
>
7
#include <
univalue_utffilter.h
>
8
9
#include <cstdint>
10
#include <cstring>
11
#include <string>
12
#include <string_view>
13
#include <utility>
14
#include <vector>
15
16
/*
17
* According to stackexchange, the original json test suite wanted
18
* to limit depth to 22. Widely-deployed PHP bails at depth 512,
19
* so we will follow PHP's lead, which should be more than sufficient
20
* (further stackexchange comments indicate depth > 32 rarely occurs).
21
*/
22
static
constexpr
size_t
MAX_JSON_DEPTH
= 512;
23
24
static
bool
json_isdigit
(
int
ch)
25
{
26
return
((ch >=
'0'
) && (ch <=
'9'
));
27
}
28
29
// convert hexadecimal string to unsigned integer
30
static
const
char
*
hatoui
(
const
char
*first,
const
char
*last,
31
unsigned
int
& out)
32
{
33
unsigned
int
result = 0;
34
for
(; first != last; ++first)
35
{
36
int
digit;
37
if
(
json_isdigit
(*first))
38
digit = *first -
'0'
;
39
40
else
if
(*first >=
'a'
&& *first <=
'f'
)
41
digit = *first -
'a'
+ 10;
42
43
else
if
(*first >=
'A'
&& *first <=
'F'
)
44
digit = *first -
'A'
+ 10;
45
46
else
47
break
;
48
49
result = 16 * result + digit;
50
}
51
out = result;
52
53
return
first;
54
}
55
56
enum
jtokentype
getJsonToken
(std::string& tokenVal,
unsigned
int
& consumed,
57
const
char
*raw,
const
char
*end)
58
{
59
tokenVal.clear();
60
consumed = 0;
61
62
const
char
*rawStart = raw;
63
64
while
(raw < end && (
json_isspace
(*raw)))
// skip whitespace
65
raw++;
66
67
if
(raw >= end)
68
return
JTOK_NONE
;
69
70
switch
(*raw) {
71
72
case
'{'
:
73
raw++;
74
consumed = (raw - rawStart);
75
return
JTOK_OBJ_OPEN
;
76
case
'}'
:
77
raw++;
78
consumed = (raw - rawStart);
79
return
JTOK_OBJ_CLOSE
;
80
case
'['
:
81
raw++;
82
consumed = (raw - rawStart);
83
return
JTOK_ARR_OPEN
;
84
case
']'
:
85
raw++;
86
consumed = (raw - rawStart);
87
return
JTOK_ARR_CLOSE
;
88
89
case
':'
:
90
raw++;
91
consumed = (raw - rawStart);
92
return
JTOK_COLON
;
93
case
','
:
94
raw++;
95
consumed = (raw - rawStart);
96
return
JTOK_COMMA
;
97
98
case
'n'
:
99
case
't'
:
100
case
'f'
:
101
if
(!strncmp(raw,
"null"
, 4)) {
102
raw += 4;
103
consumed = (raw - rawStart);
104
return
JTOK_KW_NULL
;
105
}
else
if
(!strncmp(raw,
"true"
, 4)) {
106
raw += 4;
107
consumed = (raw - rawStart);
108
return
JTOK_KW_TRUE
;
109
}
else
if
(!strncmp(raw,
"false"
, 5)) {
110
raw += 5;
111
consumed = (raw - rawStart);
112
return
JTOK_KW_FALSE
;
113
}
else
114
return
JTOK_ERR
;
115
116
case
'-'
:
117
case
'0'
:
118
case
'1'
:
119
case
'2'
:
120
case
'3'
:
121
case
'4'
:
122
case
'5'
:
123
case
'6'
:
124
case
'7'
:
125
case
'8'
:
126
case
'9'
: {
127
// part 1: int
128
std::string numStr;
129
130
const
char
*first = raw;
131
132
const
char
*firstDigit = first;
133
if
(!
json_isdigit
(*firstDigit))
134
firstDigit++;
135
if
((*firstDigit ==
'0'
) &&
json_isdigit
(firstDigit[1]))
136
return
JTOK_ERR
;
137
138
numStr += *raw;
// copy first char
139
raw++;
140
141
if
((*first ==
'-'
) && (raw < end) && (!
json_isdigit
(*raw)))
142
return
JTOK_ERR
;
143
144
while
(raw < end &&
json_isdigit
(*raw)) {
// copy digits
145
numStr += *raw;
146
raw++;
147
}
148
149
// part 2: frac
150
if
(raw < end && *raw ==
'.'
) {
151
numStr += *raw;
// copy .
152
raw++;
153
154
if
(raw >= end || !
json_isdigit
(*raw))
155
return
JTOK_ERR
;
156
while
(raw < end &&
json_isdigit
(*raw)) {
// copy digits
157
numStr += *raw;
158
raw++;
159
}
160
}
161
162
// part 3: exp
163
if
(raw < end && (*raw ==
'e'
|| *raw ==
'E'
)) {
164
numStr += *raw;
// copy E
165
raw++;
166
167
if
(raw < end && (*raw ==
'-'
|| *raw ==
'+'
)) {
// copy +/-
168
numStr += *raw;
169
raw++;
170
}
171
172
if
(raw >= end || !
json_isdigit
(*raw))
173
return
JTOK_ERR
;
174
while
(raw < end &&
json_isdigit
(*raw)) {
// copy digits
175
numStr += *raw;
176
raw++;
177
}
178
}
179
180
tokenVal = numStr;
181
consumed = (raw - rawStart);
182
return
JTOK_NUMBER
;
183
}
184
185
case
'"'
: {
186
raw++;
// skip "
187
188
std::string valStr;
189
JSONUTF8StringFilter
writer(valStr);
190
191
while
(
true
) {
192
if
(raw >= end || (
unsigned
char
)*raw < 0x20)
193
return
JTOK_ERR
;
194
195
else
if
(*raw ==
'\\'
) {
196
raw++;
// skip backslash
197
198
if
(raw >= end)
199
return
JTOK_ERR
;
200
201
switch
(*raw) {
202
case
'"'
: writer.
push_back
(
'\"'
);
break
;
203
case
'\\'
: writer.
push_back
(
'\\'
);
break
;
204
case
'/'
: writer.
push_back
(
'/'
);
break
;
205
case
'b'
: writer.
push_back
(
'\b'
);
break
;
206
case
'f'
: writer.
push_back
(
'\f'
);
break
;
207
case
'n'
: writer.
push_back
(
'\n'
);
break
;
208
case
'r'
: writer.
push_back
(
'\r'
);
break
;
209
case
't'
: writer.
push_back
(
'\t'
);
break
;
210
211
case
'u'
: {
212
unsigned
int
codepoint;
213
if
(raw + 1 + 4 >= end ||
214
hatoui
(raw + 1, raw + 1 + 4, codepoint) !=
215
raw + 1 + 4)
216
return
JTOK_ERR
;
217
writer.
push_back_u
(codepoint);
218
raw += 4;
219
break
;
220
}
221
default
:
222
return
JTOK_ERR
;
223
224
}
225
226
raw++;
// skip esc'd char
227
}
228
229
else
if
(*raw ==
'"'
) {
230
raw++;
// skip "
231
break
;
// stop scanning
232
}
233
234
else
{
235
writer.
push_back
(
static_cast<
unsigned
char
>
(*raw));
236
raw++;
237
}
238
}
239
240
if
(!writer.
finalize
())
241
return
JTOK_ERR
;
242
tokenVal = valStr;
243
consumed = (raw - rawStart);
244
return
JTOK_STRING
;
245
}
246
247
default
:
248
return
JTOK_ERR
;
249
}
250
}
251
252
enum
expect_bits
:
unsigned
{
253
EXP_OBJ_NAME
= (1U << 0),
254
EXP_COLON
= (1U << 1),
255
EXP_ARR_VALUE
= (1U << 2),
256
EXP_VALUE
= (1U << 3),
257
EXP_NOT_VALUE
= (1U << 4),
258
};
259
260
#define expect(bit) (expectMask & (EXP_##bit))
261
#define setExpect(bit) (expectMask |= EXP_##bit)
262
#define clearExpect(bit) (expectMask &= ~EXP_##bit)
263
264
bool
UniValue::read
(std::string_view json)
265
{
266
UniValue
parsed;
267
if
(!parsed.
read_impl
(json)) {
268
setNull
();
269
return
false
;
270
}
271
*
this
= std::move(parsed);
272
return
true
;
273
}
274
275
bool
UniValue::read_impl
(std::string_view str_in)
276
{
277
clear
();
278
279
uint32_t expectMask = 0;
280
std::vector<UniValue*> stack;
281
282
std::string tokenVal;
283
unsigned
int
consumed;
284
enum
jtokentype
tok =
JTOK_NONE
;
285
enum
jtokentype
last_tok =
JTOK_NONE
;
286
const
char
* raw{str_in.data()};
287
const
char
* end{raw + str_in.size()};
288
do
{
289
last_tok = tok;
290
291
tok =
getJsonToken
(tokenVal, consumed, raw, end);
292
if
(tok ==
JTOK_NONE
|| tok ==
JTOK_ERR
)
293
return
false
;
294
raw += consumed;
295
296
bool
isValueOpen = jsonTokenIsValue(tok) ||
297
tok ==
JTOK_OBJ_OPEN
|| tok ==
JTOK_ARR_OPEN
;
298
299
if
(
expect
(VALUE)) {
300
if
(!isValueOpen)
301
return
false
;
302
clearExpect
(VALUE);
303
304
}
else
if
(
expect
(ARR_VALUE)) {
305
bool
isArrValue = isValueOpen || (tok ==
JTOK_ARR_CLOSE
);
306
if
(!isArrValue)
307
return
false
;
308
309
clearExpect
(ARR_VALUE);
310
311
}
else
if
(
expect
(OBJ_NAME)) {
312
bool
isObjName = (tok ==
JTOK_OBJ_CLOSE
|| tok ==
JTOK_STRING
);
313
if
(!isObjName)
314
return
false
;
315
316
}
else
if
(
expect
(COLON)) {
317
if
(tok !=
JTOK_COLON
)
318
return
false
;
319
clearExpect
(COLON);
320
321
}
else
if
(!
expect
(COLON) && (tok ==
JTOK_COLON
)) {
322
return
false
;
323
}
324
325
if
(
expect
(NOT_VALUE)) {
326
if
(isValueOpen)
327
return
false
;
328
clearExpect
(NOT_VALUE);
329
}
330
331
switch
(tok) {
332
333
case
JTOK_OBJ_OPEN
:
334
case
JTOK_ARR_OPEN
: {
335
VType
utyp = (tok ==
JTOK_OBJ_OPEN
?
VOBJ
:
VARR
);
336
if
(!stack.size()) {
337
if
(utyp ==
VOBJ
)
338
setObject
();
339
else
340
setArray
();
341
stack.push_back(
this
);
342
}
else
{
343
UniValue
tmpVal(utyp);
344
UniValue
*top = stack.back();
345
top->
values
.push_back(tmpVal);
346
347
UniValue
*newTop = &(top->
values
.back());
348
stack.push_back(newTop);
349
}
350
351
if
(stack.size() >
MAX_JSON_DEPTH
)
352
return
false
;
353
354
if
(utyp ==
VOBJ
)
355
setExpect
(OBJ_NAME);
356
else
357
setExpect
(ARR_VALUE);
358
break
;
359
}
360
361
case
JTOK_OBJ_CLOSE
:
362
case
JTOK_ARR_CLOSE
: {
363
if
(!stack.size() || (last_tok ==
JTOK_COMMA
))
364
return
false
;
365
366
VType
utyp = (tok ==
JTOK_OBJ_CLOSE
?
VOBJ
:
VARR
);
367
UniValue
*top = stack.back();
368
if
(utyp != top->
getType
())
369
return
false
;
370
371
stack.pop_back();
372
clearExpect
(OBJ_NAME);
373
setExpect
(NOT_VALUE);
374
break
;
375
}
376
377
case
JTOK_COLON
: {
378
if
(!stack.size())
379
return
false
;
380
381
UniValue
*top = stack.back();
382
if
(top->
getType
() !=
VOBJ
)
383
return
false
;
384
385
setExpect
(VALUE);
386
break
;
387
}
388
389
case
JTOK_COMMA
: {
390
if
(!stack.size() ||
391
(last_tok ==
JTOK_COMMA
) || (last_tok ==
JTOK_ARR_OPEN
))
392
return
false
;
393
394
UniValue
*top = stack.back();
395
if
(top->
getType
() ==
VOBJ
)
396
setExpect
(OBJ_NAME);
397
else
398
setExpect
(ARR_VALUE);
399
break
;
400
}
401
402
case
JTOK_KW_NULL
:
403
case
JTOK_KW_TRUE
:
404
case
JTOK_KW_FALSE
: {
405
UniValue
tmpVal;
406
switch
(tok) {
407
case
JTOK_KW_NULL
:
408
// do nothing more
409
break
;
410
case
JTOK_KW_TRUE
:
411
tmpVal.
setBool
(
true
);
412
break
;
413
case
JTOK_KW_FALSE
:
414
tmpVal.
setBool
(
false
);
415
break
;
416
default
:
/* impossible */
break
;
417
}
418
419
if
(!stack.size()) {
420
*
this
= tmpVal;
421
break
;
422
}
423
424
UniValue
*top = stack.back();
425
top->
values
.push_back(tmpVal);
426
427
setExpect
(NOT_VALUE);
428
break
;
429
}
430
431
case
JTOK_NUMBER
: {
432
UniValue
tmpVal(
VNUM
, tokenVal);
433
if
(!stack.size()) {
434
*
this
= tmpVal;
435
break
;
436
}
437
438
UniValue
*top = stack.back();
439
top->
values
.push_back(tmpVal);
440
441
setExpect
(NOT_VALUE);
442
break
;
443
}
444
445
case
JTOK_STRING
: {
446
if
(
expect
(OBJ_NAME)) {
447
UniValue
*top = stack.back();
448
top->
keys
.push_back(tokenVal);
449
clearExpect
(OBJ_NAME);
450
setExpect
(COLON);
451
}
else
{
452
UniValue
tmpVal(
VSTR
, tokenVal);
453
if
(!stack.size()) {
454
*
this
= tmpVal;
455
break
;
456
}
457
UniValue
*top = stack.back();
458
top->
values
.push_back(tmpVal);
459
}
460
461
setExpect
(NOT_VALUE);
462
break
;
463
}
464
465
default
:
466
return
false
;
467
}
468
}
while
(!stack.empty ());
469
470
/* Check that nothing follows the initial construct (parsed above). */
471
tok =
getJsonToken
(tokenVal, consumed, raw, end);
472
if
(tok !=
JTOK_NONE
)
473
return
false
;
474
475
return
true
;
476
}
JSONUTF8StringFilter
Filter that generates and validates UTF-8, as well as collates UTF-16 surrogate pairs as specified in...
Definition
univalue_utffilter.h:14
JSONUTF8StringFilter::push_back
void push_back(unsigned char ch)
Definition
univalue_utffilter.h:21
JSONUTF8StringFilter::finalize
bool finalize()
Definition
univalue_utffilter.h:74
JSONUTF8StringFilter::push_back_u
void push_back_u(unsigned int codepoint_)
Definition
univalue_utffilter.h:49
UniValue::getType
enum VType getType() const
Definition
univalue.h:67
UniValue::VType
VType
Definition
univalue.h:24
UniValue::VOBJ
@ VOBJ
Definition
univalue.h:24
UniValue::VSTR
@ VSTR
Definition
univalue.h:24
UniValue::VARR
@ VARR
Definition
univalue.h:24
UniValue::VNUM
@ VNUM
Definition
univalue.h:24
UniValue::setArray
void setArray()
Definition
univalue.cpp:91
UniValue::clear
void clear()
Definition
univalue.cpp:17
UniValue::setNull
void setNull()
Definition
univalue.cpp:25
UniValue::read_impl
bool read_impl(std::string_view str_in)
Internal parser: May leave this value in an invalid state on failure.
Definition
univalue_read.cpp:275
UniValue::setBool
void setBool(bool val)
Definition
univalue.cpp:30
UniValue::values
std::vector< UniValue > values
Definition
univalue.h:109
UniValue::keys
std::vector< std::string > keys
Definition
univalue.h:108
UniValue::setObject
void setObject()
Definition
univalue.cpp:97
UniValue::read
bool read(std::string_view json)
Parse JSON; set value to null on failure.
Definition
univalue_read.cpp:264
UniValue::UniValue
UniValue()
Definition
univalue.h:31
univalue.h
getJsonToken
enum jtokentype getJsonToken(std::string &tokenVal, unsigned int &consumed, const char *raw, const char *end)
Definition
univalue_read.cpp:56
json_isspace
static bool json_isspace(int ch)
Definition
univalue.h:192
jtokentype
jtokentype
Definition
univalue.h:155
JTOK_OBJ_CLOSE
@ JTOK_OBJ_CLOSE
Definition
univalue.h:159
JTOK_STRING
@ JTOK_STRING
Definition
univalue.h:168
JTOK_COLON
@ JTOK_COLON
Definition
univalue.h:162
JTOK_OBJ_OPEN
@ JTOK_OBJ_OPEN
Definition
univalue.h:158
JTOK_NUMBER
@ JTOK_NUMBER
Definition
univalue.h:167
JTOK_KW_NULL
@ JTOK_KW_NULL
Definition
univalue.h:164
JTOK_COMMA
@ JTOK_COMMA
Definition
univalue.h:163
JTOK_ARR_CLOSE
@ JTOK_ARR_CLOSE
Definition
univalue.h:161
JTOK_KW_TRUE
@ JTOK_KW_TRUE
Definition
univalue.h:165
JTOK_ARR_OPEN
@ JTOK_ARR_OPEN
Definition
univalue.h:160
JTOK_KW_FALSE
@ JTOK_KW_FALSE
Definition
univalue.h:166
JTOK_ERR
@ JTOK_ERR
Definition
univalue.h:156
JTOK_NONE
@ JTOK_NONE
Definition
univalue.h:157
json_isdigit
static bool json_isdigit(int ch)
Definition
univalue_read.cpp:24
clearExpect
#define clearExpect(bit)
Definition
univalue_read.cpp:262
MAX_JSON_DEPTH
static constexpr size_t MAX_JSON_DEPTH
Definition
univalue_read.cpp:22
expect
#define expect(bit)
Definition
univalue_read.cpp:260
expect_bits
expect_bits
Definition
univalue_read.cpp:252
EXP_ARR_VALUE
@ EXP_ARR_VALUE
Definition
univalue_read.cpp:255
EXP_NOT_VALUE
@ EXP_NOT_VALUE
Definition
univalue_read.cpp:257
EXP_COLON
@ EXP_COLON
Definition
univalue_read.cpp:254
EXP_VALUE
@ EXP_VALUE
Definition
univalue_read.cpp:256
EXP_OBJ_NAME
@ EXP_OBJ_NAME
Definition
univalue_read.cpp:253
hatoui
static const char * hatoui(const char *first, const char *last, unsigned int &out)
Definition
univalue_read.cpp:30
setExpect
#define setExpect(bit)
Definition
univalue_read.cpp:261
univalue_utffilter.h
Generated on
for Bitcoin Core by
1.18.0