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