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