From 28af4212b6e2afe1d42729c9c36215ed8a8d38cb Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Tue, 3 Nov 2020 18:40:28 +0100 Subject: - 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 --- storage/connect/json.cpp | 1798 ++++++++++++++++++++++++++++------------------ 1 file changed, 1093 insertions(+), 705 deletions(-) (limited to 'storage/connect/json.cpp') 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,427 +829,169 @@ 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"); - err: - throw("Unexpected EOF in number"); -} // 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 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; - - } // endif Prty - - } 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(',')) - 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 - - if (SerializeValue(js, jarp->GetValue(i))) - return true; - - } // endfor i - - if (b && js->Prty() == 1 && js->WriteStr(EL)) - return true; - - return ((!b || js->Prty()) && js->WriteChr(']')); -} // end of SerializeArray - -/***********************************************************************/ -/* Serialize a JSON Object. */ -/***********************************************************************/ -bool SerializeObject(JOUT *js, PJOB jobp) -{ - bool first = true; - - if (js->WriteChr('{')) - return true; - - for (PJPR pair = jobp->First; pair; pair = pair->Next) { - if (first) - first = false; - else if (js->WriteChr(',')) - return true; - - if (js->WriteChr('"') || - js->WriteStr(pair->Key) || - js->WriteChr('"') || - js->WriteChr(':') || - SerializeValue(js, pair->Val)) - return true; - - } // endfor i - - return js->WriteChr('}'); -} // end of SerializeObject - -/***********************************************************************/ -/* Serialize a JSON Value. */ -/***********************************************************************/ -bool SerializeValue(JOUT *js, PJVAL jvp) -{ - PJAR jap; - PJOB jop; - PVAL valp; - - if ((jap = jvp->GetArray())) - return SerializeArray(js, jap, false); - else if ((jop = jvp->GetObject())) - return SerializeObject(js, jop); - else if (!(valp = jvp->Value) || valp->IsNull()) - 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()); - default: - if (valp->IsTypeNum()) { - char buf[32]; - - return js->WriteStr(valp->GetCharString(buf)); - } // endif valp - - } // endswitch Type - - 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 + err: + throw("Unexpected EOF in number"); +} // end of ParseNumeric /***********************************************************************/ -/* Write a character to the Serialize file. */ +/* Serialize a JSON Array. */ /***********************************************************************/ -bool JOUTFILE::WriteChr(const char c) +bool JDOC::SerializeArray(PJAR jarp, bool b) { - // This is temporary - fputc(c, Stream); - return false; -} // end of WriteChr + bool first = true; -/***********************************************************************/ -/* Escape and Concatenate a string to the Serialize string. */ -/***********************************************************************/ -bool JOUTFILE::Escape(const char *s) -{ - // This is temporary - fputc('"', Stream); + if (b) { + if (js->Prty()) { + if (js->WriteChr('[')) + return true; + else if (js->Prty() == 1 && (js->WriteStr(EL) || js->WriteChr('\t'))) + return true; - 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] + } // endif Prty - fputc('"', Stream); - return false; -} // end of Escape + } else if (js->WriteChr('[')) + return true; -/* ------------------------- Class JOUTPRT --------------------------- */ + for (int i = 0; i < jarp->size(); i++) { + if (first) + first = false; + 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; -/***********************************************************************/ -/* Write a string to the Serialize pretty file. */ -/***********************************************************************/ -bool JOUTPRT::WriteStr(const char *s) -{ - // This is temporary - if (B) { - fputs(EL, Stream); - M--; + } // endif b - for (int i = 0; i < M; i++) - fputc('\t', Stream); + if (SerializeValue(jarp->GetValue(i))) + return true; - B = false; - } // endif B + } // endfor i - fputs(s, Stream); - return false; -} // end of WriteStr + if (b && js->Prty() == 1 && js->WriteStr(EL)) + return true; + + return ((!b || js->Prty()) && js->WriteChr(']')); +} // end of SerializeArray /***********************************************************************/ -/* Write a character to the Serialize pretty file. */ +/* Serialize a JSON Object. */ /***********************************************************************/ -bool JOUTPRT::WriteChr(const char c) +bool JDOC::SerializeObject(PJOB jobp) { - 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 + bool first = true; - fputc(c, Stream); - fputs(EL, Stream); - M++; + if (js->WriteChr('{')) + return true; - for (int i = 0; i < M; i++) - fputc('\t', Stream); + for (PJPR pair = jobp->GetFirst(); pair; pair = pair->Next) { + if (first) + first = false; + else if (js->WriteChr(',')) + return true; - break; - case '}': - case ']': - M--; - fputs(EL, Stream); + if (js->WriteChr('"') || + js->WriteStr(pair->Key) || + js->WriteChr('"') || + js->WriteChr(':') || + SerializeValue(pair->Val)) + return true; - for (int i = 0; i < M; i++) - fputc('\t', Stream); + } // endfor i - fputc(c, Stream); - B = true; - break; - case ',': - fputc(c, Stream); - fputs(EL, Stream); + return js->WriteChr('}'); +} // end of SerializeObject - for (int i = 0; i < M; i++) - fputc('\t', Stream); +/***********************************************************************/ +/* Serialize a JSON Value. */ +/***********************************************************************/ +bool JDOC::SerializeValue(PJVAL jvp) +{ + char buf[64]; + PJAR jap; + PJOB jop; + PVL vlp; - B = false; - break; + if ((jap = jvp->GetArray())) + return SerializeArray(jap, false); + else if ((jop = jvp->GetObject())) + return SerializeObject(jop); + else if (!(vlp = jvp->Val)) + return js->WriteStr("null"); + 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: - fputc(c, Stream); - } // endswitch c + return js->WriteStr("???"); // TODO + } // endswitch Type -return false; -} // end of WriteChr + strcpy(js->g->Message, "Unrecognized value"); + return true; +} // end of SerializeValue /* -------------------------- 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; - - for (PJPR jpp = First; jpp; jpp = jpp->Next) - if (jpp->Val && !jpp->Val->IsNull()) - n++; +int JOBJECT::GetSize(bool b) { + int n = 0; - return n; - } else - return Size; + for (PJPR jpp = First; jpp; jpp = jpp->Next) + // If b return only non null pairs + if (!b || jpp->Val && !jpp->Val->IsNull()) + n++; -} // 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 -- cgit v1.2.1 From 49428c8fa6905c87b2b89e094c72f48a1e75b383 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Wed, 4 Nov 2020 11:36:29 +0100 Subject: Fix compile error on LINUX (no suitable operator delete) --- storage/connect/json.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'storage/connect/json.cpp') diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index ce3ddd865a5..d461b60470d 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -1820,7 +1820,7 @@ PJSON SWAP::MptrJson(PJSON ojp) { // ojp is an offset PJAR SWAP::MptrArray(PJAR ojar) { PJAR jarp = (PJAR)MakePtr(Base, (size_t)ojar); - jarp = (PJAR)new((size_t)jarp) JARRAY(NULL); + jarp = (PJAR)new((long long)jarp) JARRAY(NULL); if (jarp->First) { for (int i = 0; i < jarp->Size; i++) @@ -1839,7 +1839,7 @@ PJAR SWAP::MptrArray(PJAR ojar) { PJOB SWAP::MptrObject(PJOB ojob) { PJOB jobp = (PJOB)MakePtr(Base, (size_t)ojob); - jobp = (PJOB)new((size_t)jobp) JOBJECT(NULL); + jobp = (PJOB)new((long long)jobp) JOBJECT(NULL); if (jobp->First) { jobp->First = (PJPR)MptrPair(jobp->First); @@ -1872,7 +1872,7 @@ PJPR SWAP::MptrPair(PJPR ojp) { PJVAL SWAP::MptrJValue(PJVAL ojv) { PJVAL jvp = (PJVAL)MakePtr(Base, (size_t)ojv); - jvp = (PJVAL)new((size_t)jvp) JVALUE(0); + jvp = (PJVAL)new((long long)jvp) JVALUE(0); if (!jvp->Del) { if (jvp->Jsp) -- cgit v1.2.1 From 6a94ad98fb8da214a9d917a72f704e6da795e338 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Wed, 4 Nov 2020 15:46:02 +0100 Subject: Fix crash on Json date columns --- storage/connect/json.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'storage/connect/json.cpp') diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index d461b60470d..c4d2c006da1 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -1587,7 +1587,17 @@ void JVALUE::SetValue(PGLOBAL g, PVAL valp) Val->Type = TYPE_NULL; } else switch (valp->GetType()) { case TYPE_STRING: - case TYPE_DATE: + if (((DTVAL*)valp)->IsFormatted()) + Val->Strp = valp->GetCharValue(); + else { + char buf[32]; + + Val->Strp = PlugDup(g, valp->GetCharString(buf)); + } // endif Formatted + + Val->Type = TYPE_DTM; + break; + case TYPE_DATE: Val->Strp = valp->GetCharValue(); Val->Type = TYPE_STRG; break; -- cgit v1.2.1 From ecb00f3cd8cd55b402f504d4edc9e2ff08360809 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Thu, 5 Nov 2020 19:13:26 +0100 Subject: Try to fix failing tests --- storage/connect/json.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'storage/connect/json.cpp') diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index c4d2c006da1..dd12bf546de 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -1533,10 +1533,11 @@ PSZ JVALUE::GetString(PGLOBAL g) sprintf(buf, "%.*lf", Val->Nd, Val->F); break; case TYPE_BOOL: - p = (Val->B) ? "true" : "false"; + p = (char*)PlugDup(g, (Val->B) ? "true" : "false"); break; case TYPE_NULL: - p = "null"; + p = (char*)PlugDup(g, "null") + ; break; default: p = NULL; @@ -1545,7 +1546,7 @@ PSZ JVALUE::GetString(PGLOBAL g) } else p = NULL; - return p; + return (p == buf)? (char*)PlugDup(g, buf) : p; } // end of GetString /***********************************************************************/ -- cgit v1.2.1 From addb28f62dc205e61c70e6ca8ef8547bfa44c50a Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Thu, 5 Nov 2020 22:14:01 +0100 Subject: Try to fix failing tests --- storage/connect/json.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'storage/connect/json.cpp') diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index dd12bf546de..11553e2f0dd 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -1053,7 +1053,7 @@ PSZ JOBJECT::GetText(PGLOBAL g, PSZ text) return text; if (!text) { - text = (char*)PlugSubAlloc(g, NULL, 0); + text = (char*)PlugSubAlloc(g, NULL, 512); // TODO: get size text[0] = 0; n = 1; } else @@ -1079,8 +1079,8 @@ PSZ JOBJECT::GetText(PGLOBAL g, PSZ text) } else for (PJPR jp = First; jp; jp = jp->Next) jp->Val->GetText(g, text); - if (n) - PlugSubAlloc(g, NULL, strlen(text) + 1); + //if (n) + // PlugSubAlloc(g, NULL, strlen(text) + 1); return text + n; } // end of GetText; @@ -1290,7 +1290,7 @@ PSZ JARRAY::GetText(PGLOBAL g, PSZ text) PJVAL jp; if (!text) { - text = (char*)PlugSubAlloc(g, NULL, 0); + text = (char*)PlugSubAlloc(g, NULL, 512); text[0] = 0; n = 1; } else @@ -1299,8 +1299,8 @@ PSZ JARRAY::GetText(PGLOBAL g, PSZ 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; } // end of GetText; @@ -1536,8 +1536,7 @@ PSZ JVALUE::GetString(PGLOBAL g) p = (char*)PlugDup(g, (Val->B) ? "true" : "false"); break; case TYPE_NULL: - p = (char*)PlugDup(g, "null") - ; + p = (char*)PlugDup(g, "null"); break; default: p = NULL; @@ -1546,7 +1545,7 @@ PSZ JVALUE::GetString(PGLOBAL g) } else p = NULL; - return (p == buf)? (char*)PlugDup(g, buf) : p; + return (p == buf) ? (char*)PlugDup(g, buf) : p; } // end of GetString /***********************************************************************/ -- cgit v1.2.1 From a4e999eec5ad08eb663f94fef0e9590daf1e5b5f Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Thu, 5 Nov 2020 23:04:37 +0100 Subject: Try to fix failing tests --- storage/connect/json.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'storage/connect/json.cpp') diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index 11553e2f0dd..1006c9c9de1 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -1053,7 +1053,7 @@ PSZ JOBJECT::GetText(PGLOBAL g, PSZ text) return text; if (!text) { - text = (char*)PlugSubAlloc(g, NULL, 512); // TODO: get size + text = (PSZ)malloc(1024); // TODO: get size text[0] = 0; n = 1; } else @@ -1079,10 +1079,14 @@ PSZ JOBJECT::GetText(PGLOBAL g, PSZ text) } else for (PJPR jp = First; jp; jp = jp->Next) jp->Val->GetText(g, text); - //if (n) - // PlugSubAlloc(g, NULL, strlen(text) + 1); + if (n) { + PSZ txt = (PSZ)PlugSubAlloc(g, NULL, strlen(text)); + strcpy(txt, text + 1); // Remove leading blank + free(text); + text = txt; + } // endif n - return text + n; + return text; } // end of GetText; /***********************************************************************/ @@ -1290,7 +1294,7 @@ PSZ JARRAY::GetText(PGLOBAL g, PSZ text) PJVAL jp; if (!text) { - text = (char*)PlugSubAlloc(g, NULL, 512); + text = (char*)malloc(1024); // Should be large enough text[0] = 0; n = 1; } else @@ -1299,10 +1303,14 @@ PSZ JARRAY::GetText(PGLOBAL g, PSZ text) for (jp = First; jp; jp = jp->Next) jp->GetText(g, text); - //if (n) - // PlugSubAlloc(g, NULL, strlen(text) + 1); + if (n) { + PSZ txt = (PSZ)PlugSubAlloc(g, NULL, strlen(text)); + strcpy(txt, text + 1); // Remove leading blank + free(text); + text = txt; + } // endif n - return text + n; + return text; } // end of GetText; /***********************************************************************/ -- cgit v1.2.1 From 46edfd6338f7709aca65070496019c9970bf8ecf Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Sat, 7 Nov 2020 15:40:46 +0100 Subject: - Getting text of json items now includes all array members modified: storage/connect/json.cpp modified: storage/connect/json.h modified: storage/connect/jsonudf.cpp modified: storage/connect/jsonudf.h 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_mongo_c.result modified: storage/connect/mysql-test/connect/r/json_udf.result modified: storage/connect/mysql-test/connect/r/json_udf_bin.result modified: storage/connect/mysql-test/connect/r/zip.result modified: storage/connect/mysql-test/connect/t/zip.test modified: storage/connect/tabjson.cpp modified: storage/connect/tabjson.h modified: storage/connect/xobject.h --- storage/connect/json.cpp | 149 +++++++++++++++++++++++++++-------------------- 1 file changed, 86 insertions(+), 63 deletions(-) (limited to 'storage/connect/json.cpp') diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index 1006c9c9de1..9af5761c9ee 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -1045,48 +1045,57 @@ PJVAL JOBJECT::GetValue(const char* key) /***********************************************************************/ /* Return the text corresponding to all keys (XML like). */ /***********************************************************************/ -PSZ JOBJECT::GetText(PGLOBAL g, PSZ text) +PSZ JOBJECT::GetText(PGLOBAL g, PSTRG text) { - int n; + if (First) { + bool b; - if (!First) - return text; + if (!text) { + text = new(g) STRING(g, 256); + b = true; + } else { + if (text->GetLastChar() != ' ') + text->Append(' '); - if (!text) { - text = (PSZ)malloc(1024); // TODO: get size - text[0] = 0; - n = 1; - } else - n = 0; + b = false; + } // endif text - if (n == 1 && !First->Next && !strcmp(First->Key, "$date")) { - int i; + if (b && !First->Next && !strcmp(First->Key, "$date")) { + int i; + PSZ s; - First->Val->GetText(g, text); - i = (text[1] == '-' ? 2 : 1); + First->Val->GetText(g, text); + s = text->GetStr(); + i = (s[1] == '-' ? 2 : 1); - if (IsNum(text + i)) { - // Date is in milliseconds - int j = (int)strlen(text); + if (IsNum(s + i)) { + // Date is in milliseconds + int j = text->GetLength(); - if (j >= 4 + i) - text[j - 3] = 0; // Change it to seconds - else - strcpy(text, " 0"); + if (j >= 4 + i) { + s[j - 3] = 0; // Change it to seconds + text->SetLength((uint)strlen(s)); + } else + text->Set(" 0"); - } // endif text + } // endif text - } else for (PJPR jp = First; jp; jp = jp->Next) - jp->Val->GetText(g, text); + } else for (PJPR jp = First; jp; jp = jp->Next) { + jp->Val->GetText(g, text); - if (n) { - PSZ txt = (PSZ)PlugSubAlloc(g, NULL, strlen(text)); - strcpy(txt, text + 1); // Remove leading blank - free(text); - text = txt; - } // endif n + if (jp->Next) + text->Append(' '); - return text; + } // endfor jp + + if (b) { + text->Trim(); + return text->GetStr(); + } // endif b + + } // endif First + + return NULL; } // end of GetText; /***********************************************************************/ @@ -1288,29 +1297,42 @@ bool JARRAY::SetValue(PGLOBAL g, PJVAL jvp, int n) /***********************************************************************/ /* Return the text corresponding to all values. */ /***********************************************************************/ -PSZ JARRAY::GetText(PGLOBAL g, PSZ text) +PSZ JARRAY::GetText(PGLOBAL g, PSTRG text) { - int n; - PJVAL jp; + if (First) { + bool b; + PJVAL jp; - if (!text) { - text = (char*)malloc(1024); // Should be large enough - text[0] = 0; - n = 1; - } else - n = 0; + if (!text) { + text = new(g) STRING(g, 256); + b = true; + } else { + if (text->GetLastChar() != ' ') + text->Append(" ("); + else + text->Append('('); - for (jp = First; jp; jp = jp->Next) - jp->GetText(g, text); + b = false; + } + + for (jp = First; jp; jp = jp->Next) { + jp->GetText(g, text); + + if (jp->Next) + text->Append(", "); + else if (!b) + text->Append(')'); - if (n) { - PSZ txt = (PSZ)PlugSubAlloc(g, NULL, strlen(text)); - strcpy(txt, text + 1); // Remove leading blank - free(text); - text = txt; - } // endif n + } // endfor jp - return text; + if (b) { + text->Trim(); + return text->GetStr(); + } // endif b + + } // endif First + + return NULL; } // end of GetText; /***********************************************************************/ @@ -1520,10 +1542,10 @@ double JVALUE::GetFloat(void) /***********************************************************************/ /* Return the Value's String value. */ /***********************************************************************/ -PSZ JVALUE::GetString(PGLOBAL g) +PSZ JVALUE::GetString(PGLOBAL g, char *buff) { char buf[32]; - char *p = buf; + char *p = (buff) ? buff : buf; if (Val) { switch (Val->Type) { @@ -1532,19 +1554,19 @@ PSZ JVALUE::GetString(PGLOBAL g) p = Val->Strp; break; case TYPE_INTG: - sprintf(buf, "%d", Val->N); + sprintf(p, "%d", Val->N); break; case TYPE_BINT: - sprintf(buf, "%lld", Val->LLn); + sprintf(p, "%lld", Val->LLn); break; case TYPE_DBL: - sprintf(buf, "%.*lf", Val->Nd, Val->F); + sprintf(p, "%.*lf", Val->Nd, Val->F); break; case TYPE_BOOL: - p = (char*)PlugDup(g, (Val->B) ? "true" : "false"); + p = (char*)((Val->B) ? "true" : "false"); break; case TYPE_NULL: - p = (char*)PlugDup(g, "null"); + p = (char*)"null"; break; default: p = NULL; @@ -1559,19 +1581,20 @@ PSZ JVALUE::GetString(PGLOBAL g) /***********************************************************************/ /* Return the Value's String value. */ /***********************************************************************/ -PSZ JVALUE::GetText(PGLOBAL g, PSZ text) +PSZ JVALUE::GetText(PGLOBAL g, PSTRG text) { if (Jsp) return Jsp->GetText(g, text); - PSZ s = (Val) ? GetString(g) : NULL; + char buff[32]; + PSZ s = (Val) ? GetString(g, buff) : NULL; - if (s) - strcat(strcat(text, " "), s); - else if (GetJsonNull()) - strcat(strcat(text, " "), GetJsonNull()); + if (s) + text->Append(s); + else if (GetJsonNull()) + text->Append(GetJsonNull()); - return text; + return NULL; } // end of GetText void JVALUE::SetValue(PJSON jsp) -- cgit v1.2.1 From fb86a496c04d688d4d4973d958e664f866b04881 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Sat, 7 Nov 2020 22:36:50 +0100 Subject: Re-fix compile error (overloaded-virtual) --- storage/connect/json.cpp | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) (limited to 'storage/connect/json.cpp') diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index 9af5761c9ee..6fdb7e9c15c 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -531,7 +531,7 @@ PJAR JDOC::ParseArray(PGLOBAL g, int& i) sprintf(g->Message, "Unexpected value near %.*s", ARGS); throw 1; } else - jarp->AddValue(g, ParseValue(g, i)); + jarp->AddArrayValue(g, ParseValue(g, i)); level = (b) ? 1 : 2; break; @@ -886,7 +886,7 @@ bool JDOC::SerializeArray(PJAR jarp, bool b) } // endif b - if (SerializeValue(jarp->GetValue(i))) + if (SerializeValue(jarp->GetArrayValue(i))) return true; } // endfor i @@ -1010,7 +1010,7 @@ PJAR JOBJECT::GetKeyList(PGLOBAL g) PJAR jarp = new(g) JARRAY(); for (PJPR jpp = First; jpp; jpp = jpp->Next) - jarp->AddValue(g, new(g) JVALUE(g, jpp->Key)); + jarp->AddArrayValue(g, new(g) JVALUE(g, jpp->Key)); jarp->InitArray(g); return jarp; @@ -1024,7 +1024,7 @@ PJAR JOBJECT::GetValList(PGLOBAL g) PJAR jarp = new(g) JARRAY(); for (PJPR jpp = First; jpp; jpp = jpp->Next) - jarp->AddValue(g, jpp->Val); + jarp->AddArrayValue(g, jpp->Val); jarp->InitArray(g); return jarp; @@ -1033,7 +1033,7 @@ PJAR JOBJECT::GetValList(PGLOBAL g) /***********************************************************************/ /* Get the value corresponding to the given key. */ /***********************************************************************/ -PJVAL JOBJECT::GetValue(const char* key) +PJVAL JOBJECT::GetKeyValue(const char* key) { for (PJPR jp = First; jp; jp = jp->Next) if (!strcmp(jp->Key, key)) @@ -1111,7 +1111,7 @@ bool JOBJECT::Merge(PGLOBAL g, PJSON jsp) PJOB jobp = (PJOB)jsp; for (PJPR jpp = jobp->First; jpp; jpp = jpp->Next) - SetValue(g, jpp->Val, jpp->Key); + SetKeyValue(g, jpp->Val, jpp->Key); return false; } // end of Marge; @@ -1119,7 +1119,7 @@ bool JOBJECT::Merge(PGLOBAL g, PJSON jsp) /***********************************************************************/ /* Set or add a value corresponding to the given key. */ /***********************************************************************/ -void JOBJECT::SetValue(PGLOBAL g, PJVAL jvp, PCSZ key) +void JOBJECT::SetKeyValue(PGLOBAL g, PJVAL jvp, PCSZ key) { PJPR jp; @@ -1166,6 +1166,18 @@ bool JOBJECT::IsNull(void) /* -------------------------- Class JARRAY --------------------------- */ +/***********************************************************************/ +/* JARRAY constructor. */ +/***********************************************************************/ +JARRAY::JARRAY(void) : JSON() +{ + Type = TYPE_JAR; + Size = 0; + Alloc = 0; + First = Last = NULL; + Mvals = NULL; +} // end of JARRAY constructor + /***********************************************************************/ /* Return the number of values in this object. */ /***********************************************************************/ @@ -1216,7 +1228,7 @@ void JARRAY::InitArray(PGLOBAL g) /***********************************************************************/ /* Get the Nth value of an Array. */ /***********************************************************************/ -PJVAL JARRAY::GetValue(int i) +PJVAL JARRAY::GetArrayValue(int i) { if (Mvals && i >= 0 && i < Size) return Mvals[i]; @@ -1227,7 +1239,7 @@ PJVAL JARRAY::GetValue(int i) /***********************************************************************/ /* Add a Value to the Array Value list. */ /***********************************************************************/ -PJVAL JARRAY::AddValue(PGLOBAL g, PJVAL jvp, int *x) +PJVAL JARRAY::AddArrayValue(PGLOBAL g, PJVAL jvp, int *x) { if (!jvp) jvp = new(g) JVALUE; @@ -1271,7 +1283,7 @@ bool JARRAY::Merge(PGLOBAL g, PJSON jsp) PJAR arp = (PJAR)jsp; for (int i = 0; i < arp->size(); i++) - AddValue(g, arp->GetValue(i)); + AddArrayValue(g, arp->GetArrayValue(i)); InitArray(g); return false; @@ -1280,7 +1292,7 @@ bool JARRAY::Merge(PGLOBAL g, PJSON jsp) /***********************************************************************/ /* Set the nth Value of the Array Value list. */ /***********************************************************************/ -bool JARRAY::SetValue(PGLOBAL g, PJVAL jvp, int n) +bool JARRAY::SetArrayValue(PGLOBAL g, PJVAL jvp, int n) { int i = 0; PJVAL jp, *jpp = &First; @@ -1340,7 +1352,7 @@ PSZ JARRAY::GetText(PGLOBAL g, PSTRG text) /***********************************************************************/ bool JARRAY::DeleteValue(int n) { - PJVAL jvp = GetValue(n); + PJVAL jvp = GetArrayValue(n); if (jvp) { jvp->Del = true; @@ -1365,7 +1377,7 @@ bool JARRAY::IsNull(void) /* -------------------------- Class JVALUE- -------------------------- */ /***********************************************************************/ -/* Constructor for a JSON. */ +/* Constructor for a JVALUE. */ /***********************************************************************/ JVALUE::JVALUE(PJSON jsp) : JSON() { @@ -1383,7 +1395,7 @@ JVALUE::JVALUE(PJSON jsp) : JSON() } // end of JVALUE constructor /***********************************************************************/ -/* Constructor for a Val with a given string or numeric value. */ +/* Constructor for a JVALUE with a given string or numeric value. */ /***********************************************************************/ JVALUE::JVALUE(PGLOBAL g, PVL vlp) : JSON() { @@ -1395,7 +1407,7 @@ JVALUE::JVALUE(PGLOBAL g, PVL vlp) : JSON() } // end of JVALUE constructor /***********************************************************************/ -/* Constructor for a Value with a given string or numeric value. */ +/* Constructor for a JVALUE with a given string or numeric value. */ /***********************************************************************/ JVALUE::JVALUE(PGLOBAL g, PVAL valp) : JSON() { Jsp = NULL; -- cgit v1.2.1 From 90405763cf71a18ae1c7556fe51e13feb5333e46 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Sat, 7 Nov 2020 23:58:57 +0100 Subject: Re-fix compile error (sign-unsign) Modified filamtxt.cpp --- storage/connect/json.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'storage/connect/json.cpp') diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index 6fdb7e9c15c..5a7570567c8 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -1873,7 +1873,7 @@ PJSON SWAP::MptrJson(PJSON ojp) { // ojp is an offset PJAR SWAP::MptrArray(PJAR ojar) { PJAR jarp = (PJAR)MakePtr(Base, (size_t)ojar); - jarp = (PJAR)new((long long)jarp) JARRAY(NULL); + jarp = (PJAR)new((long long)jarp) JARRAY(0); if (jarp->First) { for (int i = 0; i < jarp->Size; i++) -- cgit v1.2.1 From 73850edd044130402abf796beaa8c4bc94b6d81e Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Sun, 8 Nov 2020 12:14:33 +0100 Subject: Re-fix compile error (conversion-null) Modified json.cpp --- storage/connect/json.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'storage/connect/json.cpp') diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index 5a7570567c8..5e04f65f748 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -1892,7 +1892,7 @@ PJAR SWAP::MptrArray(PJAR ojar) { PJOB SWAP::MptrObject(PJOB ojob) { PJOB jobp = (PJOB)MakePtr(Base, (size_t)ojob); - jobp = (PJOB)new((long long)jobp) JOBJECT(NULL); + jobp = (PJOB)new((long long)jobp) JOBJECT(0); if (jobp->First) { jobp->First = (PJPR)MptrPair(jobp->First); -- cgit v1.2.1 From 038381e110c4cb03d79839f5672299a22bbc1489 Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Fri, 20 Nov 2020 15:21:06 +0100 Subject: Fix compile error. Modified json.cpp --- storage/connect/json.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'storage/connect/json.cpp') diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index eba9d0d8575..bf7ff7170ff 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -1780,7 +1780,7 @@ void SWAP::SwapJson(PJSON jsp, bool move) /* Replace all pointers by offsets. */ /***********************************************************************/ size_t SWAP::MoffJson(PJSON jsp) { - size_t res = NULL; + size_t res = 0; if (jsp) switch (jsp->Type) { -- cgit v1.2.1 From ceacffbb3b9504c88d0649d472396fa42397a62c Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Tue, 15 Dec 2020 12:28:03 +0100 Subject: - Fix pretty=2 Tabjson bug on INSERT. Occuring when inserting more than one line in one statement. modified: storage/connect/json.cpp - Fix a wrong if statement modified: storage/connect/tabjson.cpp - Continue BSON implementation modified: storage/connect/bson.cpp modified: storage/connect/bson.h modified: storage/connect/filamtxt.cpp modified: storage/connect/filamtxt.h modified: storage/connect/tabbson.cpp modified: storage/connect/tabbson.h - No need anymore deleted: storage/connect/mysql-test/connect/r/bson.result deleted: storage/connect/mysql-test/connect/t/bson.test --- storage/connect/json.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'storage/connect/json.cpp') diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index bf7ff7170ff..7c1748e0fde 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -1665,7 +1665,7 @@ void JVALUE::SetValue(PGLOBAL g, PVAL valp) } else switch (valp->GetType()) { case TYPE_DATE: if (((DTVAL*)valp)->IsFormatted()) - Strp = valp->GetCharValue(); + Strp = PlugDup(g, valp->GetCharValue()); else { char buf[32]; @@ -1675,7 +1675,7 @@ void JVALUE::SetValue(PGLOBAL g, PVAL valp) DataType = TYPE_DTM; break; case TYPE_STRING: - Strp = valp->GetCharValue(); + Strp = PlugDup(g, valp->GetCharValue()); DataType = TYPE_STRG; break; case TYPE_DOUBLE: -- cgit v1.2.1 From 24c18ce8926105d77ebff2d63611af440aaa8bee Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Fri, 18 Dec 2020 18:59:52 +0100 Subject: - Fix json parser (void objects not recognized) modified: json.cpp --- storage/connect/json.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'storage/connect/json.cpp') diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index 7c1748e0fde..bcbd71b5031 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -554,7 +554,7 @@ PJAR JDOC::ParseArray(PGLOBAL g, int& i) PJOB JDOC::ParseObject(PGLOBAL g, int& i) { PSZ key; - int level = 0; + int level = -1; PJOB jobp = new(g) JOBJECT; PJPR jpp = NULL; @@ -590,7 +590,7 @@ PJOB JDOC::ParseObject(PGLOBAL g, int& i) break; case '}': - if (level < 2) { + if (level == 0 || level == 1) { sprintf(g->Message, "Unexpected '}' near %.*s", ARGS); throw 2; } // endif level -- cgit v1.2.1 From 8f34d45404817a4fe63251ac2ab74da96b6849fa Mon Sep 17 00:00:00 2001 From: Olivier Bertrand Date: Fri, 8 Jan 2021 22:18:52 +0100 Subject: - Add the new BSON temporary type for testing modified: storage/connect/CMakeLists.txt modified: storage/connect/bson.cpp modified: storage/connect/bson.h modified: storage/connect/bsonudf.cpp modified: storage/connect/bsonudf.h modified: storage/connect/global.h modified: storage/connect/json.cpp modified: storage/connect/jsonudf.cpp modified: storage/connect/mysql-test/connect/disabled.def modified: storage/connect/mysql-test/connect/t/mongo_test.inc modified: storage/connect/plugutil.cpp modified: storage/connect/tabbson.cpp modified: storage/connect/tabjson.cpp --- storage/connect/json.cpp | 88 ++++++++++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 37 deletions(-) (limited to 'storage/connect/json.cpp') diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index bcbd71b5031..0152a44fffa 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -333,25 +333,30 @@ bool JOUTSTR::WriteChr(const char c) { /***********************************************************************/ /* Escape and Concatenate a string to the Serialize string. */ /***********************************************************************/ -bool JOUTSTR::Escape(const char* s) { - WriteChr('"'); +bool JOUTSTR::Escape(const char* s) +{ + if (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] + 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('"'); + } else + WriteStr("null"); - WriteChr('"'); return false; } // end of Escape @@ -360,7 +365,8 @@ bool JOUTSTR::Escape(const char* s) { /***********************************************************************/ /* Write a string to the Serialize file. */ /***********************************************************************/ -bool JOUTFILE::WriteStr(const char* s) { +bool JOUTFILE::WriteStr(const char* s) +{ // This is temporary fputs(s, Stream); return false; @@ -369,7 +375,8 @@ bool JOUTFILE::WriteStr(const char* s) { /***********************************************************************/ /* Write a character to the Serialize file. */ /***********************************************************************/ -bool JOUTFILE::WriteChr(const char c) { +bool JOUTFILE::WriteChr(const char c) +{ // This is temporary fputc(c, Stream); return false; @@ -378,25 +385,30 @@ bool JOUTFILE::WriteChr(const char c) { /***********************************************************************/ /* Escape and Concatenate a string to the Serialize string. */ /***********************************************************************/ -bool JOUTFILE::Escape(const char* s) { +bool JOUTFILE::Escape(const char* s) +{ // This is temporary - fputc('"', Stream); + if (s) { + 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] + 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); + } else + fputs("null", Stream); - fputc('"', Stream); return false; } // end of Escape @@ -405,7 +417,8 @@ bool JOUTFILE::Escape(const char* s) { /***********************************************************************/ /* Write a string to the Serialize pretty file. */ /***********************************************************************/ -bool JOUTPRT::WriteStr(const char* s) { +bool JOUTPRT::WriteStr(const char* s) +{ // This is temporary if (B) { fputs(EL, Stream); @@ -424,7 +437,8 @@ bool JOUTPRT::WriteStr(const char* s) { /***********************************************************************/ /* Write a character to the Serialize pretty file. */ /***********************************************************************/ -bool JOUTPRT::WriteChr(const char c) { +bool JOUTPRT::WriteChr(const char c) +{ switch (c) { case ':': fputs(": ", Stream); -- cgit v1.2.1