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 
25 static const char* skip_spaces(const char* s)
26 {
27  while (1) {
28  // per RFC 4627, "Insignificant whitespace"
29  switch (*s) {
30  default: return s;
31  case ' ': s++; break;
32  case '\t': s++; break;
33  case '\n': s++; break;
34  case '\r': s++; break;
35  }
36  }
37  // NOT REACHED
38 }
39 
40 static int hexToInt(char c)
41 {
42  if (c == 0)
43  return -1;
44  if (c >= '0' && c <= '9')
45  return c-'0';
46  if (c >= 'a' && c <= 'f')
47  return c-'a'+10;
48  if (c >= 'A' && c <= 'F')
49  return c-'A'+10;
50  return -1;
51 }
52 
53 static int xparse_unicode(const char* s, const char** sout)
54 {
55  int unicode = 0;
56 
57  for (int i=0; i<4; i++) {
58  int v = hexToInt(*s);
59  if (v < 0) {
60  *sout = s;
61  return -1;
62  }
63  unicode = unicode*16 + v;
64  s++;
65  }
66 
67  *sout = s;
68  return unicode;
69 }
70 
71 static std::string xoutput_unicode(int unicode, bool* error)
72 {
73  // see http://en.wikipedia.org/wiki/UTF-8
74  if (unicode >= 0 && unicode <= 0x7F) { // 7 bits
75  char buf[2];
76  buf[0] = unicode & 0x7F;
77  buf[1] = 0;
78  return buf;
79  }
80 
81  // FIXME: does this unicode gibberish work right?
82 
83  if (unicode >= 0x80 && unicode <= 0x7FF) { // 11 bits
84  char buf[3];
85  buf[0] = 0x80|0x40|((unicode>>6)&0x1F); // 5 bits
86  buf[1] = 0x80|((unicode>>0)&0x3F); // 6 bits
87  buf[2] = 0;
88  return buf;
89  }
90 
91  if (unicode >= 0x800 && unicode <= 0xFFFF) { // 16 bits
92  char buf[4];
93  buf[0] = 0x80|0x40|0x20|((unicode>>12)&0xF); // 4 bits
94  buf[1] = 0x80|((unicode>>6)&0x3F); // 6 bits
95  buf[2] = 0x80|((unicode>>0)&0x3F); // 6 bits
96  buf[3] = 0;
97  return buf;
98  }
99 
100  *error = true;
101  return "";
102 }
103 
104 static std::string xparse_string(const char* s, const char** sout, bool *error)
105 {
106  //printf("xstring-->%s\n", s);
107 
108  std::string v;
109 
110  while (1) {
111  if (*s == 0) {
112  // error
113  *sout = s;
114  *error = true;
115  return "";
116  } else if (*s == '\"') {
117  // end of string
118  *sout = s+1;
119  return v;
120  } else if (*s == '\\') {
121  // escape sequence
122  s++;
123  //printf("escape %d (%c)\n", *s, *s);
124  switch (*s) {
125  case 0:
126  // maybe error - unexpected end of string
127  *sout = s;
128  *error = true;
129  return v;
130  default:
131  // error - unknown escape
132  *sout = s;
133  *error = true;
134  return v;
135  case '\"': v += '\"'; s++; break;
136  case '\\': v += '\\'; s++; break;
137  case '/': v += '/'; s++; break;
138  case 'b': v += '\b'; s++; break;
139  case 'f': v += '\f'; s++; break;
140  case 'n': v += '\n'; s++; break;
141  case 'r': v += '\r'; s++; break;
142  case 't': v += '\t'; s++; break;
143  case 'u': {
144  s++;
145  int unicode = xparse_unicode(s, sout);
146  //printf("unicode %d (0x%x), next %c\n", unicode, unicode, **sout);
147  if (unicode < 0) {
148  // error - bad unicode
149  *sout = s;
150  *error = true;
151  return v;
152  }
153  v += xoutput_unicode(unicode, error);
154  if (*error) {
155  // error - bad unicode
156  //*sout = s; // stay pointing at the bad unicode
157  *error = true;
158  return v;
159  }
160  s = *sout;
161  break;
162  }
163  }
164  } else {
165  v += *s;
166  s++;
167  }
168  }
169 
170  // NOT REACHED
171 }
172 
173 static MJsonNode* parse_something(const char* sin, const char* s, const char** sout);
174 
175 static MJsonNode* parse_array(const char* sin, const char* s, const char** sout)
176 {
177  //printf("array-->%s\n", s);
179 
180  s = skip_spaces(s);
181 
182  if (*s == ']') {
183  // empty array
184  *sout = s+1;
185  return n;
186  }
187 
188  while (1) {
189  s = skip_spaces(s);
190 
191  if (*s == 0) {
192  *sout = s;
193  return MJsonNode::MakeError(n, "unexpected end of string while parsing array", sin, s);
194  }
195 
196  MJsonNode *p = parse_something(sin, s, sout);
197  if (p == NULL) {
198  // sout set by parse_something()
199  return MJsonNode::MakeError(n, "cannot parse array element", sin, *sout);
200  }
201  if (p->GetType() == MJSON_ERROR) {
202  // sout set by parse_something()
203  return MJsonNode::MakeError(n, "error parsing array element", sin, *sout);
204  }
205 
206  n->AddToArray(p);
207 
208  s = skip_spaces(*sout);
209 
210  if (*s == ']') {
211  // end of array
212  *sout = s+1;
213  return n;
214  }
215 
216  if (*s == ',') {
217  s++;
218  continue;
219  }
220 
221  *sout = s;
222  return MJsonNode::MakeError(n, "unexpected char after array element, should be \',\' or \']\'", sin, s);
223  }
224 
225  // NOT REACHED
226 }
227 
228 static MJsonNode* parse_object(const char* sin, const char* s, const char** sout)
229 {
230  //printf("object-->%s\n", s);
231 
233 
234  s = skip_spaces(s);
235 
236  if (*s == '}') {
237  // empty object
238  *sout = s+1;
239  return n;
240  }
241 
242  while (1) {
243  s = skip_spaces(s);
244 
245  //printf("xobject-->%s\n", s);
246 
247  if (*s == 0) {
248  *sout = s;
249  return MJsonNode::MakeError(n, "unexpected end of string while parsing object", sin, s);
250  } else if (*s != '\"') {
251  *sout = s;
252  return MJsonNode::MakeError(n, "unexpected char while parsing object, should be \"\"\"", sin, s);
253  }
254 
255  bool error = false;
256  std::string name = xparse_string(s+1, sout, &error);
257  if (error || name.length() < 1) {
258  // sout set by parse_something()
259  return MJsonNode::MakeError(n, "cannot parse name of object element", sin, *sout);
260  }
261 
262  s = skip_spaces(*sout);
263 
264  if (*s == 0) {
265  *sout = s;
266  return MJsonNode::MakeError(n, "unexpected end of string after name of object element", sin, s);
267  } else if (*s != ':') {
268  *sout = s;
269  return MJsonNode::MakeError(n, "unexpected char after name of object element, should be \":\"", sin, s);
270  }
271 
272  MJsonNode *p = parse_something(sin, s+1, sout);
273  if (p == NULL) {
274  // sout set by parse_something()
275  return MJsonNode::MakeError(n, "cannot parse object element", sin, *sout);
276  }
277  if (p->GetType() == MJSON_ERROR) {
278  // sout set by parse_something()
279  return MJsonNode::MakeError(n, "error parsing object element", sin, *sout);
280  }
281 
282  n->AddToObject(name.c_str(), p);
283 
284  s = skip_spaces(*sout);
285 
286  //printf("xobject-->%s\n", s);
287 
288  if (*s == '}') {
289  // end of object
290  *sout = s+1;
291  return n;
292  }
293 
294  if (*s == ',') {
295  s++;
296  continue;
297  }
298 
299  // error
300  *sout = s;
301  return MJsonNode::MakeError(n, "unexpected char after object element, should be \"}\" or \",\"", sin, s);
302  }
303 
304  // NOT REACHED
305 }
306 
307 static MJsonNode* parse_string(const char* sin, const char* s, const char** sout)
308 {
309  //printf("string-->%s\n", s);
310 
311  bool error = false;
312  std::string v = xparse_string(s, sout, &error);
313 
314  if (error)
315  return MJsonNode::MakeError(NULL, "cannot parse string", sin, *sout);
316 
317  return MJsonNode::MakeString(v.c_str());
318 }
319 
320 static std::string parse_digits(const char* s, const char** sout)
321 {
322  std::string v;
323  v.reserve(32); // allocate space for a longish number
324 
325  while (*s) {
326  if (*s < '0')
327  break;
328  if (*s > '9')
329  break;
330 
331  v += *s;
332  s++;
333  }
334 
335  *sout = s;
336  return v;
337 }
338 
339 static int patoi_with_overflow(const char* s)
340 {
341  const int kMAX = INT_MAX/10;
342  const int kLAST = INT_MAX - kMAX*10;
343  int v = 0;
344  for ( ; *s != 0; s++) {
345  int vadd = (*s)-'0';
346  //printf("compare: %d kMAX: %d, v*10: %d, vadd %d, kLAST %d\n", v, kMAX, v*10, vadd, kLAST);
347  if (v > kMAX)
348  return -1;
349  if (v == kMAX && vadd > kLAST) {
350  return -1;
351  }
352  v = v*10 + vadd;
353  }
354  return v;
355 }
356 
357 static int matoi_with_overflow(const char* s)
358 {
359  const int kMIN = INT_MIN/10;
360  const int kLAST = -(INT_MIN - kMIN*10);
361  int v = 0;
362  for ( ; *s != 0; s++) {
363  int vadd = (*s)-'0';
364  //printf("compare: %d kMIN: %d, v*10: %d, vadd %d, kLAST %d\n", v, kMIN, v*10, vadd, kLAST);
365  if (v < kMIN)
366  return 1;
367  if (v == kMIN && vadd > kLAST) {
368  return 1;
369  }
370  v = v*10 - vadd;
371  }
372  return v;
373 }
374 
375 static void test_atoi_with_overflow_value(int sign, const char*s, int v)
376 {
377  int vv;
378  if (sign > 0)
379  vv = patoi_with_overflow(s);
380  else
381  vv = matoi_with_overflow(s);
382 
383  //printf("atoi test: [%s] [%s] -> %d (0x%x) should be %d (0x%x)\n", (sign>0)?"+":"-", s, vv, vv, v, v);
384 
385  if (vv == v)
386  return;
387 
388  printf("atoi test failed: [%s] [%s] -> %d (0x%x) != %d (0x%x)\n", (sign>0)?"+":"-", s, vv, vv, v, v);
389  assert(!"mjson self test: my atoi() is broken, bye!");
390  abort();
391  // DOES NOT RETURN
392 }
393 
395 {
396  int i = 0x80000000;
397  // test positive values
400  test_atoi_with_overflow_value(1, "12", 12);
401  test_atoi_with_overflow_value(1, "1234", 1234);
402  if (i < 0) { // check overflow of 32-bit integers
403  test_atoi_with_overflow_value(1, "2147483646", 0x80000000-2);
404  test_atoi_with_overflow_value(1, "2147483647", 0x80000000-1);
405  test_atoi_with_overflow_value(1, "2147483648", -1);
406  test_atoi_with_overflow_value(1, "2147483649", -1);
407  }
408  test_atoi_with_overflow_value(1, "999999999999999999999999999999999999999999999999999999", -1);
409 
410  // test negative
411  test_atoi_with_overflow_value(-1, "0", 0);
412  test_atoi_with_overflow_value(-1, "1", -1);
413  test_atoi_with_overflow_value(-1, "12", -12);
414  test_atoi_with_overflow_value(-1, "1234", -1234);
415  if (i < 0) { // check overflow of 32-bit integers
416  test_atoi_with_overflow_value(-1, "2147483646", 0x80000000+2);
417  test_atoi_with_overflow_value(-1, "2147483647", 0x80000000+1);
418  test_atoi_with_overflow_value(-1, "2147483648", 0x80000000+0);
419  test_atoi_with_overflow_value(-1, "2147483649", 1);
420  test_atoi_with_overflow_value(-1, "2147483650", 1);
421  }
422  test_atoi_with_overflow_value(-1, "999999999999999999999999999999999999999999999999999999", 1);
423 }
424 
425 static MJsonNode* parse_number(const char* sin, const char* s, const char** sout)
426 {
427  //printf("number-->%s\n", s);
428 
429  static int once = 1;
430  if (once) {
431  once = 0;
433  }
434 
435  // per RFC 4627
436  // A number contains an integer component that
437  // may be prefixed with an optional minus sign, which may be followed by
438  // a fraction part and/or an exponent part.
439  //
440  // number = [ minus ] int [ frac ] [ exp ]
441  // decimal-point = %x2E ; .
442  // digit1-9 = %x31-39 ; 1-9
443  // e = %x65 / %x45 ; e E
444  // exp = e [ minus / plus ] 1*DIGIT
445  // frac = decimal-point 1*DIGIT
446  // int = zero / ( digit1-9 *DIGIT )
447  // minus = %x2D ; -
448  // plus = %x2B ; +
449  // zero = %x30 ; 0
450 
451  int sign = 1;
452  std::string sint;
453  std::string sfrac;
454  int expsign = 1;
455  std::string sexp;
456 
457  if (*s == '-') {
458  sign = -1;
459  s++;
460  }
461 
462  if (*s == '0') {
463  sint += *s;
464  s++;
465  } else {
466  sint = parse_digits(s, sout);
467  s = *sout;
468  }
469 
470  if (*s == '.') {
471  s++;
472  sfrac = parse_digits(s, sout);
473  s = *sout;
474  }
475 
476  if (*s == 'e' || *s == 'E') {
477  s++;
478 
479  if (*s == '-') {
480  expsign = -1;
481  s++;
482  }
483 
484  if (*s == '+') {
485  expsign = +1;
486  s++;
487  }
488 
489  sexp = parse_digits(s, sout);
490  s = *sout;
491  }
492 
493  //printf("number: sign %d, sint [%s], sfrac [%s], expsign %d, sexp [%s]\n", sign, sint.c_str(), sfrac.c_str(), expsign, sexp.c_str());
494 
495  // check for floatign point
496 
497  if (expsign < 0 || sfrac.length() > 0) {
498  // definitely floating point number
499  double v1 = atof(sint.c_str());
500  double v2 = 0;
501  double vm = 0.1;
502  const char* p = sfrac.c_str();
503  for ( ; *p != 0; p++, vm/=10.0) {
504  v2 += (*p-'0')*vm;
505  }
506 
507  int e = patoi_with_overflow(sexp.c_str());
508 
509  if (e < 0 || e > 400) {
510  // overflow or exponent will not fit into IEEE754 double precision number
511  // convert to 0 or +/- infinity
512  printf("overflow!\n");
513  if (expsign > 0) {
514  *sout = s;
515  double one = 1;
516  double zero = 0;
517  double inf = one/zero; // IEEE-754 1.0/0.0 is "+infinity", +infinity*(-1) => -infinity
518  return MJsonNode::MakeNumber(sign*inf);
519  } else {
520  *sout = s;
521  return MJsonNode::MakeNumber(sign*0.0);
522  }
523  }
524 
525  double ee = 1.0;
526  if (e != 0)
527  ee = pow(10, (double)(expsign*e));
528  double v = sign*(v1+v2)*ee;
529  //printf("v1: %f, v2: %f, e: %d, ee: %g, v: %g\n", v1, v2, e, ee, v);
530 
531  *sout = s;
532  return MJsonNode::MakeNumber(v);
533  } else {
534  // no sfrac, expsign is positive, so this is an integer, unless it overflows
535 
536  int e = patoi_with_overflow(sexp.c_str()); // may overflow
537 
538  if (e < 0 || e > 400) {
539  // overflow or exponent will not fit into IEEE754 double precision number
540  // convert to +/- infinity
541  //printf("overflow!\n");
542  *sout = s;
543  double one = 1;
544  double zero = 0;
545  double inf = one/zero; // IEEE-754 1.0/0.0 is "+infinity", +infinity*(-1) => -infinity
546  return MJsonNode::MakeNumber(sign*inf);
547  }
548 
549  // this is stupid but quicker than calling pow(). Unless they feed us stupid exponents that are not really integers anyway
550  for (int ee=0; ee<e; ee++)
551  sint += "0";
552 
553  int overflow = 0;
554  int v = 0;
555 
556  if (sign > 0) {
557  v = patoi_with_overflow(sint.c_str());
558  if (v < 0)
559  overflow = 1;
560  } else {
561  v = matoi_with_overflow(sint.c_str());
562  if (v > 0)
563  overflow = 1;
564  }
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::EncodeInt(int intvalue)
711 {
712  char buf[256];
713  sprintf(buf, "%d", intvalue);
714  return buf;
715 }
716 
717 std::string MJsonNode::EncodeDouble(double numbervalue)
718 {
719  if (isfinite(numbervalue)) {
720  char buf[256];
721  sprintf(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 (unsigned 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 (unsigned i=0; i<objectnames.size(); i++) {
754  if (i > 0)
755  v += ",";
756  v += std::string("\"") + Encode(objectnames[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(stringvalue.c_str()) + "\"";
765  }
766  case MJSON_INT: {
767  return EncodeInt(intvalue);
768  }
769  case MJSON_NUMBER: {
770  return EncodeDouble(numbervalue);
771  }
772  case MJSON_BOOL:
773  if (intvalue)
774  return "true";
775  else
776  return "false";
777  case MJSON_NULL:
778  return "null";
779  case MJSON_JSON:
780  return stringvalue;
781  case MJSON_ARRAYBUFFER:
782  return "arraybuffer";
783  case MJSON_ERROR:
784  return std::string("json parse error: ") + stringvalue;
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->stringvalue = 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  sprintf(msg, " at char \"%c\" file offset %d, line %d position %d, around text \"%s\"", *serror, offset, lineno, lineoff, sample);
816  n->stringvalue += 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->stringvalue = value;
835  return n;
836 }
837 
839 {
840  MJsonNode* n = new MJsonNode(MJSON_INT);
841  n->intvalue = value;
842  n->numbervalue = value;
843  return n;
844 }
845 
847 {
848  MJsonNode* n = new MJsonNode(MJSON_NUMBER);
849  n->numbervalue = value;
850  return n;
851 }
852 
854 {
855  MJsonNode* n = new MJsonNode(MJSON_BOOL);
856  if (value)
857  n->intvalue = 1;
858  else
859  n->intvalue = 0;
860  return n;
861 }
862 
864 {
865  return new MJsonNode(MJSON_NULL);
866 }
867 
868 MJsonNode* MJsonNode::MakeJSON(const char* json)
869 {
870  MJsonNode* n = new MJsonNode(MJSON_JSON);
871  n->stringvalue = json;
872  return n;
873 }
874 
875 MJsonNode* MJsonNode::MakeArrayBuffer(char* ptr, size_t size)
876 {
878  n->arraybuffer_ptr = ptr;
879  n->arraybuffer_size = size;
880  return n;
881 }
882 
884 {
885  if (type == MJSON_ARRAY) {
886  subnodes.push_back(node);
887  return;
888  }
889 
890  assert(!"not an array");
891 }
892 
893 void MJsonNode::AddToObject(const char* name, MJsonNode* node) /// add node to an object
894 {
895  if (type == MJSON_OBJECT) {
896  objectnames.push_back(name);
897  subnodes.push_back(node);
898  //objectvalue[name] = node;
899  return;
900  }
901 
902  assert(!"not an object");
903 }
904 
905 int MJsonNode::GetType() const /// get node type: MJSON_xxx
906 {
907  return type;
908 }
909 
911 {
912  if (type == MJSON_ARRAY || type == MJSON_NULL)
913  return &subnodes;
914  else
915  return NULL;
916 }
917 
919 {
920  if (type == MJSON_OBJECT || type == MJSON_NULL)
921  return &objectnames;
922  else
923  return NULL;
924 }
925 
927 {
928  if (type == MJSON_OBJECT || type == MJSON_NULL)
929  return &subnodes;
930  else
931  return NULL;
932 }
933 
934 const MJsonNode* MJsonNode::FindObjectNode(const char* name) const
935 {
936  if (type != MJSON_OBJECT)
937  return NULL;
938  for (unsigned i=0; i<objectnames.size(); i++)
939  if (strcmp(objectnames[i].c_str(), name) == 0)
940  return subnodes[i];
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<objectnames.size(); i++)
949  if (strcmp(objectnames[i].c_str(), name) == 0) {
950  objectnames[i] = "";
951  delete subnodes[i];
952  subnodes[i] = NULL;
953 
954  objectnames.erase(objectnames.begin()+i);
955  subnodes.erase(subnodes.begin()+i);
956  return;
957  }
958 }
959 
960 std::string MJsonNode::GetString() const
961 {
962  if (type == MJSON_STRING)
963  return stringvalue;
964  else
965  return "";
966 }
967 
968 int MJsonNode::GetInt() const
969 {
970  if (type == MJSON_INT)
971  return intvalue;
972  else
973  return 0;
974 }
975 
976 double MJsonNode::GetDouble() const
977 {
978  if (type == MJSON_INT)
979  return intvalue;
980  else if (type == MJSON_NUMBER)
981  return numbervalue;
982  else if (type == MJSON_STRING) {
983  if (stringvalue == "NaN") {
984  double zero1 = 0;
985  double zero2 = 0;
986  return zero1/zero2; // IEEE-754 0.0/0.0 is a NaN
987  } else if (stringvalue == "Infinity") {
988  double zero = 0;
989  double one = 1;
990  return one/zero; // IEEE-754 1.0/0.0 is +infinity
991  } else if (stringvalue == "-Infinity") {
992  double zero = 0;
993  double one = -1;
994  return one/zero; // IEEE-754 -1.0/0.0 is -infinity
995  }
996  return 0;
997  } else
998  return 0;
999 }
1000 
1001 bool MJsonNode::GetBool() const /// get boolean value, false if not a boolean or value is JSON "null"
1002 {
1003  if (type == MJSON_BOOL)
1004  return (intvalue != 0);
1005  else
1006  return false;
1007 }
1008 
1009 void MJsonNode::GetArrayBuffer(const char** pptr, size_t* psize) const
1010 {
1011  if (type == MJSON_ARRAYBUFFER) {
1012  if (pptr)
1013  *pptr = arraybuffer_ptr;
1014  if (psize)
1015  *psize = arraybuffer_size;
1016  } else {
1017  if (pptr)
1018  *pptr = NULL;
1019  if (psize)
1020  *psize = 0;
1021  }
1022 }
1023 
1024 std::string MJsonNode::GetError() const
1025 {
1026  if (type == MJSON_ERROR)
1027  return stringvalue;
1028  else
1029  return "";
1030 }
1031 
1032 MJsonNode::MJsonNode(int xtype) // default constructor
1033 {
1034  // C++ does not know how to initialize elemental types, we have to do it by hand:
1035  type = xtype;
1036  intvalue = 0;
1037  numbervalue = 0;
1038  arraybuffer_size = 0;
1039  arraybuffer_ptr = NULL;
1040 }
1041 
1042 const char* MJsonNode::TypeToString(int type)
1043 {
1044  switch (type) {
1045  default: return "UNKNOWN";
1046  case MJSON_ERROR: return "ERROR";
1047  case MJSON_NONE: return "NONE";
1048  case MJSON_ARRAY: return "ARRAY";
1049  case MJSON_OBJECT: return "OBJECT";
1050  case MJSON_STRING: return "STRING";
1051  case MJSON_INT: return "INT";
1052  case MJSON_NUMBER: return "NUMBER";
1053  case MJSON_BOOL: return "BOOL";
1054  case MJSON_NULL: return "NULL";
1055  case MJSON_JSON: return "JSON";
1056  case MJSON_ARRAYBUFFER: return "ARRAYBUFFER";
1057  }
1058 }
1059 
1060 static void pnest(int nest)
1061 {
1062  for (int i=0; i<nest; i++)
1063  printf(" ");
1064 }
1065 
1066 void MJsonNode::Dump(int nest) const // debug
1067 {
1068  printf("Node type %d (%s)", type, TypeToString(type));
1069  switch (type) {
1070  default: printf("\n"); break;
1071  case MJSON_STRING: printf(", value [%s]\n", stringvalue.c_str()); break;
1072  case MJSON_INT: printf(", value %d\n", intvalue); break;
1073  case MJSON_NUMBER: printf(", value %g\n", numbervalue); break;
1074  case MJSON_BOOL: printf(", value %d\n", intvalue); break;
1075  case MJSON_NULL: printf(", null\n"); break;
1076  case MJSON_JSON: printf(", json [%s]\n", stringvalue.c_str()); break;
1077  case MJSON_ARRAYBUFFER: printf(", arraybuffer size %d\n", (int)arraybuffer_size); break;
1078  case MJSON_ARRAY:
1079  printf("\n");
1080  for (unsigned i=0; i<subnodes.size(); i++) {
1081  pnest(nest);
1082  printf("element %d: ", i);
1083  subnodes[i]->Dump(nest+1);
1084  }
1085  break;
1086  case MJSON_OBJECT:
1087  printf("\n");
1088  for (unsigned i=0; i<objectnames.size(); i++) {
1089  pnest(nest);
1090  printf("%s: ", objectnames[i].c_str());
1091  subnodes[i]->Dump(nest+1);
1092  }
1093  break;
1094  case MJSON_ERROR:
1095  printf(": %s\n", stringvalue.c_str());
1096  for (unsigned i=0; i<subnodes.size(); i++) {
1097  pnest(nest);
1098  printf("errorelement %d: ", i);
1099  subnodes[i]->Dump(nest+1);
1100  }
1101  break;
1102  }
1103 }
1104 
1106 {
1107  MJsonNode* n = new MJsonNode(*this);
1108  assert(n->objectnames.size() == objectnames.size());
1109  assert(n->subnodes.size() == subnodes.size());
1110  for (unsigned i=0; i<n->subnodes.size(); i++) {
1111  n->subnodes[i] = subnodes[i]->Copy();
1112  }
1113  if (arraybuffer_size > 0) {
1115  n->arraybuffer_ptr = (char*)malloc(arraybuffer_size);
1117  } else {
1118  n->arraybuffer_size = 0;
1119  n->arraybuffer_ptr = NULL;
1120  }
1121  return n;
1122 }
1123 
1124 /* emacs
1125  * Local Variables:
1126  * tab-width: 8
1127  * c-basic-offset: 3
1128  * indent-tabs-mode: nil
1129  * End:
1130  */
std::string GetString() const
find subnode with given name, NULL if not object, NULL is name not found
Definition: mjson.cxx:960
static MJsonNode * MakeJSON(const char *json)
Definition: mjson.cxx:868
#define MJSON_STRING
Definition: mjson.h:23
void Dump(int nest=0) const
return node type as string
Definition: mjson.cxx:1066
#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:1105
const MJsonNodeVector * GetArray() const
get node type: MJSON_xxx
Definition: mjson.cxx:910
int GetType() const
delete a node from an object
Definition: mjson.cxx:905
int GetInt() const
get string value, "" if not string or value is JSON "null"
Definition: mjson.cxx:968
void AddToArray(MJsonNode *node)
Definition: mjson.cxx:883
static MJsonNode * MakeNumber(double value)
Definition: mjson.cxx:846
int intvalue
Definition: mjson.h:42
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
std::vector< MJsonNode * > MJsonNodeVector
Definition: mjson.h:34
std::vector< std::string > MJsonStringVector
Definition: mjson.h:31
MJsonNode(int type)
make a copy of the json tree
Definition: mjson.cxx:1032
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:893
double GetDouble() const
get integer value, 0 if not an integer or value is JSON "null"
Definition: mjson.cxx:976
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:926
#define MJSON_OBJECT
Definition: mjson.h:22
static MJsonNode * MakeBool(bool value)
Definition: mjson.cxx:853
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:1001
double numbervalue
Definition: mjson.h:43
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:1009
MJsonStringVector objectnames
Definition: mjson.h:40
#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:918
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
std::string stringvalue
Definition: mjson.h:41
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:934
#define MJSON_INT
Definition: mjson.h:24
static MJsonNode * MakeArrayBuffer(char *ptr, size_t size)
Definition: mjson.cxx:875
static MJsonNode * MakeNull()
Definition: mjson.cxx:863
std::string GetError() const
Definition: mjson.cxx:1024
static MJsonNode * Parse(const char *jsonstring)
Definition: mjson.cxx:645
static std::string EncodeInt(int v)
Definition: mjson.cxx:710
#define MJSON_NUMBER
Definition: mjson.h:25
MJsonNodeVector subnodes
Definition: mjson.h:39
static MJsonNode * MakeInt(int value)
Definition: mjson.cxx:838
static const char * TypeToString(int type)
get error message from MJSON_ERROR nodes
Definition: mjson.cxx:1042
static MJsonNode * parse_number(const char *sin, const char *s, const char **sout)
Definition: mjson.cxx:425
static char toHexChar(int c)
Definition: mjson.cxx:668
static std::string xoutput_unicode(int unicode, bool *error)
Definition: mjson.cxx:71
static void test_atoi_with_overflow()
Definition: mjson.cxx:394
static int patoi_with_overflow(const char *s)
Definition: mjson.cxx:339
static MJsonNode * parse_string(const char *sin, const char *s, const char **sout)
Definition: mjson.cxx:307
static int xparse_unicode(const char *s, const char **sout)
Definition: mjson.cxx:53
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:25
static int matoi_with_overflow(const char *s)
Definition: mjson.cxx:357
static std::string xparse_string(const char *s, const char **sout, bool *error)
Definition: mjson.cxx:104
static int hexToInt(char c)
Definition: mjson.cxx:40
static MJsonNode * parse_object(const char *sin, const char *s, const char **sout)
Definition: mjson.cxx:228
static void pnest(int nest)
Definition: mjson.cxx:1060
static std::string parse_digits(const char *s, const char **sout)
Definition: mjson.cxx:320
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:175
static void test_atoi_with_overflow_value(int sign, const char *s, int v)
Definition: mjson.cxx:375
static const int one
Definition: xxhash.c:179