summaryrefslogtreecommitdiff
path: root/storage/connect/json.cpp
diff options
context:
space:
mode:
authorOlivier Bertrand <bertrandop@gmail.com>2020-11-03 18:40:28 +0100
committerOlivier Bertrand <bertrandop@gmail.com>2020-11-03 18:40:28 +0100
commit28af4212b6e2afe1d42729c9c36215ed8a8d38cb (patch)
treeefae59d39a7a391fe87f8a6512945311a9cf6e32 /storage/connect/json.cpp
parentdc3a693b7039cb4b1d46d797ca86364ac3173be7 (diff)
downloadmariadb-git-28af4212b6e2afe1d42729c9c36215ed8a8d38cb.tar.gz
- Implementation of the Json BJSON representation.
VAL structures replace VALUE classes in binary trees. These parsed binary trees are swapped and saved on file Swapping is to replace pointers by offsets to make it portable. In restoring, class pointers to functions are realloced on place. Making BJSON files is done by the new UDF function jfile_bjson. modified: storage/connect/block.h modified: storage/connect/filamtxt.cpp modified: storage/connect/filamtxt.h modified: storage/connect/global.h modified: storage/connect/json.cpp modified: storage/connect/json.h modified: storage/connect/jsonudf.cpp modified: storage/connect/jsonudf.h modified: storage/connect/tabjson.cpp modified: storage/connect/tabjson.h modified: storage/connect/value.h - Make file (record) length and map memory possibly larger than MAX_INT modified: storage/connect/filamap.cpp modified: storage/connect/filamvct.cpp modified: storage/connect/maputil.cpp modified: storage/connect/maputil.h modified: storage/connect/tabdos.cpp modified: storage/connect/xindex.cpp - Make column length as bytes (not characters) This when making column definitions modified: storage/connect/ha_connect.cc - Change the message when making index fails modified: storage/connect/ha_connect.cc - Update tests and results to reflect recent changes modified: storage/connect/mysql-test/connect/r/alter_xml.result modified: storage/connect/mysql-test/connect/r/alter_xml2.result modified: storage/connect/mysql-test/connect/r/jdbc_oracle.result modified: storage/connect/mysql-test/connect/r/json.result modified: storage/connect/mysql-test/connect/r/json_java_2.result modified: storage/connect/mysql-test/connect/r/json_java_3.result modified: storage/connect/mysql-test/connect/r/json_mongo_c.result modified: storage/connect/mysql-test/connect/r/mongo_c.result modified: storage/connect/mysql-test/connect/r/mongo_java_2.result modified: storage/connect/mysql-test/connect/r/mongo_java_3.result modified: storage/connect/mysql-test/connect/r/odbc_oracle.result modified: storage/connect/mysql-test/connect/r/xml.result modified: storage/connect/mysql-test/connect/r/xml2.result modified: storage/connect/mysql-test/connect/r/xml2_html.result modified: storage/connect/mysql-test/connect/r/xml2_mult.result modified: storage/connect/mysql-test/connect/r/xml2_zip.result modified: storage/connect/mysql-test/connect/r/xml_html.result modified: storage/connect/mysql-test/connect/r/xml_mult.result modified: storage/connect/mysql-test/connect/r/xml_zip.result modified: storage/connect/mysql-test/connect/t/alter_xml.test modified: storage/connect/mysql-test/connect/t/alter_xml2.test modified: storage/connect/mysql-test/connect/t/jdbc_oracle.test modified: storage/connect/mysql-test/connect/t/json.test modified: storage/connect/mysql-test/connect/t/mongo_test.inc modified: storage/connect/mysql-test/connect/t/odbc_oracle.test modified: storage/connect/mysql-test/connect/t/xml.test modified: storage/connect/mysql-test/connect/t/xml2.test modified: storage/connect/mysql-test/connect/t/xml2_html.test modified: storage/connect/mysql-test/connect/t/xml2_mult.test modified: storage/connect/mysql-test/connect/t/xml2_zip.test modified: storage/connect/mysql-test/connect/t/xml_html.test modified: storage/connect/mysql-test/connect/t/xml_mult.test modified: storage/connect/mysql-test/connect/t/xml_zip.test - Typo modified: storage/connect/value.cpp
Diffstat (limited to 'storage/connect/json.cpp')
-rw-r--r--storage/connect/json.cpp1718
1 files changed, 1053 insertions, 665 deletions
diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp
index ea3ea18da0b..ce3ddd865a5 100644
--- a/storage/connect/json.cpp
+++ b/storage/connect/json.cpp
@@ -1,7 +1,7 @@
/*************** json CPP Declares Source Code File (.H) ***************/
-/* Name: json.cpp Version 1.4 */
+/* Name: json.cpp Version 1.5 */
/* */
-/* (C) Copyright to the author Olivier BERTRAND 2014 - 2017 */
+/* (C) Copyright to the author Olivier BERTRAND 2014 - 2020 */
/* */
/* This file contains the JSON classes functions. */
/***********************************************************************/
@@ -21,7 +21,7 @@
#include "plgdbsem.h"
#include "json.h"
-#define ARGS MY_MIN(24,len-i),s+MY_MAX(i-3,0)
+#define ARGS MY_MIN(24,(int)len-i),s+MY_MAX(i-3,0)
#if defined(__WIN__)
#define EL "\r\n"
@@ -38,16 +38,16 @@
class SE_Exception {
public:
- SE_Exception(unsigned int n, PEXCEPTION_RECORD p) : nSE(n), eRec(p) {}
- ~SE_Exception() {}
+ SE_Exception(unsigned int n, PEXCEPTION_RECORD p) : nSE(n), eRec(p) {}
+ ~SE_Exception() {}
- unsigned int nSE;
- PEXCEPTION_RECORD eRec;
+ 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);
+ throw SE_Exception(u, pExp->ExceptionRecord);
} // end of trans_func
char *GetExceptionDesc(PGLOBAL g, unsigned int e);
@@ -58,46 +58,58 @@ char *GetJsonNull(void);
/***********************************************************************/
/* IsNum: check whether this string is all digits. */
/***********************************************************************/
-bool IsNum(PSZ s)
-{
- for (char *p = s; *p; p++)
- if (*p == ']')
- break;
- else if (!isdigit(*p) || *p == '-')
- return false;
+bool IsNum(PSZ s) {
+ for (char* p = s; *p; p++)
+ if (*p == ']')
+ break;
+ else if (!isdigit(*p) || *p == '-')
+ return false;
- return true;
-} // end of IsNum
+ return true;
+} // end of IsNum
/***********************************************************************/
/* NextChr: return the first found '[' or Sep pointer. */
/***********************************************************************/
-char *NextChr(PSZ s, char sep)
+char* NextChr(PSZ s, char sep)
{
- char *p1 = strchr(s, '[');
- char *p2 = strchr(s, sep);
+ char* p1 = strchr(s, '[');
+ char* p2 = strchr(s, sep);
- if (!p2)
- return p1;
- else if (p1)
- return MY_MIN(p1, p2);
+ if (!p2)
+ return p1;
+ else if (p1)
+ return MY_MIN(p1, p2);
- return p2;
-} // end of NextChr
+ return p2;
+} // end of NextChr
+/***********************************************************************/
+/* Allocate a VAL structure, make sure common field and Nd are zeroed. */
+/***********************************************************************/
+PVL AllocVal(PGLOBAL g, JTYP type)
+{
+ PVL vlp = (PVL)PlugSubAlloc(g, NULL, sizeof(VAL));
+
+ vlp->LLn = 0;
+ vlp->Nd = 0;
+ vlp->Type = type;
+ return vlp;
+} // end of AllocVal
/***********************************************************************/
/* Parse a json string. */
/* Note: when pretty is not known, the caller set pretty to 3. */
/***********************************************************************/
-PJSON ParseJson(PGLOBAL g, char *s, int len, int *ptyp, bool *comma)
+PJSON ParseJson(PGLOBAL g, char* s, size_t len, int* ptyp, bool* comma)
{
- int i, pretty = (ptyp) ? *ptyp : 3;
- bool b = false, pty[3] = {true,true,true};
- PJSON jsp = NULL, jp = NULL;
+ int i, pretty = (ptyp) ? *ptyp : 3;
+ bool b = false, pty[3] = { true,true,true };
+ PJSON jsp = NULL;
+ PJDOC jdp = NULL;
- if (trace(1))
- htrc("ParseJson: s=%.10s len=%d\n", s, len);
+ if (trace(1))
+ htrc("ParseJson: s=%.10s len=%zd\n", s, len);
if (!s || !len) {
strcpy(g->Message, "Void JSON object");
@@ -105,116 +117,388 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int *ptyp, bool *comma)
} else if (comma)
*comma = false;
- // Trying to guess the pretty format
- if (s[0] == '[' && (s[1] == '\n' || (s[1] == '\r' && s[2] == '\n')))
- pty[0] = false;
-
- try {
- jp = new(g) JSON();
- jp->s = s;
- jp->len = len;
- jp->pty = pty;
-
- for (i = 0; i < jp->len; i++)
- switch (s[i]) {
- case '[':
- if (jsp)
- jsp = jp->ParseAsArray(g, i, pretty, ptyp);
- else
- jsp = jp->ParseArray(g, ++i);
-
- break;
- case '{':
- if (jsp)
- jsp = jp->ParseAsArray(g, i, pretty, ptyp);
- else if (!(jsp = jp->ParseObject(g, ++i)))
- throw 2;
-
- break;
- case ' ':
- case '\t':
- case '\n':
- case '\r':
- break;
- case ',':
- if (jsp && (pretty == 1 || pretty == 3)) {
- if (comma)
- *comma = true;
-
- pty[0] = pty[2] = false;
- break;
- } // endif pretty
-
- sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty);
- throw 3;
- case '(':
- b = true;
- break;
- case ')':
- if (b) {
- b = false;
- break;
- } // endif b
-
- default:
- if (jsp)
- jsp = jp->ParseAsArray(g, i, pretty, ptyp);
- else if (!(jsp = jp->ParseValue(g, i)))
- throw 4;
-
- break;
- }; // endswitch s[i]
-
- if (!jsp)
- sprintf(g->Message, "Invalid Json string '%.*s'", MY_MIN(len, 50), s);
- else if (ptyp && pretty == 3) {
- *ptyp = 3; // Not recognized pretty
-
- for (i = 0; i < 3; i++)
- if (pty[i]) {
- *ptyp = i;
- break;
- } // endif pty
-
- } // endif ptyp
-
- } catch (int n) {
- if (trace(1))
- htrc("Exception %d: %s\n", n, g->Message);
- jsp = NULL;
- } catch (const char *msg) {
- strcpy(g->Message, msg);
- jsp = NULL;
- } // end catch
-
- return jsp;
+ // Trying to guess the pretty format
+ if (s[0] == '[' && (s[1] == '\n' || (s[1] == '\r' && s[2] == '\n')))
+ pty[0] = false;
+
+ try {
+ jdp = new(g) JDOC;
+ jdp->s = s;
+ jdp->len = len;
+ jdp->pty = pty;
+
+ for (i = 0; i < jdp->len; i++)
+ switch (s[i]) {
+ case '[':
+ if (jsp)
+ jsp = jdp->ParseAsArray(g, i, pretty, ptyp);
+ else
+ jsp = jdp->ParseArray(g, ++i);
+
+ break;
+ case '{':
+ if (jsp)
+ jsp = jdp->ParseAsArray(g, i, pretty, ptyp);
+ else if (!(jsp = jdp->ParseObject(g, ++i)))
+ throw 2;
+
+ break;
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ break;
+ case ',':
+ if (jsp && (pretty == 1 || pretty == 3)) {
+ if (comma)
+ *comma = true;
+
+ pty[0] = pty[2] = false;
+ break;
+ } // endif pretty
+
+ sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty);
+ throw 3;
+ case '(':
+ b = true;
+ break;
+ case ')':
+ if (b) {
+ b = false;
+ break;
+ } // endif b
+
+ default:
+ if (jsp)
+ jsp = jdp->ParseAsArray(g, i, pretty, ptyp);
+ else if (!(jsp = jdp->ParseValue(g, i)))
+ throw 4;
+
+ break;
+ }; // endswitch s[i]
+
+ if (!jsp)
+ sprintf(g->Message, "Invalid Json string '%.*s'", MY_MIN((int)len, 50), s);
+ else if (ptyp && pretty == 3) {
+ *ptyp = 3; // Not recognized pretty
+
+ for (i = 0; i < 3; i++)
+ if (pty[i]) {
+ *ptyp = i;
+ break;
+ } // endif pty
+
+ } // endif ptyp
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ jsp = NULL;
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ jsp = NULL;
+ } // end catch
+
+ return jsp;
} // end of ParseJson
/***********************************************************************/
+/* Serialize a JSON document tree: */
+/***********************************************************************/
+PSZ Serialize(PGLOBAL g, PJSON jsp, char* fn, int pretty) {
+ PSZ str = NULL;
+ bool b = false, err = true;
+ JOUT* jp;
+ FILE* fs = NULL;
+ PJDOC jdp = NULL;
+
+ g->Message[0] = 0;
+
+ try {
+ jdp = new(g) JDOC; // MUST BE ALLOCATED BEFORE jp !!!!!
+
+ if (!jsp) {
+ strcpy(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"))) {
+ sprintf(g->Message, MSG(OPEN_MODE_ERROR),
+ "w", (int)errno, fn);
+ strcat(strcat(g->Message, ": "), 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
+
+ jdp->SetJp(jp);
+
+ switch (jsp->GetType()) {
+ case TYPE_JAR:
+ err = jdp->SerializeArray((PJAR)jsp, b);
+ break;
+ case TYPE_JOB:
+ err = ((b && jp->Prty()) && jp->WriteChr('\t'));
+ err |= jdp->SerializeObject((PJOB)jsp);
+ break;
+ case TYPE_JVAL:
+ err = jdp->SerializeValue((PJVAL)jsp);
+ break;
+ default:
+ strcpy(g->Message, "Invalid json tree");
+ } // 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");
+
+ } // endif's
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ str = NULL;
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ str = NULL;
+ } // end catch
+
+ return str;
+} // end of Serialize
+
+
+/* -------------------------- Class JOUTSTR -------------------------- */
+
+/***********************************************************************/
+/* JOUTSTR constructor. */
+/***********************************************************************/
+JOUTSTR::JOUTSTR(PGLOBAL g) : JOUT(g) {
+ PPOOLHEADER pph = (PPOOLHEADER)g->Sarea;
+
+ N = 0;
+ Max = pph->FreeBlk;
+ Max = (Max > 32) ? Max - 32 : Max;
+ Strp = (char*)PlugSubAlloc(g, NULL, 0); // Size not know yet
+} // end of JOUTSTR constructor
+
+/***********************************************************************/
+/* Concatenate a string to the Serialize string. */
+/***********************************************************************/
+bool JOUTSTR::WriteStr(const char* s) {
+ if (s) {
+ size_t len = strlen(s);
+
+ if (N + len > Max)
+ return true;
+
+ memcpy(Strp + N, s, len);
+ N += len;
+ return false;
+ } else
+ return true;
+
+} // end of WriteStr
+
+/***********************************************************************/
+/* Concatenate a character to the Serialize string. */
+/***********************************************************************/
+bool JOUTSTR::WriteChr(const char c) {
+ if (N + 1 > Max)
+ return true;
+
+ Strp[N++] = c;
+ return false;
+} // end of WriteChr
+
+/***********************************************************************/
+/* Escape and Concatenate a string to the Serialize string. */
+/***********************************************************************/
+bool JOUTSTR::Escape(const char* s) {
+ WriteChr('"');
+
+ for (unsigned int i = 0; s[i]; i++)
+ switch (s[i]) {
+ case '"':
+ case '\\':
+ case '\t':
+ case '\n':
+ case '\r':
+ case '\b':
+ case '\f': WriteChr('\\');
+ // fall through
+ default:
+ WriteChr(s[i]);
+ break;
+ } // endswitch s[i]
+
+ WriteChr('"');
+ return false;
+} // end of Escape
+
+/* ------------------------- Class JOUTFILE -------------------------- */
+
+/***********************************************************************/
+/* Write a string to the Serialize file. */
+/***********************************************************************/
+bool JOUTFILE::WriteStr(const char* s) {
+ // This is temporary
+ fputs(s, Stream);
+ return false;
+} // end of WriteStr
+
+/***********************************************************************/
+/* Write a character to the Serialize file. */
+/***********************************************************************/
+bool JOUTFILE::WriteChr(const char c) {
+ // This is temporary
+ fputc(c, Stream);
+ return false;
+} // end of WriteChr
+
+/***********************************************************************/
+/* Escape and Concatenate a string to the Serialize string. */
+/***********************************************************************/
+bool JOUTFILE::Escape(const char* s) {
+ // This is temporary
+ fputc('"', Stream);
+
+ for (unsigned int i = 0; s[i]; i++)
+ switch (s[i]) {
+ case '"': fputs("\\\"", Stream); break;
+ case '\\': fputs("\\\\", Stream); break;
+ case '\t': fputs("\\t", Stream); break;
+ case '\n': fputs("\\n", Stream); break;
+ case '\r': fputs("\\r", Stream); break;
+ case '\b': fputs("\\b", Stream); break;
+ case '\f': fputs("\\f", Stream); break;
+ default:
+ fputc(s[i], Stream);
+ break;
+ } // endswitch s[i]
+
+ fputc('"', Stream);
+ return false;
+} // end of Escape
+
+/* ------------------------- Class JOUTPRT --------------------------- */
+
+/***********************************************************************/
+/* Write a string to the Serialize pretty file. */
+/***********************************************************************/
+bool JOUTPRT::WriteStr(const char* s) {
+ // This is temporary
+ if (B) {
+ fputs(EL, Stream);
+ M--;
+
+ for (int i = 0; i < M; i++)
+ fputc('\t', Stream);
+
+ B = false;
+ } // endif B
+
+ fputs(s, Stream);
+ return false;
+} // end of WriteStr
+
+/***********************************************************************/
+/* Write a character to the Serialize pretty file. */
+/***********************************************************************/
+bool JOUTPRT::WriteChr(const char c) {
+ switch (c) {
+ case ':':
+ fputs(": ", Stream);
+ break;
+ case '{':
+ case '[':
+#if 0
+ if (M)
+ fputs(EL, Stream);
+
+ for (int i = 0; i < M; i++)
+ fputc('\t', Stream);
+#endif // 0
+
+ fputc(c, Stream);
+ fputs(EL, Stream);
+ M++;
+
+ for (int i = 0; i < M; i++)
+ fputc('\t', Stream);
+
+ break;
+ case '}':
+ case ']':
+ M--;
+ fputs(EL, Stream);
+
+ for (int i = 0; i < M; i++)
+ fputc('\t', Stream);
+
+ fputc(c, Stream);
+ B = true;
+ break;
+ case ',':
+ fputc(c, Stream);
+ fputs(EL, Stream);
+
+ for (int i = 0; i < M; i++)
+ fputc('\t', Stream);
+
+ B = false;
+ break;
+ default:
+ fputc(c, Stream);
+ } // endswitch c
+
+ return false;
+} // end of WriteChr
+
+/* --------------------------- Class JDOC ---------------------------- */
+
+/***********************************************************************/
/* Parse several items as being in an array. */
/***********************************************************************/
-PJAR JSON::ParseAsArray(PGLOBAL g, int& i, int pretty, int *ptyp)
+PJAR JDOC::ParseAsArray(PGLOBAL g, int& i, int pretty, int *ptyp)
{
- if (pty[0] && (!pretty || pretty > 2)) {
- PJAR jsp;
+ if (pty[0] && (!pretty || pretty > 2)) {
+ PJAR jsp;
- if ((jsp = ParseArray(g, (i = 0))) && ptyp && pretty == 3)
- *ptyp = (pty[0]) ? 0 : 3;
+ if ((jsp = ParseArray(g, (i = 0))) && ptyp && pretty == 3)
+ *ptyp = (pty[0]) ? 0 : 3;
- return jsp;
- } else
- strcpy(g->Message, "More than one item in file");
+ return jsp;
+ } else
+ strcpy(g->Message, "More than one item in file");
- return NULL;
+ return NULL;
} // end of ParseAsArray
/***********************************************************************/
/* Parse a JSON Array. */
/***********************************************************************/
-PJAR JSON::ParseArray(PGLOBAL g, int& i)
+PJAR JDOC::ParseArray(PGLOBAL g, int& i)
{
- int level = 0;
- bool b = (!i);
+ int level = 0;
+ bool b = (!i);
PJAR jarp = new(g) JARRAY;
for (; i < len; i++)
@@ -235,11 +519,11 @@ PJAR JSON::ParseArray(PGLOBAL g, int& i)
jarp->InitArray(g);
return jarp;
- case '\n':
- if (!b)
- pty[0] = pty[1] = false;
- case '\r':
- case ' ':
+ case '\n':
+ if (!b)
+ pty[0] = pty[1] = false;
+ case '\r':
+ case ' ':
case '\t':
break;
default:
@@ -253,11 +537,11 @@ PJAR JSON::ParseArray(PGLOBAL g, int& i)
break;
}; // endswitch s[i]
- if (b) {
- // Case of Pretty == 0
- jarp->InitArray(g);
- return jarp;
- } // endif b
+ if (b) {
+ // Case of Pretty == 0
+ jarp->InitArray(g);
+ return jarp;
+ } // endif b
throw ("Unexpected EOF in array");
} // end of ParseArray
@@ -265,7 +549,7 @@ PJAR JSON::ParseArray(PGLOBAL g, int& i)
/***********************************************************************/
/* Parse a JSON Object. */
/***********************************************************************/
-PJOB JSON::ParseObject(PGLOBAL g, int& i)
+PJOB JDOC::ParseObject(PGLOBAL g, int& i)
{
PSZ key;
int level = 0;
@@ -276,7 +560,7 @@ PJOB JSON::ParseObject(PGLOBAL g, int& i)
switch (s[i]) {
case '"':
if (level < 2) {
- key = ParseString(g, ++i);
+ key = ParseString(g, ++i);
jpp = jobp->AddPair(g, key);
level = 1;
} else {
@@ -287,7 +571,7 @@ PJOB JSON::ParseObject(PGLOBAL g, int& i)
break;
case ':':
if (level == 1) {
- jpp->Val = ParseValue(g, ++i);
+ jpp->Val = ParseValue(g, ++i);
level = 2;
} else {
sprintf(g->Message, "Unexpected ':' near %.*s", ARGS);
@@ -310,10 +594,10 @@ PJOB JSON::ParseObject(PGLOBAL g, int& i)
} // endif level
return jobp;
- case '\n':
- pty[0] = pty[1] = false;
- case '\r':
- case ' ':
+ case '\n':
+ pty[0] = pty[1] = false;
+ case '\r':
+ case ' ':
case '\t':
break;
default:
@@ -329,38 +613,38 @@ PJOB JSON::ParseObject(PGLOBAL g, int& i)
/***********************************************************************/
/* Parse a JSON Value. */
/***********************************************************************/
-PJVAL JSON::ParseValue(PGLOBAL g, int& i)
+PJVAL JDOC::ParseValue(PGLOBAL g, int& i)
{
- int n;
PJVAL jvp = new(g) JVALUE;
for (; i < len; i++)
- switch (s[i]) {
- case '\n':
- pty[0] = pty[1] = false;
- case '\r':
- case ' ':
- case '\t':
- break;
- default:
- goto suite;
- } // endswitch
+ 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 '[':
- jvp->Jsp = ParseArray(g, ++i);
+ jvp->Jsp = ParseArray(g, ++i);
break;
case '{':
- jvp->Jsp = ParseObject(g, ++i);
+ jvp->Jsp = ParseObject(g, ++i);
break;
case '"':
- jvp->Value = AllocateValue(g, ParseString(g, ++i), TYPE_STRING);
+ jvp->Val = AllocVal(g, TYPE_STRG);
+ jvp->Val->Strp = ParseString(g, ++i);
break;
case 't':
if (!strncmp(s + i, "true", 4)) {
- n = 1;
- jvp->Value = AllocateValue(g, &n, TYPE_TINY);
+ jvp->Val = AllocVal(g, TYPE_BOOL);
+ jvp->Val->B = true;
i += 3;
} else
goto err;
@@ -368,8 +652,8 @@ PJVAL JSON::ParseValue(PGLOBAL g, int& i)
break;
case 'f':
if (!strncmp(s + i, "false", 5)) {
- n = 0;
- jvp->Value = AllocateValue(g, &n, TYPE_TINY);
+ jvp->Val = AllocVal(g, TYPE_BOOL);
+ jvp->Val->B = false;
i += 4;
} else
goto err;
@@ -385,7 +669,7 @@ PJVAL JSON::ParseValue(PGLOBAL g, int& i)
case '-':
default:
if (s[i] == '-' || isdigit(s[i]))
- jvp->Value = ParseNumeric(g, i);
+ jvp->Val = ParseNumeric(g, i);
else
goto err;
@@ -401,7 +685,7 @@ err:
/***********************************************************************/
/* Unescape and parse a JSON string. */
/***********************************************************************/
-char *JSON::ParseString(PGLOBAL g, int& i)
+char *JDOC::ParseString(PGLOBAL g, int& i)
{
uchar *p;
int n = 0;
@@ -488,15 +772,15 @@ char *JSON::ParseString(PGLOBAL g, int& i)
/***********************************************************************/
/* Parse a JSON numeric value. */
/***********************************************************************/
-PVAL JSON::ParseNumeric(PGLOBAL g, int& i)
+PVL JDOC::ParseNumeric(PGLOBAL g, int& i)
{
char buf[50];
int n = 0;
short nd = 0;
- bool has_dot = false;
- bool has_e = false;
- bool found_digit = false;
- PVAL valp = NULL;
+ bool has_dot = false;
+ bool has_e = false;
+ bool found_digit = false;
+ PVL vlp = NULL;
for (; i < len; i++) {
switch (s[i]) {
@@ -545,15 +829,24 @@ PVAL JSON::ParseNumeric(PGLOBAL g, int& i)
if (has_dot || has_e) {
double dv = strtod(buf, NULL);
- valp = AllocateValue(g, &dv, TYPE_DOUBLE, nd);
+ vlp = AllocVal(g, TYPE_DBL);
+ vlp->F = dv;
+ vlp->Nd = nd;
} else {
long long iv = strtoll(buf, NULL, 10);
- valp = AllocateValue(g, &iv, TYPE_BIGINT);
+ if (iv > INT_MAX32 || iv < INT_MIN32) {
+ vlp = AllocVal(g, TYPE_BINT);
+ vlp->LLn = iv;
+ } else {
+ vlp = AllocVal(g, TYPE_INTG);
+ vlp->N = (int)iv;
+ } // endif iv
+
} // endif has
i--; // Unstack following character
- return valp;
+ return vlp;
} else
throw("No digit found");
@@ -562,137 +855,59 @@ PVAL JSON::ParseNumeric(PGLOBAL g, int& i)
} // end of ParseNumeric
/***********************************************************************/
-/* Serialize a JSON tree: */
-/***********************************************************************/
-PSZ Serialize(PGLOBAL g, PJSON jsp, char *fn, int pretty)
-{
- PSZ str = NULL;
- bool b = false, err = true;
- JOUT *jp;
- FILE *fs = NULL;
-
- g->Message[0] = 0;
-
- try {
- if (!jsp) {
- strcpy(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"))) {
- sprintf(g->Message, MSG(OPEN_MODE_ERROR),
- "w", (int)errno, fn);
- strcat(strcat(g->Message, ": "), 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 (jsp->GetType()) {
- case TYPE_JAR:
- err = SerializeArray(jp, (PJAR)jsp, b);
- break;
- case TYPE_JOB:
- err = ((b && jp->Prty()) && jp->WriteChr('\t'));
- err |= SerializeObject(jp, (PJOB)jsp);
- break;
- case TYPE_JVAL:
- err = SerializeValue(jp, (PJVAL)jsp);
- break;
- default:
- strcpy(g->Message, "Invalid json tree");
- } // 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");
-
- } // endif's
-
- } catch (int n) {
- if (trace(1))
- htrc("Exception %d: %s\n", n, g->Message);
- str = NULL;
- } catch (const char *msg) {
- strcpy(g->Message, msg);
- str = NULL;
- } // end catch
-
- return str;
-} // end of Serialize
-
-/***********************************************************************/
/* Serialize a JSON Array. */
/***********************************************************************/
-bool SerializeArray(JOUT *js, PJAR jarp, bool b)
+bool JDOC::SerializeArray(PJAR jarp, bool b)
{
bool first = true;
- if (b) {
- if (js->Prty()) {
- if (js->WriteChr('['))
- return true;
- else if (js->Prty() == 1 && (js->WriteStr(EL) || js->WriteChr('\t')))
- return true;
+ if (b) {
+ if (js->Prty()) {
+ if (js->WriteChr('['))
+ return true;
+ else if (js->Prty() == 1 && (js->WriteStr(EL) || js->WriteChr('\t')))
+ return true;
- } // endif Prty
+ } // endif Prty
- } else if (js->WriteChr('['))
- return true;
+ } else if (js->WriteChr('['))
+ return true;
for (int i = 0; i < jarp->size(); i++) {
if (first)
first = false;
- else if ((!b || js->Prty()) && js->WriteChr(','))
+ else if ((!b || js->Prty()) && js->WriteChr(','))
return true;
- else if (b) {
- if (js->Prty() < 2 && js->WriteStr(EL))
- return true;
- else if (js->Prty() == 1 && js->WriteChr('\t'))
- return true;
+ else if (b) {
+ if (js->Prty() < 2 && js->WriteStr(EL))
+ return true;
+ else if (js->Prty() == 1 && js->WriteChr('\t'))
+ return true;
- } // endif b
+ } // endif b
- if (SerializeValue(js, jarp->GetValue(i)))
+ if (SerializeValue(jarp->GetValue(i)))
return true;
} // endfor i
- if (b && js->Prty() == 1 && js->WriteStr(EL))
+ if (b && js->Prty() == 1 && js->WriteStr(EL))
return true;
- return ((!b || js->Prty()) && js->WriteChr(']'));
+ return ((!b || js->Prty()) && js->WriteChr(']'));
} // end of SerializeArray
/***********************************************************************/
/* Serialize a JSON Object. */
/***********************************************************************/
-bool SerializeObject(JOUT *js, PJOB jobp)
+bool JDOC::SerializeObject(PJOB jobp)
{
bool first = true;
if (js->WriteChr('{'))
return true;
- for (PJPR pair = jobp->First; pair; pair = pair->Next) {
+ for (PJPR pair = jobp->GetFirst(); pair; pair = pair->Next) {
if (first)
first = false;
else if (js->WriteChr(','))
@@ -702,7 +917,7 @@ bool SerializeObject(JOUT *js, PJOB jobp)
js->WriteStr(pair->Key) ||
js->WriteChr('"') ||
js->WriteChr(':') ||
- SerializeValue(js, pair->Val))
+ SerializeValue(pair->Val))
return true;
} // endfor i
@@ -713,259 +928,70 @@ bool SerializeObject(JOUT *js, PJOB jobp)
/***********************************************************************/
/* Serialize a JSON Value. */
/***********************************************************************/
-bool SerializeValue(JOUT *js, PJVAL jvp)
+bool JDOC::SerializeValue(PJVAL jvp)
{
+ char buf[64];
PJAR jap;
PJOB jop;
- PVAL valp;
+ PVL vlp;
if ((jap = jvp->GetArray()))
- return SerializeArray(js, jap, false);
+ return SerializeArray(jap, false);
else if ((jop = jvp->GetObject()))
- return SerializeObject(js, jop);
- else if (!(valp = jvp->Value) || valp->IsNull())
+ return SerializeObject(jop);
+ else if (!(vlp = jvp->Val))
return js->WriteStr("null");
- else switch (valp->GetType()) {
- case TYPE_TINY:
- return js->WriteStr(valp->GetTinyValue() ? "true" : "false");
- case TYPE_STRING:
- return js->Escape(valp->GetCharValue());
+ else switch (vlp->Type) {
+ case TYPE_BOOL:
+ return js->WriteStr(vlp->B ? "true" : "false");
+ case TYPE_STRG:
+ case TYPE_DTM:
+ return js->Escape(vlp->Strp);
+ case TYPE_INTG:
+ sprintf(buf, "%d", vlp->N);
+ return js->WriteStr(buf);
+ case TYPE_BINT:
+ sprintf(buf, "%lld", vlp->LLn);
+ return js->WriteStr(buf);
+ case TYPE_DBL:
+ sprintf(buf, "%.*lf", vlp->Nd, vlp->F);
+ return js->WriteStr(buf);
+ case TYPE_NULL:
+ return js->WriteStr("null");
default:
- if (valp->IsTypeNum()) {
- char buf[32];
+ return js->WriteStr("???"); // TODO
+ } // endswitch Type
- return js->WriteStr(valp->GetCharString(buf));
- } // endif valp
-
- } // endswitch Type
-
- strcpy(js->g->Message, "Unrecognized value");
- return true;
+ strcpy(js->g->Message, "Unrecognized value");
+ return true;
} // end of SerializeValue
-/* -------------------------- Class JOUTSTR -------------------------- */
-
-/***********************************************************************/
-/* JOUTSTR constructor. */
-/***********************************************************************/
-JOUTSTR::JOUTSTR(PGLOBAL g) : JOUT(g)
-{
- PPOOLHEADER pph = (PPOOLHEADER)g->Sarea;
-
- N = 0;
- Max = pph->FreeBlk;
- Max = (Max > 32) ? Max - 32 : Max;
- Strp = (char*)PlugSubAlloc(g, NULL, 0); // Size not know yet
-} // end of JOUTSTR constructor
-
-/***********************************************************************/
-/* Concatenate a string to the Serialize string. */
-/***********************************************************************/
-bool JOUTSTR::WriteStr(const char *s)
-{
- if (s) {
- size_t len = strlen(s);
-
- if (N + len > Max)
- return true;
-
- memcpy(Strp + N, s, len);
- N += len;
- return false;
- } else
- return true;
-
-} // end of WriteStr
-
-/***********************************************************************/
-/* Concatenate a character to the Serialize string. */
-/***********************************************************************/
-bool JOUTSTR::WriteChr(const char c)
-{
- if (N + 1 > Max)
- return true;
-
- Strp[N++] = c;
- return false;
-} // end of WriteChr
-
-/***********************************************************************/
-/* Escape and Concatenate a string to the Serialize string. */
-/***********************************************************************/
-bool JOUTSTR::Escape(const char *s)
-{
- WriteChr('"');
-
- for (unsigned int i = 0; s[i]; i++)
- switch (s[i]) {
- case '"':
- case '\\':
- case '\t':
- case '\n':
- case '\r':
- case '\b':
- case '\f': WriteChr('\\');
- // fall through
- default:
- WriteChr(s[i]);
- break;
- } // endswitch s[i]
-
- WriteChr('"');
- return false;
-} // end of Escape
-
-/* ------------------------- Class JOUTFILE -------------------------- */
-
-/***********************************************************************/
-/* Write a string to the Serialize file. */
-/***********************************************************************/
-bool JOUTFILE::WriteStr(const char *s)
-{
- // This is temporary
- fputs(s, Stream);
- return false;
-} // end of WriteStr
-
-/***********************************************************************/
-/* Write a character to the Serialize file. */
-/***********************************************************************/
-bool JOUTFILE::WriteChr(const char c)
-{
- // This is temporary
- fputc(c, Stream);
- return false;
-} // end of WriteChr
-
-/***********************************************************************/
-/* Escape and Concatenate a string to the Serialize string. */
-/***********************************************************************/
-bool JOUTFILE::Escape(const char *s)
-{
- // This is temporary
- fputc('"', Stream);
-
- for (unsigned int i = 0; s[i]; i++)
- switch (s[i]) {
- case '"': fputs("\\\"", Stream); break;
- case '\\': fputs("\\\\", Stream); break;
- case '\t': fputs("\\t", Stream); break;
- case '\n': fputs("\\n", Stream); break;
- case '\r': fputs("\\r", Stream); break;
- case '\b': fputs("\\b", Stream); break;
- case '\f': fputs("\\f", Stream); break;
- default:
- fputc(s[i], Stream);
- break;
- } // endswitch s[i]
-
- fputc('"', Stream);
- return false;
-} // end of Escape
-
-/* ------------------------- Class JOUTPRT --------------------------- */
-
-/***********************************************************************/
-/* Write a string to the Serialize pretty file. */
-/***********************************************************************/
-bool JOUTPRT::WriteStr(const char *s)
-{
- // This is temporary
- if (B) {
- fputs(EL, Stream);
- M--;
-
- for (int i = 0; i < M; i++)
- fputc('\t', Stream);
-
- B = false;
- } // endif B
-
- fputs(s, Stream);
- return false;
-} // end of WriteStr
-
-/***********************************************************************/
-/* Write a character to the Serialize pretty file. */
-/***********************************************************************/
-bool JOUTPRT::WriteChr(const char c)
-{
- switch (c) {
- case ':':
- fputs(": ", Stream);
- break;
- case '{':
- case '[':
-#if 0
- if (M)
- fputs(EL, Stream);
-
- for (int i = 0; i < M; i++)
- fputc('\t', Stream);
-#endif // 0
-
- fputc(c, Stream);
- fputs(EL, Stream);
- M++;
-
- for (int i = 0; i < M; i++)
- fputc('\t', Stream);
-
- break;
- case '}':
- case ']':
- M--;
- fputs(EL, Stream);
-
- for (int i = 0; i < M; i++)
- fputc('\t', Stream);
-
- fputc(c, Stream);
- B = true;
- break;
- case ',':
- fputc(c, Stream);
- fputs(EL, Stream);
-
- for (int i = 0; i < M; i++)
- fputc('\t', Stream);
-
- B = false;
- break;
- default:
- fputc(c, Stream);
- } // endswitch c
-
-return false;
-} // end of WriteChr
-
/* -------------------------- Class JOBJECT -------------------------- */
/***********************************************************************/
/* Return the number of pairs in this object. */
/***********************************************************************/
-int JOBJECT::GetSize(bool b)
-{
- if (b) {
- // Return only non null pairs
- int n = 0;
+int JOBJECT::GetSize(bool b) {
+ int n = 0;
- for (PJPR jpp = First; jpp; jpp = jpp->Next)
- if (jpp->Val && !jpp->Val->IsNull())
- n++;
+ for (PJPR jpp = First; jpp; jpp = jpp->Next)
+ // If b return only non null pairs
+ if (!b || jpp->Val && !jpp->Val->IsNull())
+ n++;
- return n;
- } else
- return Size;
-
-} // end of GetSize
+ return n;
+} // end of GetSize
/***********************************************************************/
/* Add a new pair to an Object. */
/***********************************************************************/
PJPR JOBJECT::AddPair(PGLOBAL g, PCSZ key)
{
- PJPR jpp = new(g) JPAIR(key);
+ PJPR jpp = (PJPR)PlugSubAlloc(g, NULL, sizeof(JPAIR));
+
+ jpp->Key = key;
+ jpp->Next = NULL;
+ jpp->Val = NULL;
if (Last)
Last->Next = jpp;
@@ -973,7 +999,6 @@ PJPR JOBJECT::AddPair(PGLOBAL g, PCSZ key)
First = jpp;
Last = jpp;
- Size++;
return jpp;
} // end of AddPair
@@ -982,13 +1007,13 @@ PJPR JOBJECT::AddPair(PGLOBAL g, PCSZ key)
/***********************************************************************/
PJAR JOBJECT::GetKeyList(PGLOBAL g)
{
- PJAR jarp = new(g) JARRAY();
+ PJAR jarp = new(g) JARRAY();
- for (PJPR jpp = First; jpp; jpp = jpp->Next)
- jarp->AddValue(g, new(g) JVALUE(g, jpp->GetKey()));
+ for (PJPR jpp = First; jpp; jpp = jpp->Next)
+ jarp->AddValue(g, new(g) JVALUE(g, jpp->Key));
- jarp->InitArray(g);
- return jarp;
+ jarp->InitArray(g);
+ return jarp;
} // end of GetKeyList
/***********************************************************************/
@@ -996,13 +1021,13 @@ PJAR JOBJECT::GetKeyList(PGLOBAL g)
/***********************************************************************/
PJAR JOBJECT::GetValList(PGLOBAL g)
{
- PJAR jarp = new(g) JARRAY();
+ PJAR jarp = new(g) JARRAY();
- for (PJPR jpp = First; jpp; jpp = jpp->Next)
- jarp->AddValue(g, jpp->GetVal());
+ for (PJPR jpp = First; jpp; jpp = jpp->Next)
+ jarp->AddValue(g, jpp->Val);
- jarp->InitArray(g);
- return jarp;
+ jarp->InitArray(g);
+ return jarp;
} // end of GetValList
/***********************************************************************/
@@ -1024,6 +1049,9 @@ PSZ JOBJECT::GetText(PGLOBAL g, PSZ text)
{
int n;
+ if (!First)
+ return text;
+
if (!text) {
text = (char*)PlugSubAlloc(g, NULL, 0);
text[0] = 0;
@@ -1031,26 +1059,24 @@ PSZ JOBJECT::GetText(PGLOBAL g, PSZ text)
} else
n = 0;
- if (!First && n)
- return NULL;
- else if (n == 1 && Size == 1 && !strcmp(First->GetKey(), "$date")) {
- int i;
+ if (n == 1 && !First->Next && !strcmp(First->Key, "$date")) {
+ int i;
- First->Val->GetText(g, text);
- i = (text[1] == '-' ? 2 : 1);
+ First->Val->GetText(g, text);
+ i = (text[1] == '-' ? 2 : 1);
- if (IsNum(text + i)) {
- // Date is in milliseconds
- int j = (int)strlen(text);
+ if (IsNum(text + i)) {
+ // Date is in milliseconds
+ int j = (int)strlen(text);
- if (j >= 4 + i)
- text[j - 3] = 0; // Change it to seconds
- else
- strcpy(text, " 0");
+ if (j >= 4 + i)
+ text[j - 3] = 0; // Change it to seconds
+ else
+ strcpy(text, " 0");
- } // endif text
+ } // endif text
- } else for (PJPR jp = First; jp; jp = jp->Next)
+ } else for (PJPR jp = First; jp; jp = jp->Next)
jp->Val->GetText(g, text);
if (n)
@@ -1064,17 +1090,17 @@ PSZ JOBJECT::GetText(PGLOBAL g, PSZ text)
/***********************************************************************/
bool JOBJECT::Merge(PGLOBAL g, PJSON jsp)
{
- if (jsp->GetType() != TYPE_JOB) {
- strcpy(g->Message, "Second argument is not an object");
- return true;
- } // endif Type
+ if (jsp->GetType() != TYPE_JOB) {
+ strcpy(g->Message, "Second argument is not an object");
+ return true;
+ } // endif Type
- PJOB jobp = (PJOB)jsp;
+ PJOB jobp = (PJOB)jsp;
- for (PJPR jpp = jobp->First; jpp; jpp = jpp->Next)
- SetValue(g, jpp->GetVal(), jpp->GetKey());
+ for (PJPR jpp = jobp->First; jpp; jpp = jpp->Next)
+ SetValue(g, jpp->Val, jpp->Key);
- return false;
+ return false;
} // end of Marge;
/***********************************************************************/
@@ -1082,7 +1108,7 @@ bool JOBJECT::Merge(PGLOBAL g, PJSON jsp)
/***********************************************************************/
void JOBJECT::SetValue(PGLOBAL g, PJVAL jvp, PCSZ key)
{
- PJPR jp;
+ PJPR jp;
for (jp = First; jp; jp = jp->Next)
if (!strcmp(jp->Key, key)) {
@@ -1102,15 +1128,14 @@ void JOBJECT::SetValue(PGLOBAL g, PJVAL jvp, PCSZ key)
/***********************************************************************/
void JOBJECT::DeleteKey(PCSZ key)
{
- PJPR jp, *pjp = &First;
+ PJPR jp, *pjp = &First;
- for (jp = First; jp; jp = jp->Next)
- if (!strcmp(jp->Key, key)) {
- *pjp = jp->Next;
- Size--;
- break;
- } else
- pjp = &jp->Next;
+ for (jp = First; jp; jp = jp->Next)
+ if (!strcmp(jp->Key, key)) {
+ *pjp = jp->Next;
+ break;
+ } else
+ pjp = &jp->Next;
} // end of DeleteKey
@@ -1133,19 +1158,19 @@ bool JOBJECT::IsNull(void)
/***********************************************************************/
int JARRAY::GetSize(bool b)
{
- if (b) {
- // Return only non null values
- int n = 0;
+ if (b) {
+ // Return only non null values
+ int n = 0;
- for (PJVAL jvp = First; jvp; jvp = jvp->Next)
- if (!jvp->IsNull())
- n++;
+ for (PJVAL jvp = First; jvp; jvp = jvp->Next)
+ if (!jvp->IsNull())
+ n++;
- return n;
- } else
- return Size;
+ return n;
+ } else
+ return Size;
-} // end of GetSize
+} // end of GetSize
/***********************************************************************/
/* Make the array of values from the values list. */
@@ -1166,12 +1191,12 @@ void JARRAY::InitArray(PGLOBAL g)
} // endif Size
for (i = 0, jvp = First; jvp; jvp = jvp->Next)
- if (!jvp->Del) {
- Mvals[i++] = jvp;
- pjvp = &jvp->Next;
- Last = jvp;
- } else
- *pjvp = jvp->Next;
+ if (!jvp->Del) {
+ Mvals[i++] = jvp;
+ pjvp = &jvp->Next;
+ Last = jvp;
+ } else
+ *pjvp = jvp->Next;
} // end of InitArray
@@ -1194,28 +1219,28 @@ PJVAL JARRAY::AddValue(PGLOBAL g, PJVAL jvp, int *x)
if (!jvp)
jvp = new(g) JVALUE;
- if (x) {
- int i = 0, n = *x;
- PJVAL jp, *jpp = &First;
+ if (x) {
+ int i = 0, n = *x;
+ PJVAL jp, *jpp = &First;
- for (jp = First; jp && i < n; i++, jp = *(jpp = &jp->Next));
+ for (jp = First; jp && i < n; i++, jp = *(jpp = &jp->Next));
- (*jpp) = jvp;
+ (*jpp) = jvp;
- if (!(jvp->Next = jp))
- Last = jvp;
+ if (!(jvp->Next = jp))
+ Last = jvp;
- } else {
- if (!First)
- First = jvp;
- else if (Last == First)
- First->Next = Last = jvp;
- else
- Last->Next = jvp;
+ } else {
+ if (!First)
+ First = jvp;
+ else if (Last == First)
+ First->Next = Last = jvp;
+ else
+ Last->Next = jvp;
- Last = jvp;
- Last->Next = NULL;
- } // endif x
+ Last = jvp;
+ Last->Next = NULL;
+ } // endif x
return jvp;
} // end of AddValue
@@ -1225,18 +1250,18 @@ PJVAL JARRAY::AddValue(PGLOBAL g, PJVAL jvp, int *x)
/***********************************************************************/
bool JARRAY::Merge(PGLOBAL g, PJSON jsp)
{
- if (jsp->GetType() != TYPE_JAR) {
- strcpy(g->Message, "Second argument is not an array");
- return true;
- } // endif Type
+ if (jsp->GetType() != TYPE_JAR) {
+ strcpy(g->Message, "Second argument is not an array");
+ return true;
+ } // endif Type
- PJAR arp = (PJAR)jsp;
+ PJAR arp = (PJAR)jsp;
- for (int i = 0; i < jsp->size(); i++)
- AddValue(g, arp->GetValue(i));
+ for (int i = 0; i < arp->size(); i++)
+ AddValue(g, arp->GetValue(i));
- InitArray(g);
- return false;
+ InitArray(g);
+ return false;
} // end of Merge
/***********************************************************************/
@@ -1261,23 +1286,23 @@ bool JARRAY::SetValue(PGLOBAL g, PJVAL jvp, int n)
/***********************************************************************/
PSZ JARRAY::GetText(PGLOBAL g, PSZ text)
{
- int n;
- PJVAL jp;
+ int n;
+ PJVAL jp;
- if (!text) {
- text = (char*)PlugSubAlloc(g, NULL, 0);
- text[0] = 0;
- n = 1;
- } else
- n = 0;
+ if (!text) {
+ text = (char*)PlugSubAlloc(g, NULL, 0);
+ text[0] = 0;
+ n = 1;
+ } else
+ n = 0;
- for (jp = First; jp; jp = jp->Next)
- jp->GetText(g, text);
+ for (jp = First; jp; jp = jp->Next)
+ jp->GetText(g, text);
- if (n)
- PlugSubAlloc(g, NULL, strlen(text) + 1);
+ if (n)
+ PlugSubAlloc(g, NULL, strlen(text) + 1);
- return text + n;
+ return text + n;
} // end of GetText;
/***********************************************************************/
@@ -1285,13 +1310,13 @@ PSZ JARRAY::GetText(PGLOBAL g, PSZ text)
/***********************************************************************/
bool JARRAY::DeleteValue(int n)
{
- PJVAL jvp = GetValue(n);
+ PJVAL jvp = GetValue(n);
- if (jvp) {
- jvp->Del = true;
- return false;
- } else
- return true;
+ if (jvp) {
+ jvp->Del = true;
+ return false;
+ } else
+ return true;
} // end of DeleteValue
@@ -1314,28 +1339,41 @@ bool JARRAY::IsNull(void)
/***********************************************************************/
JVALUE::JVALUE(PJSON jsp) : JSON()
{
- if (jsp->GetType() == TYPE_JVAL) {
- Jsp = jsp->GetJsp();
- Value = jsp->GetValue();
- } else {
- Jsp = jsp;
- Value = NULL;
- } // endif Type
+ if (jsp->GetType() == TYPE_JVAL) {
+ Jsp = jsp->GetJsp();
+ Val = ((PJVAL)jsp)->GetVal();
+ } else {
+ Jsp = jsp;
+ Val = NULL;
+ } // endif Type
- Next = NULL;
- Del = false;
- Size = 1;
-} // end of JVALUE constructor
+ Next = NULL;
+ Del = false;
+ Type = TYPE_JVAL;
+} // end of JVALUE constructor
/***********************************************************************/
-/* Constructor for a Value with a given string or numeric value. */
+/* Constructor for a Val with a given string or numeric value. */
/***********************************************************************/
-JVALUE::JVALUE(PGLOBAL g, PVAL valp) : JSON()
+JVALUE::JVALUE(PGLOBAL g, PVL vlp) : JSON()
{
Jsp = NULL;
- Value = AllocateValue(g, valp);
+ Val = vlp;
+ Next = NULL;
+ Del = false;
+ Type = TYPE_JVAL;
+} // end of JVALUE constructor
+
+/***********************************************************************/
+/* Constructor for a Value with a given string or numeric value. */
+/***********************************************************************/
+JVALUE::JVALUE(PGLOBAL g, PVAL valp) : JSON() {
+ Jsp = NULL;
+ Val = NULL;
+ SetValue(g, valp);
Next = NULL;
Del = false;
+ Type = TYPE_JVAL;
} // end of JVALUE constructor
/***********************************************************************/
@@ -1343,10 +1381,12 @@ JVALUE::JVALUE(PGLOBAL g, PVAL valp) : JSON()
/***********************************************************************/
JVALUE::JVALUE(PGLOBAL g, PCSZ strp) : JSON()
{
- Jsp = NULL;
- Value = AllocateValue(g, (void*)strp, TYPE_STRING);
- Next = NULL;
- Del = false;
+ Jsp = NULL;
+ Val = AllocVal(g, TYPE_STRG);
+ Val->Strp = (char*)strp;
+ Next = NULL;
+ Del = false;
+ Type = TYPE_JVAL;
} // end of JVALUE constructor
/***********************************************************************/
@@ -1356,8 +1396,8 @@ JTYP JVALUE::GetValType(void)
{
if (Jsp)
return Jsp->GetType();
- else if (Value)
- return (JTYP)Value->GetType();
+ else if (Val)
+ return Val->Type;
else
return TYPE_NULL;
@@ -1386,11 +1426,41 @@ PJAR JVALUE::GetArray(void)
} // end of GetArray
/***********************************************************************/
-/* Return the Value's Integer value. */
+/* Return the Value's as a Value class. */
/***********************************************************************/
-int JVALUE::GetInteger(void)
+PVAL JVALUE::GetValue(PGLOBAL g)
{
- return (Value) ? Value->GetIntValue() : 0;
+ PVAL valp = NULL;
+
+ if (Val)
+ if (Val->Type == TYPE_STRG)
+ valp = AllocateValue(g, Val->Strp, Val->Type, Val->Nd);
+ else
+ valp = AllocateValue(g, Val, Val->Type, Val->Nd);
+
+ return valp;
+} // end of GetValue
+
+/***********************************************************************/
+/* Return the Value's Integer value. */
+/***********************************************************************/
+int JVALUE::GetInteger(void) {
+ int n;
+
+ if (!Val)
+ n = 0;
+ else switch (Val->Type) {
+ case TYPE_INTG: n = Val->N; break;
+ case TYPE_DBL: n = (int)Val->F; break;
+ case TYPE_DTM:
+ case TYPE_STRG: n = atoi(Val->Strp); break;
+ case TYPE_BOOL: n = (Val->B) ? 1 : 0; break;
+ case TYPE_BINT: n = (int)Val->LLn; break;
+ default:
+ n = 0;
+ } // endswitch Type
+
+ return n;
} // end of GetInteger
/***********************************************************************/
@@ -1398,7 +1468,22 @@ int JVALUE::GetInteger(void)
/***********************************************************************/
long long JVALUE::GetBigint(void)
{
- return (Value) ? Value->GetBigintValue() : 0;
+ long long lln;
+
+ if (!Val)
+ lln = 0;
+ else switch (Val->Type) {
+ case TYPE_BINT: lln = Val->LLn; break;
+ case TYPE_INTG: lln = (long long)Val->N; break;
+ case TYPE_DBL: lln = (long long)Val->F; break;
+ case TYPE_DTM:
+ case TYPE_STRG: lln = atoll(Val->Strp); break;
+ case TYPE_BOOL: lln = (Val->B) ? 1 : 0; break;
+ default:
+ lln = 0;
+ } // endswitch Type
+
+ return lln;
} // end of GetBigint
/***********************************************************************/
@@ -1406,7 +1491,22 @@ long long JVALUE::GetBigint(void)
/***********************************************************************/
double JVALUE::GetFloat(void)
{
- return (Value) ? Value->GetFloatValue() : 0.0;
+ double d;
+
+ if (!Val)
+ d = 0.0;
+ else switch (Val->Type) {
+ case TYPE_DBL: d = Val->F; break;
+ case TYPE_BINT: d = (double)Val->LLn; break;
+ case TYPE_INTG: d = (double)Val->N; break;
+ case TYPE_DTM:
+ case TYPE_STRG: d = atof(Val->Strp); break;
+ case TYPE_BOOL: d = (Val->B) ? 1.0 : 0.0; break;
+ default:
+ d = 0.0;
+ } // endswitch Type
+
+ return d;
} // end of GetFloat
/***********************************************************************/
@@ -1414,18 +1514,38 @@ double JVALUE::GetFloat(void)
/***********************************************************************/
PSZ JVALUE::GetString(PGLOBAL g)
{
- char *p;
-
- if (Value) {
- char buf[32];
-
- if ((p = Value->GetCharString(buf)) == buf)
- p = PlugDup(g, buf);
+ char buf[32];
+ char *p = buf;
+
+ if (Val) {
+ switch (Val->Type) {
+ case TYPE_DTM:
+ case TYPE_STRG:
+ p = Val->Strp;
+ break;
+ case TYPE_INTG:
+ sprintf(buf, "%d", Val->N);
+ break;
+ case TYPE_BINT:
+ sprintf(buf, "%lld", Val->LLn);
+ break;
+ case TYPE_DBL:
+ sprintf(buf, "%.*lf", Val->Nd, Val->F);
+ break;
+ case TYPE_BOOL:
+ p = (Val->B) ? "true" : "false";
+ break;
+ case TYPE_NULL:
+ p = "null";
+ break;
+ default:
+ p = NULL;
+ } // endswitch Type
- } else
- p = NULL;
+ } else
+ p = NULL;
- return p;
+ return p;
} // end of GetString
/***********************************************************************/
@@ -1436,8 +1556,7 @@ PSZ JVALUE::GetText(PGLOBAL g, PSZ text)
if (Jsp)
return Jsp->GetText(g, text);
- char buf[32];
- PSZ s = (Value) ? Value->GetCharString(buf) : NULL;
+ PSZ s = (Val) ? GetString(g) : NULL;
if (s)
strcat(strcat(text, " "), s);
@@ -1449,32 +1568,74 @@ PSZ JVALUE::GetText(PGLOBAL g, PSZ text)
void JVALUE::SetValue(PJSON jsp)
{
- if (jsp && jsp->GetType() == TYPE_JVAL) {
- Jsp = jsp->GetJsp();
- Value = jsp->GetValue();
- } else {
- Jsp = jsp;
- Value = NULL;
- } // endif Type
+ if (jsp && jsp->GetType() == TYPE_JVAL) {
+ Jsp = jsp->GetJsp();
+ Val = ((PJVAL)jsp)->GetVal();
+ } else {
+ Jsp = jsp;
+ Val = NULL;
+ } // endif Type
+
+} // end of SetValue;
+
+void JVALUE::SetValue(PGLOBAL g, PVAL valp)
+{
+ if (!Val)
+ Val = AllocVal(g, TYPE_VAL);
+
+ if (!valp || valp->IsNull()) {
+ Val->Type = TYPE_NULL;
+ } else switch (valp->GetType()) {
+ case TYPE_STRING:
+ case TYPE_DATE:
+ Val->Strp = valp->GetCharValue();
+ Val->Type = TYPE_STRG;
+ break;
+ case TYPE_DOUBLE:
+ case TYPE_DECIM:
+ Val->F = valp->GetFloatValue();
+
+ if (IsTypeNum(valp->GetType()))
+ Val->Nd = valp->GetValPrec();
+
+ Val->Type = TYPE_DBL;
+ break;
+ case TYPE_TINY:
+ Val->B = valp->GetTinyValue() != 0;
+ Val->Type = TYPE_BOOL;
+ case TYPE_INT:
+ Val->N = valp->GetIntValue();
+ Val->Type = TYPE_INTG;
+ break;
+ case TYPE_BIGINT:
+ Val->LLn = valp->GetBigintValue();
+ Val->Type = TYPE_BINT;
+ break;
+ default:
+ sprintf(g->Message, "Unsupported typ %d\n", valp->GetType());
+ throw(777);
+ } // endswitch Type
-} // end of SetValue;
+} // end of SetValue
/***********************************************************************/
/* Set the Value's value as the given integer. */
/***********************************************************************/
void JVALUE::SetInteger(PGLOBAL g, int n)
{
- Value = AllocateValue(g, &n, TYPE_INT);
- Jsp = NULL;
+ Val = AllocVal(g, TYPE_INTG);
+ Val->N = n;
+ Jsp = NULL;
} // end of SetInteger
/***********************************************************************/
/* Set the Value's Boolean value as a tiny integer. */
/***********************************************************************/
-void JVALUE::SetTiny(PGLOBAL g, char n)
+void JVALUE::SetBool(PGLOBAL g, bool b)
{
- Value = AllocateValue(g, &n, TYPE_TINY);
- Jsp = NULL;
+ Val = AllocVal(g, TYPE_BOOL);
+ Val->B = b;
+ Jsp = NULL;
} // end of SetTiny
/***********************************************************************/
@@ -1482,8 +1643,9 @@ void JVALUE::SetTiny(PGLOBAL g, char n)
/***********************************************************************/
void JVALUE::SetBigint(PGLOBAL g, long long ll)
{
- Value = AllocateValue(g, &ll, TYPE_BIGINT);
- Jsp = NULL;
+ Val = AllocVal(g, TYPE_BINT);
+ Val->LLn = ll;
+ Jsp = NULL;
} // end of SetBigint
/***********************************************************************/
@@ -1491,17 +1653,21 @@ void JVALUE::SetBigint(PGLOBAL g, long long ll)
/***********************************************************************/
void JVALUE::SetFloat(PGLOBAL g, double f)
{
- Value = AllocateValue(g, &f, TYPE_DOUBLE, 6);
- Jsp = NULL;
+ Val = AllocVal(g, TYPE_DBL);
+ Val->F = f;
+ Val->Nd = 6;
+ Jsp = NULL;
} // end of SetFloat
/***********************************************************************/
/* Set the Value's value as the given string. */
/***********************************************************************/
-void JVALUE::SetString(PGLOBAL g, PSZ s, short c)
+void JVALUE::SetString(PGLOBAL g, PSZ s, int ci)
{
- Value = AllocateValue(g, s, TYPE_STRING, c);
- Jsp = NULL;
+ Val = AllocVal(g, TYPE_STRG);
+ Val->Strp = s;
+ Val->Nd = ci;
+ Jsp = NULL;
} // end of SetString
/***********************************************************************/
@@ -1509,6 +1675,228 @@ void JVALUE::SetString(PGLOBAL g, PSZ s, short c)
/***********************************************************************/
bool JVALUE::IsNull(void)
{
- return (Jsp) ? Jsp->IsNull() : (Value) ? Value->IsNull() : true;
+ return (Jsp) ? Jsp->IsNull() : (Val) ? Val->Type == TYPE_NULL : true;
} // end of IsNull
+
+/* ---------------------------- Class SWAP --------------------------- */
+
+/***********************************************************************/
+/* Replace all pointers by offsets or the opposite. */
+/***********************************************************************/
+void SWAP::SwapJson(PJSON jsp, bool move)
+{
+ if (move)
+ MoffJson(jsp);
+ else
+ MptrJson((PJSON)MakeOff(Base, jsp));
+
+ return;
+} // end of SwapJson
+
+/***********************************************************************/
+/* Replace all pointers by offsets. */
+/***********************************************************************/
+size_t SWAP::MoffJson(PJSON jsp) {
+ size_t res;
+
+ if (jsp)
+ switch (jsp->Type) {
+ case TYPE_JAR:
+ res = MoffArray((PJAR)jsp);
+ break;
+ case TYPE_JOB:
+ res = MoffObject((PJOB)jsp);
+ break;
+ case TYPE_JVAL:
+ res = MoffJValue((PJVAL)jsp);
+ break;
+ default:
+ throw "Invalid json tree";
+ } // endswitch Type
+
+ return res;
+} // end of MoffJson
+
+/***********************************************************************/
+/* Replace all array pointers by offsets. */
+/***********************************************************************/
+size_t SWAP::MoffArray(PJAR jarp)
+{
+ if (jarp->First) {
+ for (int i = 0; i < jarp->Size; i++)
+ jarp->Mvals[i] = (PJVAL)MakeOff(Base, jarp->Mvals[i]);
+
+ jarp->First = (PJVAL)MoffJValue(jarp->First);
+ jarp->Last = (PJVAL)MakeOff(Base, jarp->Last);
+ } // endif First
+
+ return MakeOff(Base, jarp);
+} // end of MoffArray
+
+/***********************************************************************/
+/* Replace all object pointers by offsets. */
+/***********************************************************************/
+size_t SWAP::MoffObject(PJOB jobp) {
+ if (jobp->First) {
+ jobp->First = (PJPR)MoffPair(jobp->First);
+ jobp->Last = (PJPR)MakeOff(Base, jobp->Last);
+ } // endif First
+
+ return MakeOff(Base, jobp);
+} // end of MoffObject
+
+/***********************************************************************/
+/* Replace all pair pointers by offsets. */
+/***********************************************************************/
+size_t SWAP::MoffPair(PJPR jpp) {
+ jpp->Key = (PCSZ)MakeOff(Base, (void*)jpp->Key);
+
+ if (jpp->Val)
+ jpp->Val = (PJVAL)MoffJValue(jpp->Val);
+
+ if (jpp->Next)
+ jpp->Next = (PJPR)MoffPair(jpp->Next);
+
+ return MakeOff(Base, jpp);
+} // end of MoffPair
+
+/***********************************************************************/
+/* Replace all jason value pointers by offsets. */
+/***********************************************************************/
+size_t SWAP::MoffJValue(PJVAL jvp) {
+ if (!jvp->Del) {
+ if (jvp->Jsp)
+ jvp->Jsp = (PJSON)MoffJson(jvp->Jsp);
+
+ if (jvp->Val)
+ jvp->Val = (PVL)MoffVal(jvp->Val);
+
+ } // endif Del
+
+ if (jvp->Next)
+ jvp->Next = (PJVAL)MoffJValue(jvp->Next);
+
+ return MakeOff(Base, jvp);
+} // end of MoffJValue
+
+/***********************************************************************/
+/* Replace string pointers by offset. */
+/***********************************************************************/
+size_t SWAP::MoffVal(PVL vlp) {
+ if (vlp->Type == TYPE_STRG)
+ vlp->Strp = (PSZ)MakeOff(Base, (vlp->Strp));
+
+ return MakeOff(Base, vlp);
+} // end of MoffVal
+
+/***********************************************************************/
+/* Replace all offsets by pointers. */
+/***********************************************************************/
+PJSON SWAP::MptrJson(PJSON ojp) { // ojp is an offset
+ PJSON jsp = (PJSON)MakePtr(Base, (size_t)ojp);
+
+ if (ojp)
+ switch (jsp->Type) {
+ case TYPE_JAR:
+ jsp = MptrArray((PJAR)ojp);
+ break;
+ case TYPE_JOB:
+ jsp = MptrObject((PJOB)ojp);
+ break;
+ case TYPE_JVAL:
+ jsp = MptrJValue((PJVAL)ojp);
+ break;
+ default:
+ throw "Invalid json tree";
+ } // endswitch Type
+
+ return jsp;
+} // end of MptrJson
+
+/***********************************************************************/
+/* Replace all array offsets by pointers. */
+/***********************************************************************/
+PJAR SWAP::MptrArray(PJAR ojar) {
+ PJAR jarp = (PJAR)MakePtr(Base, (size_t)ojar);
+
+ jarp = (PJAR)new((size_t)jarp) JARRAY(NULL);
+
+ if (jarp->First) {
+ for (int i = 0; i < jarp->Size; i++)
+ jarp->Mvals[i] = (PJVAL)MakePtr(Base, (size_t)jarp->Mvals[i]);
+
+ jarp->First = (PJVAL)MptrJValue(jarp->First);
+ jarp->Last = (PJVAL)MakePtr(Base, (size_t)jarp->Last);
+ } // endif First
+
+ return jarp;
+} // end of MptrArray
+
+/***********************************************************************/
+/* Replace all object offsets by pointers. */
+/***********************************************************************/
+PJOB SWAP::MptrObject(PJOB ojob) {
+ PJOB jobp = (PJOB)MakePtr(Base, (size_t)ojob);
+
+ jobp = (PJOB)new((size_t)jobp) JOBJECT(NULL);
+
+ if (jobp->First) {
+ jobp->First = (PJPR)MptrPair(jobp->First);
+ jobp->Last = (PJPR)MakePtr(Base, (size_t)jobp->Last);
+ } // endif First
+
+ return jobp;
+} // end of MptrObject
+
+/***********************************************************************/
+/* Replace all pair offsets by pointers. */
+/***********************************************************************/
+PJPR SWAP::MptrPair(PJPR ojp) {
+ PJPR jpp = (PJPR)MakePtr(Base, (size_t)ojp);
+
+ jpp->Key = (PCSZ)MakePtr(Base, (size_t)jpp->Key);
+
+ if (jpp->Val)
+ jpp->Val = (PJVAL)MptrJValue(jpp->Val);
+
+ if (jpp->Next)
+ jpp->Next = (PJPR)MptrPair(jpp->Next);
+
+ return jpp;
+} // end of MptrPair
+
+/***********************************************************************/
+/* Replace all value offsets by pointers. */
+/***********************************************************************/
+PJVAL SWAP::MptrJValue(PJVAL ojv) {
+ PJVAL jvp = (PJVAL)MakePtr(Base, (size_t)ojv);
+
+ jvp = (PJVAL)new((size_t)jvp) JVALUE(0);
+
+ if (!jvp->Del) {
+ if (jvp->Jsp)
+ jvp->Jsp = (PJSON)MptrJson(jvp->Jsp);
+
+ if (jvp->Val)
+ jvp->Val = (PVL)MptrVal(jvp->Val);
+
+ } // endif Del
+
+ if (jvp->Next)
+ jvp->Next = (PJVAL)MptrJValue(jvp->Next);
+
+ return jvp;
+} // end of MptrJValue
+
+/***********************************************************************/
+/* Replace string offsets by a pointer. */
+/***********************************************************************/
+PVL SWAP::MptrVal(PVL ovl) {
+ PVL vlp = (PVL)MakePtr(Base, (size_t)ovl);
+
+ if (vlp->Type == TYPE_STRG)
+ vlp->Strp = (PSZ)MakePtr(Base, (size_t)vlp->Strp);
+
+ return vlp;
+} // end of MptrValue