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     if (DataType == TYPE_STRG)
1585       valp = AllocateValue(g, Strp, DataType, Nd);
1586     else
1587       valp = AllocateValue(g, &LLn, DataType, Nd);
1588 
1589   return valp;
1590 } // end of GetValue
1591 
1592 /***********************************************************************/
1593 /* Return the Value's Integer value.                                   */
1594 /***********************************************************************/
GetInteger(void)1595 int JVALUE::GetInteger(void) {
1596   int n;
1597 
1598   switch (DataType) {
1599   case TYPE_INTG: n = N;           break;
1600   case TYPE_DBL:  n = (int)F;      break;
1601   case TYPE_DTM:
1602   case TYPE_STRG: n = atoi(Strp);  break;
1603   case TYPE_BOOL: n = (B) ? 1 : 0; break;
1604   case TYPE_BINT: n = (int)LLn;    break;
1605   default:
1606     n = 0;
1607   } // endswitch Type
1608 
1609   return n;
1610 } // end of GetInteger
1611 
1612 /***********************************************************************/
1613 /* Return the Value's Big integer value.                               */
1614 /***********************************************************************/
GetBigint(void)1615 long long JVALUE::GetBigint(void)
1616 {
1617   long long lln;
1618 
1619   switch (DataType) {
1620   case TYPE_BINT: lln = LLn;          break;
1621   case TYPE_INTG: lln = (long long)N; break;
1622   case TYPE_DBL:  lln = (long long)F; break;
1623   case TYPE_DTM:
1624   case TYPE_STRG: lln = atoll(Strp);  break;
1625   case TYPE_BOOL: lln = (B) ? 1 : 0;  break;
1626   default:
1627     lln = 0;
1628   } // endswitch Type
1629 
1630   return lln;
1631 } // end of GetBigint
1632 
1633 /***********************************************************************/
1634 /* Return the Value's Double value.                                    */
1635 /***********************************************************************/
GetFloat(void)1636 double JVALUE::GetFloat(void)
1637 {
1638   double d;
1639 
1640   switch (DataType) {
1641   case TYPE_DBL:  d = F;               break;
1642   case TYPE_BINT: d = (double)LLn;     break;
1643   case TYPE_INTG: d = (double)N;       break;
1644   case TYPE_DTM:
1645   case TYPE_STRG: d = atof(Strp);      break;
1646   case TYPE_BOOL: d = (B) ? 1.0 : 0.0; break;
1647   default:
1648     d = 0.0;
1649   } // endswitch Type
1650 
1651   return d;
1652 } // end of GetFloat
1653 
1654 /***********************************************************************/
1655 /* Return the Value's String value.                                    */
1656 /***********************************************************************/
GetString(PGLOBAL g,char * buff)1657 PSZ JVALUE::GetString(PGLOBAL g, char *buff)
1658 {
1659   char  buf[32];
1660   char *p = (buff) ? buff : buf;
1661 
1662   switch (DataType) {
1663   case TYPE_DTM:
1664   case TYPE_STRG:
1665     p = Strp;
1666     break;
1667   case TYPE_INTG:
1668     sprintf(p, "%d", N);
1669     break;
1670   case TYPE_BINT:
1671     sprintf(p, "%lld", LLn);
1672     break;
1673   case TYPE_DBL:
1674     sprintf(p, "%.*lf", Nd, F);
1675     break;
1676   case TYPE_BOOL:
1677     p = (char*)((B) ? "true" : "false");
1678     break;
1679   case TYPE_NULL:
1680     p = (char*)"null";
1681     break;
1682   default:
1683     p = NULL;
1684   } // endswitch Type
1685 
1686 
1687   return (p == buf) ? (char*)PlugDup(g, buf) : p;
1688 } // end of GetString
1689 
1690 /***********************************************************************/
1691 /* Return the Value's String value.                                    */
1692 /***********************************************************************/
GetText(PGLOBAL g,PSTRG text)1693 PSZ JVALUE::GetText(PGLOBAL g, PSTRG text)
1694 {
1695   if (DataType == TYPE_JSON)
1696     return Jsp->GetText(g, text);
1697 
1698 	char buff[32];
1699   PSZ  s = (DataType == TYPE_NULL) ? NULL : GetString(g, buff);
1700 
1701 	if (s)
1702 		text->Append(s);
1703 	else if (GetJsonNull())
1704 		text->Append(GetJsonNull());
1705 
1706   return NULL;
1707 } // end of GetText
1708 
SetValue(PJSON jsp)1709 void JVALUE::SetValue(PJSON jsp)
1710 {
1711   if (DataType == TYPE_JSON && jsp->GetType() == TYPE_JVAL) {
1712     Jsp = jsp->GetJsp();
1713     Nd = ((PJVAL)jsp)->Nd;
1714     DataType = ((PJVAL)jsp)->DataType;
1715     //  Val = ((PJVAL)jsp)->GetVal();
1716   } else {
1717     Jsp = jsp;
1718     DataType = TYPE_JSON;
1719   } // endif Type
1720 
1721 } // end of SetValue;
1722 
SetValue(PGLOBAL g,PVAL valp)1723 void JVALUE::SetValue(PGLOBAL g, PVAL valp)
1724 {
1725 //if (!Val)
1726 //  Val = AllocVal(g, TYPE_VAL);
1727 
1728   if (!valp || valp->IsNull()) {
1729     DataType = TYPE_NULL;
1730   } else switch (valp->GetType()) {
1731   case TYPE_DATE:
1732 		if (((DTVAL*)valp)->IsFormatted())
1733 			Strp = PlugDup(g, valp->GetCharValue());
1734 		else {
1735 			char buf[32];
1736 
1737 			Strp = PlugDup(g, valp->GetCharString(buf));
1738 		}	// endif Formatted
1739 
1740 		DataType = TYPE_DTM;
1741 		break;
1742 	case TYPE_STRING:
1743     Strp = PlugDup(g, valp->GetCharValue());
1744     DataType = TYPE_STRG;
1745     break;
1746   case TYPE_DOUBLE:
1747   case TYPE_DECIM:
1748     F = valp->GetFloatValue();
1749 
1750     if (IsTypeNum(valp->GetType()))
1751       Nd = valp->GetValPrec();
1752 
1753     DataType = TYPE_DBL;
1754     break;
1755   case TYPE_TINY:
1756     B = valp->GetTinyValue() != 0;
1757     DataType = TYPE_BOOL;
1758   case TYPE_INT:
1759     N = valp->GetIntValue();
1760     DataType = TYPE_INTG;
1761     break;
1762   case TYPE_BIGINT:
1763     LLn = valp->GetBigintValue();
1764     DataType = TYPE_BINT;
1765     break;
1766   default:
1767     sprintf(g->Message, "Unsupported typ %d\n", valp->GetType());
1768     throw(777);
1769   } // endswitch Type
1770 
1771 } // end of SetValue
1772 
1773 /***********************************************************************/
1774 /* Set the Value's value as the given integer.                         */
1775 /***********************************************************************/
SetInteger(PGLOBAL g,int n)1776 void JVALUE::SetInteger(PGLOBAL g, int n)
1777 {
1778   N = n;
1779   DataType = TYPE_INTG;
1780 } // end of SetInteger
1781 
1782 /***********************************************************************/
1783 /* Set the Value's Boolean value as a tiny integer.                    */
1784 /***********************************************************************/
SetBool(PGLOBAL g,bool b)1785 void JVALUE::SetBool(PGLOBAL g, bool b)
1786 {
1787   B = b;
1788   DataType = TYPE_BOOL;
1789 } // end of SetTiny
1790 
1791 /***********************************************************************/
1792 /* Set the Value's value as the given big integer.                     */
1793 /***********************************************************************/
SetBigint(PGLOBAL g,long long ll)1794 void JVALUE::SetBigint(PGLOBAL g, long long ll)
1795 {
1796   LLn = ll;
1797   DataType = TYPE_BINT;
1798 } // end of SetBigint
1799 
1800 /***********************************************************************/
1801 /* Set the Value's value as the given DOUBLE.                          */
1802 /***********************************************************************/
SetFloat(PGLOBAL g,double f)1803 void JVALUE::SetFloat(PGLOBAL g, double f)
1804 {
1805   F = f;
1806   Nd = GetDefaultPrec();
1807   DataType = TYPE_DBL;
1808 } // end of SetFloat
1809 
1810 /***********************************************************************/
1811 /* Set the Value's value as the given string.                          */
1812 /***********************************************************************/
SetString(PGLOBAL g,PSZ s,int ci)1813 void JVALUE::SetString(PGLOBAL g, PSZ s, int ci)
1814 {
1815   Strp = s;
1816   Nd = ci;
1817   DataType = TYPE_STRG;
1818 } // end of SetString
1819 
1820 /***********************************************************************/
1821 /* True when its JSON or normal value is null.                         */
1822 /***********************************************************************/
IsNull(void)1823 bool JVALUE::IsNull(void)
1824 {
1825   return (DataType == TYPE_JSON) ? Jsp->IsNull() : DataType == TYPE_NULL;
1826 } // end of IsNull
1827 
1828 
1829 /* ---------------------------- Class SWAP --------------------------- */
1830 
1831 /***********************************************************************/
1832 /* Replace all pointers by offsets or the opposite.                    */
1833 /***********************************************************************/
SwapJson(PJSON jsp,bool move)1834 void SWAP::SwapJson(PJSON jsp, bool move)
1835 {
1836   if (move)
1837     MoffJson(jsp);
1838   else
1839     MptrJson((PJSON)MakeOff(Base, jsp));
1840 
1841   return;
1842 } // end of SwapJson
1843 
1844 /***********************************************************************/
1845 /* Replace all pointers by offsets.                                    */
1846 /***********************************************************************/
MoffJson(PJSON jsp)1847 size_t SWAP::MoffJson(PJSON jsp) {
1848   size_t res = 0;
1849 
1850   if (jsp)
1851     switch (jsp->Type) {
1852     case TYPE_JAR:
1853       res = MoffArray((PJAR)jsp);
1854       break;
1855     case TYPE_JOB:
1856       res = MoffObject((PJOB)jsp);
1857       break;
1858     case TYPE_JVAL:
1859       res = MoffJValue((PJVAL)jsp);
1860       break;
1861     default:
1862       throw "Invalid json tree";
1863     } // endswitch Type
1864 
1865   return res;
1866 } // end of MoffJson
1867 
1868 /***********************************************************************/
1869 /* Replace all array pointers by offsets.                              */
1870 /***********************************************************************/
MoffArray(PJAR jarp)1871 size_t SWAP::MoffArray(PJAR jarp)
1872 {
1873   if (jarp->First) {
1874     for (int i = 0; i < jarp->Size; i++)
1875       jarp->Mvals[i] = (PJVAL)MakeOff(Base, jarp->Mvals[i]);
1876 
1877     jarp->Mvals = (PJVAL*)MakeOff(Base, jarp->Mvals);
1878     jarp->First = (PJVAL)MoffJValue(jarp->First);
1879     jarp->Last = (PJVAL)MakeOff(Base, jarp->Last);
1880   } // endif First
1881 
1882   return MakeOff(Base, jarp);
1883 } // end of MoffArray
1884 
1885 /***********************************************************************/
1886 /* Replace all object pointers by offsets.                             */
1887 /***********************************************************************/
MoffObject(PJOB jobp)1888 size_t SWAP::MoffObject(PJOB jobp) {
1889   if (jobp->First) {
1890     jobp->First = (PJPR)MoffPair(jobp->First);
1891     jobp->Last = (PJPR)MakeOff(Base, jobp->Last);
1892   } // endif First
1893 
1894   return MakeOff(Base, jobp);
1895 } // end of MoffObject
1896 
1897 /***********************************************************************/
1898 /* Replace all pair pointers by offsets.                               */
1899 /***********************************************************************/
MoffPair(PJPR jpp)1900 size_t SWAP::MoffPair(PJPR jpp) {
1901   jpp->Key = (PCSZ)MakeOff(Base, (void*)jpp->Key);
1902 
1903   if (jpp->Val)
1904     jpp->Val = (PJVAL)MoffJValue(jpp->Val);
1905 
1906   if (jpp->Next)
1907     jpp->Next = (PJPR)MoffPair(jpp->Next);
1908 
1909   return MakeOff(Base, jpp);
1910 } // end of MoffPair
1911 
1912 /***********************************************************************/
1913 /* Replace all jason value pointers by offsets.                        */
1914 /***********************************************************************/
MoffJValue(PJVAL jvp)1915 size_t SWAP::MoffJValue(PJVAL jvp) {
1916   if (!jvp->Del) {
1917     if (jvp->DataType == TYPE_JSON)
1918       jvp->Jsp = (PJSON)MoffJson(jvp->Jsp);
1919     else if (jvp->DataType == TYPE_STRG)
1920       jvp->Strp = (PSZ)MakeOff(Base, (jvp->Strp));
1921 
1922 //  if (jvp->Val)
1923 //    jvp->Val = (PVL)MoffVal(jvp->Val);
1924 
1925   } // endif Del
1926 
1927   if (jvp->Next)
1928     jvp->Next = (PJVAL)MoffJValue(jvp->Next);
1929 
1930   return MakeOff(Base, jvp);
1931 } // end of MoffJValue
1932 
1933 #if 0
1934 /***********************************************************************/
1935 /* Replace string pointers by offset.                                  */
1936 /***********************************************************************/
1937 size_t SWAP::MoffVal(PVL vlp) {
1938   if (vlp->Type == TYPE_STRG)
1939     vlp->Strp = (PSZ)MakeOff(Base, (vlp->Strp));
1940 
1941   return MakeOff(Base, vlp);
1942 } // end of MoffVal
1943 #endif // 0
1944 
1945 /***********************************************************************/
1946 /* Replace all offsets by pointers.                                    */
1947 /***********************************************************************/
MptrJson(PJSON ojp)1948 PJSON SWAP::MptrJson(PJSON ojp) {      // ojp is an offset
1949   PJSON jsp = (PJSON)MakePtr(Base, (size_t)ojp);
1950 
1951   if (ojp)
1952     switch (jsp->Type) {
1953     case TYPE_JAR:
1954       jsp = MptrArray((PJAR)ojp);
1955       break;
1956     case TYPE_JOB:
1957       jsp = MptrObject((PJOB)ojp);
1958       break;
1959     case TYPE_JVAL:
1960       jsp = MptrJValue((PJVAL)ojp);
1961       break;
1962     default:
1963       throw "Invalid json tree";
1964     } // endswitch Type
1965 
1966   return jsp;
1967 } // end of MptrJson
1968 
1969 /***********************************************************************/
1970 /* Replace all array offsets by pointers.                              */
1971 /***********************************************************************/
MptrArray(PJAR ojar)1972 PJAR SWAP::MptrArray(PJAR ojar) {
1973   PJAR jarp = (PJAR)MakePtr(Base, (size_t)ojar);
1974 
1975   jarp = (PJAR)new((long long)jarp) JARRAY(0);
1976 
1977   if (jarp->First) {
1978     jarp->Mvals = (PJVAL*)MakePtr(Base, (size_t)jarp->Mvals);
1979 
1980     for (int i = 0; i < jarp->Size; i++)
1981       jarp->Mvals[i] = (PJVAL)MakePtr(Base, (size_t)jarp->Mvals[i]);
1982 
1983     jarp->First = (PJVAL)MptrJValue(jarp->First);
1984     jarp->Last = (PJVAL)MakePtr(Base, (size_t)jarp->Last);
1985   } // endif First
1986 
1987   return jarp;
1988 } // end of MptrArray
1989 
1990 /***********************************************************************/
1991 /* Replace all object offsets by pointers.                             */
1992 /***********************************************************************/
MptrObject(PJOB ojob)1993 PJOB SWAP::MptrObject(PJOB ojob) {
1994   PJOB jobp = (PJOB)MakePtr(Base, (size_t)ojob);
1995 
1996   jobp = (PJOB)new((long long)jobp) JOBJECT(0);
1997 
1998   if (jobp->First) {
1999     jobp->First = (PJPR)MptrPair(jobp->First);
2000     jobp->Last = (PJPR)MakePtr(Base, (size_t)jobp->Last);
2001   } // endif First
2002 
2003   return jobp;
2004 } // end of MptrObject
2005 
2006 /***********************************************************************/
2007 /* Replace all pair offsets by pointers.                               */
2008 /***********************************************************************/
MptrPair(PJPR ojp)2009 PJPR SWAP::MptrPair(PJPR ojp) {
2010   PJPR jpp = (PJPR)MakePtr(Base, (size_t)ojp);
2011 
2012   jpp->Key = (PCSZ)MakePtr(Base, (size_t)jpp->Key);
2013 
2014   if (jpp->Val)
2015     jpp->Val = (PJVAL)MptrJValue(jpp->Val);
2016 
2017   if (jpp->Next)
2018     jpp->Next = (PJPR)MptrPair(jpp->Next);
2019 
2020   return jpp;
2021 } // end of MptrPair
2022 
2023 /***********************************************************************/
2024 /* Replace all value offsets by pointers.                              */
2025 /***********************************************************************/
MptrJValue(PJVAL ojv)2026 PJVAL SWAP::MptrJValue(PJVAL ojv) {
2027   PJVAL jvp = (PJVAL)MakePtr(Base, (size_t)ojv);
2028 
2029   jvp = (PJVAL)new((long long)jvp) JVALUE(0);
2030 
2031   if (!jvp->Del) {
2032     if (jvp->DataType == TYPE_JSON)
2033       jvp->Jsp = (PJSON)MptrJson(jvp->Jsp);
2034     else if (jvp->DataType == TYPE_STRG)
2035       jvp->Strp = (PSZ)MakePtr(Base, (size_t)jvp->Strp);
2036 
2037 //  if (jvp->Val)
2038 //    jvp->Val = (PVL)MptrVal(jvp->Val);
2039 
2040   } // endif Del
2041 
2042   if (jvp->Next)
2043     jvp->Next = (PJVAL)MptrJValue(jvp->Next);
2044 
2045   return jvp;
2046 } // end of MptrJValue
2047 
2048 #if 0
2049 /***********************************************************************/
2050 /* Replace string offsets by a pointer.                                */
2051 /***********************************************************************/
2052 PVL SWAP::MptrVal(PVL ovl) {
2053   PVL vlp = (PVL)MakePtr(Base, (size_t)ovl);
2054 
2055   if (vlp->Type == TYPE_STRG)
2056     vlp->Strp = (PSZ)MakePtr(Base, (size_t)vlp->Strp);
2057 
2058   return vlp;
2059 } // end of MptrValue
2060 #endif // 0
2061