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