ROOTANA
Loading...
Searching...
No Matches
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
26static 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
41static 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
54static 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
72static 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
105static 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
174static MJsonNode* parse_something(const char* sin, const char* s, const char** sout);
175
176static 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
229static 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
308static 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
321static 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
340bool 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
358static 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{
413public:
418};
419
421
422static 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
585static 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
596static 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
607static 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
619static 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
645MJsonNode* 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);
661 arraybuffer_ptr = NULL;
662 }
663
664 // poison deleted nodes
666}
667
668static 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
678std::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
710std::string MJsonNode::EncodeLL(long long value)
711{
712 char buf[256];
713 snprintf(buf, sizeof(buf), "%lld", value);
714 return buf;
715}
716
717std::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
736std::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: {
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;
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
791MJsonNode* MJsonNode::MakeError(MJsonNode* errornode, const char* errormessage, const char* sin, const char* serror)
792{
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
825
830
832{
834 n->string_value = value;
835 return n;
836}
837
839{
840 MJsonNode* n = new MJsonNode(MJSON_INT);
841 n->ll_value = value;
842 return n;
843}
844
846{
848 n->double_value = value;
849 return n;
850}
851
853{
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
868{
870 n->string_value = json;
871 return n;
872}
873
874MJsonNode* 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
892void 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
904int 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
933const 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
944void 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
961std::string MJsonNode::GetString() const
962{
963 if (type == MJSON_STRING)
964 return string_value;
965 else
966 return "";
967}
968
969long long MJsonNode::GetInt() const
970{
971 if (type == MJSON_INT)
972 return ll_value;
973 else
974 return 0;
975}
976
977long long MJsonNode::GetLL() const
978{
979 if (type == MJSON_INT)
980 return ll_value;
981 else
982 return 0;
983}
984
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
1011bool 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
1019void 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
1034std::string MJsonNode::GetError() const
1035{
1036 if (type == MJSON_ERROR)
1037 return string_value;
1038 else
1039 return "";
1040}
1041
1042MJsonNode::MJsonNode(int xtype) // default constructor
1043{
1044 type = xtype;
1045}
1046
1047const 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
1065static void pnest(int nest)
1066{
1067 for (int i=0; i<nest; i++)
1068 printf(" ");
1069}
1070
1071void 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:33
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 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 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_something(const char *sin, const char *s, const char **sout)
Definition mjson.cxx:619
static MJsonNode * parse_string(const char *sin, const char *s, const char **sout)
Definition mjson.cxx:308
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_object(const char *sin, const char *s, const char **sout)
Definition mjson.cxx:229
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_null(const char *sin, const char *s, const char **sout)
Definition mjson.cxx:585
static void pnest(int nest)
Definition mjson.cxx:1065
static const char * skip_spaces(const char *s)
Definition mjson.cxx:26
static std::string parse_digits(const char *s, const char **sout)
Definition mjson.cxx:321
static MJsonNode * parse_number(const char *sin, const char *s, const char **sout)
Definition mjson.cxx:422
static void test_atoll_with_overflow()
Definition mjson.cxx:378
static MJsonNode * parse_array(const char *sin, const char *s, const char **sout)
Definition mjson.cxx:176
static const int one
Definition xxhash.cxx:179