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