ROOTANA
mjson.cxx
Go to the documentation of this file.
1 /********************************************************************\
2 
3  Name: mjson.cxx
4  Created by: Konstantin Olchanski
5 
6  Contents: JSON encoder and decoder
7 
8  The JSON parser is written to the specifications at:
9  http://www.json.org/
10  http://www.ietf.org/rfc/rfc4627.txt
11 
12 \********************************************************************/
13 
14 #undef NDEBUG // midas required assert() to be always enabled
15 
16 #include "mjson.h"
17 
18 #include <stdio.h>
19 #include <assert.h>
20 #include <math.h>
21 #include <string.h>
22 #include <limits.h>
23 #include <stdlib.h>
24 #include <cerrno>
25 
26 static const char* skip_spaces(const char* s)
27 {
28  while (1) {
29  // per RFC 4627, "Insignificant whitespace"
30  switch (*s) {
31  default: return s;
32  case ' ': s++; break;
33  case '\t': s++; break;
34  case '\n': s++; break;
35  case '\r': s++; break;
36  }
37  }
38  // NOT REACHED
39 }
40 
41 static int hexToInt(char c)
42 {
43  if (c == 0)
44  return -1;
45  if (c >= '0' && c <= '9')
46  return c-'0';
47  if (c >= 'a' && c <= 'f')
48  return c-'a'+10;
49  if (c >= 'A' && c <= 'F')
50  return c-'A'+10;
51  return -1;
52 }
53 
54 static int xparse_unicode(const char* s, const char** sout)
55 {
56  int unicode = 0;
57 
58  for (int i=0; i<4; i++) {
59  int v = hexToInt(*s);
60  if (v < 0) {
61  *sout = s;
62  return -1;
63  }
64  unicode = unicode*16 + v;
65  s++;
66  }
67 
68  *sout = s;
69  return unicode;
70 }
71 
72 static std::string xoutput_unicode(int unicode, bool* error)
73 {
74  // see http://en.wikipedia.org/wiki/UTF-8
75  if (unicode >= 0 && unicode <= 0x7F) { // 7 bits
76  char buf[2];
77  buf[0] = unicode & 0x7F;
78  buf[1] = 0;
79  return buf;
80  }
81 
82  // FIXME: does this unicode gibberish work right?
83 
84  if (unicode >= 0x80 && unicode <= 0x7FF) { // 11 bits
85  char buf[3];
86  buf[0] = 0x80|0x40|((unicode>>6)&0x1F); // 5 bits
87  buf[1] = 0x80|((unicode>>0)&0x3F); // 6 bits
88  buf[2] = 0;
89  return buf;
90  }
91 
92  if (unicode >= 0x800 && unicode <= 0xFFFF) { // 16 bits
93  char buf[4];
94  buf[0] = 0x80|0x40|0x20|((unicode>>12)&0xF); // 4 bits
95  buf[1] = 0x80|((unicode>>6)&0x3F); // 6 bits
96  buf[2] = 0x80|((unicode>>0)&0x3F); // 6 bits
97  buf[3] = 0;
98  return buf;
99  }
100 
101  *error = true;
102  return "";
103 }
104 
105 static std::string xparse_string(const char* s, const char** sout, bool *error)
106 {
107  //printf("xstring-->%s\n", s);
108 
109  std::string v;
110 
111  while (1) {
112  if (*s == 0) {
113  // error
114  *sout = s;
115  *error = true;
116  return "";
117  } else if (*s == '\"') {
118  // end of string
119  *sout = s+1;
120  return v;
121  } else if (*s == '\\') {
122  // escape sequence
123  s++;
124  //printf("escape %d (%c)\n", *s, *s);
125  switch (*s) {
126  case 0:
127  // maybe error - unexpected end of string
128  *sout = s;
129  *error = true;
130  return v;
131  default:
132  // error - unknown escape
133  *sout = s;
134  *error = true;
135  return v;
136  case '\"': v += '\"'; s++; break;
137  case '\\': v += '\\'; s++; break;
138  case '/': v += '/'; s++; break;
139  case 'b': v += '\b'; s++; break;
140  case 'f': v += '\f'; s++; break;
141  case 'n': v += '\n'; s++; break;
142  case 'r': v += '\r'; s++; break;
143  case 't': v += '\t'; s++; break;
144  case 'u': {
145  s++;
146  int unicode = xparse_unicode(s, sout);
147  //printf("unicode %d (0x%x), next %c\n", unicode, unicode, **sout);
148  if (unicode < 0) {
149  // error - bad unicode
150  *sout = s;
151  *error = true;
152  return v;
153  }
154  v += xoutput_unicode(unicode, error);
155  if (*error) {
156  // error - bad unicode
157  //*sout = s; // stay pointing at the bad unicode
158  *error = true;
159  return v;
160  }
161  s = *sout;
162  break;
163  }
164  }
165  } else {
166  v += *s;
167  s++;
168  }
169  }
170 
171  // NOT REACHED
172 }
173 
174 static MJsonNode* parse_something(const char* sin, const char* s, const char** sout);
175 
176 static MJsonNode* parse_array(const char* sin, const char* s, const char** sout)
177 {
178  //printf("array-->%s\n", s);
180 
181  s = skip_spaces(s);
182 
183  if (*s == ']') {
184  // empty array
185  *sout = s+1;
186  return n;
187  }
188 
189  while (1) {
190  s = skip_spaces(s);
191 
192  if (*s == 0) {
193  *sout = s;
194  return MJsonNode::MakeError(n, "unexpected end of string while parsing array", sin, s);
195  }
196 
197  MJsonNode *p = parse_something(sin, s, sout);
198  if (p == NULL) {
199  // sout set by parse_something()
200  return MJsonNode::MakeError(n, "cannot parse array element", sin, *sout);
201  }
202  if (p->GetType() == MJSON_ERROR) {
203  // sout set by parse_something()
204  return MJsonNode::MakeError(n, "error parsing array element", sin, *sout);
205  }
206 
207  n->AddToArray(p);
208 
209  s = skip_spaces(*sout);
210 
211  if (*s == ']') {
212  // end of array
213  *sout = s+1;
214  return n;
215  }
216 
217  if (*s == ',') {
218  s++;
219  continue;
220  }
221 
222  *sout = s;
223  return MJsonNode::MakeError(n, "unexpected char after array element, should be \',\' or \']\'", sin, s);
224  }
225 
226  // NOT REACHED
227 }
228 
229 static MJsonNode* parse_object(const char* sin, const char* s, const char** sout)
230 {
231  //printf("object-->%s\n", s);
232 
234 
235  s = skip_spaces(s);
236 
237  if (*s == '}') {
238  // empty object
239  *sout = s+1;
240  return n;
241  }
242 
243  while (1) {
244  s = skip_spaces(s);
245 
246  //printf("xobject-->%s\n", s);
247 
248  if (*s == 0) {
249  *sout = s;
250  return MJsonNode::MakeError(n, "unexpected end of string while parsing object", sin, s);
251  } else if (*s != '\"') {
252  *sout = s;
253  return MJsonNode::MakeError(n, "unexpected char while parsing object, should be \"\"\"", sin, s);
254  }
255 
256  bool error = false;
257  std::string name = xparse_string(s+1, sout, &error);
258  if (error || name.length() < 1) {
259  // sout set by parse_something()
260  return MJsonNode::MakeError(n, "cannot parse name of object element", sin, *sout);
261  }
262 
263  s = skip_spaces(*sout);
264 
265  if (*s == 0) {
266  *sout = s;
267  return MJsonNode::MakeError(n, "unexpected end of string after name of object element", sin, s);
268  } else if (*s != ':') {
269  *sout = s;
270  return MJsonNode::MakeError(n, "unexpected char after name of object element, should be \":\"", sin, s);
271  }
272 
273  MJsonNode *p = parse_something(sin, s+1, sout);
274  if (p == NULL) {
275  // sout set by parse_something()
276  return MJsonNode::MakeError(n, "cannot parse object element", sin, *sout);
277  }
278  if (p->GetType() == MJSON_ERROR) {
279  // sout set by parse_something()
280  return MJsonNode::MakeError(n, "error parsing object element", sin, *sout);
281  }
282 
283  n->AddToObject(name.c_str(), p);
284 
285  s = skip_spaces(*sout);
286 
287  //printf("xobject-->%s\n", s);
288 
289  if (*s == '}') {
290  // end of object
291  *sout = s+1;
292  return n;
293  }
294 
295  if (*s == ',') {
296  s++;
297  continue;
298  }
299 
300  // error
301  *sout = s;
302  return MJsonNode::MakeError(n, "unexpected char after object element, should be \"}\" or \",\"", sin, s);
303  }
304 
305  // NOT REACHED
306 }
307 
308 static MJsonNode* parse_string(const char* sin, const char* s, const char** sout)
309 {
310  //printf("string-->%s\n", s);
311 
312  bool error = false;
313  std::string v = xparse_string(s, sout, &error);
314 
315  if (error)
316  return MJsonNode::MakeError(NULL, "cannot parse string", sin, *sout);
317 
318  return MJsonNode::MakeString(v.c_str());
319 }
320 
321 static std::string parse_digits(const char* s, const char** sout)
322 {
323  std::string v;
324  v.reserve(32); // allocate space for a longish number
325 
326  while (*s) {
327  if (*s < '0')
328  break;
329  if (*s > '9')
330  break;
331 
332  v += *s;
333  s++;
334  }
335 
336  *sout = s;
337  return v;
338 }
339 
340 bool atoll_with_overflow(const char *str, long long& number)
341 {
342  char *end = nullptr;
343  errno = 0;
344 
345  number = std::strtoll(str, &end, 10);
346 
347  if ((number == LLONG_MAX || number == LLONG_MIN) && errno == ERANGE)
348  // iff stroll sets errno to ERANGE, an over- or underflow occurred
349  return false;
350 
351  if (end == str)
352  // if no characters were converted, the input was invalid
353  return false;
354 
355  return true;
356 }
357 
358 static void test_atoll_with_overflow_value(const char*s, long long v, bool flag)
359 {
360  long long vv;
361 
362  bool ff = atoll_with_overflow(s, vv);
363 
364  //printf("atoll test: [%s] -> %lld (0x%llx) should be %lld (0x%llx)\n", s, vv, vv, v, v);
365 
366  if (vv == v)
367  return;
368 
369  if (ff == flag)
370  return;
371 
372  printf("atoll test failed: [%s] -> %lld (0x%llx) != %lld (0x%llx)\n", s, vv, vv, v, v);
373  assert(!"mjson self test: my atoll() is broken, bye!");
374  abort();
375  // DOES NOT RETURN
376 }
377 
379 {
380  // test positive values
381  test_atoll_with_overflow_value("0", 0, true);
382  test_atoll_with_overflow_value("1", 1, true);
383  test_atoll_with_overflow_value("12", 12, true);
384  test_atoll_with_overflow_value("1234", 1234, true);
385 
386  // check overflow of 64-bit integers
387  test_atoll_with_overflow_value("9223372036854775806", 9223372036854775806, true);
388  test_atoll_with_overflow_value("9223372036854775807", 9223372036854775807, true);
389  test_atoll_with_overflow_value("9223372036854775808", 0, false);
390  test_atoll_with_overflow_value("9223372036854775809", 0, false);
391 
392  test_atoll_with_overflow_value("999999999999999999999999999999999999999999999999999999", 0, false);
393 
394  // test negative
395  test_atoll_with_overflow_value("-0", 0, true);
396  test_atoll_with_overflow_value("-1", -1, true);
397  test_atoll_with_overflow_value("-12", -12, true);
398  test_atoll_with_overflow_value("-1234", -1234, true);
399 
400  test_atoll_with_overflow_value("-9223372036854775807", 0x8000000000000000+1, true);
401  test_atoll_with_overflow_value("-9223372036854775808", 0x8000000000000000, true);
402  test_atoll_with_overflow_value("-9223372036854775809", 0, false);
403  test_atoll_with_overflow_value("-9223372036854775810", 0, false);
404 
405  test_atoll_with_overflow_value("-999999999999999999999999999999999999999999999999999999", 0, false);
406 
407  //printf("sizeof(int): %zu\n", sizeof(int));
408  //printf("sizeof(long long): %zu\n", sizeof(long long));
409 }
410 
412 {
413 public:
415  {
417  }
418 };
419 
421 
422 static MJsonNode* parse_number(const char* sin, const char* s, const char** sout)
423 {
424  //printf("number-->%s\n", s);
425 
426  // thread sanitizer complains about this. run the test
427  // function on program startup (before main()) from
428  // contructor of static object. K.O.
429  //
430  //static int once = 1;
431  //if (once) {
432  // once = 0;
433  // test_atoll_with_overflow();
434  //}
435 
436  // per RFC 4627
437  // A number contains an integer component that
438  // may be prefixed with an optional minus sign, which may be followed by
439  // a fraction part and/or an exponent part.
440  //
441  // number = [ minus ] int [ frac ] [ exp ]
442  // decimal-point = %x2E ; .
443  // digit1-9 = %x31-39 ; 1-9
444  // e = %x65 / %x45 ; e E
445  // exp = e [ minus / plus ] 1*DIGIT
446  // frac = decimal-point 1*DIGIT
447  // int = zero / ( digit1-9 *DIGIT )
448  // minus = %x2D ; -
449  // plus = %x2B ; +
450  // zero = %x30 ; 0
451 
452  int sign = 1;
453  std::string sint;
454  std::string sfrac;
455  int expsign = 1;
456  std::string sexp;
457 
458  if (*s == '-') {
459  sign = -1;
460  s++;
461  }
462 
463  if (*s == '0') {
464  sint += *s;
465  s++;
466  } else {
467  sint = parse_digits(s, sout);
468  s = *sout;
469  }
470 
471  if (*s == '.') {
472  s++;
473  sfrac = parse_digits(s, sout);
474  s = *sout;
475  }
476 
477  if (*s == 'e' || *s == 'E') {
478  s++;
479 
480  if (*s == '-') {
481  expsign = -1;
482  s++;
483  }
484 
485  if (*s == '+') {
486  expsign = +1;
487  s++;
488  }
489 
490  sexp = parse_digits(s, sout);
491  s = *sout;
492  }
493 
494  //printf("number: sign %d, sint [%s], sfrac [%s], expsign %d, sexp [%s]\n", sign, sint.c_str(), sfrac.c_str(), expsign, sexp.c_str());
495 
496  // check for floating point
497 
498  bool flag;
499  long long e;
500 
501  if (expsign < 0 || sfrac.length() > 0) {
502  // definitely floating point number
503  double v1 = atof(sint.c_str());
504  double v2 = 0;
505  double vm = 0.1;
506  const char* p = sfrac.c_str();
507  for ( ; *p != 0; p++, vm/=10.0) {
508  v2 += (*p-'0')*vm;
509  }
510 
511  flag = atoll_with_overflow(sexp.c_str(), e);
512 
513  if (flag && (e < 0 || e > 400)) {
514  // overflow or exponent will not fit into IEEE754 double precision number
515  // convert to 0 or +/- infinity
516  printf("overflow!\n");
517  if (expsign > 0) {
518  *sout = s;
519  double one = 1;
520  double zero = 0;
521  double inf = one/zero; // IEEE-754 1.0/0.0 is "+infinity", +infinity*(-1) => -infinity
522  return MJsonNode::MakeNumber(sign*inf);
523  } else {
524  *sout = s;
525  return MJsonNode::MakeNumber(sign*0.0);
526  }
527  }
528 
529  double ee = 1.0;
530  if (e != 0)
531  ee = pow(10, (double)(expsign*e));
532  double v = sign*(v1+v2)*ee;
533  //printf("v1: %f, v2: %f, e: %d, ee: %g, v: %g\n", v1, v2, e, ee, v);
534 
535  *sout = s;
536  return MJsonNode::MakeNumber(v);
537  } else {
538  // no sfrac, expsign is positive, so this is an integer, unless it overflows
539 
540  flag = atoll_with_overflow(sexp.c_str(), e); // may overflow
541 
542  if (flag && (e < 0 || e > 400)) {
543  // overflow or exponent will not fit into IEEE754 double precision number
544  // convert to +/- infinity
545  //printf("overflow!\n");
546  *sout = s;
547  double one = 1;
548  double zero = 0;
549  double inf = one/zero; // IEEE-754 1.0/0.0 is "+infinity", +infinity*(-1) => -infinity
550  return MJsonNode::MakeNumber(sign*inf);
551  }
552 
553  // this is stupid but quicker than calling pow(). Unless they feed us stupid exponents that are not really integers anyway
554  for (int ee=0; ee<e; ee++)
555  sint += "0";
556 
557  int overflow = 0;
558  long long v = 0;
559 
560  std::string sstr = sign == 1 ? sint : "-" + sint;
561 
562  flag = atoll_with_overflow(sstr.c_str(), v);
563  if (!flag)
564  overflow = 1;
565 
566  if (overflow) {
567  // overflow, convert to double
568  //printf("integer overflow: sign %d, int: [%s], frac [%s], expsign %d, exp [%s]\n", sign, sint.c_str(), sfrac.c_str(), expsign, sexp.c_str());
569 
570  double vv = atof(sint.c_str());
571  *sout = s;
572  return MJsonNode::MakeNumber(sign*vv);
573  }
574 
575  *sout = s;
576  return MJsonNode::MakeInt(v);
577  }
578 
579  /* code will never be executed
580  *sout = s;
581  return MJsonNode::MakeError(NULL, "cannot parse number", sin, s);
582  */
583 }
584 
585 static MJsonNode* parse_null(const char* sin, const char* s, const char** sout)
586 {
587  if (s[0] == 'n' && s[1] == 'u' && s[2] == 'l' && s[3] == 'l') {
588  *sout = s+4;
589  return MJsonNode::MakeNull();
590  }
591 
592  *sout = s;
593  return MJsonNode::MakeError(NULL, "cannot parse \"null\"", sin, s);
594 }
595 
596 static MJsonNode* parse_true(const char* sin, const char* s, const char** sout)
597 {
598  if (s[0] == 't' && s[1] == 'r' && s[2] == 'u' && s[3] == 'e') {
599  *sout = s+4;
600  return MJsonNode::MakeBool(true);
601  }
602 
603  *sout = s;
604  return MJsonNode::MakeError(NULL, "cannot parse \"true\"", sin, s);
605 }
606 
607 static MJsonNode* parse_false(const char* sin, const char* s, const char** sout)
608 {
609  if (s[0] == 'f' && s[1] == 'a' && s[2] == 'l' && s[3] == 's' && s[4] == 'e') {
610  *sout = s+5;
611  return MJsonNode::MakeBool(false);
612  }
613 
614  *sout = s;
615  return MJsonNode::MakeError(NULL, "cannot parse \"false\"", sin, s);
616 }
617 
618 
619 static MJsonNode* parse_something(const char* sin, const char* s, const char** sout)
620 {
621  s = skip_spaces(s);
622 
623  if (*s == '[') {
624  return parse_array(sin, s+1, sout);
625  } else if (*s == '{') {
626  return parse_object(sin, s+1, sout);
627  } else if (*s == '\"') {
628  return parse_string(sin, s+1, sout);
629  } else if (*s == '-') {
630  return parse_number(sin, s, sout);
631  } else if (*s >= '0' && *s <= '9') {
632  return parse_number(sin, s, sout);
633  } else if (*s == 'n') {
634  return parse_null(sin, s, sout);
635  } else if (*s == 't') {
636  return parse_true(sin, s, sout);
637  } else if (*s == 'f') {
638  return parse_false(sin, s, sout);
639  }
640 
641  *sout = s;
642  return MJsonNode::MakeError(NULL, "unexpected char at top level", sin, s);
643 }
644 
645 MJsonNode* MJsonNode::Parse(const char* jsonstring)
646 {
647  const char*sout;
648  return parse_something(jsonstring, jsonstring, &sout);
649 }
650 
652 {
653  for (unsigned i=0; i<subnodes.size(); i++)
654  delete subnodes[i];
655  subnodes.clear();
656 
657  if (arraybuffer_size > 0) {
658  assert(arraybuffer_ptr != NULL);
659  free(arraybuffer_ptr);
660  arraybuffer_size = 0;
661  arraybuffer_ptr = NULL;
662  }
663 
664  // poison deleted nodes
665  type = MJSON_NONE;
666 }
667 
668 static char toHexChar(int c)
669 {
670  assert(c>=0);
671  assert(c<=15);
672  if (c <= 9)
673  return '0' + c;
674  else
675  return 'A' + c - 10;
676 }
677 
678 std::string MJsonNode::Encode(const char* s)
679 {
680  std::string v;
681  while (*s) {
682  switch (*s) {
683  case '\"': v += "\\\""; s++; break;
684  case '\\': v += "\\\\"; s++; break;
685  //case '/': v += "\\/"; s++; break;
686  case '\b': v += "\\b"; s++; break;
687  case '\f': v += "\\f"; s++; break;
688  case '\n': v += "\\n"; s++; break;
689  case '\r': v += "\\r"; s++; break;
690  case '\t': v += "\\t"; s++; break;
691  default: {
692  if (iscntrl(*s)) {
693  v += "\\u";
694  v += "0";
695  v += "0";
696  v += toHexChar(((*s)>>4) & 0xF);
697  v += toHexChar(((*s)>>0) & 0xF);
698  s++;
699  break;
700  } else {
701  v += *s; s++;
702  break;
703  }
704  }
705  }
706  }
707  return v;
708 }
709 
710 std::string MJsonNode::EncodeLL(long long value)
711 {
712  char buf[256];
713  snprintf(buf, sizeof(buf), "%lld", value);
714  return buf;
715 }
716 
717 std::string MJsonNode::EncodeDouble(double numbervalue)
718 {
719  if (isfinite(numbervalue)) {
720  char buf[256];
721  snprintf(buf, sizeof(buf), "%.16e", numbervalue);
722  return buf;
723  } else if (isnan(numbervalue)) {
724  return "\"NaN\"";
725  } else if (isinf(numbervalue)) {
726  if (numbervalue > 0)
727  return "\"Infinity\"";
728  else
729  return "\"-Infinity\"";
730  } else {
731  assert(!"this cannot happen!");
732  }
733  return "";
734 }
735 
736 std::string MJsonNode::Stringify(int flags) const
737 {
738  switch (type) {
739  case MJSON_ARRAY: {
740  std::string v;
741  v += "[";
742  for (size_t i=0; i<subnodes.size(); i++) {
743  if (i > 0)
744  v += ",";
745  v += subnodes[i]->Stringify(flags);
746  }
747  v += "]";
748  return v;
749  }
750  case MJSON_OBJECT: {
751  std::string v;
752  v += "{";
753  for (size_t i=0; i<object_names.size(); i++) {
754  if (i > 0)
755  v += ",";
756  v += std::string("\"") + Encode(object_names[i].c_str()) + "\"";
757  v += ":";
758  v += subnodes[i]->Stringify(flags);
759  }
760  v += "}";
761  return v;
762  }
763  case MJSON_STRING: {
764  return std::string("\"") + Encode(string_value.c_str()) + "\"";
765  }
766  case MJSON_INT: {
767  return EncodeLL(ll_value);
768  }
769  case MJSON_NUMBER: {
770  return EncodeDouble(double_value);
771  }
772  case MJSON_BOOL:
773  if (ll_value)
774  return "true";
775  else
776  return "false";
777  case MJSON_NULL:
778  return "null";
779  case MJSON_JSON:
780  return string_value;
781  case MJSON_ARRAYBUFFER:
782  return "arraybuffer";
783  case MJSON_ERROR:
784  return std::string("json parse error: ") + string_value;
785  default:
786  assert(!"should not come here");
787  return ""; // NOT REACHED
788  }
789 }
790 
791 MJsonNode* MJsonNode::MakeError(MJsonNode* errornode, const char* errormessage, const char* sin, const char* serror)
792 {
793  MJsonNode* n = new MJsonNode(MJSON_ERROR);
794  if (errornode)
795  n->subnodes.push_back(errornode);
796  n->string_value = errormessage;
797  if (sin && serror) {
798  char msg[256];
799  char sample[32];
800  strncpy(sample, serror, 31);
801  sample[31] = 0;
802  int offset = serror-sin;
803  int lineno = 1;
804  int lineoff = 0;
805  for (const char* s = sin; s != serror; s++) {
806  if (*s == 0)
807  break;
808  if (*s == '\n') {
809  lineno++;
810  lineoff=0;
811  } else {
812  lineoff++;
813  }
814  }
815  snprintf(msg, sizeof(msg), " at char \"%c\" file offset %d, line %d position %d, around text \"%s\"", *serror, offset, lineno, lineoff, sample);
816  n->string_value += msg;
817  }
818  return n;
819 }
820 
822 {
823  return new MJsonNode(MJSON_ARRAY);
824 }
825 
827 {
828  return new MJsonNode(MJSON_OBJECT);
829 }
830 
831 MJsonNode* MJsonNode::MakeString(const char* value)
832 {
833  MJsonNode* n = new MJsonNode(MJSON_STRING);
834  n->string_value = value;
835  return n;
836 }
837 
838 MJsonNode* MJsonNode::MakeInt(long long value)
839 {
840  MJsonNode* n = new MJsonNode(MJSON_INT);
841  n->ll_value = value;
842  return n;
843 }
844 
846 {
847  MJsonNode* n = new MJsonNode(MJSON_NUMBER);
848  n->double_value = value;
849  return n;
850 }
851 
853 {
854  MJsonNode* n = new MJsonNode(MJSON_BOOL);
855  if (value)
856  n->ll_value = 1;
857  else
858  n->ll_value = 0;
859  return n;
860 }
861 
863 {
864  return new MJsonNode(MJSON_NULL);
865 }
866 
867 MJsonNode* MJsonNode::MakeJSON(const char* json)
868 {
869  MJsonNode* n = new MJsonNode(MJSON_JSON);
870  n->string_value = json;
871  return n;
872 }
873 
874 MJsonNode* MJsonNode::MakeArrayBuffer(char* ptr, size_t size)
875 {
877  n->arraybuffer_ptr = ptr;
878  n->arraybuffer_size = size;
879  return n;
880 }
881 
883 {
884  if (type == MJSON_ARRAY) {
885  subnodes.push_back(node);
886  return;
887  }
888 
889  assert(!"not an array");
890 }
891 
892 void MJsonNode::AddToObject(const char* name, MJsonNode* node) /// add node to an object
893 {
894  if (type == MJSON_OBJECT) {
895  object_names.push_back(name);
896  subnodes.push_back(node);
897  //objectvalue[name] = node;
898  return;
899  }
900 
901  assert(!"not an object");
902 }
903 
904 int MJsonNode::GetType() const /// get node type: MJSON_xxx
905 {
906  return type;
907 }
908 
910 {
911  if (type == MJSON_ARRAY || type == MJSON_NULL)
912  return &subnodes;
913  else
914  return NULL;
915 }
916 
918 {
919  if (type == MJSON_OBJECT || type == MJSON_NULL)
920  return &object_names;
921  else
922  return NULL;
923 }
924 
926 {
927  if (type == MJSON_OBJECT || type == MJSON_NULL)
928  return &subnodes;
929  else
930  return NULL;
931 }
932 
933 const MJsonNode* MJsonNode::FindObjectNode(const char* name) const
934 {
935  if (type != MJSON_OBJECT)
936  return NULL;
937  for (unsigned i=0; i<object_names.size(); i++) {
938  if (strcmp(object_names[i].c_str(), name) == 0)
939  return subnodes[i];
940  }
941  return NULL;
942 }
943 
944 void MJsonNode::DeleteObjectNode(const char* name)
945 {
946  if (type != MJSON_OBJECT)
947  return;
948  for (unsigned i=0; i<object_names.size(); i++) {
949  if (strcmp(object_names[i].c_str(), name) == 0) {
950  object_names[i] = "";
951  delete subnodes[i];
952  subnodes[i] = NULL;
953 
954  object_names.erase(object_names.begin()+i);
955  subnodes.erase(subnodes.begin()+i);
956  return;
957  }
958  }
959 }
960 
961 std::string MJsonNode::GetString() const
962 {
963  if (type == MJSON_STRING)
964  return string_value;
965  else
966  return "";
967 }
968 
969 long long MJsonNode::GetInt() const
970 {
971  if (type == MJSON_INT)
972  return ll_value;
973  else
974  return 0;
975 }
976 
977 long long MJsonNode::GetLL() const
978 {
979  if (type == MJSON_INT)
980  return ll_value;
981  else
982  return 0;
983 }
984 
985 double MJsonNode::GetDouble() const
986 {
987  if (type == MJSON_INT) {
988  return ll_value;
989  } else if (type == MJSON_NUMBER) {
990  return double_value;
991  } else if (type == MJSON_STRING) {
992  if (string_value == "NaN") {
993  double zero1 = 0;
994  double zero2 = 0;
995  return zero1/zero2; // IEEE-754 0.0/0.0 is a NaN
996  } else if (string_value == "Infinity") {
997  double zero = 0;
998  double one = 1;
999  return one/zero; // IEEE-754 1.0/0.0 is +infinity
1000  } else if (string_value == "-Infinity") {
1001  double zero = 0;
1002  double one = -1;
1003  return one/zero; // IEEE-754 -1.0/0.0 is -infinity
1004  }
1005  return 0;
1006  } else {
1007  return 0;
1008  }
1009 }
1010 
1011 bool MJsonNode::GetBool() const /// get boolean value, false if not a boolean or value is JSON "null"
1012 {
1013  if (type == MJSON_BOOL)
1014  return (ll_value != 0);
1015  else
1016  return false;
1017 }
1018 
1019 void MJsonNode::GetArrayBuffer(const char** pptr, size_t* psize) const
1020 {
1021  if (type == MJSON_ARRAYBUFFER) {
1022  if (pptr)
1023  *pptr = arraybuffer_ptr;
1024  if (psize)
1025  *psize = arraybuffer_size;
1026  } else {
1027  if (pptr)
1028  *pptr = NULL;
1029  if (psize)
1030  *psize = 0;
1031  }
1032 }
1033 
1034 std::string MJsonNode::GetError() const
1035 {
1036  if (type == MJSON_ERROR)
1037  return string_value;
1038  else
1039  return "";
1040 }
1041 
1042 MJsonNode::MJsonNode(int xtype) // default constructor
1043 {
1044  type = xtype;
1045 }
1046 
1047 const char* MJsonNode::TypeToString(int type)
1048 {
1049  switch (type) {
1050  default: return "UNKNOWN";
1051  case MJSON_ERROR: return "ERROR";
1052  case MJSON_NONE: return "NONE";
1053  case MJSON_ARRAY: return "ARRAY";
1054  case MJSON_OBJECT: return "OBJECT";
1055  case MJSON_STRING: return "STRING";
1056  case MJSON_INT: return "INT";
1057  case MJSON_NUMBER: return "NUMBER";
1058  case MJSON_BOOL: return "BOOL";
1059  case MJSON_NULL: return "NULL";
1060  case MJSON_JSON: return "JSON";
1061  case MJSON_ARRAYBUFFER: return "ARRAYBUFFER";
1062  }
1063 }
1064 
1065 static void pnest(int nest)
1066 {
1067  for (int i=0; i<nest; i++)
1068  printf(" ");
1069 }
1070 
1071 void MJsonNode::Dump(int nest) const // debug
1072 {
1073  printf("Node type %d (%s)", type, TypeToString(type));
1074  switch (type) {
1075  default: printf("\n"); break;
1076  case MJSON_STRING: printf(", value [%s]\n", string_value.c_str()); break;
1077  case MJSON_INT: printf(", value %lld\n", ll_value); break;
1078  case MJSON_NUMBER: printf(", value %g\n", double_value); break;
1079  case MJSON_BOOL: printf(", value %lld\n", ll_value); break;
1080  case MJSON_NULL: printf(", null\n"); break;
1081  case MJSON_JSON: printf(", json [%s]\n", string_value.c_str()); break;
1082  case MJSON_ARRAYBUFFER: printf(", arraybuffer size %d\n", (int)arraybuffer_size); break;
1083  case MJSON_ARRAY:
1084  printf("\n");
1085  for (size_t i=0; i<subnodes.size(); i++) {
1086  pnest(nest);
1087  printf("element %zu: ", i);
1088  subnodes[i]->Dump(nest+1);
1089  }
1090  break;
1091  case MJSON_OBJECT:
1092  printf("\n");
1093  for (size_t i=0; i<object_names.size(); i++) {
1094  pnest(nest);
1095  printf("%s: ", object_names[i].c_str());
1096  subnodes[i]->Dump(nest+1);
1097  }
1098  break;
1099  case MJSON_ERROR:
1100  printf(": %s\n", string_value.c_str());
1101  for (size_t i=0; i<subnodes.size(); i++) {
1102  pnest(nest);
1103  printf("errorelement %zu: ", i);
1104  subnodes[i]->Dump(nest+1);
1105  }
1106  break;
1107  }
1108 }
1109 
1111 {
1112  MJsonNode* n = new MJsonNode(*this);
1113  assert(n->object_names.size() == object_names.size());
1114  assert(n->subnodes.size() == subnodes.size());
1115  for (size_t i=0; i<n->subnodes.size(); i++) {
1116  n->subnodes[i] = subnodes[i]->Copy();
1117  }
1118  if (arraybuffer_size > 0) {
1120  n->arraybuffer_ptr = (char*)malloc(arraybuffer_size);
1121  assert(n->arraybuffer_ptr != NULL);
1123  } else {
1124  n->arraybuffer_size = 0;
1125  n->arraybuffer_ptr = NULL;
1126  }
1127  return n;
1128 }
1129 
1130 /* emacs
1131  * Local Variables:
1132  * tab-width: 8
1133  * c-basic-offset: 3
1134  * indent-tabs-mode: nil
1135  * End:
1136  */
std::string GetString() const
find subnode with given name, NULL if not object, NULL is name not found
Definition: mjson.cxx:961
static MJsonNode * MakeJSON(const char *json)
Definition: mjson.cxx:867
#define MJSON_STRING
Definition: mjson.h:23
void Dump(int nest=0) const
return node type as string
Definition: mjson.cxx:1071
#define MJSON_ARRAYBUFFER
Definition: mjson.h:29
static MJsonNode * MakeArray()
Definition: mjson.cxx:821
MJsonNode * Copy() const
dump the subtree to standard output
Definition: mjson.cxx:1110
const MJsonNodeVector * GetArray() const
get node type: MJSON_xxx
Definition: mjson.cxx:909
long long GetLL() const
get integer value, 0 if not an integer or value is JSON "null"
Definition: mjson.cxx:977
MJsonStringVector object_names
Definition: mjson.h:40
int GetType() const
delete a node from an object
Definition: mjson.cxx:904
void AddToArray(MJsonNode *node)
Definition: mjson.cxx:882
static MJsonNode * MakeNumber(double value)
Definition: mjson.cxx:845
static std::string Encode(const char *s)
Definition: mjson.cxx:678
#define MJSON_ERROR
Definition: mjson.h:19
#define MJSON_JSON
Definition: mjson.h:28
double double_value
Definition: mjson.h:43
std::vector< MJsonNode * > MJsonNodeVector
Definition: mjson.h:34
std::vector< std::string > MJsonStringVector
Definition: mjson.h:31
long long GetInt() const
get string value, "" if not string or value is JSON "null"
Definition: mjson.cxx:969
MJsonNode(int type)
make a copy of the json tree
Definition: mjson.cxx:1042
static MJsonNode * MakeObject()
Definition: mjson.cxx:826
void AddToObject(const char *name, MJsonNode *node)
add node to an array. the array takes ownership of this node
Definition: mjson.cxx:892
double GetDouble() const
get 64-bit long long value, 0 if not an integer or value is JSON "null"
Definition: mjson.cxx:985
int type
Definition: mjson.h:38
#define MJSON_BOOL
Definition: mjson.h:26
const MJsonNodeVector * GetObjectNodes() const
get array of object names, NULL if not object, empty array if value is JSON "null"
Definition: mjson.cxx:925
#define MJSON_OBJECT
Definition: mjson.h:22
static MJsonNode * MakeBool(bool value)
Definition: mjson.cxx:852
size_t arraybuffer_size
Definition: mjson.h:44
std::string Stringify(int flags=0) const
Definition: mjson.cxx:736
#define MJSON_ARRAY
Definition: mjson.h:21
static MJsonNode * MakeString(const char *value)
Definition: mjson.cxx:831
void DeleteObjectNode(const char *name)
add node to an object. the object takes ownership of this node
Definition: mjson.cxx:944
#define MJSON_NULL
Definition: mjson.h:27
bool GetBool() const
get number or integer value, 0 if not a number or value is JSON "null"
Definition: mjson.cxx:1011
static MJsonNode * MakeInt(long long value)
Definition: mjson.cxx:838
static std::string EncodeDouble(double v)
Definition: mjson.cxx:717
~MJsonNode()
Definition: mjson.cxx:651
void GetArrayBuffer(const char **pptr, size_t *psize) const
get boolean value, false if not a boolean or value is JSON "null"
Definition: mjson.cxx:1019
long long ll_value
Definition: mjson.h:42
std::string string_value
Definition: mjson.h:41
#define MJSON_NONE
Definition: mjson.h:20
const MJsonStringVector * GetObjectNames() const
get array value, NULL if not array, empty array if value is JSON "null"
Definition: mjson.cxx:917
char * arraybuffer_ptr
Definition: mjson.h:45
static MJsonNode * MakeError(MJsonNode *errornode, const char *errormessage, const char *sin, const char *serror)
the node takes ownership of the buffer
Definition: mjson.cxx:791
const MJsonNode * FindObjectNode(const char *name) const
get array of object subnodes, NULL if not object, empty array if value is JSON "null"
Definition: mjson.cxx:933
#define MJSON_INT
Definition: mjson.h:24
static MJsonNode * MakeArrayBuffer(char *ptr, size_t size)
Definition: mjson.cxx:874
static std::string EncodeLL(long long v)
Definition: mjson.cxx:710
static MJsonNode * MakeNull()
Definition: mjson.cxx:862
std::string GetError() const
Definition: mjson.cxx:1034
static MJsonNode * Parse(const char *jsonstring)
Definition: mjson.cxx:645
#define MJSON_NUMBER
Definition: mjson.h:25
MJsonNodeVector subnodes
Definition: mjson.h:39
static const char * TypeToString(int type)
get error message from MJSON_ERROR nodes
Definition: mjson.cxx:1047
static MJsonNode * parse_number(const char *sin, const char *s, const char **sout)
Definition: mjson.cxx:422
static char toHexChar(int c)
Definition: mjson.cxx:668
static std::string xoutput_unicode(int unicode, bool *error)
Definition: mjson.cxx:72
bool atoll_with_overflow(const char *str, long long &number)
Definition: mjson.cxx:340
static MJsonNode * parse_string(const char *sin, const char *s, const char **sout)
Definition: mjson.cxx:308
static int xparse_unicode(const char *s, const char **sout)
Definition: mjson.cxx:54
static void test_atoll_with_overflow_value(const char *s, long long v, bool flag)
Definition: mjson.cxx:358
static MJsonNode * parse_false(const char *sin, const char *s, const char **sout)
Definition: mjson.cxx:607
static MJsonNode * parse_true(const char *sin, const char *s, const char **sout)
Definition: mjson.cxx:596
static MJsonNode * parse_something(const char *sin, const char *s, const char **sout)
Definition: mjson.cxx:619
static const char * skip_spaces(const char *s)
Definition: mjson.cxx:26
static TestAtollWithOverflow runme
Definition: mjson.cxx:420
static std::string xparse_string(const char *s, const char **sout, bool *error)
Definition: mjson.cxx:105
static int hexToInt(char c)
Definition: mjson.cxx:41
static MJsonNode * parse_object(const char *sin, const char *s, const char **sout)
Definition: mjson.cxx:229
static void pnest(int nest)
Definition: mjson.cxx:1065
static std::string parse_digits(const char *s, const char **sout)
Definition: mjson.cxx:321
static MJsonNode * parse_null(const char *sin, const char *s, const char **sout)
Definition: mjson.cxx:585
static MJsonNode * parse_array(const char *sin, const char *s, const char **sout)
Definition: mjson.cxx:176
static void test_atoll_with_overflow()
Definition: mjson.cxx:378
static const int one
Definition: xxhash.cxx:179