1 /*************** json CPP Declares Source Code File (.H) ***************/
2 /* Name: json.cpp Version 1.6 */
3 /* */
4 /* (C) Copyright to the author Olivier BERTRAND 2014 - 2021 */
5 /* */
6 /* This file contains the JSON classes functions. */
7 /***********************************************************************/
8
9 /***********************************************************************/
10 /* Include relevant sections of the MariaDB header file. */
11 /***********************************************************************/
12 #include <my_global.h>
13
14 /***********************************************************************/
15 /* Include application header files: */
16 /* global.h is header containing all global declarations. */
17 /* plgdbsem.h is header containing the DB application declarations. */
18 /* xjson.h is header containing the JSON classes declarations. */
19 /***********************************************************************/
20 #include "global.h"
21 #include "plgdbsem.h"
22 #include "json.h"
23
24 #define ARGS MY_MIN(24,(int)len-i),s+MY_MAX(i-3,0)
25
26 #if defined(_WIN32)
27 #define EL "\r\n"
28 #else
29 #define EL "\n"
30 #undef SE_CATCH // Does not work for Linux
31 #endif
32
33 #if defined(SE_CATCH)
34 /**************************************************************************/
35 /* This is the support of catching C interrupts to prevent crashes. */
36 /**************************************************************************/
37 #include <eh.h>
38
39 class SE_Exception {
40 public:
SE_Exception(unsigned int n,PEXCEPTION_RECORD p)41 SE_Exception(unsigned int n, PEXCEPTION_RECORD p) : nSE(n), eRec(p) {}
~SE_Exception()42 ~SE_Exception() {}
43
44 unsigned int nSE;
45 PEXCEPTION_RECORD eRec;
46 }; // end of class SE_Exception
47
trans_func(unsigned int u,_EXCEPTION_POINTERS * pExp)48 void trans_func(unsigned int u, _EXCEPTION_POINTERS* pExp)
49 {
50 throw SE_Exception(u, pExp->ExceptionRecord);
51 } // end of trans_func
52
53 char *GetExceptionDesc(PGLOBAL g, unsigned int e);
54 #endif // SE_CATCH
55
56 char *GetJsonNull(void);
57 int GetDefaultPrec(void);
58 int PrepareColist(char*);
59
60 /***********************************************************************/
61 /* IsNum: check whether this string is all digits. */
62 /***********************************************************************/
IsNum(PSZ s)63 bool IsNum(PSZ s)
64 {
65 char* p = s;
66
67 if (*p == '-')
68 p++;
69
70 if (*p == ']')
71 return false;
72 else for (; *p; p++)
73 if (*p == ']')
74 break;
75 else if (!isdigit(*p))
76 return false;
77
78 return true;
79 } // end of IsNum
80
81 /***********************************************************************/
82 /* IsArray: check whether this is a Mongo array path. */
83 /***********************************************************************/
IsArray(PSZ s)84 bool IsArray(PSZ s)
85 {
86 char* p = s;
87
88 if (!p || !*p)
89 return false;
90 else for (; *p; p++)
91 if (*p == '.')
92 break;
93 else if (!isdigit(*p))
94 return false;
95
96 return true;
97 } // end of IsArray
98
99 /***********************************************************************/
100 /* NextChr: return the first found '[' or Sep pointer. */
101 /***********************************************************************/
NextChr(PSZ s,char sep)102 char* NextChr(PSZ s, char sep)
103 {
104 char* p1 = strchr(s, '[');
105 char* p2 = strchr(s, sep);
106
107 if (!p2)
108 return p1;
109 else if (p1)
110 return MY_MIN(p1, p2);
111
112 return p2;
113 } // end of NextChr
114
115 /***********************************************************************/
116 /* Stringified: check that this column is in the stringified list. */
117 /***********************************************************************/
Stringified(PCSZ strfy,char * colname)118 bool Stringified(PCSZ strfy, char *colname)
119 {
120 if (strfy) {
121 char *p, colist[512];
122 int n;
123
124 strncpy(colist, strfy, sizeof(colist) - 1);
125 n = PrepareColist(colist);
126
127 for (p = colist; n && p; p += (strlen(p) + 1), n--)
128 if (!stricmp(p, colname))
129 return true;
130
131 } // endif strfy
132
133 return false;
134 } // end of Stringified
135
136 #if 0
137 /***********************************************************************/
138 /* Allocate a VAL structure, make sure common field and Nd are zeroed. */
139 /***********************************************************************/
140 PVL AllocVal(PGLOBAL g, JTYP type)
141 {
142 PVL vlp = (PVL)PlugSubAlloc(g, NULL, sizeof(VAL));
143
144 vlp->LLn = 0;
145 vlp->Nd = 0;
146 vlp->Type = type;
147 return vlp;
148 } // end of AllocVal
149 #endif // 0
150
151 /***********************************************************************/
152 /* Parse a json string. */
153 /* Note: when pretty is not known, the caller set pretty to 3. */
154 /***********************************************************************/
ParseJson(PGLOBAL g,char * s,size_t len,int * ptyp,bool * comma)155 PJSON ParseJson(PGLOBAL g, char* s, size_t len, int* ptyp, bool* comma)
156 {
157 int i, pretty = (ptyp) ? *ptyp : 3;
158 bool b = false, pty[3] = { true,true,true };
159 PJSON jsp = NULL;
160 PJDOC jdp = NULL;
161
162 if (trace(1))
163 htrc("ParseJson: s=%.10s len=%zd\n", s, len);
164
165 if (!s || !len) {
166 strcpy(g->Message, "Void JSON object");
167 return NULL;
168 } else if (comma)
169 *comma = false;
170
171 // Trying to guess the pretty format
172 if (s[0] == '[' && (s[1] == '\n' || (s[1] == '\r' && s[2] == '\n')))
173 pty[0] = false;
174
175 try {
176 jdp = new(g) JDOC;
177 jdp->s = s;
178 jdp->len = len;
179 jdp->pty = pty;
180
181 for (i = 0; i < jdp->len; i++)
182 switch (s[i]) {
183 case '[':
184 if (jsp)
185 jsp = jdp->ParseAsArray(g, i, pretty, ptyp);
186 else
187 jsp = jdp->ParseArray(g, ++i);
188
189 break;
190 case '{':
191 if (jsp)
192 jsp = jdp->ParseAsArray(g, i, pretty, ptyp);
193 else if (!(jsp = jdp->ParseObject(g, ++i)))
194 throw 2;
195
196 break;
197 case ' ':
198 case '\t':
199 case '\n':
200 case '\r':
201 break;
202 case ',':
203 if (jsp && (pretty == 1 || pretty == 3)) {
204 if (comma)
205 *comma = true;
206
207 pty[0] = pty[2] = false;
208 break;
209 } // endif pretty
210
211 sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty);
212 throw 3;
213 case '(':
214 b = true;
215 break;
216 case ')':
217 if (b) {
218 b = false;
219 break;
220 } // endif b
221 /* falls through */
222 default:
223 if (jsp)
224 jsp = jdp->ParseAsArray(g, i, pretty, ptyp);
225 else if (!(jsp = jdp->ParseValue(g, i)))
226 throw 4;
227
228 break;
229 }; // endswitch s[i]
230
231 if (!jsp)
232 sprintf(g->Message, "Invalid Json string '%.*s'", MY_MIN((int)len, 50), s);
233 else if (ptyp && pretty == 3) {
234 *ptyp = 3; // Not recognized pretty
235
236 for (i = 0; i < 3; i++)
237 if (pty[i]) {
238 *ptyp = i;
239 break;
240 } // endif pty
241
242 } // endif ptyp
243
244 } catch (int n) {
245 if (trace(1))
246 htrc("Exception %d: %s\n", n, g->Message);
247 jsp = NULL;
248 } catch (const char* msg) {
249 strcpy(g->Message, msg);
250 jsp = NULL;
251 } // end catch
252
253 return jsp;
254 } // end of ParseJson
255
256 /***********************************************************************/
257 /* Serialize a JSON document tree: */
258 /***********************************************************************/
Serialize(PGLOBAL g,PJSON jsp,char * fn,int pretty)259 PSZ Serialize(PGLOBAL g, PJSON jsp, char* fn, int pretty) {
260 PSZ str = NULL;
261 bool b = false, err = true;
262 JOUT* jp;
263 FILE* fs = NULL;
264 PJDOC jdp = NULL;
265
266 g->Message[0] = 0;
267
268 try {
269 jdp = new(g) JDOC; // MUST BE ALLOCATED BEFORE jp !!!!!
270 jdp->dfp = GetDefaultPrec();
271
272 if (!jsp) {
273 strcpy(g->Message, "Null json tree");
274 throw 1;
275 } else if (!fn) {
276 // Serialize to a string
277 jp = new(g) JOUTSTR(g);
278 b = pretty == 1;
279 } else {
280 if (!(fs = fopen(fn, "wb"))) {
281 sprintf(g->Message, MSG(OPEN_MODE_ERROR),
282 "w", (int)errno, fn);
283 strcat(strcat(g->Message, ": "), strerror(errno));
284 throw 2;
285 } else if (pretty >= 2) {
286 // Serialize to a pretty file
287 jp = new(g)JOUTPRT(g, fs);
288 } else {
289 // Serialize to a flat file
290 b = true;
291 jp = new(g)JOUTFILE(g, fs, pretty);
292 } // endif's
293
294 } // endif's
295
296 jdp->SetJp(jp);
297
298 switch (jsp->GetType()) {
299 case TYPE_JAR:
300 err = jdp->SerializeArray((PJAR)jsp, b);
301 break;
302 case TYPE_JOB:
303 err = ((b && jp->Prty()) && jp->WriteChr('\t'));
304 err |= jdp->SerializeObject((PJOB)jsp);
305 break;
306 case TYPE_JVAL:
307 err = jdp->SerializeValue((PJVAL)jsp);
308 break;
309 default:
310 strcpy(g->Message, "Invalid json tree");
311 } // endswitch Type
312
313 if (fs) {
314 fputs(EL, fs);
315 fclose(fs);
316 str = (err) ? NULL : strcpy(g->Message, "Ok");
317 } else if (!err) {
318 str = ((JOUTSTR*)jp)->Strp;
319 jp->WriteChr('\0');
320 PlugSubAlloc(g, NULL, ((JOUTSTR*)jp)->N);
321 } else {
322 if (!g->Message[0])
323 strcpy(g->Message, "Error in Serialize");
324
325 } // endif's
326
327 } catch (int n) {
328 if (trace(1))
329 htrc("Exception %d: %s\n", n, g->Message);
330 str = NULL;
331 } catch (const char* msg) {
332 strcpy(g->Message, msg);
333 str = NULL;
334 } // end catch
335
336 return str;
337 } // end of Serialize
338
339
340 /* -------------------------- Class JOUTSTR -------------------------- */
341
342 /***********************************************************************/
343 /* JOUTSTR constructor. */
344 /***********************************************************************/
JOUTSTR(PGLOBAL g)345 JOUTSTR::JOUTSTR(PGLOBAL g) : JOUT(g) {
346 PPOOLHEADER pph = (PPOOLHEADER)g->Sarea;
347
348 N = 0;
349 Max = pph->FreeBlk;
350 Max = (Max > 32) ? Max - 32 : Max;
351 Strp = (char*)PlugSubAlloc(g, NULL, 0); // Size not know yet
352 } // end of JOUTSTR constructor
353
354 /***********************************************************************/
355 /* Concatenate a string to the Serialize string. */
356 /***********************************************************************/
WriteStr(const char * s)357 bool JOUTSTR::WriteStr(const char* s) {
358 if (s) {
359 size_t len = strlen(s);
360
361 if (N + len > Max)
362 return true;
363
364 memcpy(Strp + N, s, len);
365 N += len;
366 return false;
367 } else
368 return true;
369
370 } // end of WriteStr
371
372 /***********************************************************************/
373 /* Concatenate a character to the Serialize string. */
374 /***********************************************************************/
WriteChr(const char c)375 bool JOUTSTR::WriteChr(const char c) {
376 if (N + 1 > Max)
377 return true;
378
379 Strp[N++] = c;
380 return false;
381 } // end of WriteChr
382
383 /***********************************************************************/
384 /* Escape and Concatenate a string to the Serialize string. */
385 /***********************************************************************/
Escape(const char * s)386 bool JOUTSTR::Escape(const char* s)
387 {
388 if (s) {
389 WriteChr('"');
390
391 for (unsigned int i = 0; s[i]; i++)
392 switch (s[i]) {
393 case '"':
394 case '\\':
395 case '\t':
396 case '\n':
397 case '\r':
398 case '\b':
399 case '\f': WriteChr('\\');
400 // fall through
401 default:
402 WriteChr(s[i]);
403 break;
404 } // endswitch s[i]
405
406 WriteChr('"');
407 } else
408 WriteStr("null");
409
410 return false;
411 } // end of Escape
412
413 /* ------------------------- Class JOUTFILE -------------------------- */
414
415 /***********************************************************************/
416 /* Write a string to the Serialize file. */
417 /***********************************************************************/
WriteStr(const char * s)418 bool JOUTFILE::WriteStr(const char* s)
419 {
420 // This is temporary
421 fputs(s, Stream);
422 return false;
423 } // end of WriteStr
424
425 /***********************************************************************/
426 /* Write a character to the Serialize file. */
427 /***********************************************************************/
WriteChr(const char c)428 bool JOUTFILE::WriteChr(const char c)
429 {
430 // This is temporary
431 fputc(c, Stream);
432 return false;
433 } // end of WriteChr
434
435 /***********************************************************************/
436 /* Escape and Concatenate a string to the Serialize string. */
437 /***********************************************************************/
Escape(const char * s)438 bool JOUTFILE::Escape(const char* s)
439 {
440 // This is temporary
441 if (s) {
442 fputc('"', Stream);
443
444 for (unsigned int i = 0; s[i]; i++)
445 switch (s[i]) {
446 case '"': fputs("\\\"", Stream); break;
447 case '\\': fputs("\\\\", Stream); break;
448 case '\t': fputs("\\t", Stream); break;
449 case '\n': fputs("\\n", Stream); break;
450 case '\r': fputs("\\r", Stream); break;
451 case '\b': fputs("\\b", Stream); break;
452 case '\f': fputs("\\f", Stream); break;
453 default:
454 fputc(s[i], Stream);
455 break;
456 } // endswitch s[i]
457
458 fputc('"', Stream);
459 } else
460 fputs("null", Stream);
461
462 return false;
463 } // end of Escape
464
465 /* ------------------------- Class JOUTPRT --------------------------- */
466
467 /***********************************************************************/
468 /* Write a string to the Serialize pretty file. */
469 /***********************************************************************/
WriteStr(const char * s)470 bool JOUTPRT::WriteStr(const char* s)
471 {
472 // This is temporary
473 if (B) {
474 fputs(EL, Stream);
475 M--;
476
477 for (int i = 0; i < M; i++)
478 fputc('\t', Stream);
479
480 B = false;
481 } // endif B
482
483 fputs(s, Stream);
484 return false;
485 } // end of WriteStr
486
487 /***********************************************************************/
488 /* Write a character to the Serialize pretty file. */
489 /***********************************************************************/
WriteChr(const char c)490 bool JOUTPRT::WriteChr(const char c)
491 {
492 switch (c) {
493 case ':':
494 fputs(": ", Stream);
495 break;
496 case '{':
497 case '[':
498 #if 0
499 if (M)
500 fputs(EL, Stream);
501
502 for (int i = 0; i < M; i++)
503 fputc('\t', Stream);
504 #endif // 0
505
506 fputc(c, Stream);
507 fputs(EL, Stream);
508 M++;
509
510 for (int i = 0; i < M; i++)
511 fputc('\t', Stream);
512
513 break;
514 case '}':
515 case ']':
516 M--;
517 fputs(EL, Stream);
518
519 for (int i = 0; i < M; i++)
520 fputc('\t', Stream);
521
522 fputc(c, Stream);
523 B = true;
524 break;
525 case ',':
526 fputc(c, Stream);
527 fputs(EL, Stream);
528
529 for (int i = 0; i < M; i++)
530 fputc('\t', Stream);
531
532 B = false;
533 break;
534 default:
535 fputc(c, Stream);
536 } // endswitch c
537
538 return false;
539 } // end of WriteChr
540
541 /* --------------------------- Class JDOC ---------------------------- */
542
543 /***********************************************************************/
544 /* Parse several items as being in an array. */
545 /***********************************************************************/
ParseAsArray(PGLOBAL g,int & i,int pretty,int * ptyp)546 PJAR JDOC::ParseAsArray(PGLOBAL g, int& i, int pretty, int *ptyp)
547 {
548 if (pty[0] && (!pretty || pretty > 2)) {
549 PJAR jsp;
550
551 if ((jsp = ParseArray(g, (i = 0))) && ptyp && pretty == 3)
552 *ptyp = (pty[0]) ? 0 : 3;
553
554 return jsp;
555 } else
556 strcpy(g->Message, "More than one item in file");
557
558 return NULL;
559 } // end of ParseAsArray
560
561 /***********************************************************************/
562 /* Parse a JSON Array. */
563 /***********************************************************************/
ParseArray(PGLOBAL g,int & i)564 PJAR JDOC::ParseArray(PGLOBAL g, int& i)
565 {
566 int level = 0;
567 bool b = (!i);
568 PJAR jarp = new(g) JARRAY;
569
570 for (; i < len; i++)
571 switch (s[i]) {
572 case ',':
573 if (level < 2) {
574 sprintf(g->Message, "Unexpected ',' near %.*s",ARGS);
575 throw 1;
576 } else
577 level = 1;
578
579 break;
580 case ']':
581 if (level == 1) {
582 sprintf(g->Message, "Unexpected ',]' near %.*s", ARGS);
583 throw 1;
584 } // endif level
585
586 jarp->InitArray(g);
587 return jarp;
588 case '\n':
589 if (!b)
590 pty[0] = pty[1] = false;
591 case '\r':
592 case ' ':
593 case '\t':
594 break;
595 default:
596 if (level == 2) {
597 sprintf(g->Message, "Unexpected value near %.*s", ARGS);
598 throw 1;
599 } else
600 jarp->AddArrayValue(g, ParseValue(g, i));
601
602 level = (b) ? 1 : 2;
603 break;
604 }; // endswitch s[i]
605
606 if (b) {
607 // Case of Pretty == 0
608 jarp->InitArray(g);
609 return jarp;
610 } // endif b
611
612 throw ("Unexpected EOF in array");
613 } // end of ParseArray
614
615 /***********************************************************************/
616 /* Parse a JSON Object. */
617 /***********************************************************************/
ParseObject(PGLOBAL g,int & i)618 PJOB JDOC::ParseObject(PGLOBAL g, int& i)
619 {
620 PSZ key;
621 int level = -1;
622 PJOB jobp = new(g) JOBJECT;
623 PJPR jpp = NULL;
624
625 for (; i < len; i++)
626 switch (s[i]) {
627 case '"':
628 if (level < 2) {
629 key = ParseString(g, ++i);
630 jpp = jobp->AddPair(g, key);
631 level = 1;
632 } else {
633 sprintf(g->Message, "misplaced string near %.*s", ARGS);
634 throw 2;
635 } // endif level
636
637 break;
638 case ':':
639 if (level == 1) {
640 jpp->Val = ParseValue(g, ++i);
641 level = 2;
642 } else {
643 sprintf(g->Message, "Unexpected ':' near %.*s", ARGS);
644 throw 2;
645 } // endif level
646
647 break;
648 case ',':
649 if (level < 2) {
650 sprintf(g->Message, "Unexpected ',' near %.*s", ARGS);
651 throw 2;
652 } else
653 level = 0;
654
655 break;
656 case '}':
657 if (level == 0 || level == 1) {
658 sprintf(g->Message, "Unexpected '}' near %.*s", ARGS);
659 throw 2;
660 } // endif level
661
662 return jobp;
663 case '\n':
664 pty[0] = pty[1] = false;
665 case '\r':
666 case ' ':
667 case '\t':
668 break;
669 default:
670 sprintf(g->Message, "Unexpected character '%c' near %.*s",
671 s[i], ARGS);
672 throw 2;
673 }; // endswitch s[i]
674
675 strcpy(g->Message, "Unexpected EOF in Object");
676 throw 2;
677 } // end of ParseObject
678
679 /***********************************************************************/
680 /* Parse a JSON Value. */
681 /***********************************************************************/
ParseValue(PGLOBAL g,int & i)682 PJVAL JDOC::ParseValue(PGLOBAL g, int& i)
683 {
684 PJVAL jvp = new(g) JVALUE;
685
686 for (; i < len; i++)
687 switch (s[i]) {
688 case '\n':
689 pty[0] = pty[1] = false;
690 case '\r':
691 case ' ':
692 case '\t':
693 break;
694 default:
695 goto suite;
696 } // endswitch
697
698 suite:
699 switch (s[i]) {
700 case '[':
701 jvp->Jsp = ParseArray(g, ++i);
702 jvp->DataType = TYPE_JSON;
703 break;
704 case '{':
705 jvp->Jsp = ParseObject(g, ++i);
706 jvp->DataType = TYPE_JSON;
707 break;
708 case '"':
709 // jvp->Val = AllocVal(g, TYPE_STRG);
710 jvp->Strp = ParseString(g, ++i);
711 jvp->DataType = TYPE_STRG;
712 break;
713 case 't':
714 if (!strncmp(s + i, "true", 4)) {
715 // jvp->Val = AllocVal(g, TYPE_BOOL);
716 jvp->B = true;
717 jvp->DataType = TYPE_BOOL;
718 i += 3;
719 } else
720 goto err;
721
722 break;
723 case 'f':
724 if (!strncmp(s + i, "false", 5)) {
725 // jvp->Val = AllocVal(g, TYPE_BOOL);
726 jvp->B = false;
727 jvp->DataType = TYPE_BOOL;
728 i += 4;
729 } else
730 goto err;
731
732 break;
733 case 'n':
734 if (!strncmp(s + i, "null", 4)) {
735 jvp->DataType = TYPE_NULL;
736 i += 3;
737 } else
738 goto err;
739
740 break;
741 case '-':
742 default:
743 if (s[i] == '-' || isdigit(s[i]))
744 ParseNumeric(g, i, jvp);
745 else
746 goto err;
747
748 }; // endswitch s[i]
749
750 return jvp;
751
752 err:
753 sprintf(g->Message, "Unexpected character '%c' near %.*s", s[i], ARGS);
754 throw 3;
755 } // end of ParseValue
756
757 /***********************************************************************/
758 /* Unescape and parse a JSON string. */
759 /***********************************************************************/
ParseString(PGLOBAL g,int & i)760 char *JDOC::ParseString(PGLOBAL g, int& i)
761 {
762 uchar *p;
763 int n = 0;
764
765 // Be sure of memory availability
766 if (((size_t)len + 1 - i) > ((PPOOLHEADER)g->Sarea)->FreeBlk)
767 throw("ParseString: Out of memory");
768
769 // The size to allocate is not known yet
770 p = (uchar*)PlugSubAlloc(g, NULL, 0);
771
772 for (; i < len; i++)
773 switch (s[i]) {
774 case '"':
775 p[n++] = 0;
776 PlugSubAlloc(g, NULL, n);
777 return (char*)p;
778 case '\\':
779 if (++i < len) {
780 if (s[i] == 'u') {
781 if (len - i > 5) {
782 // if (charset == utf8) {
783 char xs[5];
784 uint hex;
785
786 xs[0] = s[++i];
787 xs[1] = s[++i];
788 xs[2] = s[++i];
789 xs[3] = s[++i];
790 xs[4] = 0;
791 hex = strtoul(xs, NULL, 16);
792
793 if (hex < 0x80) {
794 p[n] = (uchar)hex;
795 } else if (hex < 0x800) {
796 p[n++] = (uchar)(0xC0 | (hex >> 6));
797 p[n] = (uchar)(0x80 | (hex & 0x3F));
798 } else if (hex < 0x10000) {
799 p[n++] = (uchar)(0xE0 | (hex >> 12));
800 p[n++] = (uchar)(0x80 | ((hex >> 6) & 0x3f));
801 p[n] = (uchar)(0x80 | (hex & 0x3f));
802 } else
803 p[n] = '?';
804
805 #if 0
806 } else {
807 char xs[3];
808 UINT hex;
809
810 i += 2;
811 xs[0] = s[++i];
812 xs[1] = s[++i];
813 xs[2] = 0;
814 hex = strtoul(xs, NULL, 16);
815 p[n] = (char)hex;
816 } // endif charset
817 #endif // 0
818 } else
819 goto err;
820
821 } else switch(s[i]) {
822 case 't': p[n] = '\t'; break;
823 case 'n': p[n] = '\n'; break;
824 case 'r': p[n] = '\r'; break;
825 case 'b': p[n] = '\b'; break;
826 case 'f': p[n] = '\f'; break;
827 default: p[n] = s[i]; break;
828 } // endswitch
829
830 n++;
831 } else
832 goto err;
833
834 break;
835 default:
836 p[n++] = s[i];
837 break;
838 }; // endswitch s[i]
839
840 err:
841 throw("Unexpected EOF in String");
842 } // end of ParseString
843
844 /***********************************************************************/
845 /* Parse a JSON numeric value. */
846 /***********************************************************************/
ParseNumeric(PGLOBAL g,int & i,PJVAL vlp)847 void JDOC::ParseNumeric(PGLOBAL g, int& i, PJVAL vlp)
848 {
849 char buf[50];
850 int n = 0;
851 short nd = 0;
852 bool has_dot = false;
853 bool has_e = false;
854 bool found_digit = false;
855 //PVL vlp = NULL;
856
857 for (; i < len; i++) {
858 switch (s[i]) {
859 case '.':
860 if (!found_digit || has_dot || has_e)
861 goto err;
862
863 has_dot = true;
864 break;
865 case 'e':
866 case 'E':
867 if (!found_digit || has_e)
868 goto err;
869
870 has_e = true;
871 found_digit = false;
872 break;
873 case '+':
874 if (!has_e)
875 goto err;
876
877 // fall through
878 case '-':
879 if (found_digit)
880 goto err;
881
882 break;
883 default:
884 if (isdigit(s[i])) {
885 if (has_dot && !has_e)
886 nd++; // Number of decimals
887
888 found_digit = true;
889 } else
890 goto fin;
891
892 }; // endswitch s[i]
893
894 buf[n++] = s[i];
895 } // endfor i
896
897 fin:
898 if (found_digit) {
899 buf[n] = 0;
900
901 if (has_dot || has_e) {
902 double dv = strtod(buf, NULL);
903
904 // vlp = AllocVal(g, TYPE_DBL);
905 vlp->F = dv;
906 vlp->Nd = nd;
907 vlp->DataType = TYPE_DBL;
908 } else {
909 long long iv = strtoll(buf, NULL, 10);
910
911 if (iv > INT_MAX32 || iv < INT_MIN32) {
912 // vlp = AllocVal(g, TYPE_BINT);
913 vlp->LLn = iv;
914 vlp->DataType = TYPE_BINT;
915 } else {
916 // vlp = AllocVal(g, TYPE_INTG);
917 vlp->N = (int)iv;
918 vlp->DataType = TYPE_INTG;
919 } // endif iv
920
921 } // endif has
922
923 i--; // Unstack following character
924 return;
925 } else
926 throw("No digit found");
927
928 err:
929 throw("Unexpected EOF in number");
930 } // end of ParseNumeric
931
932 /***********************************************************************/
933 /* Serialize a JSON Array. */
934 /***********************************************************************/
SerializeArray(PJAR jarp,bool b)935 bool JDOC::SerializeArray(PJAR jarp, bool b)
936 {
937 bool first = true;
938
939 if (b) {
940 if (js->Prty()) {
941 if (js->WriteChr('['))
942 return true;
943 else if (js->Prty() == 1 && (js->WriteStr(EL) || js->WriteChr('\t')))
944 return true;
945
946 } // endif Prty
947
948 } else if (js->WriteChr('['))
949 return true;
950
951 for (int i = 0; i < jarp->size(); i++) {
952 if (first)
953 first = false;
954 else if ((!b || js->Prty()) && js->WriteChr(','))
955 return true;
956 else if (b) {
957 if (js->Prty() < 2 && js->WriteStr(EL))
958 return true;
959 else if (js->Prty() == 1 && js->WriteChr('\t'))
960 return true;
961
962 } // endif b
963
964 if (SerializeValue(jarp->GetArrayValue(i)))
965 return true;
966
967 } // endfor i
968
969 if (b && js->Prty() == 1 && js->WriteStr(EL))
970 return true;
971
972 return ((!b || js->Prty()) && js->WriteChr(']'));
973 } // end of SerializeArray
974
975 /***********************************************************************/
976 /* Serialize a JSON Object. */
977 /***********************************************************************/
SerializeObject(PJOB jobp)978 bool JDOC::SerializeObject(PJOB jobp)
979 {
980 bool first = true;
981
982 if (js->WriteChr('{'))
983 return true;
984
985 for (PJPR pair = jobp->GetFirst(); pair; pair = pair->Next) {
986 if (first)
987 first = false;
988 else if (js->WriteChr(','))
989 return true;
990
991 if (js->WriteChr('"') ||
992 js->WriteStr(pair->Key) ||
993 js->WriteChr('"') ||
994 js->WriteChr(':') ||
995 SerializeValue(pair->Val))
996 return true;
997
998 } // endfor i
999
1000 return js->WriteChr('}');
1001 } // end of SerializeObject
1002
1003 /***********************************************************************/
1004 /* Serialize a JSON Value. */
1005 /***********************************************************************/
SerializeValue(PJVAL jvp)1006 bool JDOC::SerializeValue(PJVAL jvp)
1007 {
1008 char buf[64];
1009 PJAR jap;
1010 PJOB jop;
1011 //PVL vlp;
1012
1013 if ((jap = jvp->GetArray()))
1014 return SerializeArray(jap, false);
1015 else if ((jop = jvp->GetObject()))
1016 return SerializeObject(jop);
1017 //else if (!(vlp = jvp->Val))
1018 // return js->WriteStr("null");
1019 else switch (jvp->DataType) {
1020 case TYPE_BOOL:
1021 return js->WriteStr(jvp->B ? "true" : "false");
1022 case TYPE_STRG:
1023 case TYPE_DTM:
1024 return js->Escape(jvp->Strp);
1025 case TYPE_INTG:
1026 sprintf(buf, "%d", jvp->N);
1027 return js->WriteStr(buf);
1028 case TYPE_BINT:
1029 sprintf(buf, "%lld", jvp->LLn);
1030 return js->WriteStr(buf);
1031 case TYPE_DBL: // dfp to limit to the default number of decimals
1032 sprintf(buf, "%.*f", MY_MIN(jvp->Nd, dfp), jvp->F);
1033 return js->WriteStr(buf);
1034 case TYPE_NULL:
1035 return js->WriteStr("null");
1036 default:
1037 return js->WriteStr("???"); // TODO
1038 } // endswitch Type
1039
1040 strcpy(js->g->Message, "Unrecognized value");
1041 return true;
1042 } // end of SerializeValue
1043
1044 /* -------------------------- Class JOBJECT -------------------------- */
1045
1046 /***********************************************************************/
1047 /* Return the number of pairs in this object. */
1048 /***********************************************************************/
GetSize(bool b)1049 int JOBJECT::GetSize(bool b) {
1050 int n = 0;
1051
1052 for (PJPR jpp = First; jpp; jpp = jpp->Next)
1053 // If b return only non null pairs
1054 if (!b || (jpp->Val && !jpp->Val->IsNull()))
1055 n++;
1056
1057 return n;
1058 } // end of GetSize
1059
1060 /***********************************************************************/
1061 /* Add a new pair to an Object. */
1062 /***********************************************************************/
AddPair(PGLOBAL g,PCSZ key)1063 PJPR JOBJECT::AddPair(PGLOBAL g, PCSZ key)
1064 {
1065 PJPR jpp = (PJPR)PlugSubAlloc(g, NULL, sizeof(JPAIR));
1066
1067 jpp->Key = key;
1068 jpp->Next = NULL;
1069 jpp->Val = NULL;
1070
1071 if (Last)
1072 Last->Next = jpp;
1073 else
1074 First = jpp;
1075
1076 Last = jpp;
1077 return jpp;
1078 } // end of AddPair
1079
1080 /***********************************************************************/
1081 /* Return all keys as an array. */
1082 /***********************************************************************/
GetKeyList(PGLOBAL g)1083 PJAR JOBJECT::GetKeyList(PGLOBAL g)
1084 {
1085 PJAR jarp = new(g) JARRAY();
1086
1087 for (PJPR jpp = First; jpp; jpp = jpp->Next)
1088 jarp->AddArrayValue(g, new(g) JVALUE(g, jpp->Key));
1089
1090 jarp->InitArray(g);
1091 return jarp;
1092 } // end of GetKeyList
1093
1094 /***********************************************************************/
1095 /* Return all values as an array. */
1096 /***********************************************************************/
GetValList(PGLOBAL g)1097 PJAR JOBJECT::GetValList(PGLOBAL g)
1098 {
1099 PJAR jarp = new(g) JARRAY();
1100
1101 for (PJPR jpp = First; jpp; jpp = jpp->Next)
1102 jarp->AddArrayValue(g, jpp->Val);
1103
1104 jarp->InitArray(g);
1105 return jarp;
1106 } // end of GetValList
1107
1108 /***********************************************************************/
1109 /* Get the value corresponding to the given key. */
1110 /***********************************************************************/
GetKeyValue(const char * key)1111 PJVAL JOBJECT::GetKeyValue(const char* key)
1112 {
1113 for (PJPR jp = First; jp; jp = jp->Next)
1114 if (!strcmp(jp->Key, key))
1115 return jp->Val;
1116
1117 return NULL;
1118 } // end of GetValue;
1119
1120 /***********************************************************************/
1121 /* Return the text corresponding to all keys (XML like). */
1122 /***********************************************************************/
GetText(PGLOBAL g,PSTRG text)1123 PSZ JOBJECT::GetText(PGLOBAL g, PSTRG text)
1124 {
1125 if (First) {
1126 bool b;
1127
1128 if (!text) {
1129 text = new(g) STRING(g, 256);
1130 b = true;
1131 } else {
1132 if (text->GetLastChar() != ' ')
1133 text->Append(' ');
1134
1135 b = false;
1136 } // endif text
1137
1138 if (b && !First->Next && !strcmp(First->Key, "$date")) {
1139 int i;
1140 PSZ s;
1141
1142 First->Val->GetText(g, text);
1143 s = text->GetStr();
1144 i = (s[1] == '-' ? 2 : 1);
1145
1146 if (IsNum(s + i)) {
1147 // Date is in milliseconds
1148 int j = text->GetLength();
1149
1150 if (j >= 4 + i) {
1151 s[j - 3] = 0; // Change it to seconds
1152 text->SetLength((uint)strlen(s));
1153 } else
1154 text->Set(" 0");
1155
1156 } // endif text
1157
1158 } else for (PJPR jp = First; jp; jp = jp->Next) {
1159 jp->Val->GetText(g, text);
1160
1161 if (jp->Next)
1162 text->Append(' ');
1163
1164 } // endfor jp
1165
1166 if (b) {
1167 text->Trim();
1168 return text->GetStr();
1169 } // endif b
1170
1171 } // endif First
1172
1173 return NULL;
1174 } // end of GetText;
1175
1176 /***********************************************************************/
1177 /* Merge two objects. */
1178 /***********************************************************************/
Merge(PGLOBAL g,PJSON jsp)1179 bool JOBJECT::Merge(PGLOBAL g, PJSON jsp)
1180 {
1181 if (jsp->GetType() != TYPE_JOB) {
1182 strcpy(g->Message, "Second argument is not an object");
1183 return true;
1184 } // endif Type
1185
1186 PJOB jobp = (PJOB)jsp;
1187
1188 for (PJPR jpp = jobp->First; jpp; jpp = jpp->Next)
1189 SetKeyValue(g, jpp->Val, jpp->Key);
1190
1191 return false;
1192 } // end of Marge;
1193
1194 /***********************************************************************/
1195 /* Set or add a value corresponding to the given key. */
1196 /***********************************************************************/
SetKeyValue(PGLOBAL g,PJVAL jvp,PCSZ key)1197 void JOBJECT::SetKeyValue(PGLOBAL g, PJVAL jvp, PCSZ key)
1198 {
1199 PJPR jp;
1200
1201 for (jp = First; jp; jp = jp->Next)
1202 if (!strcmp(jp->Key, key)) {
1203 jp->Val = jvp;
1204 break;
1205 } // endif key
1206
1207 if (!jp) {
1208 jp = AddPair(g, key);
1209 jp->Val = jvp;
1210 } // endif jp
1211
1212 } // end of SetValue
1213
1214 /***********************************************************************/
1215 /* Delete a value corresponding to the given key. */
1216 /***********************************************************************/
DeleteKey(PCSZ key)1217 void JOBJECT::DeleteKey(PCSZ key)
1218 {
1219 PJPR jp, *pjp = &First;
1220
1221 for (jp = First; jp; jp = jp->Next)
1222 if (!strcmp(jp->Key, key)) {
1223 *pjp = jp->Next;
1224 break;
1225 } else
1226 pjp = &jp->Next;
1227
1228 } // end of DeleteKey
1229
1230 /***********************************************************************/
1231 /* True if void or if all members are nulls. */
1232 /***********************************************************************/
IsNull(void)1233 bool JOBJECT::IsNull(void)
1234 {
1235 for (PJPR jp = First; jp; jp = jp->Next)
1236 if (!jp->Val->IsNull())
1237 return false;
1238
1239 return true;
1240 } // end of IsNull
1241
1242 /* -------------------------- Class JARRAY --------------------------- */
1243
1244 /***********************************************************************/
1245 /* JARRAY constructor. */
1246 /***********************************************************************/
JARRAY(void)1247 JARRAY::JARRAY(void) : JSON()
1248 {
1249 Type = TYPE_JAR;
1250 Size = 0;
1251 Alloc = 0;
1252 First = Last = NULL;
1253 Mvals = NULL;
1254 } // end of JARRAY constructor
1255
1256 /***********************************************************************/
1257 /* Return the number of values in this object. */
1258 /***********************************************************************/
GetSize(bool b)1259 int JARRAY::GetSize(bool b)
1260 {
1261 if (b) {
1262 // Return only non null values
1263 int n = 0;
1264
1265 for (PJVAL jvp = First; jvp; jvp = jvp->Next)
1266 if (!jvp->IsNull())
1267 n++;
1268
1269 return n;
1270 } else
1271 return Size;
1272
1273 } // end of GetSize
1274
1275 /***********************************************************************/
1276 /* Make the array of values from the values list. */
1277 /***********************************************************************/
InitArray(PGLOBAL g)1278 void JARRAY::InitArray(PGLOBAL g)
1279 {
1280 int i;
1281 PJVAL jvp, *pjvp = &First;
1282
1283 for (Size = 0, jvp = First; jvp; jvp = jvp->Next)
1284 if (!jvp->Del)
1285 Size++;
1286
1287 if (Size > Alloc) {
1288 // No need to realloc after deleting values
1289 Mvals = (PJVAL*)PlugSubAlloc(g, NULL, Size * sizeof(PJVAL));
1290 Alloc = Size;
1291 } // endif Size
1292
1293 for (i = 0, jvp = First; jvp; jvp = jvp->Next)
1294 if (!jvp->Del) {
1295 Mvals[i++] = jvp;
1296 pjvp = &jvp->Next;
1297 Last = jvp;
1298 } else
1299 *pjvp = jvp->Next;
1300
1301 } // end of InitArray
1302
1303 /***********************************************************************/
1304 /* Get the Nth value of an Array. */
1305 /***********************************************************************/
GetArrayValue(int i)1306 PJVAL JARRAY::GetArrayValue(int i)
1307 {
1308 if (Mvals && i >= 0 && i < Size)
1309 return Mvals[i];
1310 else if (Mvals && i < 0 && i >= -Size)
1311 return Mvals[Size + i];
1312 else
1313 return NULL;
1314 } // end of GetValue
1315
1316 /***********************************************************************/
1317 /* Add a Value to the Array Value list. */
1318 /***********************************************************************/
AddArrayValue(PGLOBAL g,PJVAL jvp,int * x)1319 PJVAL JARRAY::AddArrayValue(PGLOBAL g, PJVAL jvp, int *x)
1320 {
1321 if (!jvp)
1322 jvp = new(g) JVALUE;
1323
1324 if (x) {
1325 int i = 0, n = *x;
1326 PJVAL jp, *jpp = &First;
1327
1328 for (jp = First; jp && i < n; i++, jp = *(jpp = &jp->Next));
1329
1330 (*jpp) = jvp;
1331
1332 if (!(jvp->Next = jp))
1333 Last = jvp;
1334
1335 } else {
1336 if (!First)
1337 First = jvp;
1338 else if (Last == First)
1339 First->Next = Last = jvp;
1340 else
1341 Last->Next = jvp;
1342
1343 Last = jvp;
1344 Last->Next = NULL;
1345 } // endif x
1346
1347 return jvp;
1348 } // end of AddValue
1349
1350 /***********************************************************************/
1351 /* Merge two arrays. */
1352 /***********************************************************************/
Merge(PGLOBAL g,PJSON jsp)1353 bool JARRAY::Merge(PGLOBAL g, PJSON jsp)
1354 {
1355 if (jsp->GetType() != TYPE_JAR) {
1356 strcpy(g->Message, "Second argument is not an array");
1357 return true;
1358 } // endif Type
1359
1360 PJAR arp = (PJAR)jsp;
1361
1362 for (int i = 0; i < arp->size(); i++)
1363 AddArrayValue(g, arp->GetArrayValue(i));
1364
1365 InitArray(g);
1366 return false;
1367 } // end of Merge
1368
1369 /***********************************************************************/
1370 /* Set the nth Value of the Array Value list or add it. */
1371 /***********************************************************************/
SetArrayValue(PGLOBAL g,PJVAL jvp,int n)1372 void JARRAY::SetArrayValue(PGLOBAL g, PJVAL jvp, int n)
1373 {
1374 int i = 0;
1375 PJVAL jp, *jpp = &First;
1376
1377 for (jp = First; i < n; i++, jp = *(jpp = &jp->Next))
1378 if (!jp)
1379 *jpp = jp = new(g) JVALUE;
1380
1381 *jpp = jvp;
1382 jvp->Next = (jp ? jp->Next : NULL);
1383 } // end of SetValue
1384
1385 /***********************************************************************/
1386 /* Return the text corresponding to all values. */
1387 /***********************************************************************/
GetText(PGLOBAL g,PSTRG text)1388 PSZ JARRAY::GetText(PGLOBAL g, PSTRG text)
1389 {
1390 if (First) {
1391 bool b;
1392 PJVAL jp;
1393
1394 if (!text) {
1395 text = new(g) STRING(g, 256);
1396 b = true;
1397 } else {
1398 if (text->GetLastChar() != ' ')
1399 text->Append(" (");
1400 else
1401 text->Append('(');
1402
1403 b = false;
1404 }
1405
1406 for (jp = First; jp; jp = jp->Next) {
1407 jp->GetText(g, text);
1408
1409 if (jp->Next)
1410 text->Append(", ");
1411 else if (!b)
1412 text->Append(')');
1413
1414 } // endfor jp
1415
1416 if (b) {
1417 text->Trim();
1418 return text->GetStr();
1419 } // endif b
1420
1421 } // endif First
1422
1423 return NULL;
1424 } // end of GetText;
1425
1426 /***********************************************************************/
1427 /* Delete a Value from the Arrays Value list. */
1428 /***********************************************************************/
DeleteValue(int n)1429 bool JARRAY::DeleteValue(int n)
1430 {
1431 PJVAL jvp = GetArrayValue(n);
1432
1433 if (jvp) {
1434 jvp->Del = true;
1435 return false;
1436 } else
1437 return true;
1438
1439 } // end of DeleteValue
1440
1441 /***********************************************************************/
1442 /* True if void or if all members are nulls. */
1443 /***********************************************************************/
IsNull(void)1444 bool JARRAY::IsNull(void)
1445 {
1446 for (int i = 0; i < Size; i++)
1447 if (!Mvals[i]->IsNull())
1448 return false;
1449
1450 return true;
1451 } // end of IsNull
1452
1453 /* -------------------------- Class JVALUE- -------------------------- */
1454
1455 /***********************************************************************/
1456 /* Constructor for a JVALUE. */
1457 /***********************************************************************/
JVALUE(PJSON jsp)1458 JVALUE::JVALUE(PJSON jsp) : JSON()
1459 {
1460 if (jsp && jsp->GetType() == TYPE_JVAL) {
1461 PJVAL jvp = (PJVAL)jsp;
1462
1463 // Val = ((PJVAL)jsp)->GetVal();
1464 if (jvp->DataType == TYPE_JSON) {
1465 Jsp = jvp->GetJsp();
1466 DataType = TYPE_JSON;
1467 Nd = 0;
1468 } else {
1469 LLn = jvp->LLn; // Must be LLn on 32 bit machines
1470 Nd = jvp->Nd;
1471 DataType = jvp->DataType;
1472 } // endelse Jsp
1473
1474 } else {
1475 Jsp = jsp;
1476 // Val = NULL;
1477 DataType = Jsp ? TYPE_JSON : TYPE_NULL;
1478 Nd = 0;
1479 } // endif Type
1480
1481 Next = NULL;
1482 Del = false;
1483 Type = TYPE_JVAL;
1484 } // end of JVALUE constructor
1485
1486 #if 0
1487 /***********************************************************************/
1488 /* Constructor for a JVALUE with a given string or numeric value. */
1489 /***********************************************************************/
1490 JVALUE::JVALUE(PGLOBAL g, PVL vlp) : JSON()
1491 {
1492 Jsp = NULL;
1493 Val = vlp;
1494 Next = NULL;
1495 Del = false;
1496 Type = TYPE_JVAL;
1497 } // end of JVALUE constructor
1498 #endif // 0
1499
1500 /***********************************************************************/
1501 /* Constructor for a JVALUE with a given string or numeric value. */
1502 /***********************************************************************/
JVALUE(PGLOBAL g,PVAL valp)1503 JVALUE::JVALUE(PGLOBAL g, PVAL valp) : JSON() {
1504 Jsp = NULL;
1505 //Val = NULL;
1506 SetValue(g, valp);
1507 Next = NULL;
1508 Del = false;
1509 Type = TYPE_JVAL;
1510 } // end of JVALUE constructor
1511
1512 /***********************************************************************/
1513 /* Constructor for a given string. */
1514 /***********************************************************************/
JVALUE(PGLOBAL g,PCSZ strp)1515 JVALUE::JVALUE(PGLOBAL g, PCSZ strp) : JSON()
1516 {
1517 Jsp = NULL;
1518 //Val = AllocVal(g, TYPE_STRG);
1519 Strp = (char*)strp;
1520 DataType = TYPE_STRG;
1521 Nd = 0;
1522 Next = NULL;
1523 Del = false;
1524 Type = TYPE_JVAL;
1525 } // end of JVALUE constructor
1526
1527 /***********************************************************************/
1528 /* Set or reset all Jvalue members. */
1529 /***********************************************************************/
Clear(void)1530 void JVALUE::Clear(void)
1531 {
1532 Jsp = NULL;
1533 Next = NULL;
1534 Type = TYPE_JVAL;
1535 Del = false;
1536 Nd = 0;
1537 DataType = TYPE_NULL;
1538 } // end of Clear
1539
1540 /***********************************************************************/
1541 /* Returns the type of the Value's value. */
1542 /***********************************************************************/
GetValType(void)1543 JTYP JVALUE::GetValType(void)
1544 {
1545 if (DataType == TYPE_JSON)
1546 return Jsp->GetType();
1547 //else if (Val)
1548 // return Val->Type;
1549 else
1550 return DataType;
1551
1552 } // end of GetValType
1553
1554 /***********************************************************************/
1555 /* Return the Value's Object value. */
1556 /***********************************************************************/
GetObject(void)1557 PJOB JVALUE::GetObject(void)
1558 {
1559 if (DataType == TYPE_JSON && Jsp->GetType() == TYPE_JOB)
1560 return (PJOB)Jsp;
1561
1562 return NULL;
1563 } // end of GetObject
1564
1565 /***********************************************************************/
1566 /* Return the Value's Array value. */
1567 /***********************************************************************/
GetArray(void)1568 PJAR JVALUE::GetArray(void)
1569 {
1570 if (DataType == TYPE_JSON && Jsp->GetType() == TYPE_JAR)
1571 return (PJAR)Jsp;
1572
1573 return NULL;
1574 } // end of GetArray
1575
1576 /***********************************************************************/
1577 /* Return the Value's as a Value class. */
1578 /***********************************************************************/
GetValue(PGLOBAL g)1579 PVAL JVALUE::GetValue(PGLOBAL g)
1580 {
1581 PVAL valp = NULL;
1582
1583 if (DataType != TYPE_JSON)
1584 {
1585 if (DataType == TYPE_STRG)
1586 valp = AllocateValue(g, Strp, DataType, Nd);
1587 else
1588 valp = AllocateValue(g, &LLn, DataType, Nd);
1589 }
1590
1591 return valp;
1592 } // end of GetValue
1593
1594 /***********************************************************************/
1595 /* Return the Value's Integer value. */
1596 /***********************************************************************/
GetInteger(void)1597 int JVALUE::GetInteger(void) {
1598 int n;
1599
1600 switch (DataType) {
1601 case TYPE_INTG: n = N; break;
1602 case TYPE_DBL: n = (int)F; break;
1603 case TYPE_DTM:
1604 case TYPE_STRG: n = atoi(Strp); break;
1605 case TYPE_BOOL: n = (B) ? 1 : 0; break;
1606 case TYPE_BINT: n = (int)LLn; break;
1607 default:
1608 n = 0;
1609 } // endswitch Type
1610
1611 return n;
1612 } // end of GetInteger
1613
1614 /***********************************************************************/
1615 /* Return the Value's Big integer value. */
1616 /***********************************************************************/
GetBigint(void)1617 long long JVALUE::GetBigint(void)
1618 {
1619 long long lln;
1620
1621 switch (DataType) {
1622 case TYPE_BINT: lln = LLn; break;
1623 case TYPE_INTG: lln = (long long)N; break;
1624 case TYPE_DBL: lln = (long long)F; break;
1625 case TYPE_DTM:
1626 case TYPE_STRG: lln = atoll(Strp); break;
1627 case TYPE_BOOL: lln = (B) ? 1 : 0; break;
1628 default:
1629 lln = 0;
1630 } // endswitch Type
1631
1632 return lln;
1633 } // end of GetBigint
1634
1635 /***********************************************************************/
1636 /* Return the Value's Double value. */
1637 /***********************************************************************/
GetFloat(void)1638 double JVALUE::GetFloat(void)
1639 {
1640 double d;
1641
1642 switch (DataType) {
1643 case TYPE_DBL: d = F; break;
1644 case TYPE_BINT: d = (double)LLn; break;
1645 case TYPE_INTG: d = (double)N; break;
1646 case TYPE_DTM:
1647 case TYPE_STRG: d = atof(Strp); break;
1648 case TYPE_BOOL: d = (B) ? 1.0 : 0.0; break;
1649 default:
1650 d = 0.0;
1651 } // endswitch Type
1652
1653 return d;
1654 } // end of GetFloat
1655
1656 /***********************************************************************/
1657 /* Return the Value's String value. */
1658 /***********************************************************************/
GetString(PGLOBAL g,char * buff)1659 PSZ JVALUE::GetString(PGLOBAL g, char *buff)
1660 {
1661 char buf[32];
1662 char *p = (buff) ? buff : buf;
1663
1664 switch (DataType) {
1665 case TYPE_DTM:
1666 case TYPE_STRG:
1667 p = Strp;
1668 break;
1669 case TYPE_INTG:
1670 sprintf(p, "%d", N);
1671 break;
1672 case TYPE_BINT:
1673 sprintf(p, "%lld", LLn);
1674 break;
1675 case TYPE_DBL:
1676 sprintf(p, "%.*lf", Nd, F);
1677 break;
1678 case TYPE_BOOL:
1679 p = (char*)((B) ? "true" : "false");
1680 break;
1681 case TYPE_NULL:
1682 p = (char*)"null";
1683 break;
1684 default:
1685 p = NULL;
1686 } // endswitch Type
1687
1688
1689 return (p == buf) ? (char*)PlugDup(g, buf) : p;
1690 } // end of GetString
1691
1692 /***********************************************************************/
1693 /* Return the Value's String value. */
1694 /***********************************************************************/
GetText(PGLOBAL g,PSTRG text)1695 PSZ JVALUE::GetText(PGLOBAL g, PSTRG text)
1696 {
1697 if (DataType == TYPE_JSON)
1698 return Jsp->GetText(g, text);
1699
1700 char buff[32];
1701 PSZ s = (DataType == TYPE_NULL) ? NULL : GetString(g, buff);
1702
1703 if (s)
1704 text->Append(s);
1705 else if (GetJsonNull())
1706 text->Append(GetJsonNull());
1707
1708 return NULL;
1709 } // end of GetText
1710
SetValue(PJSON jsp)1711 void JVALUE::SetValue(PJSON jsp)
1712 {
1713 if (DataType == TYPE_JSON && jsp->GetType() == TYPE_JVAL) {
1714 Jsp = jsp->GetJsp();
1715 Nd = ((PJVAL)jsp)->Nd;
1716 DataType = ((PJVAL)jsp)->DataType;
1717 // Val = ((PJVAL)jsp)->GetVal();
1718 } else {
1719 Jsp = jsp;
1720 DataType = TYPE_JSON;
1721 } // endif Type
1722
1723 } // end of SetValue;
1724
SetValue(PGLOBAL g,PVAL valp)1725 void JVALUE::SetValue(PGLOBAL g, PVAL valp)
1726 {
1727 //if (!Val)
1728 // Val = AllocVal(g, TYPE_VAL);
1729
1730 if (!valp || valp->IsNull()) {
1731 DataType = TYPE_NULL;
1732 } else switch (valp->GetType()) {
1733 case TYPE_DATE:
1734 if (((DTVAL*)valp)->IsFormatted())
1735 Strp = PlugDup(g, valp->GetCharValue());
1736 else {
1737 char buf[32];
1738
1739 Strp = PlugDup(g, valp->GetCharString(buf));
1740 } // endif Formatted
1741
1742 DataType = TYPE_DTM;
1743 break;
1744 case TYPE_STRING:
1745 Strp = PlugDup(g, valp->GetCharValue());
1746 DataType = TYPE_STRG;
1747 break;
1748 case TYPE_DOUBLE:
1749 case TYPE_DECIM:
1750 F = valp->GetFloatValue();
1751
1752 if (IsTypeNum(valp->GetType()))
1753 Nd = valp->GetValPrec();
1754
1755 DataType = TYPE_DBL;
1756 break;
1757 case TYPE_TINY:
1758 B = valp->GetTinyValue() != 0;
1759 DataType = TYPE_BOOL;
1760 break;
1761 case TYPE_INT:
1762 N = valp->GetIntValue();
1763 DataType = TYPE_INTG;
1764 break;
1765 case TYPE_BIGINT:
1766 LLn = valp->GetBigintValue();
1767 DataType = TYPE_BINT;
1768 break;
1769 default:
1770 sprintf(g->Message, "Unsupported typ %d\n", valp->GetType());
1771 throw(777);
1772 } // endswitch Type
1773
1774 } // end of SetValue
1775
1776 /***********************************************************************/
1777 /* Set the Value's value as the given integer. */
1778 /***********************************************************************/
SetInteger(PGLOBAL g,int n)1779 void JVALUE::SetInteger(PGLOBAL g, int n)
1780 {
1781 N = n;
1782 DataType = TYPE_INTG;
1783 } // end of SetInteger
1784
1785 /***********************************************************************/
1786 /* Set the Value's Boolean value as a tiny integer. */
1787 /***********************************************************************/
SetBool(PGLOBAL g,bool b)1788 void JVALUE::SetBool(PGLOBAL g, bool b)
1789 {
1790 B = b;
1791 DataType = TYPE_BOOL;
1792 } // end of SetTiny
1793
1794 /***********************************************************************/
1795 /* Set the Value's value as the given big integer. */
1796 /***********************************************************************/
SetBigint(PGLOBAL g,long long ll)1797 void JVALUE::SetBigint(PGLOBAL g, long long ll)
1798 {
1799 LLn = ll;
1800 DataType = TYPE_BINT;
1801 } // end of SetBigint
1802
1803 /***********************************************************************/
1804 /* Set the Value's value as the given DOUBLE. */
1805 /***********************************************************************/
SetFloat(PGLOBAL g,double f)1806 void JVALUE::SetFloat(PGLOBAL g, double f)
1807 {
1808 F = f;
1809 Nd = GetDefaultPrec();
1810 DataType = TYPE_DBL;
1811 } // end of SetFloat
1812
1813 /***********************************************************************/
1814 /* Set the Value's value as the given string. */
1815 /***********************************************************************/
SetString(PGLOBAL g,PSZ s,int ci)1816 void JVALUE::SetString(PGLOBAL g, PSZ s, int ci)
1817 {
1818 Strp = s;
1819 Nd = ci;
1820 DataType = TYPE_STRG;
1821 } // end of SetString
1822
1823 /***********************************************************************/
1824 /* True when its JSON or normal value is null. */
1825 /***********************************************************************/
IsNull(void)1826 bool JVALUE::IsNull(void)
1827 {
1828 return (DataType == TYPE_JSON) ? Jsp->IsNull() : DataType == TYPE_NULL;
1829 } // end of IsNull
1830
1831
1832 /* ---------------------------- Class SWAP --------------------------- */
1833
1834 /***********************************************************************/
1835 /* Replace all pointers by offsets or the opposite. */
1836 /***********************************************************************/
SwapJson(PJSON jsp,bool move)1837 void SWAP::SwapJson(PJSON jsp, bool move)
1838 {
1839 if (move)
1840 MoffJson(jsp);
1841 else
1842 MptrJson((PJSON)MakeOff(Base, jsp));
1843
1844 return;
1845 } // end of SwapJson
1846
1847 /***********************************************************************/
1848 /* Replace all pointers by offsets. */
1849 /***********************************************************************/
MoffJson(PJSON jsp)1850 size_t SWAP::MoffJson(PJSON jsp) {
1851 size_t res = 0;
1852
1853 if (jsp)
1854 switch (jsp->Type) {
1855 case TYPE_JAR:
1856 res = MoffArray((PJAR)jsp);
1857 break;
1858 case TYPE_JOB:
1859 res = MoffObject((PJOB)jsp);
1860 break;
1861 case TYPE_JVAL:
1862 res = MoffJValue((PJVAL)jsp);
1863 break;
1864 default:
1865 throw "Invalid json tree";
1866 } // endswitch Type
1867
1868 return res;
1869 } // end of MoffJson
1870
1871 /***********************************************************************/
1872 /* Replace all array pointers by offsets. */
1873 /***********************************************************************/
MoffArray(PJAR jarp)1874 size_t SWAP::MoffArray(PJAR jarp)
1875 {
1876 if (jarp->First) {
1877 for (int i = 0; i < jarp->Size; i++)
1878 jarp->Mvals[i] = (PJVAL)MakeOff(Base, jarp->Mvals[i]);
1879
1880 jarp->Mvals = (PJVAL*)MakeOff(Base, jarp->Mvals);
1881 jarp->First = (PJVAL)MoffJValue(jarp->First);
1882 jarp->Last = (PJVAL)MakeOff(Base, jarp->Last);
1883 } // endif First
1884
1885 return MakeOff(Base, jarp);
1886 } // end of MoffArray
1887
1888 /***********************************************************************/
1889 /* Replace all object pointers by offsets. */
1890 /***********************************************************************/
MoffObject(PJOB jobp)1891 size_t SWAP::MoffObject(PJOB jobp) {
1892 if (jobp->First) {
1893 jobp->First = (PJPR)MoffPair(jobp->First);
1894 jobp->Last = (PJPR)MakeOff(Base, jobp->Last);
1895 } // endif First
1896
1897 return MakeOff(Base, jobp);
1898 } // end of MoffObject
1899
1900 /***********************************************************************/
1901 /* Replace all pair pointers by offsets. */
1902 /***********************************************************************/
MoffPair(PJPR jpp)1903 size_t SWAP::MoffPair(PJPR jpp) {
1904 jpp->Key = (PCSZ)MakeOff(Base, (void*)jpp->Key);
1905
1906 if (jpp->Val)
1907 jpp->Val = (PJVAL)MoffJValue(jpp->Val);
1908
1909 if (jpp->Next)
1910 jpp->Next = (PJPR)MoffPair(jpp->Next);
1911
1912 return MakeOff(Base, jpp);
1913 } // end of MoffPair
1914
1915 /***********************************************************************/
1916 /* Replace all jason value pointers by offsets. */
1917 /***********************************************************************/
MoffJValue(PJVAL jvp)1918 size_t SWAP::MoffJValue(PJVAL jvp) {
1919 if (!jvp->Del) {
1920 if (jvp->DataType == TYPE_JSON)
1921 jvp->Jsp = (PJSON)MoffJson(jvp->Jsp);
1922 else if (jvp->DataType == TYPE_STRG)
1923 jvp->Strp = (PSZ)MakeOff(Base, (jvp->Strp));
1924
1925 // if (jvp->Val)
1926 // jvp->Val = (PVL)MoffVal(jvp->Val);
1927
1928 } // endif Del
1929
1930 if (jvp->Next)
1931 jvp->Next = (PJVAL)MoffJValue(jvp->Next);
1932
1933 return MakeOff(Base, jvp);
1934 } // end of MoffJValue
1935
1936 #if 0
1937 /***********************************************************************/
1938 /* Replace string pointers by offset. */
1939 /***********************************************************************/
1940 size_t SWAP::MoffVal(PVL vlp) {
1941 if (vlp->Type == TYPE_STRG)
1942 vlp->Strp = (PSZ)MakeOff(Base, (vlp->Strp));
1943
1944 return MakeOff(Base, vlp);
1945 } // end of MoffVal
1946 #endif // 0
1947
1948 /***********************************************************************/
1949 /* Replace all offsets by pointers. */
1950 /***********************************************************************/
MptrJson(PJSON ojp)1951 PJSON SWAP::MptrJson(PJSON ojp) { // ojp is an offset
1952 PJSON jsp = (PJSON)MakePtr(Base, (size_t)ojp);
1953
1954 if (ojp)
1955 switch (jsp->Type) {
1956 case TYPE_JAR:
1957 jsp = MptrArray((PJAR)ojp);
1958 break;
1959 case TYPE_JOB:
1960 jsp = MptrObject((PJOB)ojp);
1961 break;
1962 case TYPE_JVAL:
1963 jsp = MptrJValue((PJVAL)ojp);
1964 break;
1965 default:
1966 throw "Invalid json tree";
1967 } // endswitch Type
1968
1969 return jsp;
1970 } // end of MptrJson
1971
1972 /***********************************************************************/
1973 /* Replace all array offsets by pointers. */
1974 /***********************************************************************/
MptrArray(PJAR ojar)1975 PJAR SWAP::MptrArray(PJAR ojar) {
1976 PJAR jarp = (PJAR)MakePtr(Base, (size_t)ojar);
1977
1978 jarp = (PJAR)new((long long)jarp) JARRAY(0);
1979
1980 if (jarp->First) {
1981 jarp->Mvals = (PJVAL*)MakePtr(Base, (size_t)jarp->Mvals);
1982
1983 for (int i = 0; i < jarp->Size; i++)
1984 jarp->Mvals[i] = (PJVAL)MakePtr(Base, (size_t)jarp->Mvals[i]);
1985
1986 jarp->First = (PJVAL)MptrJValue(jarp->First);
1987 jarp->Last = (PJVAL)MakePtr(Base, (size_t)jarp->Last);
1988 } // endif First
1989
1990 return jarp;
1991 } // end of MptrArray
1992
1993 /***********************************************************************/
1994 /* Replace all object offsets by pointers. */
1995 /***********************************************************************/
MptrObject(PJOB ojob)1996 PJOB SWAP::MptrObject(PJOB ojob) {
1997 PJOB jobp = (PJOB)MakePtr(Base, (size_t)ojob);
1998
1999 jobp = (PJOB)new((long long)jobp) JOBJECT(0);
2000
2001 if (jobp->First) {
2002 jobp->First = (PJPR)MptrPair(jobp->First);
2003 jobp->Last = (PJPR)MakePtr(Base, (size_t)jobp->Last);
2004 } // endif First
2005
2006 return jobp;
2007 } // end of MptrObject
2008
2009 /***********************************************************************/
2010 /* Replace all pair offsets by pointers. */
2011 /***********************************************************************/
MptrPair(PJPR ojp)2012 PJPR SWAP::MptrPair(PJPR ojp) {
2013 PJPR jpp = (PJPR)MakePtr(Base, (size_t)ojp);
2014
2015 jpp->Key = (PCSZ)MakePtr(Base, (size_t)jpp->Key);
2016
2017 if (jpp->Val)
2018 jpp->Val = (PJVAL)MptrJValue(jpp->Val);
2019
2020 if (jpp->Next)
2021 jpp->Next = (PJPR)MptrPair(jpp->Next);
2022
2023 return jpp;
2024 } // end of MptrPair
2025
2026 /***********************************************************************/
2027 /* Replace all value offsets by pointers. */
2028 /***********************************************************************/
MptrJValue(PJVAL ojv)2029 PJVAL SWAP::MptrJValue(PJVAL ojv) {
2030 PJVAL jvp = (PJVAL)MakePtr(Base, (size_t)ojv);
2031
2032 jvp = (PJVAL)new((long long)jvp) JVALUE(0);
2033
2034 if (!jvp->Del) {
2035 if (jvp->DataType == TYPE_JSON)
2036 jvp->Jsp = (PJSON)MptrJson(jvp->Jsp);
2037 else if (jvp->DataType == TYPE_STRG)
2038 jvp->Strp = (PSZ)MakePtr(Base, (size_t)jvp->Strp);
2039
2040 // if (jvp->Val)
2041 // jvp->Val = (PVL)MptrVal(jvp->Val);
2042
2043 } // endif Del
2044
2045 if (jvp->Next)
2046 jvp->Next = (PJVAL)MptrJValue(jvp->Next);
2047
2048 return jvp;
2049 } // end of MptrJValue
2050
2051 #if 0
2052 /***********************************************************************/
2053 /* Replace string offsets by a pointer. */
2054 /***********************************************************************/
2055 PVL SWAP::MptrVal(PVL ovl) {
2056 PVL vlp = (PVL)MakePtr(Base, (size_t)ovl);
2057
2058 if (vlp->Type == TYPE_STRG)
2059 vlp->Strp = (PSZ)MakePtr(Base, (size_t)vlp->Strp);
2060
2061 return vlp;
2062 } // end of MptrValue
2063 #endif // 0
2064