1 /*************** bson CPP Declares Source Code File (.H) ***************/
2 /*  Name: bson.cpp   Version 1.0                                       */
3 /*                                                                     */
4 /*  (C) Copyright to the author Olivier BERTRAND          2020         */
5 /*                                                                     */
6 /*  This file contains the BJSON 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 /*  bson.h      is header containing the BSON classes declarations.    */
19 /***********************************************************************/
20 #include "global.h"
21 #include "plgdbsem.h"
22 #include "bson.h"
23 
24 /***********************************************************************/
25 /*  Check macro.                                                       */
26 /***********************************************************************/
27 #if defined(_DEBUG)
28 #define CheckType(X,Y) if (!X || X ->Type != Y) throw MSG(VALTYPE_NOMATCH);
29 #else
30 #define CheckType(X,Y)
31 #endif
32 
33 #if defined(_WIN32)
34 #define EL  "\r\n"
35 #else
36 #define EL  "\n"
37 #undef     SE_CATCH                  // Does not work for Linux
38 #endif
39 
40 int GetJsonDefPrec(void);
41 
42 #if defined(SE_CATCH)
43 /**************************************************************************/
44 /*  This is the support of catching C interrupts to prevent crashes.      */
45 /**************************************************************************/
46 #include <eh.h>
47 
48 class SE_Exception {
49 public:
SE_Exception(unsigned int n,PEXCEPTION_RECORD p)50   SE_Exception(unsigned int n, PEXCEPTION_RECORD p) : nSE(n), eRec(p) {}
~SE_Exception()51   ~SE_Exception() {}
52 
53   unsigned int      nSE;
54   PEXCEPTION_RECORD eRec;
55 };  // end of class SE_Exception
56 
trans_func(unsigned int u,_EXCEPTION_POINTERS * pExp)57 void trans_func(unsigned int u, _EXCEPTION_POINTERS* pExp) {
58   throw SE_Exception(u, pExp->ExceptionRecord);
59 } // end of trans_func
60 
61 char* GetExceptionDesc(PGLOBAL g, unsigned int e);
62 #endif   // SE_CATCH
63 
64 /* --------------------------- Class BDOC ---------------------------- */
65 
66 /***********************************************************************/
67 /*  BDOC constructor.                                                  */
68 /***********************************************************************/
BDOC(PGLOBAL G)69 BDOC::BDOC(PGLOBAL G) : BJSON(G, NULL)
70 {
71   jp = NULL;
72   s = NULL;
73   len = 0;
74   pretty = 3;
75   pty[0] = pty[1] = pty[2] = true;
76   comma = false;
77 } // end of BDOC constructor
78 
79 /***********************************************************************/
80 /* Parse a json string.                                                */
81 /* Note: when pretty is not known, the caller set pretty to 3.         */
82 /***********************************************************************/
ParseJson(PGLOBAL g,char * js,size_t lng)83 PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng)
84 {
85   size_t i;
86   bool  b = false, ptyp = (bool *)pty;
87   PBVAL bvp = NULL;
88 
89   s = js;
90   len = lng;
91   xtrc(1, "BDOC::ParseJson: s=%.10s len=%zd\n", s, len);
92 
93   if (!s || !len) {
94     strcpy(g->Message, "Void JSON object");
95     return NULL;
96   } // endif s
97 
98   // Trying to guess the pretty format
99   if (s[0] == '[' && (s[1] == '\n' || (s[1] == '\r' && s[2] == '\n')))
100     pty[0] = false;
101 
102   try {
103     bvp = NewVal();
104     bvp->Type = TYPE_UNKNOWN;
105 
106     for (i = 0; i < len; i++)
107       switch (s[i]) {
108       case '[':
109         if (bvp->Type != TYPE_UNKNOWN)
110           bvp->To_Val = ParseAsArray(i);
111         else
112           bvp->To_Val = ParseArray(++i);
113 
114         bvp->Type = TYPE_JAR;
115         break;
116       case '{':
117         if (bvp->Type != TYPE_UNKNOWN) {
118           bvp->To_Val = ParseAsArray(i);
119           bvp->Type = TYPE_JAR;
120         } else {
121           bvp->To_Val = ParseObject(++i);
122           bvp->Type = TYPE_JOB;
123         } // endif Type
124 
125         break;
126       case ' ':
127       case '\t':
128       case '\n':
129       case '\r':
130         break;
131       case ',':
132         if (bvp->Type != TYPE_UNKNOWN && (pretty == 1 || pretty == 3)) {
133           comma = true;
134           pty[0] = pty[2] = false;
135           break;
136         } // endif pretty
137 
138         sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty);
139         throw 3;
140       case '(':
141         b = true;
142         break;
143       case ')':
144         if (b) {
145           b = false;
146           break;
147         } // endif b
148 
149       default:
150         if (bvp->Type != TYPE_UNKNOWN) {
151           bvp->To_Val = ParseAsArray(i);
152           bvp->Type = TYPE_JAR;
153         } else if ((bvp->To_Val = MOF(ParseValue(i, NewVal()))))
154           bvp->Type = TYPE_JVAL;
155         else
156           throw 4;
157 
158         break;
159       }; // endswitch s[i]
160 
161     if (bvp->Type == TYPE_UNKNOWN)
162       sprintf(g->Message, "Invalid Json string '%.*s'", MY_MIN((int)len, 50), s);
163     else if (pretty == 3) {
164       for (i = 0; i < 3; i++)
165         if (pty[i]) {
166           pretty = i;
167           break;
168         } // endif pty
169 
170     } // endif ptyp
171 
172   } catch (int n) {
173     if (trace(1))
174       htrc("Exception %d: %s\n", n, G->Message);
175     GetMsg(g);
176     bvp = NULL;
177   } catch (const char* msg) {
178     strcpy(g->Message, msg);
179     bvp = NULL;
180   } // end catch
181 
182   return bvp;
183 } // end of ParseJson
184 
185 /***********************************************************************/
186 /* Parse several items as being in an array.                           */
187 /***********************************************************************/
ParseAsArray(size_t & i)188 OFFSET BDOC::ParseAsArray(size_t& i) {
189   if (pty[0] && (!pretty || pretty > 2)) {
190     OFFSET jsp;
191 
192     if ((jsp = ParseArray((i = 0))) && pretty == 3)
193       pretty = (pty[0]) ? 0 : 3;
194 
195     return jsp;
196   } else
197     strcpy(G->Message, "More than one item in file");
198 
199   return 0;
200 } // end of ParseAsArray
201 
202 /***********************************************************************/
203 /* Parse a JSON Array.                                                 */
204 /***********************************************************************/
ParseArray(size_t & i)205 OFFSET BDOC::ParseArray(size_t& i)
206 {
207   int   level = 0;
208   bool  b = (!i);
209   PBVAL vlp, firstvlp, lastvlp;
210 
211   vlp = firstvlp = lastvlp = NULL;
212 
213   for (; i < len; i++)
214     switch (s[i]) {
215     case ',':
216       if (level < 2) {
217         sprintf(G->Message, "Unexpected ',' near %.*s", (int) ARGS);
218         throw 1;
219       } else
220         level = 1;
221 
222       break;
223     case ']':
224       if (level == 1) {
225         sprintf(G->Message, "Unexpected ',]' near %.*s", (int) ARGS);
226         throw 1;
227       } // endif level
228 
229       return MOF(firstvlp);
230     case '\n':
231       if (!b)
232         pty[0] = pty[1] = false;
233     case '\r':
234     case ' ':
235     case '\t':
236       break;
237     default:
238       if (level == 2) {
239         sprintf(G->Message, "Unexpected value near %.*s", (int) ARGS);
240         throw 1;
241       } else if (lastvlp) {
242         vlp = ParseValue(i, NewVal());
243         lastvlp->Next = MOF(vlp);
244         lastvlp = vlp;
245       } else
246         firstvlp = lastvlp = ParseValue(i, NewVal());
247 
248       level = (b) ? 1 : 2;
249       break;
250     }; // endswitch s[i]
251 
252   if (b) {
253     // Case of Pretty == 0
254     return MOF(firstvlp);
255   } // endif b
256 
257   throw ("Unexpected EOF in array");
258 } // end of ParseArray
259 
260 /***********************************************************************/
261 /* Parse a JSON Object.                                                */
262 /***********************************************************************/
ParseObject(size_t & i)263 OFFSET BDOC::ParseObject(size_t& i)
264 {
265   OFFSET key;
266   int    level = 0;
267   PBPR   bpp, firstbpp, lastbpp;
268 
269   bpp = firstbpp = lastbpp = NULL;
270 
271   for (; i < len; i++)
272     switch (s[i]) {
273     case '"':
274       if (level < 2) {
275         key = ParseString(++i);
276         bpp = NewPair(key);
277 
278         if (lastbpp) {
279           lastbpp->Vlp.Next = MOF(bpp);
280           lastbpp = bpp;
281         } else
282           firstbpp = lastbpp = bpp;
283 
284         level = 2;
285       } else {
286         sprintf(G->Message, "misplaced string near %.*s", (int) ARGS);
287         throw 2;
288       } // endif level
289 
290       break;
291     case ':':
292       if (level == 2) {
293         ParseValue(++i, GetVlp(lastbpp));
294         level = 3;
295       } else {
296         sprintf(G->Message, "Unexpected ':' near %.*s", (int) ARGS);
297         throw 2;
298       } // endif level
299 
300       break;
301     case ',':
302       if (level < 3) {
303         sprintf(G->Message, "Unexpected ',' near %.*s", (int) ARGS);
304         throw 2;
305       } else
306         level = 1;
307 
308       break;
309     case '}':
310       if (!(level == 0 || level == 3)) {
311         sprintf(G->Message, "Unexpected '}' near %.*s", (int) ARGS);
312         throw 2;
313       } // endif level
314 
315       return MOF(firstbpp);
316     case '\n':
317       pty[0] = pty[1] = false;
318     case '\r':
319     case ' ':
320     case '\t':
321       break;
322     default:
323       sprintf(G->Message, "Unexpected character '%c' near %.*s",
324         s[i], (int) ARGS);
325       throw 2;
326     }; // endswitch s[i]
327 
328   strcpy(G->Message, "Unexpected EOF in Object");
329   throw 2;
330 } // end of ParseObject
331 
332 /***********************************************************************/
333 /* Parse a JSON Value.                                                 */
334 /***********************************************************************/
ParseValue(size_t & i,PBVAL bvp)335 PBVAL BDOC::ParseValue(size_t& i, PBVAL bvp)
336 {
337   for (; i < len; i++)
338     switch (s[i]) {
339     case '\n':
340       pty[0] = pty[1] = false;
341     case '\r':
342     case ' ':
343     case '\t':
344       break;
345     default:
346       goto suite;
347     } // endswitch
348 
349 suite:
350   switch (s[i]) {
351   case '[':
352     bvp->To_Val = ParseArray(++i);
353     bvp->Type = TYPE_JAR;
354     break;
355   case '{':
356     bvp->To_Val = ParseObject(++i);
357     bvp->Type = TYPE_JOB;
358     break;
359   case '"':
360     bvp->To_Val = ParseString(++i);
361     bvp->Type = TYPE_STRG;
362     break;
363   case 't':
364     if (!strncmp(s + i, "true", 4)) {
365       bvp->B = true;
366       bvp->Type = TYPE_BOOL;
367       i += 3;
368     } else
369       goto err;
370 
371     break;
372   case 'f':
373     if (!strncmp(s + i, "false", 5)) {
374       bvp->B = false;
375       bvp->Type = TYPE_BOOL;
376       i += 4;
377     } else
378       goto err;
379 
380     break;
381   case 'n':
382     if (!strncmp(s + i, "null", 4)) {
383       bvp->Type = TYPE_NULL;
384       i += 3;
385     } else
386       goto err;
387 
388     break;
389   case '-':
390   default:
391     if (s[i] == '-' || isdigit(s[i]))
392       ParseNumeric(i, bvp);
393     else
394       goto err;
395 
396   }; // endswitch s[i]
397 
398   return bvp;
399 
400 err:
401   sprintf(G->Message, "Unexpected character '%c' near %.*s", s[i], (int) ARGS);
402   throw 3;
403 } // end of ParseValue
404 
405 /***********************************************************************/
406 /*  Unescape and parse a JSON string.                                  */
407 /***********************************************************************/
ParseString(size_t & i)408 OFFSET BDOC::ParseString(size_t& i)
409 {
410   uchar* p;
411   int    n = 0;
412 
413   // Be sure of memory availability
414   if (((size_t)len + 1 - i) > ((PPOOLHEADER)G->Sarea)->FreeBlk)
415     throw("ParseString: Out of memory");
416 
417   // The size to allocate is not known yet
418   p = (uchar*)BsonSubAlloc(0);
419 
420   for (; i < len; i++)
421     switch (s[i]) {
422     case '"':
423       p[n++] = 0;
424       BsonSubAlloc(n);
425       return MOF(p);
426     case '\\':
427       if (++i < len) {
428         if (s[i] == 'u') {
429           if (len - i > 5) {
430             //            if (charset == utf8) {
431             char xs[5];
432             uint hex;
433 
434             xs[0] = s[++i];
435             xs[1] = s[++i];
436             xs[2] = s[++i];
437             xs[3] = s[++i];
438             xs[4] = 0;
439             hex = strtoul(xs, NULL, 16);
440 
441             if (hex < 0x80) {
442               p[n] = (uchar)hex;
443             } else if (hex < 0x800) {
444               p[n++] = (uchar)(0xC0 | (hex >> 6));
445               p[n] = (uchar)(0x80 | (hex & 0x3F));
446             } else if (hex < 0x10000) {
447               p[n++] = (uchar)(0xE0 | (hex >> 12));
448               p[n++] = (uchar)(0x80 | ((hex >> 6) & 0x3f));
449               p[n] = (uchar)(0x80 | (hex & 0x3f));
450             } else
451               p[n] = '?';
452 
453 #if 0
454           } else {
455             char xs[3];
456             UINT hex;
457 
458             i += 2;
459             xs[0] = s[++i];
460             xs[1] = s[++i];
461             xs[2] = 0;
462             hex = strtoul(xs, NULL, 16);
463             p[n] = (char)hex;
464           } // endif charset
465 #endif // 0
466         } else
467           goto err;
468 
469       } else switch (s[i]) {
470       case 't': p[n] = '\t'; break;
471       case 'n': p[n] = '\n'; break;
472       case 'r': p[n] = '\r'; break;
473       case 'b': p[n] = '\b'; break;
474       case 'f': p[n] = '\f'; break;
475       default:  p[n] = s[i]; break;
476       } // endswitch
477 
478       n++;
479     } else
480       goto err;
481 
482     break;
483       default:
484         p[n++] = s[i];
485         break;
486 }; // endswitch s[i]
487 
488 err:
489 throw("Unexpected EOF in String");
490 } // end of ParseString
491 
492 /***********************************************************************/
493 /* Parse a JSON numeric value.                                         */
494 /***********************************************************************/
ParseNumeric(size_t & i,PBVAL vlp)495 void BDOC::ParseNumeric(size_t& i, PBVAL vlp)
496 {
497   char  buf[50];
498   int   n = 0;
499   short nd = 0;
500   bool  has_dot = false;
501   bool  has_e = false;
502   bool  found_digit = false;
503 
504   for (; i < len; i++) {
505     switch (s[i]) {
506     case '.':
507       if (!found_digit || has_dot || has_e)
508         goto err;
509 
510       has_dot = true;
511       break;
512     case 'e':
513     case 'E':
514       if (!found_digit || has_e)
515         goto err;
516 
517       has_e = true;
518       found_digit = false;
519       break;
520     case '+':
521       if (!has_e)
522         goto err;
523 
524       // fall through
525     case '-':
526       if (found_digit)
527         goto err;
528 
529       break;
530     default:
531       if (isdigit(s[i])) {
532         if (has_dot && !has_e)
533           nd++;       // Number of decimals
534 
535         found_digit = true;
536       } else
537         goto fin;
538 
539     }; // endswitch s[i]
540 
541     buf[n++] = s[i];
542   } // endfor i
543 
544 fin:
545   if (found_digit) {
546     buf[n] = 0;
547 
548     if (has_dot || has_e) {
549       double dv = atof(buf);
550 
551       if (nd >= 6 || dv > FLT_MAX || dv < FLT_MIN) {
552         double* dvp = (double*)PlugSubAlloc(G, NULL, sizeof(double));
553 
554         *dvp = dv;
555         vlp->To_Val = MOF(dvp);
556         vlp->Type = TYPE_DBL;
557       } else {
558         vlp->F = (float)dv;
559         vlp->Type = TYPE_FLOAT;
560       } // endif nd
561 
562       vlp->Nd = MY_MIN(nd, 16);
563     } else {
564       longlong iv = strtoll(buf, NULL, 10);
565 
566       if (iv > INT_MAX32 || iv < INT_MIN32) {
567         longlong *llp = (longlong*)PlugSubAlloc(G, NULL, sizeof(longlong));
568 
569         *llp = iv;
570         vlp->To_Val = MOF(llp);
571         vlp->Type = TYPE_BINT;
572       } else {
573         vlp->N = (int)iv;
574         vlp->Type = TYPE_INTG;
575       } // endif iv
576 
577     } // endif has
578 
579     i--;  // Unstack  following character
580     return;
581   } else
582     throw("No digit found");
583 
584 err:
585   throw("Unexpected EOF in number");
586 } // end of ParseNumeric
587 
588 /***********************************************************************/
589 /* Serialize a BJSON document tree:                                    */
590 /***********************************************************************/
Serialize(PGLOBAL g,PBVAL bvp,char * fn,int pretty)591 PSZ BDOC::Serialize(PGLOBAL g, PBVAL bvp, char* fn, int pretty)
592 {
593   PSZ   str = NULL;
594   bool  b = false, err = true;
595   FILE* fs = NULL;
596 
597   G->Message[0] = 0;
598 
599   try {
600     if (!bvp) {
601       strcpy(g->Message, "Null json tree");
602       throw 1;
603     } else if (!fn) {
604       // Serialize to a string
605       jp = new(g) JOUTSTR(g);
606       b = pretty == 1;
607     } else {
608       if (!(fs = fopen(fn, "wb"))) {
609         sprintf(g->Message, MSG(OPEN_MODE_ERROR),
610           "w", (int)errno, fn);
611         strcat(strcat(g->Message, ": "), strerror(errno));
612         throw 2;
613       } else if (pretty >= 2) {
614         // Serialize to a pretty file
615         jp = new(g)JOUTPRT(g, fs);
616       } else {
617         // Serialize to a flat file
618         b = true;
619         jp = new(g)JOUTFILE(g, fs, pretty);
620       } // endif's
621 
622     } // endif's
623 
624     switch (bvp->Type) {
625     case TYPE_JAR:
626       err = SerializeArray(bvp->To_Val, b);
627       break;
628     case TYPE_JOB:
629       err = ((b && jp->Prty()) && jp->WriteChr('\t'));
630       err |= SerializeObject(bvp->To_Val);
631       break;
632     case TYPE_JVAL:
633       err = SerializeValue(MVP(bvp->To_Val));
634       break;
635     default:
636       err = SerializeValue(bvp, true);
637     } // endswitch Type
638 
639     if (fs) {
640       fputs(EL, fs);
641       fclose(fs);
642       str = (err) ? NULL : strcpy(g->Message, "Ok");
643     } else if (!err) {
644       str = ((JOUTSTR*)jp)->Strp;
645       jp->WriteChr('\0');
646       PlugSubAlloc(g, NULL, ((JOUTSTR*)jp)->N);
647     } else if (G->Message[0])
648         strcpy(g->Message, "Error in Serialize");
649       else
650         GetMsg(g);
651 
652   } catch (int n) {
653     if (trace(1))
654       htrc("Exception %d: %s\n", n, G->Message);
655     GetMsg(g);
656     str = NULL;
657   } catch (const char* msg) {
658     strcpy(g->Message, msg);
659     str = NULL;
660   } // end catch
661 
662   return str;
663 } // end of Serialize
664 
665 
666 /***********************************************************************/
667 /* Serialize a JSON Array.                                             */
668 /***********************************************************************/
SerializeArray(OFFSET arp,bool b)669 bool BDOC::SerializeArray(OFFSET arp, bool b)
670 {
671   bool  first = true;
672   PBVAL vp = MVP(arp);
673 
674   if (b) {
675     if (jp->Prty()) {
676       if (jp->WriteChr('['))
677         return true;
678       else if (jp->Prty() == 1 && (jp->WriteStr(EL) || jp->WriteChr('\t')))
679         return true;
680 
681     } // endif Prty
682 
683   } else if (jp->WriteChr('['))
684     return true;
685 
686   for (vp; vp; vp = MVP(vp->Next)) {
687     if (first)
688       first = false;
689     else if ((!b || jp->Prty()) && jp->WriteChr(','))
690       return true;
691     else if (b) {
692       if (jp->Prty() < 2 && jp->WriteStr(EL))
693         return true;
694       else if (jp->Prty() == 1 && jp->WriteChr('\t'))
695         return true;
696 
697     } // endif b
698 
699     if (SerializeValue(vp))
700       return true;
701 
702   } // endfor vp
703 
704   if (b && jp->Prty() == 1 && jp->WriteStr(EL))
705     return true;
706 
707   return ((!b || jp->Prty()) && jp->WriteChr(']'));
708 } // end of SerializeArray
709 
710 /***********************************************************************/
711 /* Serialize a JSON Object.                                            */
712 /***********************************************************************/
SerializeObject(OFFSET obp)713 bool BDOC::SerializeObject(OFFSET obp)
714 {
715   bool first = true;
716   PBPR prp = MPP(obp);
717 
718   if (jp->WriteChr('{'))
719     return true;
720 
721   for (prp; prp; prp = GetNext(prp)) {
722     if (first)
723       first = false;
724     else if (jp->WriteChr(','))
725       return true;
726 
727     if (jp->WriteChr('"') ||
728       jp->WriteStr(MZP(prp->Key)) ||
729       jp->WriteChr('"') ||
730       jp->WriteChr(':') ||
731       SerializeValue(GetVlp(prp)))
732       return true;
733 
734   } // endfor i
735 
736   return jp->WriteChr('}');
737 } // end of SerializeObject
738 
739 /***********************************************************************/
740 /* Serialize a JSON Value.                                             */
741 /***********************************************************************/
SerializeValue(PBVAL jvp,bool b)742 bool BDOC::SerializeValue(PBVAL jvp, bool b)
743 {
744   char buf[64];
745 
746   if (jvp) switch (jvp->Type) {
747   case TYPE_JAR:
748     return SerializeArray(jvp->To_Val, false);
749   case TYPE_JOB:
750     return SerializeObject(jvp->To_Val);
751   case TYPE_BOOL:
752     return jp->WriteStr(jvp->B ? "true" : "false");
753   case TYPE_STRG:
754   case TYPE_DTM:
755     if (b) {
756       return jp->WriteStr(MZP(jvp->To_Val));
757     } else
758       return jp->Escape(MZP(jvp->To_Val));
759 
760   case TYPE_INTG:
761     sprintf(buf, "%d", jvp->N);
762     return jp->WriteStr(buf);
763   case TYPE_BINT:
764     sprintf(buf, "%lld", *(longlong*)MakePtr(Base, jvp->To_Val));
765     return jp->WriteStr(buf);
766   case TYPE_FLOAT:
767     sprintf(buf, "%.*f", jvp->Nd, jvp->F);
768     return jp->WriteStr(buf);
769   case TYPE_DBL:
770     sprintf(buf, "%.*lf", jvp->Nd, *(double*)MakePtr(Base, jvp->To_Val));
771     return jp->WriteStr(buf);
772   case TYPE_NULL:
773     return jp->WriteStr("null");
774   case TYPE_JVAL:
775     return SerializeValue(MVP(jvp->To_Val));
776   default:
777     return jp->WriteStr("???");   // TODO
778   } // endswitch Type
779 
780   return  jp->WriteStr("null");
781 } // end of SerializeValue
782 
783 /* --------------------------- Class BJSON --------------------------- */
784 
785 /***********************************************************************/
786 /*  Program for sub-allocating Bjson structures.                       */
787 /***********************************************************************/
BsonSubAlloc(size_t size)788 void* BJSON::BsonSubAlloc(size_t size)
789 {
790   PPOOLHEADER pph;                           /* Points on area header. */
791   void* memp = G->Sarea;
792 
793   size = ((size + 3) / 4) * 4;       /* Round up size to multiple of 4 */
794   pph = (PPOOLHEADER)memp;
795 
796   xtrc(16, "SubAlloc in %p size=%zd used=%zd free=%zd\n",
797     memp, size, pph->To_Free, pph->FreeBlk);
798 
799   if (size > pph->FreeBlk) {   /* Not enough memory left in pool */
800     sprintf(G->Message,
801       "Not enough memory for request of %zd (used=%zd free=%zd)",
802       size, pph->To_Free, pph->FreeBlk);
803     xtrc(1, "BsonSubAlloc: %s\n", G->Message);
804 
805     if (Throw)
806       throw(1234);
807     else
808       return NULL;
809 
810   } /* endif size OS32 code */
811 
812   // Do the suballocation the simplest way
813   memp = MakePtr(memp, pph->To_Free); /* Points to suballocated block  */
814   pph->To_Free += size;               /* New offset of pool free block */
815   pph->FreeBlk -= size;               /* New size   of pool free block */
816   xtrc(16, "Done memp=%p used=%zd free=%zd\n",
817     memp, pph->To_Free, pph->FreeBlk);
818   return memp;
819 } // end of BsonSubAlloc
820 
821 /*********************************************************************************/
822 /*  Program for SubSet re-initialization of the memory pool.                     */
823 /*********************************************************************************/
NewStr(PSZ str)824 PSZ BJSON::NewStr(PSZ str)
825 {
826   if (str) {
827     PSZ sm = (PSZ)BsonSubAlloc(strlen(str) + 1);
828 
829     strcpy(sm, str);
830     return sm;
831   } else
832     return NULL;
833 
834 } // end of NewStr
835 
836 /*********************************************************************************/
837 /*  Program for SubSet re-initialization of the memory pool.                     */
838 /*********************************************************************************/
SubSet(bool b)839 void BJSON::SubSet(bool b)
840 {
841   PPOOLHEADER pph = (PPOOLHEADER)G->Sarea;
842 
843   pph->To_Free = (G->Saved_Size) ? G->Saved_Size : sizeof(POOLHEADER);
844   pph->FreeBlk = G->Sarea_Size - pph->To_Free;
845 
846   if (b)
847     G->Saved_Size = 0;
848 
849 } // end of SubSet
850 
851 /*********************************************************************************/
852 /*  Set the beginning of suballocations.                                         */
853 /*********************************************************************************/
MemSet(size_t size)854 void BJSON::MemSet(size_t size)
855 {
856   PPOOLHEADER pph = (PPOOLHEADER)G->Sarea;
857 
858   pph->To_Free = size + sizeof(POOLHEADER);
859   pph->FreeBlk = G->Sarea_Size - pph->To_Free;
860 } // end of MemSet
861 
862   /* ------------------------ Bobject functions ------------------------ */
863 
864 /***********************************************************************/
865 /* Set a pair vlp to some PVAL values.                                 */
866 /***********************************************************************/
SetPairValue(PBPR brp,PBVAL bvp)867 void BJSON::SetPairValue(PBPR brp, PBVAL bvp)
868 {
869   if (bvp) {
870     brp->Vlp.To_Val = bvp->To_Val;
871     brp->Vlp.Nd = bvp->Nd;
872     brp->Vlp.Type = bvp->Type;
873   } else {
874     brp->Vlp.To_Val = 0;
875     brp->Vlp.Nd = 0;
876     brp->Vlp.Type = TYPE_NULL;
877   } // endif bvp
878 
879 } // end of SetPairValue
880 
881   /***********************************************************************/
882 /* Sub-allocate and initialize a BPAIR.                                */
883 /***********************************************************************/
NewPair(OFFSET key,int type)884 PBPR BJSON::NewPair(OFFSET key, int type)
885 {
886   PBPR bpp = (PBPR)BsonSubAlloc(sizeof(BPAIR));
887 
888   bpp->Key = key;
889   bpp->Vlp.Type = type;
890   bpp->Vlp.To_Val = 0;
891   bpp->Vlp.Nd = 0;
892   bpp->Vlp.Next = 0;
893   return bpp;
894 } // end of SubAllocPair
895 
896 /***********************************************************************/
897 /* Return the number of pairs in this object.                          */
898 /***********************************************************************/
GetObjectSize(PBVAL bop,bool b)899 int BJSON::GetObjectSize(PBVAL bop, bool b)
900 {
901   CheckType(bop, TYPE_JOB);
902   int n = 0;
903 
904   for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
905     // If b return only non null pairs
906     if (!b || (brp->Vlp.To_Val && brp->Vlp.Type != TYPE_NULL))
907       n++;
908 
909   return n;
910 } // end of GetObjectSize
911 
912 /***********************************************************************/
913 /* Add a new pair to an Object and return it.                          */
914 /***********************************************************************/
AddPair(PBVAL bop,PSZ key,int type)915 PBVAL BJSON::AddPair(PBVAL bop, PSZ key, int type)
916 {
917   CheckType(bop, TYPE_JOB);
918   PBPR   brp;
919   OFFSET nrp = NewPair(key, type);
920 
921   if (bop->To_Val) {
922     for (brp = GetObject(bop); brp->Vlp.Next; brp = GetNext(brp));
923 
924     brp->Vlp.Next = nrp;
925   } else
926     bop->To_Val = nrp;
927 
928   bop->Nd++;
929   return GetVlp(MPP(nrp));
930 } // end of AddPair
931 
932 /***********************************************************************/
933 /* Return all object keys as an array.                                 */
934 /***********************************************************************/
GetKeyList(PBVAL bop)935 PBVAL BJSON::GetKeyList(PBVAL bop)
936 {
937   CheckType(bop, TYPE_JOB);
938   PBVAL arp = NewVal(TYPE_JAR);
939 
940   for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
941     AddArrayValue(arp, MOF(SubAllocVal(brp->Key, TYPE_STRG)));
942 
943   return arp;
944 } // end of GetKeyList
945 
946 /***********************************************************************/
947 /* Return all object values as an array.                               */
948 /***********************************************************************/
GetObjectValList(PBVAL bop)949 PBVAL BJSON::GetObjectValList(PBVAL bop)
950 {
951   CheckType(bop, TYPE_JOB);
952   PBVAL arp = NewVal(TYPE_JAR);
953 
954   for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
955     AddArrayValue(arp, DupVal(GetVlp(brp)));
956 
957   return arp;
958 } // end of GetObjectValList
959 
960 /***********************************************************************/
961 /* Get the value corresponding to the given key.                       */
962 /***********************************************************************/
GetKeyValue(PBVAL bop,PSZ key)963 PBVAL BJSON::GetKeyValue(PBVAL bop, PSZ key)
964 {
965   CheckType(bop, TYPE_JOB);
966 
967   for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
968     if (!strcmp(GetKey(brp), key))
969       return GetVlp(brp);
970 
971   return NULL;
972 } // end of GetKeyValue;
973 
974 /***********************************************************************/
975 /* Return the text corresponding to all keys (XML like).               */
976 /***********************************************************************/
GetObjectText(PGLOBAL g,PBVAL bop,PSTRG text)977 PSZ BJSON::GetObjectText(PGLOBAL g, PBVAL bop, PSTRG text)
978 {
979   CheckType(bop, TYPE_JOB);
980   PBPR brp = GetObject(bop);
981 
982   if (brp) {
983     bool b;
984 
985     if (!text) {
986       text = new(g) STRING(g, 256);
987       b = true;
988     } else {
989       if (text->GetLastChar() != ' ')
990         text->Append(' ');
991 
992       b = false;
993     }	// endif text
994 
995     if (b && !brp->Vlp.Next && !strcmp(MZP(brp->Key), "$date")) {
996       int i;
997       PSZ s;
998 
999       GetValueText(g, GetVlp(brp), text);
1000       s = text->GetStr();
1001       i = (s[1] == '-' ? 2 : 1);
1002 
1003       if (IsNum(s + i)) {
1004         // Date is in milliseconds
1005         int j = text->GetLength();
1006 
1007         if (j >= 4 + i) {
1008           s[j - 3] = 0;        // Change it to seconds
1009           text->SetLength((uint)strlen(s));
1010         } else
1011           text->Set(" 0");
1012 
1013       } // endif text
1014 
1015     } else for (; brp; brp = GetNext(brp)) {
1016       GetValueText(g, GetVlp(brp), text);
1017 
1018       if (brp->Vlp.Next)
1019         text->Append(' ');
1020 
1021     }	// endfor brp
1022 
1023     if (b) {
1024       text->Trim();
1025       return text->GetStr();
1026     }	// endif b
1027 
1028   } // endif bop
1029 
1030   return NULL;
1031 } // end of GetObjectText;
1032 
1033 /***********************************************************************/
1034 /* Set or add a value corresponding to the given key.                  */
1035 /***********************************************************************/
SetKeyValue(PBVAL bop,OFFSET bvp,PSZ key)1036 void BJSON::SetKeyValue(PBVAL bop, OFFSET bvp, PSZ key)
1037 {
1038   CheckType(bop, TYPE_JOB);
1039   PBPR brp, prp = NULL;
1040 
1041   if (bop->To_Val) {
1042     for (brp = GetObject(bop); brp; brp = GetNext(brp))
1043       if (!strcmp(GetKey(brp), key))
1044         break;
1045       else
1046         prp = brp;
1047 
1048     if (!brp)
1049       brp = MPP(prp->Vlp.Next = NewPair(key));
1050 
1051   } else
1052     brp = MPP(bop->To_Val = NewPair(key));
1053 
1054   SetPairValue(brp, MVP(bvp));
1055   bop->Nd++;
1056 } // end of SetKeyValue
1057 
1058 /***********************************************************************/
1059 /* Merge two objects.                                                  */
1060 /***********************************************************************/
MergeObject(PBVAL bop1,PBVAL bop2)1061 PBVAL BJSON::MergeObject(PBVAL bop1, PBVAL bop2)
1062 {
1063   CheckType(bop1, TYPE_JOB);
1064   CheckType(bop2, TYPE_JOB);
1065 
1066   if (bop1->To_Val)
1067     for (PBPR brp = GetObject(bop2); brp; brp = GetNext(brp))
1068       SetKeyValue(bop1, GetVlp(brp), GetKey(brp));
1069 
1070   else {
1071     bop1->To_Val = bop2->To_Val;
1072     bop1->Nd = bop2->Nd;
1073   } // endelse To_Val
1074 
1075   return bop1;
1076 } // end of MergeObject;
1077 
1078 /***********************************************************************/
1079 /* Delete a value corresponding to the given key.                      */
1080 /***********************************************************************/
DeleteKey(PBVAL bop,PCSZ key)1081 bool BJSON::DeleteKey(PBVAL bop, PCSZ key)
1082 {
1083   CheckType(bop, TYPE_JOB);
1084   PBPR brp, pbrp = NULL;
1085 
1086   for (brp = GetObject(bop); brp; brp = GetNext(brp))
1087     if (!strcmp(MZP(brp->Key), key)) {
1088       if (pbrp) {
1089         pbrp->Vlp.Next = brp->Vlp.Next;
1090       } else
1091         bop->To_Val = brp->Vlp.Next;
1092 
1093       bop->Nd--;
1094       return true;;
1095     } else
1096       pbrp = brp;
1097 
1098   return false;
1099 } // end of DeleteKey
1100 
1101 /***********************************************************************/
1102 /* True if void or if all members are nulls.                           */
1103 /***********************************************************************/
IsObjectNull(PBVAL bop)1104 bool BJSON::IsObjectNull(PBVAL bop)
1105 {
1106   CheckType(bop, TYPE_JOB);
1107 
1108   for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
1109     if (brp->Vlp.To_Val && brp->Vlp.Type != TYPE_NULL)
1110       return false;
1111 
1112   return true;
1113 } // end of IsObjectNull
1114 
1115 /* ------------------------- Barray functions ------------------------ */
1116 
1117 /***********************************************************************/
1118 /* Return the number of values in this object.                         */
1119 /***********************************************************************/
GetArraySize(PBVAL bap,bool b)1120 int BJSON::GetArraySize(PBVAL bap, bool b)
1121 {
1122   CheckType(bap, TYPE_JAR);
1123   int n = 0;
1124 
1125   for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp))
1126     //  If b, return only non null values
1127     if (!b || bvp->Type != TYPE_NULL)
1128       n++;
1129 
1130   return n;
1131 } // end of GetArraySize
1132 
1133 /***********************************************************************/
1134 /* Get the Nth value of an Array.                                      */
1135 /***********************************************************************/
GetArrayValue(PBVAL bap,int n)1136 PBVAL BJSON::GetArrayValue(PBVAL bap, int n)
1137 {
1138   CheckType(bap, TYPE_JAR);
1139   int i = 0;
1140 
1141   if (n < 0)
1142     n += GetArraySize(bap);
1143 
1144   for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp), i++)
1145     if (i == n)
1146       return bvp;
1147 
1148   return NULL;
1149 } // end of GetArrayValue
1150 
1151 /***********************************************************************/
1152 /* Add a Value to the Array Value list.                                */
1153 /***********************************************************************/
AddArrayValue(PBVAL bap,OFFSET nbv,int * x)1154 void BJSON::AddArrayValue(PBVAL bap, OFFSET nbv, int* x)
1155 {
1156   CheckType(bap, TYPE_JAR);
1157   int   i = 0;
1158   PBVAL bvp, lbp = NULL;
1159 
1160   if (!nbv)
1161     nbv = MOF(NewVal());
1162 
1163   for (bvp = GetArray(bap); bvp; bvp = GetNext(bvp), i++)
1164     if (x && i == *x)
1165       break;
1166     else
1167       lbp = bvp;
1168 
1169   if (lbp) {
1170     MVP(nbv)->Next = lbp->Next;
1171     lbp->Next = nbv;
1172   } else {
1173     MVP(nbv)->Next = bap->To_Val;
1174     bap->To_Val = nbv;
1175   } // endif lbp
1176 
1177   bap->Nd++;
1178 } // end of AddArrayValue
1179 
1180 /***********************************************************************/
1181 /* Merge two arrays.                                                   */
1182 /***********************************************************************/
MergeArray(PBVAL bap1,PBVAL bap2)1183 void BJSON::MergeArray(PBVAL bap1, PBVAL bap2)
1184 {
1185   CheckType(bap1, TYPE_JAR);
1186   CheckType(bap2, TYPE_JAR);
1187 
1188   if (bap1->To_Val) {
1189     for (PBVAL bvp = GetArray(bap2); bvp; bvp = GetNext(bvp))
1190       AddArrayValue(bap1, MOF(DupVal(bvp)));
1191 
1192   } else {
1193     bap1->To_Val = bap2->To_Val;
1194     bap1->Nd = bap2->Nd;
1195   } // endif To_Val
1196 
1197 } // end of MergeArray
1198 
1199 /***********************************************************************/
1200 /* Set the nth Value of the Array Value list or add it.                */
1201 /***********************************************************************/
SetArrayValue(PBVAL bap,PBVAL nvp,int n)1202 void BJSON::SetArrayValue(PBVAL bap, PBVAL nvp, int n)
1203 {
1204   CheckType(bap, TYPE_JAR);
1205   int   i = 0;
1206   PBVAL bvp = NULL;
1207 
1208   for (bvp = GetArray(bap); i < n; i++, bvp = bvp ? GetNext(bvp) : NULL)
1209     if (!bvp)
1210       AddArrayValue(bap, NewVal());
1211 
1212   if (!bvp)
1213     AddArrayValue(bap, MOF(nvp));
1214   else
1215     SetValueVal(bvp, nvp);
1216 
1217 } // end of SetValue
1218 
1219 /***********************************************************************/
1220 /* Return the text corresponding to all values.                        */
1221 /***********************************************************************/
GetArrayText(PGLOBAL g,PBVAL bap,PSTRG text)1222 PSZ BJSON::GetArrayText(PGLOBAL g, PBVAL bap, PSTRG text)
1223 {
1224   CheckType(bap, TYPE_JAR);
1225 
1226   if (bap->To_Val) {
1227     bool  b;
1228 
1229     if (!text) {
1230       text = new(g) STRING(g, 256);
1231       b = true;
1232     } else {
1233       if (text->GetLastChar() != ' ')
1234         text->Append(" (");
1235       else
1236         text->Append('(');
1237 
1238       b = false;
1239     } // endif text
1240 
1241     for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp)) {
1242       GetValueText(g, bvp, text);
1243 
1244       if (bvp->Next)
1245         text->Append(", ");
1246       else if (!b)
1247         text->Append(')');
1248 
1249     }	// endfor bvp
1250 
1251     if (b) {
1252       text->Trim();
1253       return text->GetStr();
1254     }	// endif b
1255 
1256   } // endif To_Val
1257 
1258   return NULL;
1259 } // end of GetText;
1260 
1261 /***********************************************************************/
1262 /* Delete a Value from the Arrays Value list.                          */
1263 /***********************************************************************/
DeleteValue(PBVAL bap,int n)1264 bool BJSON::DeleteValue(PBVAL bap, int n)
1265 {
1266   CheckType(bap, TYPE_JAR);
1267   int   i = 0;
1268   PBVAL bvp, pvp = NULL;
1269 
1270   for (bvp = GetArray(bap); bvp; i++, bvp = GetNext(bvp))
1271     if (i == n) {
1272       if (pvp)
1273         pvp->Next = bvp->Next;
1274       else
1275         bap->To_Val = bvp->Next;
1276 
1277       bap->Nd--;
1278       return true;;
1279     } else
1280       pvp = bvp;
1281 
1282   return false;
1283 } // end of DeleteValue
1284 
1285 /***********************************************************************/
1286 /* True if void or if all members are nulls.                           */
1287 /***********************************************************************/
IsArrayNull(PBVAL bap)1288 bool BJSON::IsArrayNull(PBVAL bap)
1289 {
1290   CheckType(bap, TYPE_JAR);
1291 
1292   for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp))
1293     if (bvp->Type != TYPE_NULL)
1294       return false;
1295 
1296   return true;
1297 } // end of IsNull
1298 
1299 /* ------------------------- Bvalue functions ------------------------ */
1300 
1301 /***********************************************************************/
1302 /* Sub-allocate and clear a BVAL.                                      */
1303 /***********************************************************************/
NewVal(int type)1304 PBVAL BJSON::NewVal(int type)
1305 {
1306   PBVAL bvp = (PBVAL)BsonSubAlloc(sizeof(BVAL));
1307 
1308   bvp->To_Val = 0;
1309   bvp->Nd = 0;
1310   bvp->Type = type;
1311   bvp->Next = 0;
1312   return bvp;
1313 } // end of SubAllocVal
1314 
1315 /***********************************************************************/
1316 /* Sub-allocate and initialize a BVAL as type.                         */
1317 /***********************************************************************/
SubAllocVal(OFFSET toval,int type,short nd)1318 PBVAL BJSON::SubAllocVal(OFFSET toval, int type, short nd)
1319 {
1320   PBVAL bvp = NewVal(type);
1321 
1322   bvp->To_Val = toval;
1323   bvp->Nd = nd;
1324   return bvp;
1325 } // end of SubAllocVal
1326 
1327 /***********************************************************************/
1328 /* Sub-allocate and initialize a BVAL as string.                       */
1329 /***********************************************************************/
SubAllocStr(OFFSET toval,short nd)1330 PBVAL BJSON::SubAllocStr(OFFSET toval, short nd)
1331 {
1332   PBVAL bvp = NewVal(TYPE_STRG);
1333 
1334   bvp->To_Val = toval;
1335   bvp->Nd = nd;
1336   return bvp;
1337 } // end of SubAllocStr
1338 
1339 /***********************************************************************/
1340 /* Allocate a BVALUE with a given string or numeric value.             */
1341 /***********************************************************************/
NewVal(PVAL valp)1342 PBVAL BJSON::NewVal(PVAL valp)
1343 {
1344   PBVAL vlp = NewVal();
1345 
1346   SetValue(vlp, valp);
1347   return vlp;
1348 } // end of SubAllocVal
1349 
1350 /***********************************************************************/
1351 /* Sub-allocate and initialize a BVAL from another BVAL.               */
1352 /***********************************************************************/
DupVal(PBVAL bvlp)1353 PBVAL BJSON::DupVal(PBVAL bvlp)
1354 {
1355   if (bvlp) {
1356     PBVAL bvp = NewVal();
1357 
1358     *bvp = *bvlp;
1359     bvp->Next = 0;
1360     return bvp;
1361   } else
1362     return NULL;
1363 
1364 } // end of DupVal
1365 
1366 /***********************************************************************/
1367 /* Return the size of value's value.                                   */
1368 /***********************************************************************/
GetSize(PBVAL vlp,bool b)1369 int BJSON::GetSize(PBVAL vlp, bool b)
1370 {
1371   switch (vlp->Type) {
1372   case TYPE_JAR:
1373     return GetArraySize(vlp);
1374   case TYPE_JOB:
1375     return GetObjectSize(vlp);
1376   default:
1377     return 1;
1378   } // enswitch Type
1379 
1380 } // end of GetSize
1381 
GetBson(PBVAL bvp)1382 PBVAL BJSON::GetBson(PBVAL bvp)
1383 {
1384   PBVAL bp = NULL;
1385 
1386   switch (bvp->Type) {
1387     case TYPE_JAR:
1388       bp = MVP(bvp->To_Val);
1389       break;
1390     case TYPE_JOB:
1391       bp = GetVlp(MPP(bvp->To_Val));
1392       break;
1393     default:
1394       bp = bvp;
1395       break;
1396   } // endswitch Type
1397 
1398   return bp;
1399 } // end of GetBson
1400 
1401 /***********************************************************************/
1402 /* Return the Value's as a Value struct.                               */
1403 /***********************************************************************/
GetValue(PGLOBAL g,PBVAL vp)1404 PVAL BJSON::GetValue(PGLOBAL g, PBVAL vp)
1405 {
1406   double d;
1407   PVAL   valp;
1408   PBVAL  vlp = vp->Type == TYPE_JVAL ? MVP(vp->To_Val) : vp;
1409 
1410   switch (vlp->Type) {
1411     case TYPE_STRG:
1412     case TYPE_DBL:
1413     case TYPE_BINT:
1414       valp = AllocateValue(g, MP(vlp->To_Val), vlp->Type, vlp->Nd);
1415       break;
1416     case TYPE_INTG:
1417     case TYPE_BOOL:
1418       valp = AllocateValue(g, vlp, vlp->Type);
1419       break;
1420     case TYPE_FLOAT:
1421       d = (double)vlp->F;
1422       valp = AllocateValue(g, &d, TYPE_DOUBLE, vlp->Nd);
1423       break;
1424     default:
1425       valp = NULL;
1426       break;
1427   } // endswitch Type
1428 
1429   return valp;
1430 } // end of GetValue
1431 
1432 /***********************************************************************/
1433 /* Return the Value's Integer value.                                   */
1434 /***********************************************************************/
GetInteger(PBVAL vp)1435 int BJSON::GetInteger(PBVAL vp) {
1436   int   n;
1437   PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
1438 
1439   switch (vlp->Type) {
1440   case TYPE_INTG:
1441     n = vlp->N;
1442     break;
1443   case TYPE_FLOAT:
1444     n = (int)vlp->F;
1445     break;
1446   case TYPE_DTM:
1447   case TYPE_STRG:
1448     n = atoi(MZP(vlp->To_Val));
1449     break;
1450   case TYPE_BOOL:
1451     n = (vlp->B) ? 1 : 0;
1452     break;
1453   case TYPE_BINT:
1454     n = (int)*(longlong*)MP(vlp->To_Val);
1455     break;
1456   case TYPE_DBL:
1457     n = (int)*(double*)MP(vlp->To_Val);
1458     break;
1459   default:
1460     n = 0;
1461   } // endswitch Type
1462 
1463   return n;
1464 } // end of GetInteger
1465 
1466 /***********************************************************************/
1467 /* Return the Value's Big integer value.                               */
1468 /***********************************************************************/
GetBigint(PBVAL vp)1469 longlong BJSON::GetBigint(PBVAL vp) {
1470   longlong lln;
1471   PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
1472 
1473   switch (vlp->Type) {
1474   case TYPE_BINT:
1475     lln = *(longlong*)MP(vlp->To_Val);
1476     break;
1477   case TYPE_INTG:
1478     lln = (longlong)vlp->N;
1479     break;
1480   case TYPE_FLOAT:
1481     lln = (longlong)vlp->F;
1482     break;
1483   case TYPE_DBL:
1484     lln = (longlong)*(double*)MP(vlp->To_Val);
1485     break;
1486   case TYPE_DTM:
1487   case TYPE_STRG:
1488     lln = atoll(MZP(vlp->To_Val));
1489     break;
1490   case TYPE_BOOL:
1491     lln = (vlp->B) ? 1 : 0;
1492     break;
1493   default:
1494     lln = 0;
1495   } // endswitch Type
1496 
1497   return lln;
1498 } // end of GetBigint
1499 
1500 /***********************************************************************/
1501 /* Return the Value's Double value.                                    */
1502 /***********************************************************************/
GetDouble(PBVAL vp)1503 double BJSON::GetDouble(PBVAL vp)
1504 {
1505   double d;
1506   PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
1507 
1508   switch (vlp->Type) {
1509     case TYPE_DBL:
1510       d = *(double*)MP(vlp->To_Val);
1511       break;
1512     case TYPE_BINT:
1513       d = (double)*(longlong*)MP(vlp->To_Val);
1514       break;
1515     case TYPE_INTG:
1516       d = (double)vlp->N;
1517       break;
1518     case TYPE_FLOAT:
1519       d = (double)vlp->F;
1520       break;
1521     case TYPE_DTM:
1522     case TYPE_STRG:
1523       d = atof(MZP(vlp->To_Val));
1524       break;
1525     case TYPE_BOOL:
1526       d = (vlp->B) ? 1.0 : 0.0;
1527       break;
1528     default:
1529       d = 0.0;
1530   } // endswitch Type
1531 
1532   return d;
1533 } // end of GetDouble
1534 
1535 /***********************************************************************/
1536 /* Return the Value's String value.                                    */
1537 /***********************************************************************/
GetString(PBVAL vp,char * buff)1538 PSZ BJSON::GetString(PBVAL vp, char* buff)
1539 {
1540   char  buf[32];
1541   char* p = (buff) ? buff : buf;
1542   PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
1543 
1544   switch (vlp->Type) {
1545   case TYPE_DTM:
1546   case TYPE_STRG:
1547     p = MZP(vlp->To_Val);
1548     break;
1549   case TYPE_INTG:
1550     sprintf(p, "%d", vlp->N);
1551     break;
1552   case TYPE_FLOAT:
1553     sprintf(p, "%.*f", vlp->Nd, vlp->F);
1554     break;
1555   case TYPE_BINT:
1556     sprintf(p, "%lld", *(longlong*)MP(vlp->To_Val));
1557     break;
1558   case TYPE_DBL:
1559     sprintf(p, "%.*lf", vlp->Nd, *(double*)MP(vlp->To_Val));
1560     break;
1561   case TYPE_BOOL:
1562     p = (PSZ)((vlp->B) ? "true" : "false");
1563     break;
1564   case TYPE_NULL:
1565     p = (PSZ)"null";
1566     break;
1567   default:
1568     p = NULL;
1569   } // endswitch Type
1570 
1571   return (p == buf) ? (PSZ)PlugDup(G, buf) : p;
1572 } // end of GetString
1573 
1574 /***********************************************************************/
1575 /* Return the Value's String value.                                    */
1576 /***********************************************************************/
GetValueText(PGLOBAL g,PBVAL vlp,PSTRG text)1577 PSZ BJSON::GetValueText(PGLOBAL g, PBVAL vlp, PSTRG text)
1578 {
1579   if (vlp->Type == TYPE_JOB)
1580     return GetObjectText(g, vlp, text);
1581   else if (vlp->Type == TYPE_JAR)
1582     return GetArrayText(g, vlp, text);
1583 
1584   char buff[32];
1585   PSZ  s = (vlp->Type == TYPE_NULL) ? NULL : GetString(vlp, buff);
1586 
1587   if (s)
1588     text->Append(s);
1589   else if (GetJsonNull())
1590     text->Append(GetJsonNull());
1591 
1592   return NULL;
1593 } // end of GetText
1594 
SetValueObj(PBVAL vlp,PBVAL bop)1595 void BJSON::SetValueObj(PBVAL vlp, PBVAL bop)
1596 {
1597   CheckType(bop, TYPE_JOB);
1598   vlp->To_Val = bop->To_Val;
1599   vlp->Nd = bop->Nd;
1600   vlp->Type = TYPE_JOB;
1601 } // end of SetValueObj;
1602 
SetValueArr(PBVAL vlp,PBVAL bap)1603 void BJSON::SetValueArr(PBVAL vlp, PBVAL bap)
1604 {
1605   CheckType(bap, TYPE_JAR);
1606   vlp->To_Val = bap->To_Val;
1607   vlp->Nd = bap->Nd;
1608   vlp->Type = TYPE_JAR;
1609 } // end of SetValue;
1610 
SetValueVal(PBVAL vlp,PBVAL vp)1611 void BJSON::SetValueVal(PBVAL vlp, PBVAL vp)
1612 {
1613   vlp->To_Val = vp->To_Val;
1614   vlp->Nd = vp->Nd;
1615   vlp->Type = vp->Type;
1616 } // end of SetValue;
1617 
SetValue(PBVAL vlp,PVAL valp)1618 PBVAL BJSON::SetValue(PBVAL vlp, PVAL valp)
1619 {
1620   if (!vlp)
1621     vlp = NewVal();
1622 
1623   if (!valp || valp->IsNull()) {
1624     vlp->Type = TYPE_NULL;
1625   } else switch (valp->GetType()) {
1626     case TYPE_DATE:
1627       if (((DTVAL*)valp)->IsFormatted())
1628         vlp->To_Val = DupStr(valp->GetCharValue());
1629       else {
1630         char buf[32];
1631 
1632         vlp->To_Val = DupStr(valp->GetCharString(buf));
1633       }	// endif Formatted
1634 
1635       vlp->Type = TYPE_DTM;
1636       break;
1637     case TYPE_STRING:
1638       vlp->To_Val = DupStr(valp->GetCharValue());
1639       vlp->Type = TYPE_STRG;
1640       break;
1641     case TYPE_DOUBLE:
1642     case TYPE_DECIM:
1643     { double d = valp->GetFloatValue();
1644       int    nd = (IsTypeNum(valp->GetType())) ? valp->GetValPrec() : 0;
1645 
1646       if (nd > 0 && nd <= 6 && d >= FLT_MIN && d <= FLT_MAX) {
1647         vlp->F = (float)valp->GetFloatValue();
1648         vlp->Type = TYPE_FLOAT;
1649       } else {
1650         double* dp = (double*)BsonSubAlloc(sizeof(double));
1651 
1652         *dp = d;
1653         vlp->To_Val = MOF(dp);
1654         vlp->Type = TYPE_DBL;
1655       } // endif Nd
1656 
1657       vlp->Nd = MY_MIN(nd, 16);
1658     } break;
1659     case TYPE_TINY:
1660       vlp->B = valp->GetTinyValue() != 0;
1661       vlp->Type = TYPE_BOOL;
1662       break;
1663     case TYPE_INT:
1664       vlp->N = valp->GetIntValue();
1665       vlp->Type = TYPE_INTG;
1666       break;
1667     case TYPE_BIGINT:
1668       if (valp->GetBigintValue() >= INT_MIN32 &&
1669         valp->GetBigintValue() <= INT_MAX32) {
1670         vlp->N = valp->GetIntValue();
1671         vlp->Type = TYPE_INTG;
1672       } else {
1673         longlong* llp = (longlong*)BsonSubAlloc(sizeof(longlong));
1674 
1675         *llp = valp->GetBigintValue();
1676         vlp->To_Val = MOF(llp);
1677         vlp->Type = TYPE_BINT;
1678       } // endif BigintValue
1679 
1680       break;
1681     default:
1682       sprintf(G->Message, "Unsupported typ %d\n", valp->GetType());
1683       throw(777);
1684   } // endswitch Type
1685 
1686   return vlp;
1687 } // end of SetValue
1688 
1689 /***********************************************************************/
1690 /* Set the Value's value as the given integer.                         */
1691 /***********************************************************************/
SetInteger(PBVAL vlp,int n)1692 void BJSON::SetInteger(PBVAL vlp, int n)
1693 {
1694   vlp->N = n;
1695   vlp->Type = TYPE_INTG;
1696 } // end of SetInteger
1697 
1698 /***********************************************************************/
1699 /* Set the Value's Boolean value as a tiny integer.                    */
1700 /***********************************************************************/
SetBool(PBVAL vlp,bool b)1701 void BJSON::SetBool(PBVAL vlp, bool b)
1702 {
1703   vlp->B = b;
1704   vlp->Type = TYPE_BOOL;
1705 } // end of SetTiny
1706 
1707 /***********************************************************************/
1708 /* Set the Value's value as the given big integer.                     */
1709 /***********************************************************************/
SetBigint(PBVAL vlp,longlong ll)1710 void BJSON::SetBigint(PBVAL vlp, longlong ll)
1711 {
1712   if (ll >= INT_MIN32 && ll <= INT_MAX32) {
1713     vlp->N = (int)ll;
1714     vlp->Type = TYPE_INTG;
1715   } else {
1716     longlong* llp = (longlong*)PlugSubAlloc(G, NULL, sizeof(longlong));
1717 
1718     *llp = ll;
1719     vlp->To_Val = MOF(llp);
1720     vlp->Type = TYPE_BINT;
1721   } // endif ll
1722 
1723 } // end of SetBigint
1724 
1725 /***********************************************************************/
1726 /* Set the Value's value as the given DOUBLE.                          */
1727 /***********************************************************************/
SetFloat(PBVAL vlp,double d,int prec)1728 void BJSON::SetFloat(PBVAL vlp, double d, int prec)
1729 {
1730   int nd = MY_MIN((prec < 0) ? GetJsonDefPrec() : prec, 16);
1731 
1732   if (nd < 6 && d >= FLT_MIN && d <= FLT_MAX) {
1733     vlp->F = (float)d;
1734     vlp->Type = TYPE_FLOAT;
1735   } else {
1736     double* dp = (double*)BsonSubAlloc(sizeof(double));
1737 
1738     *dp = d;
1739     vlp->To_Val = MOF(dp);
1740     vlp->Type = TYPE_DBL;
1741   } // endif nd
1742 
1743   vlp->Nd = nd;
1744 } // end of SetFloat
1745 
1746 /***********************************************************************/
1747 /* Set the Value's value as the given DOUBLE representation.                          */
1748 /***********************************************************************/
SetFloat(PBVAL vlp,PSZ s)1749 void BJSON::SetFloat(PBVAL vlp, PSZ s)
1750 {
1751   char  *p = strchr(s, '.');
1752   int    nd = 0;
1753   double d = atof(s);
1754 
1755   if (p) {
1756     for (++p; isdigit(*p); nd++, p++);
1757     for (--p; *p == '0'; nd--, p--);
1758   } // endif p
1759 
1760   SetFloat(vlp, d, nd);
1761 } // end of SetFloat
1762 
1763  /***********************************************************************/
1764 /* Set the Value's value as the given string.                          */
1765 /***********************************************************************/
SetString(PBVAL vlp,PSZ s,int ci)1766 void BJSON::SetString(PBVAL vlp, PSZ s, int ci)
1767 {
1768   vlp->To_Val = MOF(s);
1769   vlp->Nd = ci;
1770   vlp->Type = TYPE_STRG;
1771 } // end of SetString
1772 
1773 /***********************************************************************/
1774 /* True when its JSON or normal value is null.                         */
1775 /***********************************************************************/
IsValueNull(PBVAL vlp)1776 bool BJSON::IsValueNull(PBVAL vlp)
1777 {
1778   bool b;
1779 
1780   switch (vlp->Type) {
1781   case TYPE_NULL:
1782     b = true;
1783     break;
1784   case TYPE_JOB:
1785     b = IsObjectNull(vlp);
1786     break;
1787   case TYPE_JAR:
1788     b = IsArrayNull(vlp);
1789     break;
1790   default:
1791     b = false;
1792   } // endswitch Type
1793 
1794   return b;
1795   } // end of IsNull
1796