summaryrefslogtreecommitdiffstats
path: root/storage/connect/bson.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 18:00:34 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 18:00:34 +0000
commit3f619478f796eddbba6e39502fe941b285dd97b1 (patch)
treee2c7b5777f728320e5b5542b6213fd3591ba51e2 /storage/connect/bson.cpp
parentInitial commit. (diff)
downloadmariadb-upstream.tar.xz
mariadb-upstream.zip
Adding upstream version 1:10.11.6.upstream/1%10.11.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'storage/connect/bson.cpp')
-rw-r--r--storage/connect/bson.cpp1795
1 files changed, 1795 insertions, 0 deletions
diff --git a/storage/connect/bson.cpp b/storage/connect/bson.cpp
new file mode 100644
index 00000000..44d53ba1
--- /dev/null
+++ b/storage/connect/bson.cpp
@@ -0,0 +1,1795 @@
+/*************** bson CPP Declares Source Code File (.H) ***************/
+/* Name: bson.cpp Version 1.0 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2020 */
+/* */
+/* This file contains the BJSON classes functions. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the MariaDB header file. */
+/***********************************************************************/
+#include <my_global.h>
+#include <m_string.h>
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* bson.h is header containing the BSON classes declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "bson.h"
+
+/***********************************************************************/
+/* Check macro. */
+/***********************************************************************/
+#if defined(_DEBUG)
+#define CheckType(X,Y) if (!X || X ->Type != Y) throw MSG(VALTYPE_NOMATCH);
+#else
+#define CheckType(X,Y)
+#endif
+
+#if defined(_WIN32)
+#define EL "\r\n"
+#else
+#define EL "\n"
+#undef SE_CATCH // Does not work for Linux
+#endif
+
+int GetJsonDefPrec(void);
+
+#if defined(SE_CATCH)
+/**************************************************************************/
+/* This is the support of catching C interrupts to prevent crashes. */
+/**************************************************************************/
+#include <eh.h>
+
+class SE_Exception {
+public:
+ SE_Exception(unsigned int n, PEXCEPTION_RECORD p) : nSE(n), eRec(p) {}
+ ~SE_Exception() {}
+
+ unsigned int nSE;
+ PEXCEPTION_RECORD eRec;
+}; // end of class SE_Exception
+
+void trans_func(unsigned int u, _EXCEPTION_POINTERS* pExp) {
+ throw SE_Exception(u, pExp->ExceptionRecord);
+} // end of trans_func
+
+char* GetExceptionDesc(PGLOBAL g, unsigned int e);
+#endif // SE_CATCH
+
+/* --------------------------- Class BDOC ---------------------------- */
+
+/***********************************************************************/
+/* BDOC constructor. */
+/***********************************************************************/
+BDOC::BDOC(PGLOBAL G) : BJSON(G, NULL)
+{
+ jp = NULL;
+ s = NULL;
+ len = 0;
+ pretty = 3;
+ pty[0] = pty[1] = pty[2] = true;
+ comma = false;
+} // end of BDOC constructor
+
+/***********************************************************************/
+/* Parse a json string. */
+/* Note: when pretty is not known, the caller set pretty to 3. */
+/***********************************************************************/
+PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng)
+{
+ size_t i;
+ bool b = false;
+ PBVAL bvp = NULL;
+
+ s = js;
+ len = lng;
+ xtrc(1, "BDOC::ParseJson: s=%.10s len=%zd\n", s, len);
+
+ if (!s || !len) {
+ strcpy(g->Message, "Void JSON object");
+ return NULL;
+ } // endif s
+
+ // Trying to guess the pretty format
+ if (s[0] == '[' && (s[1] == '\n' || (s[1] == '\r' && s[2] == '\n')))
+ pty[0] = false;
+
+ try {
+ bvp = NewVal();
+ bvp->Type = TYPE_UNKNOWN;
+
+ for (i = 0; i < len; i++)
+ switch (s[i]) {
+ case '[':
+ if (bvp->Type != TYPE_UNKNOWN)
+ bvp->To_Val = ParseAsArray(i);
+ else
+ bvp->To_Val = ParseArray(++i);
+
+ bvp->Type = TYPE_JAR;
+ break;
+ case '{':
+ if (bvp->Type != TYPE_UNKNOWN) {
+ bvp->To_Val = ParseAsArray(i);
+ bvp->Type = TYPE_JAR;
+ } else {
+ bvp->To_Val = ParseObject(++i);
+ bvp->Type = TYPE_JOB;
+ } // endif Type
+
+ break;
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ break;
+ case ',':
+ if (bvp->Type != TYPE_UNKNOWN && (pretty == 1 || pretty == 3)) {
+ comma = true;
+ pty[0] = pty[2] = false;
+ break;
+ } // endif pretty
+
+ snprintf(g->Message, sizeof(g->Message), "Unexpected ',' (pretty=%d)", pretty);
+ throw 3;
+ case '(':
+ b = true;
+ break;
+ case ')':
+ if (b) {
+ b = false;
+ break;
+ } // endif b
+ /* fall through */
+ default:
+ if (bvp->Type != TYPE_UNKNOWN) {
+ bvp->To_Val = ParseAsArray(i);
+ bvp->Type = TYPE_JAR;
+ } else if ((bvp->To_Val = MOF(ParseValue(i, NewVal()))))
+ bvp->Type = TYPE_JVAL;
+ else
+ throw 4;
+
+ break;
+ }; // endswitch s[i]
+
+ if (bvp->Type == TYPE_UNKNOWN)
+ snprintf(g->Message, sizeof(g->Message), "Invalid Json string '%.*s'", MY_MIN((int)len, 50), s);
+ else if (pretty == 3) {
+ for (i = 0; i < 3; i++)
+ if (pty[i]) {
+ pretty = i;
+ break;
+ } // endif pty
+
+ } // endif ptyp
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, G->Message);
+ GetMsg(g);
+ bvp = NULL;
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ bvp = NULL;
+ } // end catch
+
+ return bvp;
+} // end of ParseJson
+
+/***********************************************************************/
+/* Parse several items as being in an array. */
+/***********************************************************************/
+OFFSET BDOC::ParseAsArray(size_t& i) {
+ if (pty[0] && (!pretty || pretty > 2)) {
+ OFFSET jsp;
+
+ if ((jsp = ParseArray((i = 0))) && pretty == 3)
+ pretty = (pty[0]) ? 0 : 3;
+
+ return jsp;
+ } else
+ strcpy(G->Message, "More than one item in file");
+
+ return 0;
+} // end of ParseAsArray
+
+/***********************************************************************/
+/* Parse a JSON Array. */
+/***********************************************************************/
+OFFSET BDOC::ParseArray(size_t& i)
+{
+ int level = 0;
+ bool b = (!i);
+ PBVAL vlp, firstvlp, lastvlp;
+
+ vlp = firstvlp = lastvlp = NULL;
+
+ for (; i < len; i++)
+ switch (s[i]) {
+ case ',':
+ if (level < 2) {
+ snprintf(G->Message, sizeof(G->Message), "Unexpected ',' near %.*s", (int) ARGS);
+ throw 1;
+ } else
+ level = 1;
+
+ break;
+ case ']':
+ if (level == 1) {
+ snprintf(G->Message, sizeof(G->Message), "Unexpected ',]' near %.*s", (int) ARGS);
+ throw 1;
+ } // endif level
+
+ return MOF(firstvlp);
+ case '\n':
+ if (!b)
+ pty[0] = pty[1] = false;
+ case '\r':
+ case ' ':
+ case '\t':
+ break;
+ default:
+ if (level == 2) {
+ snprintf(G->Message, sizeof(G->Message), "Unexpected value near %.*s", (int) ARGS);
+ throw 1;
+ } else if (lastvlp) {
+ vlp = ParseValue(i, NewVal());
+ lastvlp->Next = MOF(vlp);
+ lastvlp = vlp;
+ } else
+ firstvlp = lastvlp = ParseValue(i, NewVal());
+
+ level = (b) ? 1 : 2;
+ break;
+ }; // endswitch s[i]
+
+ if (b) {
+ // Case of Pretty == 0
+ return MOF(firstvlp);
+ } // endif b
+
+ throw ("Unexpected EOF in array");
+} // end of ParseArray
+
+/***********************************************************************/
+/* Parse a JSON Object. */
+/***********************************************************************/
+OFFSET BDOC::ParseObject(size_t& i)
+{
+ OFFSET key;
+ int level = 0;
+ PBPR bpp, firstbpp, lastbpp;
+
+ bpp = firstbpp = lastbpp = NULL;
+
+ for (; i < len; i++)
+ switch (s[i]) {
+ case '"':
+ if (level < 2) {
+ key = ParseString(++i);
+ bpp = NewPair(key);
+
+ if (lastbpp) {
+ lastbpp->Vlp.Next = MOF(bpp);
+ lastbpp = bpp;
+ } else
+ firstbpp = lastbpp = bpp;
+
+ level = 2;
+ } else {
+ snprintf(G->Message, sizeof(G->Message), "misplaced string near %.*s", (int) ARGS);
+ throw 2;
+ } // endif level
+
+ break;
+ case ':':
+ if (level == 2) {
+ ParseValue(++i, GetVlp(lastbpp));
+ level = 3;
+ } else {
+ snprintf(G->Message, sizeof(G->Message), "Unexpected ':' near %.*s", (int) ARGS);
+ throw 2;
+ } // endif level
+
+ break;
+ case ',':
+ if (level < 3) {
+ snprintf(G->Message, sizeof(G->Message), "Unexpected ',' near %.*s", (int) ARGS);
+ throw 2;
+ } else
+ level = 1;
+
+ break;
+ case '}':
+ if (!(level == 0 || level == 3)) {
+ snprintf(G->Message, sizeof(G->Message), "Unexpected '}' near %.*s", (int) ARGS);
+ throw 2;
+ } // endif level
+
+ return MOF(firstbpp);
+ case '\n':
+ pty[0] = pty[1] = false;
+ case '\r':
+ case ' ':
+ case '\t':
+ break;
+ default:
+ snprintf(G->Message, sizeof(G->Message), "Unexpected character '%c' near %.*s",
+ s[i], (int) ARGS);
+ throw 2;
+ }; // endswitch s[i]
+
+ strcpy(G->Message, "Unexpected EOF in Object");
+ throw 2;
+} // end of ParseObject
+
+/***********************************************************************/
+/* Parse a JSON Value. */
+/***********************************************************************/
+PBVAL BDOC::ParseValue(size_t& i, PBVAL bvp)
+{
+ for (; i < len; i++)
+ switch (s[i]) {
+ case '\n':
+ pty[0] = pty[1] = false;
+ case '\r':
+ case ' ':
+ case '\t':
+ break;
+ default:
+ goto suite;
+ } // endswitch
+
+suite:
+ switch (s[i]) {
+ case '[':
+ bvp->To_Val = ParseArray(++i);
+ bvp->Type = TYPE_JAR;
+ break;
+ case '{':
+ bvp->To_Val = ParseObject(++i);
+ bvp->Type = TYPE_JOB;
+ break;
+ case '"':
+ bvp->To_Val = ParseString(++i);
+ bvp->Type = TYPE_STRG;
+ break;
+ case 't':
+ if (!strncmp(s + i, "true", 4)) {
+ bvp->B = true;
+ bvp->Type = TYPE_BOOL;
+ i += 3;
+ } else
+ goto err;
+
+ break;
+ case 'f':
+ if (!strncmp(s + i, "false", 5)) {
+ bvp->B = false;
+ bvp->Type = TYPE_BOOL;
+ i += 4;
+ } else
+ goto err;
+
+ break;
+ case 'n':
+ if (!strncmp(s + i, "null", 4)) {
+ bvp->Type = TYPE_NULL;
+ i += 3;
+ } else
+ goto err;
+
+ break;
+ case '-':
+ default:
+ if (s[i] == '-' || isdigit(s[i]))
+ ParseNumeric(i, bvp);
+ else
+ goto err;
+
+ }; // endswitch s[i]
+
+ return bvp;
+
+err:
+ snprintf(G->Message, sizeof(G->Message), "Unexpected character '%c' near %.*s", s[i], (int) ARGS);
+ throw 3;
+} // end of ParseValue
+
+/***********************************************************************/
+/* Unescape and parse a JSON string. */
+/***********************************************************************/
+OFFSET BDOC::ParseString(size_t& i)
+{
+ uchar* p;
+ int n = 0;
+
+ // Be sure of memory availability
+ if (((size_t)len + 1 - i) > ((PPOOLHEADER)G->Sarea)->FreeBlk)
+ throw("ParseString: Out of memory");
+
+ // The size to allocate is not known yet
+ p = (uchar*)BsonSubAlloc(0);
+
+ for (; i < len; i++)
+ switch (s[i]) {
+ case '"':
+ p[n++] = 0;
+ BsonSubAlloc(n);
+ return MOF(p);
+ case '\\':
+ if (++i < len) {
+ if (s[i] == 'u') {
+ if (len - i > 5) {
+ // if (charset == utf8) {
+ char xs[5];
+ uint hex;
+
+ xs[0] = s[++i];
+ xs[1] = s[++i];
+ xs[2] = s[++i];
+ xs[3] = s[++i];
+ xs[4] = 0;
+ hex = strtoul(xs, NULL, 16);
+
+ if (hex < 0x80) {
+ p[n] = (uchar)hex;
+ } else if (hex < 0x800) {
+ p[n++] = (uchar)(0xC0 | (hex >> 6));
+ p[n] = (uchar)(0x80 | (hex & 0x3F));
+ } else if (hex < 0x10000) {
+ p[n++] = (uchar)(0xE0 | (hex >> 12));
+ p[n++] = (uchar)(0x80 | ((hex >> 6) & 0x3f));
+ p[n] = (uchar)(0x80 | (hex & 0x3f));
+ } else
+ p[n] = '?';
+
+#if 0
+ } else {
+ char xs[3];
+ UINT hex;
+
+ i += 2;
+ xs[0] = s[++i];
+ xs[1] = s[++i];
+ xs[2] = 0;
+ hex = strtoul(xs, NULL, 16);
+ p[n] = (char)hex;
+ } // endif charset
+#endif // 0
+ } else
+ goto err;
+
+ } else switch (s[i]) {
+ case 't': p[n] = '\t'; break;
+ case 'n': p[n] = '\n'; break;
+ case 'r': p[n] = '\r'; break;
+ case 'b': p[n] = '\b'; break;
+ case 'f': p[n] = '\f'; break;
+ default: p[n] = s[i]; break;
+ } // endswitch
+
+ n++;
+ } else
+ goto err;
+
+ break;
+ default:
+ p[n++] = s[i];
+ break;
+}; // endswitch s[i]
+
+err:
+throw("Unexpected EOF in String");
+} // end of ParseString
+
+/***********************************************************************/
+/* Parse a JSON numeric value. */
+/***********************************************************************/
+void BDOC::ParseNumeric(size_t& i, PBVAL vlp)
+{
+ char buf[50];
+ int n = 0;
+ short nd = 0;
+ bool has_dot = false;
+ bool has_e = false;
+ bool found_digit = false;
+
+ for (; i < len; i++) {
+ switch (s[i]) {
+ case '.':
+ if (!found_digit || has_dot || has_e)
+ goto err;
+
+ has_dot = true;
+ break;
+ case 'e':
+ case 'E':
+ if (!found_digit || has_e)
+ goto err;
+
+ has_e = true;
+ found_digit = false;
+ break;
+ case '+':
+ if (!has_e)
+ goto err;
+
+ // fall through
+ case '-':
+ if (found_digit)
+ goto err;
+
+ break;
+ default:
+ if (isdigit(s[i])) {
+ if (has_dot && !has_e)
+ nd++; // Number of decimals
+
+ found_digit = true;
+ } else
+ goto fin;
+
+ }; // endswitch s[i]
+
+ buf[n++] = s[i];
+ } // endfor i
+
+fin:
+ if (found_digit) {
+ buf[n] = 0;
+
+ if (has_dot || has_e) {
+ double dv = atof(buf);
+
+ if (nd >= 6 || dv > FLT_MAX || dv < FLT_MIN) {
+ double* dvp = (double*)PlugSubAlloc(G, NULL, sizeof(double));
+
+ *dvp = dv;
+ vlp->To_Val = MOF(dvp);
+ vlp->Type = TYPE_DBL;
+ } else {
+ vlp->F = (float)dv;
+ vlp->Type = TYPE_FLOAT;
+ } // endif nd
+
+ vlp->Nd = MY_MIN(nd, 16);
+ } else {
+ longlong iv = strtoll(buf, NULL, 10);
+
+ if (iv > INT_MAX32 || iv < INT_MIN32) {
+ longlong *llp = (longlong*)PlugSubAlloc(G, NULL, sizeof(longlong));
+
+ *llp = iv;
+ vlp->To_Val = MOF(llp);
+ vlp->Type = TYPE_BINT;
+ } else {
+ vlp->N = (int)iv;
+ vlp->Type = TYPE_INTG;
+ } // endif iv
+
+ } // endif has
+
+ i--; // Unstack following character
+ return;
+ } else
+ throw("No digit found");
+
+err:
+ throw("Unexpected EOF in number");
+} // end of ParseNumeric
+
+/***********************************************************************/
+/* Serialize a BJSON document tree: */
+/***********************************************************************/
+PSZ BDOC::Serialize(PGLOBAL g, PBVAL bvp, char* fn, int pretty)
+{
+ PSZ str = NULL;
+ bool b = false, err = true;
+ FILE* fs = NULL;
+
+ G->Message[0] = 0;
+
+ try {
+ if (!bvp) {
+ safe_strcpy(g->Message, sizeof(g->Message), "Null json tree");
+ throw 1;
+ } else if (!fn) {
+ // Serialize to a string
+ jp = new(g) JOUTSTR(g);
+ b = pretty == 1;
+ } else {
+ if (!(fs = fopen(fn, "wb"))) {
+ snprintf(g->Message, sizeof(g->Message), MSG(OPEN_MODE_ERROR) ": %s",
+ "w", (int)errno, fn, strerror(errno));
+ throw 2;
+ } else if (pretty >= 2) {
+ // Serialize to a pretty file
+ jp = new(g)JOUTPRT(g, fs);
+ } else {
+ // Serialize to a flat file
+ b = true;
+ jp = new(g)JOUTFILE(g, fs, pretty);
+ } // endif's
+
+ } // endif's
+
+ switch (bvp->Type) {
+ case TYPE_JAR:
+ err = SerializeArray(bvp->To_Val, b);
+ break;
+ case TYPE_JOB:
+ err = ((b && jp->Prty()) && jp->WriteChr('\t'));
+ err |= SerializeObject(bvp->To_Val);
+ break;
+ case TYPE_JVAL:
+ err = SerializeValue(MVP(bvp->To_Val));
+ break;
+ default:
+ err = SerializeValue(bvp, true);
+ } // endswitch Type
+
+ if (fs) {
+ fputs(EL, fs);
+ fclose(fs);
+ str = (err) ? NULL : strcpy(g->Message, "Ok");
+ } else if (!err) {
+ str = ((JOUTSTR*)jp)->Strp;
+ jp->WriteChr('\0');
+ PlugSubAlloc(g, NULL, ((JOUTSTR*)jp)->N);
+ } else if (G->Message[0])
+ strcpy(g->Message, "Error in Serialize");
+ else
+ GetMsg(g);
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, G->Message);
+ GetMsg(g);
+ str = NULL;
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ str = NULL;
+ } // end catch
+
+ return str;
+} // end of Serialize
+
+
+/***********************************************************************/
+/* Serialize a JSON Array. */
+/***********************************************************************/
+bool BDOC::SerializeArray(OFFSET arp, bool b)
+{
+ bool first = true;
+ PBVAL vp = MVP(arp);
+
+ if (b) {
+ if (jp->Prty()) {
+ if (jp->WriteChr('['))
+ return true;
+ else if (jp->Prty() == 1 && (jp->WriteStr(EL) || jp->WriteChr('\t')))
+ return true;
+
+ } // endif Prty
+
+ } else if (jp->WriteChr('['))
+ return true;
+
+ for (; vp; vp = MVP(vp->Next)) {
+ if (first)
+ first = false;
+ else if ((!b || jp->Prty()) && jp->WriteChr(','))
+ return true;
+ else if (b) {
+ if (jp->Prty() < 2 && jp->WriteStr(EL))
+ return true;
+ else if (jp->Prty() == 1 && jp->WriteChr('\t'))
+ return true;
+
+ } // endif b
+
+ if (SerializeValue(vp))
+ return true;
+
+ } // endfor vp
+
+ if (b && jp->Prty() == 1 && jp->WriteStr(EL))
+ return true;
+
+ return ((!b || jp->Prty()) && jp->WriteChr(']'));
+} // end of SerializeArray
+
+/***********************************************************************/
+/* Serialize a JSON Object. */
+/***********************************************************************/
+bool BDOC::SerializeObject(OFFSET obp)
+{
+ bool first = true;
+ PBPR prp = MPP(obp);
+
+ if (jp->WriteChr('{'))
+ return true;
+
+ for (; prp; prp = GetNext(prp)) {
+ if (first)
+ first = false;
+ else if (jp->WriteChr(','))
+ return true;
+
+ if (jp->WriteChr('"') ||
+ jp->WriteStr(MZP(prp->Key)) ||
+ jp->WriteChr('"') ||
+ jp->WriteChr(':') ||
+ SerializeValue(GetVlp(prp)))
+ return true;
+
+ } // endfor i
+
+ return jp->WriteChr('}');
+} // end of SerializeObject
+
+/***********************************************************************/
+/* Serialize a JSON Value. */
+/***********************************************************************/
+bool BDOC::SerializeValue(PBVAL jvp, bool b)
+{
+ char buf[64];
+
+ if (jvp) switch (jvp->Type) {
+ case TYPE_JAR:
+ return SerializeArray(jvp->To_Val, false);
+ case TYPE_JOB:
+ return SerializeObject(jvp->To_Val);
+ case TYPE_BOOL:
+ return jp->WriteStr(jvp->B ? "true" : "false");
+ case TYPE_STRG:
+ case TYPE_DTM:
+ if (b) {
+ return jp->WriteStr(MZP(jvp->To_Val));
+ } else
+ return jp->Escape(MZP(jvp->To_Val));
+
+ case TYPE_INTG:
+ snprintf(buf, sizeof(buf), "%d", jvp->N);
+ return jp->WriteStr(buf);
+ case TYPE_BINT:
+ snprintf(buf, sizeof(buf), "%lld", *(longlong*)MakePtr(Base, jvp->To_Val));
+ return jp->WriteStr(buf);
+ case TYPE_FLOAT:
+ snprintf(buf, sizeof(buf), "%.*f", jvp->Nd, jvp->F);
+ return jp->WriteStr(buf);
+ case TYPE_DBL:
+ snprintf(buf, sizeof(buf), "%.*lf", jvp->Nd, *(double*)MakePtr(Base, jvp->To_Val));
+ return jp->WriteStr(buf);
+ case TYPE_NULL:
+ return jp->WriteStr("null");
+ case TYPE_JVAL:
+ return SerializeValue(MVP(jvp->To_Val));
+ default:
+ return jp->WriteStr("???"); // TODO
+ } // endswitch Type
+
+ return jp->WriteStr("null");
+} // end of SerializeValue
+
+/* --------------------------- Class BJSON --------------------------- */
+
+/***********************************************************************/
+/* Program for sub-allocating Bjson structures. */
+/***********************************************************************/
+void* BJSON::BsonSubAlloc(size_t size)
+{
+ PPOOLHEADER pph; /* Points on area header. */
+ void* memp = G->Sarea;
+
+ size = ((size + 3) / 4) * 4; /* Round up size to multiple of 4 */
+ pph = (PPOOLHEADER)memp;
+
+ xtrc(16, "SubAlloc in %p size=%zd used=%zd free=%zd\n",
+ memp, size, pph->To_Free, pph->FreeBlk);
+
+ if (size > pph->FreeBlk) { /* Not enough memory left in pool */
+ snprintf(G->Message, sizeof(G->Message),
+ "Not enough memory for request of %zd (used=%zd free=%zd)",
+ size, pph->To_Free, pph->FreeBlk);
+ xtrc(1, "BsonSubAlloc: %s\n", G->Message);
+
+ if (Throw)
+ throw(1234);
+ else
+ return NULL;
+
+ } /* endif size OS32 code */
+
+ // Do the suballocation the simplest way
+ memp = MakePtr(memp, pph->To_Free); /* Points to suballocated block */
+ pph->To_Free += size; /* New offset of pool free block */
+ pph->FreeBlk -= size; /* New size of pool free block */
+ xtrc(16, "Done memp=%p used=%zd free=%zd\n",
+ memp, pph->To_Free, pph->FreeBlk);
+ return memp;
+} // end of BsonSubAlloc
+
+/*********************************************************************************/
+/* Program for SubSet re-initialization of the memory pool. */
+/*********************************************************************************/
+PSZ BJSON::NewStr(PSZ str)
+{
+ if (str) {
+ PSZ sm = (PSZ)BsonSubAlloc(strlen(str) + 1);
+
+ strcpy(sm, str);
+ return sm;
+ } else
+ return NULL;
+
+} // end of NewStr
+
+/*********************************************************************************/
+/* Program for SubSet re-initialization of the memory pool. */
+/*********************************************************************************/
+void BJSON::SubSet(bool b)
+{
+ PPOOLHEADER pph = (PPOOLHEADER)G->Sarea;
+
+ pph->To_Free = (G->Saved_Size) ? G->Saved_Size : sizeof(POOLHEADER);
+ pph->FreeBlk = G->Sarea_Size - pph->To_Free;
+
+ if (b)
+ G->Saved_Size = 0;
+
+} // end of SubSet
+
+/*********************************************************************************/
+/* Set the beginning of suballocations. */
+/*********************************************************************************/
+void BJSON::MemSet(size_t size)
+{
+ PPOOLHEADER pph = (PPOOLHEADER)G->Sarea;
+
+ pph->To_Free = size + sizeof(POOLHEADER);
+ pph->FreeBlk = G->Sarea_Size - pph->To_Free;
+} // end of MemSet
+
+ /* ------------------------ Bobject functions ------------------------ */
+
+/***********************************************************************/
+/* Set a pair vlp to some PVAL values. */
+/***********************************************************************/
+void BJSON::SetPairValue(PBPR brp, PBVAL bvp)
+{
+ if (bvp) {
+ brp->Vlp.To_Val = bvp->To_Val;
+ brp->Vlp.Nd = bvp->Nd;
+ brp->Vlp.Type = bvp->Type;
+ } else {
+ brp->Vlp.To_Val = 0;
+ brp->Vlp.Nd = 0;
+ brp->Vlp.Type = TYPE_NULL;
+ } // endif bvp
+
+} // end of SetPairValue
+
+ /***********************************************************************/
+/* Sub-allocate and initialize a BPAIR. */
+/***********************************************************************/
+PBPR BJSON::NewPair(OFFSET key, int type)
+{
+ PBPR bpp = (PBPR)BsonSubAlloc(sizeof(BPAIR));
+
+ bpp->Key = key;
+ bpp->Vlp.Type = type;
+ bpp->Vlp.To_Val = 0;
+ bpp->Vlp.Nd = 0;
+ bpp->Vlp.Next = 0;
+ return bpp;
+} // end of SubAllocPair
+
+/***********************************************************************/
+/* Return the number of pairs in this object. */
+/***********************************************************************/
+int BJSON::GetObjectSize(PBVAL bop, bool b)
+{
+ CheckType(bop, TYPE_JOB);
+ int n = 0;
+
+ for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
+ // If b return only non null pairs
+ if (!b || (brp->Vlp.To_Val && brp->Vlp.Type != TYPE_NULL))
+ n++;
+
+ return n;
+} // end of GetObjectSize
+
+/***********************************************************************/
+/* Add a new pair to an Object and return it. */
+/***********************************************************************/
+PBVAL BJSON::AddPair(PBVAL bop, PSZ key, int type)
+{
+ CheckType(bop, TYPE_JOB);
+ PBPR brp;
+ OFFSET nrp = NewPair(key, type);
+
+ if (bop->To_Val) {
+ for (brp = GetObject(bop); brp->Vlp.Next; brp = GetNext(brp));
+
+ brp->Vlp.Next = nrp;
+ } else
+ bop->To_Val = nrp;
+
+ bop->Nd++;
+ return GetVlp(MPP(nrp));
+} // end of AddPair
+
+/***********************************************************************/
+/* Return all object keys as an array. */
+/***********************************************************************/
+PBVAL BJSON::GetKeyList(PBVAL bop)
+{
+ CheckType(bop, TYPE_JOB);
+ PBVAL arp = NewVal(TYPE_JAR);
+
+ for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
+ AddArrayValue(arp, MOF(SubAllocVal(brp->Key, TYPE_STRG)));
+
+ return arp;
+} // end of GetKeyList
+
+/***********************************************************************/
+/* Return all object values as an array. */
+/***********************************************************************/
+PBVAL BJSON::GetObjectValList(PBVAL bop)
+{
+ CheckType(bop, TYPE_JOB);
+ PBVAL arp = NewVal(TYPE_JAR);
+
+ for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
+ AddArrayValue(arp, DupVal(GetVlp(brp)));
+
+ return arp;
+} // end of GetObjectValList
+
+/***********************************************************************/
+/* Get the value corresponding to the given key. */
+/***********************************************************************/
+PBVAL BJSON::GetKeyValue(PBVAL bop, PSZ key)
+{
+ CheckType(bop, TYPE_JOB);
+
+ for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
+ if (!strcmp(GetKey(brp), key))
+ return GetVlp(brp);
+
+ return NULL;
+} // end of GetKeyValue;
+
+/***********************************************************************/
+/* Return the text corresponding to all keys (XML like). */
+/***********************************************************************/
+PSZ BJSON::GetObjectText(PGLOBAL g, PBVAL bop, PSTRG text)
+{
+ CheckType(bop, TYPE_JOB);
+ PBPR brp = GetObject(bop);
+
+ if (brp) {
+ bool b;
+
+ if (!text) {
+ text = new(g) STRING(g, 256);
+ b = true;
+ } else {
+ if (text->GetLastChar() != ' ')
+ text->Append(' ');
+
+ b = false;
+ } // endif text
+
+ if (b && !brp->Vlp.Next && !strcmp(MZP(brp->Key), "$date")) {
+ int i;
+ PSZ s;
+
+ GetValueText(g, GetVlp(brp), text);
+ s = text->GetStr();
+ i = (s[1] == '-' ? 2 : 1);
+
+ if (IsNum(s + i)) {
+ // Date is in milliseconds
+ int j = text->GetLength();
+
+ if (j >= 4 + i) {
+ s[j - 3] = 0; // Change it to seconds
+ text->SetLength((uint)strlen(s));
+ } else
+ text->Set(" 0");
+
+ } // endif text
+
+ } else for (; brp; brp = GetNext(brp)) {
+ GetValueText(g, GetVlp(brp), text);
+
+ if (brp->Vlp.Next)
+ text->Append(' ');
+
+ } // endfor brp
+
+ if (b) {
+ text->Trim();
+ return text->GetStr();
+ } // endif b
+
+ } // endif bop
+
+ return NULL;
+} // end of GetObjectText;
+
+/***********************************************************************/
+/* Set or add a value corresponding to the given key. */
+/***********************************************************************/
+void BJSON::SetKeyValue(PBVAL bop, OFFSET bvp, PSZ key)
+{
+ CheckType(bop, TYPE_JOB);
+ PBPR brp, prp = NULL;
+
+ if (bop->To_Val) {
+ for (brp = GetObject(bop); brp; brp = GetNext(brp))
+ if (!strcmp(GetKey(brp), key))
+ break;
+ else
+ prp = brp;
+
+ if (!brp)
+ brp = MPP(prp->Vlp.Next = NewPair(key));
+
+ } else
+ brp = MPP(bop->To_Val = NewPair(key));
+
+ SetPairValue(brp, MVP(bvp));
+ bop->Nd++;
+} // end of SetKeyValue
+
+/***********************************************************************/
+/* Merge two objects. */
+/***********************************************************************/
+PBVAL BJSON::MergeObject(PBVAL bop1, PBVAL bop2)
+{
+ CheckType(bop1, TYPE_JOB);
+ CheckType(bop2, TYPE_JOB);
+
+ if (bop1->To_Val)
+ for (PBPR brp = GetObject(bop2); brp; brp = GetNext(brp))
+ SetKeyValue(bop1, GetVlp(brp), GetKey(brp));
+
+ else {
+ bop1->To_Val = bop2->To_Val;
+ bop1->Nd = bop2->Nd;
+ } // endelse To_Val
+
+ return bop1;
+} // end of MergeObject;
+
+/***********************************************************************/
+/* Delete a value corresponding to the given key. */
+/***********************************************************************/
+bool BJSON::DeleteKey(PBVAL bop, PCSZ key)
+{
+ CheckType(bop, TYPE_JOB);
+ PBPR brp, pbrp = NULL;
+
+ for (brp = GetObject(bop); brp; brp = GetNext(brp))
+ if (!strcmp(MZP(brp->Key), key)) {
+ if (pbrp) {
+ pbrp->Vlp.Next = brp->Vlp.Next;
+ } else
+ bop->To_Val = brp->Vlp.Next;
+
+ bop->Nd--;
+ return true;;
+ } else
+ pbrp = brp;
+
+ return false;
+} // end of DeleteKey
+
+/***********************************************************************/
+/* True if void or if all members are nulls. */
+/***********************************************************************/
+bool BJSON::IsObjectNull(PBVAL bop)
+{
+ CheckType(bop, TYPE_JOB);
+
+ for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
+ if (brp->Vlp.To_Val && brp->Vlp.Type != TYPE_NULL)
+ return false;
+
+ return true;
+} // end of IsObjectNull
+
+/* ------------------------- Barray functions ------------------------ */
+
+/***********************************************************************/
+/* Return the number of values in this object. */
+/***********************************************************************/
+int BJSON::GetArraySize(PBVAL bap, bool b)
+{
+ CheckType(bap, TYPE_JAR);
+ int n = 0;
+
+ for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp))
+ // If b, return only non null values
+ if (!b || bvp->Type != TYPE_NULL)
+ n++;
+
+ return n;
+} // end of GetArraySize
+
+/***********************************************************************/
+/* Get the Nth value of an Array. */
+/***********************************************************************/
+PBVAL BJSON::GetArrayValue(PBVAL bap, int n)
+{
+ CheckType(bap, TYPE_JAR);
+ int i = 0;
+
+ if (n < 0)
+ n += GetArraySize(bap);
+
+ for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp), i++)
+ if (i == n)
+ return bvp;
+
+ return NULL;
+} // end of GetArrayValue
+
+/***********************************************************************/
+/* Add a Value to the Array Value list. */
+/***********************************************************************/
+void BJSON::AddArrayValue(PBVAL bap, OFFSET nbv, int* x)
+{
+ CheckType(bap, TYPE_JAR);
+ int i = 0;
+ PBVAL bvp, lbp = NULL;
+
+ if (!nbv)
+ nbv = MOF(NewVal());
+
+ for (bvp = GetArray(bap); bvp; bvp = GetNext(bvp), i++)
+ if (x && i == *x)
+ break;
+ else
+ lbp = bvp;
+
+ if (lbp) {
+ MVP(nbv)->Next = lbp->Next;
+ lbp->Next = nbv;
+ } else {
+ MVP(nbv)->Next = bap->To_Val;
+ bap->To_Val = nbv;
+ } // endif lbp
+
+ bap->Nd++;
+} // end of AddArrayValue
+
+/***********************************************************************/
+/* Merge two arrays. */
+/***********************************************************************/
+void BJSON::MergeArray(PBVAL bap1, PBVAL bap2)
+{
+ CheckType(bap1, TYPE_JAR);
+ CheckType(bap2, TYPE_JAR);
+
+ if (bap1->To_Val) {
+ for (PBVAL bvp = GetArray(bap2); bvp; bvp = GetNext(bvp))
+ AddArrayValue(bap1, MOF(DupVal(bvp)));
+
+ } else {
+ bap1->To_Val = bap2->To_Val;
+ bap1->Nd = bap2->Nd;
+ } // endif To_Val
+
+} // end of MergeArray
+
+/***********************************************************************/
+/* Set the nth Value of the Array Value list or add it. */
+/***********************************************************************/
+void BJSON::SetArrayValue(PBVAL bap, PBVAL nvp, int n)
+{
+ CheckType(bap, TYPE_JAR);
+ int i = 0;
+ PBVAL bvp = NULL;
+
+ for (bvp = GetArray(bap); i < n; i++, bvp = bvp ? GetNext(bvp) : NULL)
+ if (!bvp)
+ AddArrayValue(bap, NewVal());
+
+ if (!bvp)
+ AddArrayValue(bap, MOF(nvp));
+ else
+ SetValueVal(bvp, nvp);
+
+} // end of SetValue
+
+/***********************************************************************/
+/* Return the text corresponding to all values. */
+/***********************************************************************/
+PSZ BJSON::GetArrayText(PGLOBAL g, PBVAL bap, PSTRG text)
+{
+ CheckType(bap, TYPE_JAR);
+
+ if (bap->To_Val) {
+ bool b;
+
+ if (!text) {
+ text = new(g) STRING(g, 256);
+ b = true;
+ } else {
+ if (text->GetLastChar() != ' ')
+ text->Append(" (");
+ else
+ text->Append('(');
+
+ b = false;
+ } // endif text
+
+ for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp)) {
+ GetValueText(g, bvp, text);
+
+ if (bvp->Next)
+ text->Append(", ");
+ else if (!b)
+ text->Append(')');
+
+ } // endfor bvp
+
+ if (b) {
+ text->Trim();
+ return text->GetStr();
+ } // endif b
+
+ } // endif To_Val
+
+ return NULL;
+} // end of GetText;
+
+/***********************************************************************/
+/* Delete a Value from the Arrays Value list. */
+/***********************************************************************/
+bool BJSON::DeleteValue(PBVAL bap, int n)
+{
+ CheckType(bap, TYPE_JAR);
+ int i = 0;
+ PBVAL bvp, pvp = NULL;
+
+ for (bvp = GetArray(bap); bvp; i++, bvp = GetNext(bvp))
+ if (i == n) {
+ if (pvp)
+ pvp->Next = bvp->Next;
+ else
+ bap->To_Val = bvp->Next;
+
+ bap->Nd--;
+ return true;;
+ } else
+ pvp = bvp;
+
+ return false;
+} // end of DeleteValue
+
+/***********************************************************************/
+/* True if void or if all members are nulls. */
+/***********************************************************************/
+bool BJSON::IsArrayNull(PBVAL bap)
+{
+ CheckType(bap, TYPE_JAR);
+
+ for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp))
+ if (bvp->Type != TYPE_NULL)
+ return false;
+
+ return true;
+} // end of IsNull
+
+/* ------------------------- Bvalue functions ------------------------ */
+
+/***********************************************************************/
+/* Sub-allocate and clear a BVAL. */
+/***********************************************************************/
+PBVAL BJSON::NewVal(int type)
+{
+ PBVAL bvp = (PBVAL)BsonSubAlloc(sizeof(BVAL));
+
+ bvp->To_Val = 0;
+ bvp->Nd = 0;
+ bvp->Type = type;
+ bvp->Next = 0;
+ return bvp;
+} // end of SubAllocVal
+
+/***********************************************************************/
+/* Sub-allocate and initialize a BVAL as type. */
+/***********************************************************************/
+PBVAL BJSON::SubAllocVal(OFFSET toval, int type, short nd)
+{
+ PBVAL bvp = NewVal(type);
+
+ bvp->To_Val = toval;
+ bvp->Nd = nd;
+ return bvp;
+} // end of SubAllocVal
+
+/***********************************************************************/
+/* Sub-allocate and initialize a BVAL as string. */
+/***********************************************************************/
+PBVAL BJSON::SubAllocStr(OFFSET toval, short nd)
+{
+ PBVAL bvp = NewVal(TYPE_STRG);
+
+ bvp->To_Val = toval;
+ bvp->Nd = nd;
+ return bvp;
+} // end of SubAllocStr
+
+/***********************************************************************/
+/* Allocate a BVALUE with a given string or numeric value. */
+/***********************************************************************/
+PBVAL BJSON::NewVal(PVAL valp)
+{
+ PBVAL vlp = NewVal();
+
+ SetValue(vlp, valp);
+ return vlp;
+} // end of SubAllocVal
+
+/***********************************************************************/
+/* Sub-allocate and initialize a BVAL from another BVAL. */
+/***********************************************************************/
+PBVAL BJSON::DupVal(PBVAL bvlp)
+{
+ if (bvlp) {
+ PBVAL bvp = NewVal();
+
+ *bvp = *bvlp;
+ bvp->Next = 0;
+ return bvp;
+ } else
+ return NULL;
+
+} // end of DupVal
+
+/***********************************************************************/
+/* Return the size of value's value. */
+/***********************************************************************/
+int BJSON::GetSize(PBVAL vlp, bool b)
+{
+ switch (vlp->Type) {
+ case TYPE_JAR:
+ return GetArraySize(vlp);
+ case TYPE_JOB:
+ return GetObjectSize(vlp);
+ default:
+ return 1;
+ } // enswitch Type
+
+} // end of GetSize
+
+PBVAL BJSON::GetBson(PBVAL bvp)
+{
+ PBVAL bp = NULL;
+
+ switch (bvp->Type) {
+ case TYPE_JAR:
+ bp = MVP(bvp->To_Val);
+ break;
+ case TYPE_JOB:
+ bp = GetVlp(MPP(bvp->To_Val));
+ break;
+ default:
+ bp = bvp;
+ break;
+ } // endswitch Type
+
+ return bp;
+} // end of GetBson
+
+/***********************************************************************/
+/* Return the Value's as a Value struct. */
+/***********************************************************************/
+PVAL BJSON::GetValue(PGLOBAL g, PBVAL vp)
+{
+ double d;
+ PVAL valp;
+ PBVAL vlp = vp->Type == TYPE_JVAL ? MVP(vp->To_Val) : vp;
+
+ switch (vlp->Type) {
+ case TYPE_STRG:
+ case TYPE_DBL:
+ case TYPE_BINT:
+ valp = AllocateValue(g, MP(vlp->To_Val), vlp->Type, vlp->Nd);
+ break;
+ case TYPE_INTG:
+ case TYPE_BOOL:
+ valp = AllocateValue(g, vlp, vlp->Type);
+ break;
+ case TYPE_FLOAT:
+ d = (double)vlp->F;
+ valp = AllocateValue(g, &d, TYPE_DOUBLE, vlp->Nd);
+ break;
+ default:
+ valp = NULL;
+ break;
+ } // endswitch Type
+
+ return valp;
+} // end of GetValue
+
+/***********************************************************************/
+/* Return the Value's Integer value. */
+/***********************************************************************/
+int BJSON::GetInteger(PBVAL vp) {
+ int n;
+ PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
+
+ switch (vlp->Type) {
+ case TYPE_INTG:
+ n = vlp->N;
+ break;
+ case TYPE_FLOAT:
+ n = (int)vlp->F;
+ break;
+ case TYPE_DTM:
+ case TYPE_STRG:
+ n = atoi(MZP(vlp->To_Val));
+ break;
+ case TYPE_BOOL:
+ n = (vlp->B) ? 1 : 0;
+ break;
+ case TYPE_BINT:
+ n = (int)*(longlong*)MP(vlp->To_Val);
+ break;
+ case TYPE_DBL:
+ n = (int)*(double*)MP(vlp->To_Val);
+ break;
+ default:
+ n = 0;
+ } // endswitch Type
+
+ return n;
+} // end of GetInteger
+
+/***********************************************************************/
+/* Return the Value's Big integer value. */
+/***********************************************************************/
+longlong BJSON::GetBigint(PBVAL vp) {
+ longlong lln;
+ PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
+
+ switch (vlp->Type) {
+ case TYPE_BINT:
+ lln = *(longlong*)MP(vlp->To_Val);
+ break;
+ case TYPE_INTG:
+ lln = (longlong)vlp->N;
+ break;
+ case TYPE_FLOAT:
+ lln = (longlong)vlp->F;
+ break;
+ case TYPE_DBL:
+ lln = (longlong)*(double*)MP(vlp->To_Val);
+ break;
+ case TYPE_DTM:
+ case TYPE_STRG:
+ lln = atoll(MZP(vlp->To_Val));
+ break;
+ case TYPE_BOOL:
+ lln = (vlp->B) ? 1 : 0;
+ break;
+ default:
+ lln = 0;
+ } // endswitch Type
+
+ return lln;
+} // end of GetBigint
+
+/***********************************************************************/
+/* Return the Value's Double value. */
+/***********************************************************************/
+double BJSON::GetDouble(PBVAL vp)
+{
+ double d;
+ PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
+
+ switch (vlp->Type) {
+ case TYPE_DBL:
+ d = *(double*)MP(vlp->To_Val);
+ break;
+ case TYPE_BINT:
+ d = (double)*(longlong*)MP(vlp->To_Val);
+ break;
+ case TYPE_INTG:
+ d = (double)vlp->N;
+ break;
+ case TYPE_FLOAT:
+ d = (double)vlp->F;
+ break;
+ case TYPE_DTM:
+ case TYPE_STRG:
+ d = atof(MZP(vlp->To_Val));
+ break;
+ case TYPE_BOOL:
+ d = (vlp->B) ? 1.0 : 0.0;
+ break;
+ default:
+ d = 0.0;
+ } // endswitch Type
+
+ return d;
+} // end of GetDouble
+
+/***********************************************************************/
+/* Return the Value's String value. */
+/***********************************************************************/
+PSZ BJSON::GetString(PBVAL vp, char* buff)
+{
+ char buf[32];
+ char* p = (buff) ? buff : buf;
+ PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
+
+ switch (vlp->Type) {
+ case TYPE_DTM:
+ case TYPE_STRG:
+ p = MZP(vlp->To_Val);
+ break;
+ case TYPE_INTG:
+ sprintf(p, "%d", vlp->N);
+ break;
+ case TYPE_FLOAT:
+ sprintf(p, "%.*f", vlp->Nd, vlp->F);
+ break;
+ case TYPE_BINT:
+ sprintf(p, "%lld", *(longlong*)MP(vlp->To_Val));
+ break;
+ case TYPE_DBL:
+ sprintf(p, "%.*lf", vlp->Nd, *(double*)MP(vlp->To_Val));
+ break;
+ case TYPE_BOOL:
+ p = (PSZ)((vlp->B) ? "true" : "false");
+ break;
+ case TYPE_NULL:
+ p = (PSZ)"null";
+ break;
+ default:
+ p = NULL;
+ } // endswitch Type
+
+ return (p == buf) ? (PSZ)PlugDup(G, buf) : p;
+} // end of GetString
+
+/***********************************************************************/
+/* Return the Value's String value. */
+/***********************************************************************/
+PSZ BJSON::GetValueText(PGLOBAL g, PBVAL vlp, PSTRG text)
+{
+ if (vlp->Type == TYPE_JOB)
+ return GetObjectText(g, vlp, text);
+ else if (vlp->Type == TYPE_JAR)
+ return GetArrayText(g, vlp, text);
+
+ char buff[32];
+ PSZ s = (vlp->Type == TYPE_NULL) ? NULL : GetString(vlp, buff);
+
+ if (s)
+ text->Append(s);
+ else if (GetJsonNull())
+ text->Append(GetJsonNull());
+
+ return NULL;
+} // end of GetText
+
+void BJSON::SetValueObj(PBVAL vlp, PBVAL bop)
+{
+ CheckType(bop, TYPE_JOB);
+ vlp->To_Val = bop->To_Val;
+ vlp->Nd = bop->Nd;
+ vlp->Type = TYPE_JOB;
+} // end of SetValueObj;
+
+void BJSON::SetValueArr(PBVAL vlp, PBVAL bap)
+{
+ CheckType(bap, TYPE_JAR);
+ vlp->To_Val = bap->To_Val;
+ vlp->Nd = bap->Nd;
+ vlp->Type = TYPE_JAR;
+} // end of SetValue;
+
+void BJSON::SetValueVal(PBVAL vlp, PBVAL vp)
+{
+ vlp->To_Val = vp->To_Val;
+ vlp->Nd = vp->Nd;
+ vlp->Type = vp->Type;
+} // end of SetValue;
+
+PBVAL BJSON::SetValue(PBVAL vlp, PVAL valp)
+{
+ if (!vlp)
+ vlp = NewVal();
+
+ if (!valp || valp->IsNull()) {
+ vlp->Type = TYPE_NULL;
+ } else switch (valp->GetType()) {
+ case TYPE_DATE:
+ if (((DTVAL*)valp)->IsFormatted())
+ vlp->To_Val = DupStr(valp->GetCharValue());
+ else {
+ char buf[32];
+
+ vlp->To_Val = DupStr(valp->GetCharString(buf));
+ } // endif Formatted
+
+ vlp->Type = TYPE_DTM;
+ break;
+ case TYPE_STRING:
+ vlp->To_Val = DupStr(valp->GetCharValue());
+ vlp->Type = TYPE_STRG;
+ break;
+ case TYPE_DOUBLE:
+ case TYPE_DECIM:
+ { double d = valp->GetFloatValue();
+ int nd = (IsTypeNum(valp->GetType())) ? valp->GetValPrec() : 0;
+
+ if (nd > 0 && nd <= 6 && d >= FLT_MIN && d <= FLT_MAX) {
+ vlp->F = (float)valp->GetFloatValue();
+ vlp->Type = TYPE_FLOAT;
+ } else {
+ double* dp = (double*)BsonSubAlloc(sizeof(double));
+
+ *dp = d;
+ vlp->To_Val = MOF(dp);
+ vlp->Type = TYPE_DBL;
+ } // endif Nd
+
+ vlp->Nd = MY_MIN(nd, 16);
+ } break;
+ case TYPE_TINY:
+ vlp->B = valp->GetTinyValue() != 0;
+ vlp->Type = TYPE_BOOL;
+ break;
+ case TYPE_INT:
+ vlp->N = valp->GetIntValue();
+ vlp->Type = TYPE_INTG;
+ break;
+ case TYPE_BIGINT:
+ if (valp->GetBigintValue() >= INT_MIN32 &&
+ valp->GetBigintValue() <= INT_MAX32) {
+ vlp->N = valp->GetIntValue();
+ vlp->Type = TYPE_INTG;
+ } else {
+ longlong* llp = (longlong*)BsonSubAlloc(sizeof(longlong));
+
+ *llp = valp->GetBigintValue();
+ vlp->To_Val = MOF(llp);
+ vlp->Type = TYPE_BINT;
+ } // endif BigintValue
+
+ break;
+ default:
+ snprintf(G->Message, sizeof(G->Message), "Unsupported typ %d\n", valp->GetType());
+ throw(777);
+ } // endswitch Type
+
+ return vlp;
+} // end of SetValue
+
+/***********************************************************************/
+/* Set the Value's value as the given integer. */
+/***********************************************************************/
+void BJSON::SetInteger(PBVAL vlp, int n)
+{
+ vlp->N = n;
+ vlp->Type = TYPE_INTG;
+} // end of SetInteger
+
+/***********************************************************************/
+/* Set the Value's Boolean value as a tiny integer. */
+/***********************************************************************/
+void BJSON::SetBool(PBVAL vlp, bool b)
+{
+ vlp->B = b;
+ vlp->Type = TYPE_BOOL;
+} // end of SetTiny
+
+/***********************************************************************/
+/* Set the Value's value as the given big integer. */
+/***********************************************************************/
+void BJSON::SetBigint(PBVAL vlp, longlong ll)
+{
+ if (ll >= INT_MIN32 && ll <= INT_MAX32) {
+ vlp->N = (int)ll;
+ vlp->Type = TYPE_INTG;
+ } else {
+ longlong* llp = (longlong*)PlugSubAlloc(G, NULL, sizeof(longlong));
+
+ *llp = ll;
+ vlp->To_Val = MOF(llp);
+ vlp->Type = TYPE_BINT;
+ } // endif ll
+
+} // end of SetBigint
+
+/***********************************************************************/
+/* Set the Value's value as the given DOUBLE. */
+/***********************************************************************/
+void BJSON::SetFloat(PBVAL vlp, double d, int prec)
+{
+ int nd = MY_MIN((prec < 0) ? GetJsonDefPrec() : prec, 16);
+
+ if (nd < 6 && d >= FLT_MIN && d <= FLT_MAX) {
+ vlp->F = (float)d;
+ vlp->Type = TYPE_FLOAT;
+ } else {
+ double* dp = (double*)BsonSubAlloc(sizeof(double));
+
+ *dp = d;
+ vlp->To_Val = MOF(dp);
+ vlp->Type = TYPE_DBL;
+ } // endif nd
+
+ vlp->Nd = nd;
+} // end of SetFloat
+
+/***********************************************************************/
+/* Set the Value's value as the given DOUBLE representation. */
+/***********************************************************************/
+void BJSON::SetFloat(PBVAL vlp, PSZ s)
+{
+ char *p = strchr(s, '.');
+ int nd = 0;
+ double d = atof(s);
+
+ if (p) {
+ for (++p; isdigit(*p); nd++, p++);
+ for (--p; *p == '0'; nd--, p--);
+ } // endif p
+
+ SetFloat(vlp, d, nd);
+} // end of SetFloat
+
+ /***********************************************************************/
+/* Set the Value's value as the given string. */
+/***********************************************************************/
+void BJSON::SetString(PBVAL vlp, PSZ s, int ci)
+{
+ vlp->To_Val = MOF(s);
+ vlp->Nd = ci;
+ vlp->Type = TYPE_STRG;
+} // end of SetString
+
+/***********************************************************************/
+/* True when its JSON or normal value is null. */
+/***********************************************************************/
+bool BJSON::IsValueNull(PBVAL vlp)
+{
+ bool b;
+
+ switch (vlp->Type) {
+ case TYPE_NULL:
+ b = true;
+ break;
+ case TYPE_JOB:
+ b = IsObjectNull(vlp);
+ break;
+ case TYPE_JAR:
+ b = IsArrayNull(vlp);
+ break;
+ default:
+ b = false;
+ } // endswitch Type
+
+ return b;
+ } // end of IsNull