Commit 564d41fa authored by Olivier Bertrand's avatar Olivier Bertrand

- Work on JSON and JSON UDF's

modified:
  storage/connect/json.cpp
  storage/connect/jsonudf.cpp
  storage/connect/tabjson.cpp

- CntReadNext: Enable EvalColumns for longjmp
modified:
  storage/connect/connect.cc
parent 2201aa66
...@@ -469,9 +469,12 @@ RCODE CntReadNext(PGLOBAL g, PTDB tdbp) ...@@ -469,9 +469,12 @@ RCODE CntReadNext(PGLOBAL g, PTDB tdbp)
} while (rc == RC_NF); } while (rc == RC_NF);
if (rc == RC_OK)
rc= EvalColumns(g, tdbp, false);
err: err:
g->jump_level--; g->jump_level--;
return (rc != RC_OK) ? rc : EvalColumns(g, tdbp, false); return rc;
} // end of CntReadNext } // end of CntReadNext
/***********************************************************************/ /***********************************************************************/
......
/*************** json CPP Declares Source Code File (.H) ***************/ /*************** json CPP Declares Source Code File (.H) ***************/
/* Name: json.cpp Version 1.0 */ /* Name: json.cpp Version 1.0 */
/* */ /* */
/* (C) Copyright to the author Olivier BERTRAND 2014 - 2015 */ /* (C) Copyright to the author Olivier BERTRAND 2014 - 2015 */
/* */ /* */
/* This file contains the JSON classes functions. */ /* This file contains the JSON classes functions. */
/***********************************************************************/ /***********************************************************************/
/***********************************************************************/ /***********************************************************************/
/* Include relevant sections of the MariaDB header file. */ /* Include relevant sections of the MariaDB header file. */
/***********************************************************************/ /***********************************************************************/
#include <my_global.h> #include <my_global.h>
/***********************************************************************/ /***********************************************************************/
/* Include application header files: */ /* Include application header files: */
/* global.h is header containing all global declarations. */ /* global.h is header containing all global declarations. */
/* plgdbsem.h is header containing the DB application declarations. */ /* plgdbsem.h is header containing the DB application declarations. */
/* xjson.h is header containing the JSON classes declarations. */ /* xjson.h is header containing the JSON classes declarations. */
/***********************************************************************/ /***********************************************************************/
#include "global.h" #include "global.h"
#include "plgdbsem.h" #include "plgdbsem.h"
#include "json.h" #include "json.h"
#define ARGS MY_MIN(24,len-i),s+MY_MAX(i-3,0) #define ARGS MY_MIN(24,len-i),s+MY_MAX(i-3,0)
#if defined(WIN32) #if defined(WIN32)
#define EL "\r\n" #define EL "\r\n"
#else #else
#define EL "\n" #define EL "\n"
#endif #endif
/***********************************************************************/ /***********************************************************************/
/* Parse a json string. */ /* Parse a json string. */
/***********************************************************************/ /***********************************************************************/
PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma) PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
{ {
int i; int i, rc;
bool b = false; bool b = false;
PJSON jsp = NULL; PJSON jsp = NULL;
STRG src; STRG src;
if (!s || !len) { if (!s || !len) {
strcpy(g->Message, "Void JSON object"); strcpy(g->Message, "Void JSON object");
return NULL; return NULL;
} else if (comma) } else if (comma)
*comma = false; *comma = false;
src.str = s; src.str = s;
src.len = len; src.len = len;
for (i = 0; i < len; i++) // Save stack and allocation environment and prepare error return
switch (s[i]) { if (g->jump_level == MAX_JUMP) {
case '[': strcpy(g->Message, MSG(TOO_MANY_JUMPS));
if (jsp) { return NULL;
strcpy(g->Message, "More than one item in file"); } // endif jump_level
return NULL;
} else if (!(jsp = ParseArray(g, ++i, src))) if ((rc= setjmp(g->jumper[++g->jump_level])) != 0) {
return NULL; goto err;
} // endif rc
break;
case '{': for (i = 0; i < len; i++)
if (jsp) { switch (s[i]) {
strcpy(g->Message, "More than one item in file"); case '[':
return NULL; if (jsp) {
} else if (!(jsp = ParseObject(g, ++i, src))) strcpy(g->Message, "More than one item in file");
return NULL; goto err;
break; } else if (!(jsp = ParseArray(g, ++i, src)))
case ' ': goto err;
case '\t':
case '\n': break;
case '\r': case '{':
break; if (jsp) {
case ',': strcpy(g->Message, "More than one item in file");
if (jsp && pretty == 1) { goto err;
if (comma) } else if (!(jsp = ParseObject(g, ++i, src)))
*comma = true; goto err;
break;
break; case ' ':
} // endif pretty case '\t':
case '\n':
sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty); case '\r':
return NULL; break;
case '(': case ',':
b = true; if (jsp && pretty == 1) {
break; if (comma)
case ')': *comma = true;
if (b) {
b = false; break;
break; } // endif pretty
} // endif b
sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty);
default: goto err;
sprintf(g->Message, "Bad '%c' character near %.*s", case '(':
s[i], ARGS); b = true;
return NULL; break;
}; // endswitch s[i] case ')':
if (b) {
if (!jsp) b = false;
sprintf(g->Message, "Invalid Json string '%.*s'", 50, s); break;
} // endif b
return jsp;
} // end of ParseJson default:
sprintf(g->Message, "Bad '%c' character near %.*s",
/***********************************************************************/ s[i], ARGS);
/* Parse a JSON Array. */ goto err;
/***********************************************************************/ }; // endswitch s[i]
PJAR ParseArray(PGLOBAL g, int& i, STRG& src)
{ if (!jsp)
char *s = src.str; sprintf(g->Message, "Invalid Json string '%.*s'", 50, s);
int len = src.len;
int level = 0; g->jump_level--;
PJAR jarp = new(g) JARRAY; return jsp;
PJVAL jvp = NULL;
err:
for (; i < len; i++) g->jump_level--;
switch (s[i]) { return NULL;
case ',': } // end of ParseJson
if (level < 2) {
sprintf(g->Message, "Unexpected ',' near %.*s",ARGS); /***********************************************************************/
return NULL; /* Parse a JSON Array. */
} else /***********************************************************************/
level = 1; PJAR ParseArray(PGLOBAL g, int& i, STRG& src)
{
break; char *s = src.str;
case ']': int len = src.len;
if (level == 1) { int level = 0;
sprintf(g->Message, "Unexpected ',]' near %.*s", ARGS); PJAR jarp = new(g) JARRAY;
return NULL; PJVAL jvp = NULL;
} // endif level
for (; i < len; i++)
jarp->InitArray(g); switch (s[i]) {
return jarp; case ',':
case ' ': if (level < 2) {
case '\t': sprintf(g->Message, "Unexpected ',' near %.*s",ARGS);
case '\n': return NULL;
case '\r': } else
break; level = 1;
default:
if (level == 2) { break;
sprintf(g->Message, "Unexpected value near %.*s", ARGS); case ']':
return NULL; if (level == 1) {
} else if ((jvp = ParseValue(g, i, src))) { sprintf(g->Message, "Unexpected ',]' near %.*s", ARGS);
jarp->AddValue(g, jvp); return NULL;
level = 2; } // endif level
} else
return NULL; jarp->InitArray(g);
return jarp;
level = 2; case ' ':
break; case '\t':
}; // endswitch s[i] case '\n':
case '\r':
strcpy(g->Message, "Unexpected EOF in array"); break;
return NULL; default:
} // end of ParseArray if (level == 2) {
sprintf(g->Message, "Unexpected value near %.*s", ARGS);
/***********************************************************************/ return NULL;
/* Parse a JSON Object. */ } else if ((jvp = ParseValue(g, i, src))) {
/***********************************************************************/ jarp->AddValue(g, jvp);
PJOB ParseObject(PGLOBAL g, int& i, STRG& src) level = 2;
{ } else
PSZ key; return NULL;
char *s = src.str;
int len = src.len; level = 2;
int level = 0; break;
PJOB jobp = new(g) JOBJECT; }; // endswitch s[i]
PJPR jpp = NULL;
strcpy(g->Message, "Unexpected EOF in array");
for (; i < len; i++) return NULL;
switch (s[i]) { } // end of ParseArray
case '"':
if (level < 2) { /***********************************************************************/
if ((key = ParseString(g, ++i, src))) { /* Parse a JSON Object. */
jpp = jobp->AddPair(g, key); /***********************************************************************/
level = 1; PJOB ParseObject(PGLOBAL g, int& i, STRG& src)
} else {
return NULL; PSZ key;
char *s = src.str;
} else { int len = src.len;
sprintf(g->Message, "misplaced string near %.*s", ARGS); int level = 0;
return NULL; PJOB jobp = new(g) JOBJECT;
} // endif level PJPR jpp = NULL;
break; for (; i < len; i++)
case ':': switch (s[i]) {
if (level == 1) { case '"':
if (!(jpp->Val = ParseValue(g, ++i, src))) if (level < 2) {
return NULL; if ((key = ParseString(g, ++i, src))) {
jpp = jobp->AddPair(g, key);
level = 2; level = 1;
} else { } else
sprintf(g->Message, "Unexpected ':' near %.*s", ARGS); return NULL;
return NULL;
} // endif level } else {
sprintf(g->Message, "misplaced string near %.*s", ARGS);
break; return NULL;
case ',': } // endif level
if (level < 2) {
sprintf(g->Message, "Unexpected ',' near %.*s", ARGS); break;
return NULL; case ':':
} else if (level == 1) {
level = 1; if (!(jpp->Val = ParseValue(g, ++i, src)))
return NULL;
break;
case '}': level = 2;
if (level == 1) { } else {
sprintf(g->Message, "Unexpected '}' near %.*s", ARGS); sprintf(g->Message, "Unexpected ':' near %.*s", ARGS);
return NULL; return NULL;
} // endif level } // endif level
return jobp; break;
case ' ': case ',':
case '\t': if (level < 2) {
case '\n': sprintf(g->Message, "Unexpected ',' near %.*s", ARGS);
case '\r': return NULL;
break; } else
default: level = 1;
sprintf(g->Message, "Unexpected character '%c' near %.*s",
s[i], ARGS); break;
return NULL; case '}':
}; // endswitch s[i] if (level == 1) {
sprintf(g->Message, "Unexpected '}' near %.*s", ARGS);
strcpy(g->Message, "Unexpected EOF in Object"); return NULL;
return NULL; } // endif level
} // end of ParseObject
return jobp;
/***********************************************************************/ case ' ':
/* Parse a JSON Value. */ case '\t':
/***********************************************************************/ case '\n':
PJVAL ParseValue(PGLOBAL g, int& i, STRG& src) case '\r':
{ break;
char *strval, *s = src.str; default:
int n, len = src.len; sprintf(g->Message, "Unexpected character '%c' near %.*s",
PJVAL jvp = new(g) JVALUE; s[i], ARGS);
return NULL;
for (; i < len; i++) }; // endswitch s[i]
switch (s[i]) {
case ' ': strcpy(g->Message, "Unexpected EOF in Object");
case '\t': return NULL;
case '\n': } // end of ParseObject
case '\r':
break; /***********************************************************************/
default: /* Parse a JSON Value. */
goto suite; /***********************************************************************/
} // endswitch PJVAL ParseValue(PGLOBAL g, int& i, STRG& src)
{
suite: char *strval, *s = src.str;
switch (s[i]) { int n, len = src.len;
case '[': PJVAL jvp = new(g) JVALUE;
if (!(jvp->Jsp = ParseArray(g, ++i, src)))
return NULL; for (; i < len; i++)
switch (s[i]) {
break; case ' ':
case '{': case '\t':
if (!(jvp->Jsp = ParseObject(g, ++i, src))) case '\n':
return NULL; case '\r':
break;
break; default:
case '"': goto suite;
if ((strval = ParseString(g, ++i, src))) } // endswitch
jvp->Value = AllocateValue(g, strval, TYPE_STRING);
else suite:
return NULL; switch (s[i]) {
case '[':
break; if (!(jvp->Jsp = ParseArray(g, ++i, src)))
case 't': return NULL;
if (!strncmp(s + i, "true", 4)) {
n = 1; break;
jvp->Value = AllocateValue(g, &n, TYPE_TINY); case '{':
i += 3; if (!(jvp->Jsp = ParseObject(g, ++i, src)))
} else return NULL;
goto err;
break;
break; case '"':
case 'f': if ((strval = ParseString(g, ++i, src)))
if (!strncmp(s + i, "false", 5)) { jvp->Value = AllocateValue(g, strval, TYPE_STRING);
n = 0; else
jvp->Value = AllocateValue(g, &n, TYPE_TINY); return NULL;
i += 4;
} else break;
goto err; case 't':
if (!strncmp(s + i, "true", 4)) {
break; n = 1;
case 'n': jvp->Value = AllocateValue(g, &n, TYPE_TINY);
if (!strncmp(s + i, "null", 4)) i += 3;
i += 3; } else
else goto err;
goto err;
break;
break; case 'f':
case '-': if (!strncmp(s + i, "false", 5)) {
default: n = 0;
if (s[i] == '-' || isdigit(s[i])) { jvp->Value = AllocateValue(g, &n, TYPE_TINY);
if (!(jvp->Value = ParseNumeric(g, i, src))) i += 4;
goto err; } else
goto err;
} else
goto err; break;
case 'n':
}; // endswitch s[i] if (!strncmp(s + i, "null", 4))
i += 3;
jvp->Size = 1; else
return jvp; goto err;
err: break;
sprintf(g->Message, "Unexpected character '%c' near %.*s", case '-':
s[i], ARGS); default:
return NULL; if (s[i] == '-' || isdigit(s[i])) {
} // end of ParseValue if (!(jvp->Value = ParseNumeric(g, i, src)))
goto err;
/***********************************************************************/
/* Unescape and parse a JSON string. */ } else
/***********************************************************************/ goto err;
char *ParseString(PGLOBAL g, int& i, STRG& src)
{ }; // endswitch s[i]
char *s = src.str;
uchar *p; jvp->Size = 1;
int n = 0, len = src.len; return jvp;
// The size to allocate is not known yet err:
p = (uchar*)PlugSubAlloc(g, NULL, 0); sprintf(g->Message, "Unexpected character '%c' near %.*s",
s[i], ARGS);
for (; i < len; i++) return NULL;
switch (s[i]) { } // end of ParseValue
case '"':
p[n++] = 0; /***********************************************************************/
PlugSubAlloc(g, NULL, n); /* Unescape and parse a JSON string. */
return (char*)p; /***********************************************************************/
case '\\': char *ParseString(PGLOBAL g, int& i, STRG& src)
if (++i < len) { {
if (s[i] == 'u') { char *s = src.str;
if (len - i > 5) { uchar *p;
// if (charset == utf8) { int n = 0, len = src.len;
char xs[5];
uint hex; // Be sure of memory availability
if (len + 1 - i > (signed)((PPOOLHEADER)g->Sarea)->FreeBlk) {
xs[0] = s[++i]; strcpy(g->Message, "ParseString: Out of memory");
xs[1] = s[++i]; return NULL;
xs[2] = s[++i]; } // endif len
xs[3] = s[++i];
xs[4] = 0; // The size to allocate is not known yet
hex = strtoul(xs, NULL, 16); p = (uchar*)PlugSubAlloc(g, NULL, 0);
if (hex < 0x80) { for (; i < len; i++)
p[n] = (uchar)hex; switch (s[i]) {
} else if (hex < 0x800) { case '"':
p[n++] = (uchar)(0xC0 | (hex >> 6)); p[n++] = 0;
p[n] = (uchar)(0x80 | (hex & 0x3F)); PlugSubAlloc(g, NULL, n);
} else if (hex < 0x10000) { return (char*)p;
p[n++] = (uchar)(0xE0 | (hex >> 12)); case '\\':
p[n++] = (uchar)(0x80 | ((hex >> 6) & 0x3f)); if (++i < len) {
p[n] = (uchar)(0x80 | (hex & 0x3f)); if (s[i] == 'u') {
} else if (len - i > 5) {
p[n] = '?'; // if (charset == utf8) {
char xs[5];
#if 0 uint hex;
} else {
char xs[3]; xs[0] = s[++i];
UINT hex; xs[1] = s[++i];
xs[2] = s[++i];
i += 2; xs[3] = s[++i];
xs[0] = s[++i]; xs[4] = 0;
xs[1] = s[++i]; hex = strtoul(xs, NULL, 16);
xs[2] = 0;
hex = strtoul(xs, NULL, 16); if (hex < 0x80) {
p[n] = (char)hex; p[n] = (uchar)hex;
} // endif charset } else if (hex < 0x800) {
#endif // 0 p[n++] = (uchar)(0xC0 | (hex >> 6));
} else p[n] = (uchar)(0x80 | (hex & 0x3F));
goto err; } else if (hex < 0x10000) {
p[n++] = (uchar)(0xE0 | (hex >> 12));
} else switch(s[i]) { p[n++] = (uchar)(0x80 | ((hex >> 6) & 0x3f));
case 't': p[n] = '\t'; break; p[n] = (uchar)(0x80 | (hex & 0x3f));
case 'n': p[n] = '\n'; break; } else
case 'r': p[n] = '\r'; break; p[n] = '?';
case 'b': p[n] = '\b'; break;
case 'f': p[n] = '\f'; break; #if 0
default: p[n] = s[i]; break; } else {
} // endswitch char xs[3];
UINT hex;
n++;
} else i += 2;
goto err; xs[0] = s[++i];
xs[1] = s[++i];
break; xs[2] = 0;
default: hex = strtoul(xs, NULL, 16);
p[n++] = s[i]; p[n] = (char)hex;
break; } // endif charset
}; // endswitch s[i] #endif // 0
} else
err: goto err;
strcpy(g->Message, "Unexpected EOF in String");
return NULL; } else switch(s[i]) {
} // end of ParseString case 't': p[n] = '\t'; break;
case 'n': p[n] = '\n'; break;
/***********************************************************************/ case 'r': p[n] = '\r'; break;
/* Parse a JSON numeric value. */ case 'b': p[n] = '\b'; break;
/***********************************************************************/ case 'f': p[n] = '\f'; break;
PVAL ParseNumeric(PGLOBAL g, int& i, STRG& src) default: p[n] = s[i]; break;
{ } // endswitch
char *s = src.str, buf[50];
int n = 0, len = src.len; n++;
short nd = 0; } else
bool has_dot = false; goto err;
bool has_e = false;
bool found_digit = false; break;
PVAL valp = NULL; default:
p[n++] = s[i];
for (; i < len; i++) { break;
switch (s[i]) { }; // endswitch s[i]
case '.':
if (!found_digit || has_dot || has_e) err:
goto err; strcpy(g->Message, "Unexpected EOF in String");
return NULL;
has_dot = true; } // end of ParseString
break;
case 'e': /***********************************************************************/
case 'E': /* Parse a JSON numeric value. */
if (!found_digit || has_e) /***********************************************************************/
goto err; PVAL ParseNumeric(PGLOBAL g, int& i, STRG& src)
{
has_e = true; char *s = src.str, buf[50];
found_digit = false; int n = 0, len = src.len;
break; short nd = 0;
case '+': bool has_dot = false;
if (!has_e) bool has_e = false;
goto err; bool found_digit = false;
PVAL valp = NULL;
// passthru
case '-': for (; i < len; i++) {
if (found_digit) switch (s[i]) {
goto err; case '.':
if (!found_digit || has_dot || has_e)
break; goto err;
default:
if (isdigit(s[i])) { has_dot = true;
if (has_dot && !has_e) break;
nd++; // Number of decimals case 'e':
case 'E':
found_digit = true; if (!found_digit || has_e)
} else goto err;
goto fin;
has_e = true;
}; // endswitch s[i] found_digit = false;
break;
buf[n++] = s[i]; case '+':
} // endfor i if (!has_e)
goto err;
fin:
if (found_digit) { // passthru
buf[n] = 0; case '-':
if (found_digit)
if (has_dot || has_e) { goto err;
double dv = strtod(buf, NULL);
break;
valp = AllocateValue(g, &dv, TYPE_DOUBLE, nd); default:
} else { if (isdigit(s[i])) {
int iv = strtol(buf, NULL, 10); if (has_dot && !has_e)
nd++; // Number of decimals
valp = AllocateValue(g, &iv, TYPE_INT);
} // endif has found_digit = true;
} else
i--; // Unstack following character goto fin;
return valp;
} else { }; // endswitch s[i]
strcpy(g->Message, "No digit found");
return NULL; buf[n++] = s[i];
} // endif found_digit } // endfor i
err: fin:
strcpy(g->Message, "Unexpected EOF in number"); if (found_digit) {
return NULL; buf[n] = 0;
} // end of ParseNumeric
if (has_dot || has_e) {
/***********************************************************************/ double dv = strtod(buf, NULL);
/* Serialize a JSON tree: */
/***********************************************************************/ valp = AllocateValue(g, &dv, TYPE_DOUBLE, nd);
PSZ Serialize(PGLOBAL g, PJSON jsp, FILE *fs, int pretty) } else {
{ int iv = strtol(buf, NULL, 10);
bool b = false, err = true;
JOUT *jp; valp = AllocateValue(g, &iv, TYPE_INT);
} // endif has
g->Message[0] = 0;
i--; // Unstack following character
if (!jsp) { return valp;
strcpy(g->Message, "Null json tree"); } else {
return NULL; strcpy(g->Message, "No digit found");
} else if (!fs) { return NULL;
// Serialize to a string } // endif found_digit
jp = new(g) JOUTSTR(g);
b = pretty == 1; err:
} else if (pretty == 2) { strcpy(g->Message, "Unexpected EOF in number");
// Serialize to a pretty file return NULL;
jp = new(g) JOUTPRT(g, fs); } // end of ParseNumeric
} else {
// Serialize to a flat file /***********************************************************************/
jp = new(g) JOUTFILE(g, fs); /* Serialize a JSON tree: */
b = pretty == 1; /***********************************************************************/
} // endif's PSZ Serialize(PGLOBAL g, PJSON jsp, FILE *fs, int pretty)
{
switch (jsp->GetType()) { bool b = false, err = true;
case TYPE_JAR: JOUT *jp;
err = SerializeArray(jp, (PJAR)jsp, b);
break; g->Message[0] = 0;
case TYPE_JOB:
err = (b && jp->WriteChr('\t')); if (!jsp) {
err |= SerializeObject(jp, (PJOB)jsp); strcpy(g->Message, "Null json tree");
break; return NULL;
case TYPE_JVAL: } else if (!fs) {
err = SerializeValue(jp, (PJVAL)jsp); // Serialize to a string
break; jp = new(g) JOUTSTR(g);
default: b = pretty == 1;
strcpy(g->Message, "Invalid json tree"); } else if (pretty == 2) {
} // endswitch Type // Serialize to a pretty file
jp = new(g) JOUTPRT(g, fs);
if (fs) { } else {
fputc('\n', fs); // Serialize to a flat file
fclose(fs); jp = new(g) JOUTFILE(g, fs);
return (err) ? g->Message : NULL; b = pretty == 1;
} else if (!err) { } // endif's
PSZ str = ((JOUTSTR*)jp)->Strp;
switch (jsp->GetType()) {
jp->WriteChr('\0'); case TYPE_JAR:
PlugSubAlloc(g, NULL, ((JOUTSTR*)jp)->N); err = SerializeArray(jp, (PJAR)jsp, b);
return str; break;
} else { case TYPE_JOB:
if (!g->Message[0]) err = (b && jp->WriteChr('\t'));
strcpy(g->Message, "Error in Serialize"); err |= SerializeObject(jp, (PJOB)jsp);
break;
return NULL; case TYPE_JVAL:
} // endif's err = SerializeValue(jp, (PJVAL)jsp);
break;
} // end of Serialize default:
strcpy(g->Message, "Invalid json tree");
/***********************************************************************/ } // endswitch Type
/* Serialize a JSON Array. */
/***********************************************************************/ if (fs) {
bool SerializeArray(JOUT *js, PJAR jarp, bool b) fputc('\n', fs);
{ fclose(fs);
bool first = true; return (err) ? g->Message : NULL;
} else if (!err) {
PSZ str = ((JOUTSTR*)jp)->Strp;
if (js->WriteChr('['))
return true; jp->WriteChr('\0');
else if (b && (js->WriteStr(EL) || js->WriteChr('\t'))) PlugSubAlloc(g, NULL, ((JOUTSTR*)jp)->N);
return true; return str;
} else {
for (int i = 0; i < jarp->size(); i++) { if (!g->Message[0])
if (first) strcpy(g->Message, "Error in Serialize");
first = false;
else if (js->WriteChr(',')) return NULL;
return true; } // endif's
else if (b && (js->WriteStr(EL) || js->WriteChr('\t')))
return true; } // end of Serialize
if (SerializeValue(js, jarp->GetValue(i))) /***********************************************************************/
return true; /* Serialize a JSON Array. */
/***********************************************************************/
} // endfor i bool SerializeArray(JOUT *js, PJAR jarp, bool b)
{
if (b && js->WriteStr(EL)) bool first = true;
return true;
return js->WriteChr(']'); if (js->WriteChr('['))
} // end of SerializeArray return true;
else if (b && (js->WriteStr(EL) || js->WriteChr('\t')))
/***********************************************************************/ return true;
/* Serialize a JSON Object. */
/***********************************************************************/ for (int i = 0; i < jarp->size(); i++) {
bool SerializeObject(JOUT *js, PJOB jobp) if (first)
{ first = false;
bool first = true; else if (js->WriteChr(','))
return true;
if (js->WriteChr('{')) else if (b && (js->WriteStr(EL) || js->WriteChr('\t')))
return true; return true;
for (PJPR pair = jobp->First; pair; pair = pair->Next) { if (SerializeValue(js, jarp->GetValue(i)))
if (first) return true;
first = false;
else if (js->WriteChr(',')) } // endfor i
return true;
if (b && js->WriteStr(EL))
if (js->WriteChr('"') || return true;
js->WriteStr(pair->Key) ||
js->WriteChr('"') || return js->WriteChr(']');
js->WriteChr(':') || } // end of SerializeArray
SerializeValue(js, pair->Val))
return true; /***********************************************************************/
/* Serialize a JSON Object. */
} // endfor i /***********************************************************************/
bool SerializeObject(JOUT *js, PJOB jobp)
return js->WriteChr('}'); {
} // end of SerializeObject bool first = true;
/***********************************************************************/ if (js->WriteChr('{'))
/* Serialize a JSON Value. */ return true;
/***********************************************************************/
bool SerializeValue(JOUT *js, PJVAL jvp) for (PJPR pair = jobp->First; pair; pair = pair->Next) {
{ if (first)
PJAR jap; first = false;
PJOB jop; else if (js->WriteChr(','))
PVAL valp; return true;
if ((jap = jvp->GetArray())) if (js->WriteChr('"') ||
return SerializeArray(js, jap, false); js->WriteStr(pair->Key) ||
else if ((jop = jvp->GetObject())) js->WriteChr('"') ||
return SerializeObject(js, jop); js->WriteChr(':') ||
else if (!(valp = jvp->Value) || valp->IsNull()) SerializeValue(js, pair->Val))
return js->WriteStr("null"); return true;
else switch (valp->GetType()) {
case TYPE_TINY: } // endfor i
return js->WriteStr(valp->GetTinyValue() ? "true" : "false");
case TYPE_STRING: return js->WriteChr('}');
return js->Escape(valp->GetCharValue()); } // end of SerializeObject
default:
if (valp->IsTypeNum()) { /***********************************************************************/
char buf[32]; /* Serialize a JSON Value. */
/***********************************************************************/
return js->WriteStr(valp->GetCharString(buf)); bool SerializeValue(JOUT *js, PJVAL jvp)
} // endif valp {
PJAR jap;
} // endswitch Type PJOB jop;
PVAL valp;
strcpy(js->g->Message, "Unrecognized value");
return true; if ((jap = jvp->GetArray()))
} // end of SerializeValue return SerializeArray(js, jap, false);
else if ((jop = jvp->GetObject()))
/* -------------------------- Class JOUTSTR -------------------------- */ return SerializeObject(js, jop);
else if (!(valp = jvp->Value) || valp->IsNull())
/***********************************************************************/ return js->WriteStr("null");
/* JOUTSTR constructor. */ else switch (valp->GetType()) {
/***********************************************************************/ case TYPE_TINY:
JOUTSTR::JOUTSTR(PGLOBAL g) : JOUT(g) return js->WriteStr(valp->GetTinyValue() ? "true" : "false");
{ case TYPE_STRING:
PPOOLHEADER pph = (PPOOLHEADER)g->Sarea; return js->Escape(valp->GetCharValue());
default:
N = 0; if (valp->IsTypeNum()) {
Max = pph->FreeBlk; char buf[32];
Max = (Max > 512) ? Max - 512 : Max;
Strp = (char*)PlugSubAlloc(g, NULL, 0); // Size not know yet return js->WriteStr(valp->GetCharString(buf));
} // end of JOUTSTR constructor } // endif valp
/***********************************************************************/ } // endswitch Type
/* Concatenate a string to the Serialize string. */
/***********************************************************************/ strcpy(js->g->Message, "Unrecognized value");
bool JOUTSTR::WriteStr(const char *s) return true;
{ } // end of SerializeValue
if (s) {
size_t len = strlen(s); /* -------------------------- Class JOUTSTR -------------------------- */
if (N + len > Max) /***********************************************************************/
return true; /* JOUTSTR constructor. */
/***********************************************************************/
memcpy(Strp + N, s, len); JOUTSTR::JOUTSTR(PGLOBAL g) : JOUT(g)
N += len; {
return false; PPOOLHEADER pph = (PPOOLHEADER)g->Sarea;
} else
return true; N = 0;
Max = pph->FreeBlk;
} // end of WriteStr Max = (Max > 512) ? Max - 512 : Max;
Strp = (char*)PlugSubAlloc(g, NULL, 0); // Size not know yet
/***********************************************************************/ } // end of JOUTSTR constructor
/* Concatenate a character to the Serialize string. */
/***********************************************************************/ /***********************************************************************/
bool JOUTSTR::WriteChr(const char c) /* Concatenate a string to the Serialize string. */
{ /***********************************************************************/
if (N + 1 > Max) bool JOUTSTR::WriteStr(const char *s)
return true; {
if (s) {
Strp[N++] = c; size_t len = strlen(s);
return false;
} // end of WriteChr if (N + len > Max)
return true;
/***********************************************************************/
/* Escape and Concatenate a string to the Serialize string. */ memcpy(Strp + N, s, len);
/***********************************************************************/ N += len;
bool JOUTSTR::Escape(const char *s) return false;
{ } else
WriteChr('"'); return true;
for (unsigned int i = 0; i < strlen(s); i++) } // end of WriteStr
switch (s[i]) {
case '"': /***********************************************************************/
case '\\': /* Concatenate a character to the Serialize string. */
case '\t': /***********************************************************************/
case '\n': bool JOUTSTR::WriteChr(const char c)
case '\r': {
case '\b': if (N + 1 > Max)
case '\f': WriteChr('\\'); return true;
// passthru
default: Strp[N++] = c;
WriteChr(s[i]); return false;
break; } // end of WriteChr
} // endswitch s[i]
/***********************************************************************/
WriteChr('"'); /* Escape and Concatenate a string to the Serialize string. */
return false; /***********************************************************************/
} // end of Escape bool JOUTSTR::Escape(const char *s)
{
/* ------------------------- Class JOUTFILE -------------------------- */ WriteChr('"');
/***********************************************************************/ for (unsigned int i = 0; i < strlen(s); i++)
/* Write a string to the Serialize file. */ switch (s[i]) {
/***********************************************************************/ case '"':
bool JOUTFILE::WriteStr(const char *s) case '\\':
{ case '\t':
// This is temporary case '\n':
fputs(s, Stream); case '\r':
return false; case '\b':
} // end of WriteStr case '\f': WriteChr('\\');
// passthru
/***********************************************************************/ default:
/* Write a character to the Serialize file. */ WriteChr(s[i]);
/***********************************************************************/ break;
bool JOUTFILE::WriteChr(const char c) } // endswitch s[i]
{
// This is temporary WriteChr('"');
fputc(c, Stream); return false;
return false; } // end of Escape
} // end of WriteChr
/* ------------------------- Class JOUTFILE -------------------------- */
/***********************************************************************/
/* Escape and Concatenate a string to the Serialize string. */ /***********************************************************************/
/***********************************************************************/ /* Write a string to the Serialize file. */
bool JOUTFILE::Escape(const char *s) /***********************************************************************/
{ bool JOUTFILE::WriteStr(const char *s)
// This is temporary {
fputc('"', Stream); // This is temporary
fputs(s, Stream);
for (unsigned int i = 0; i < strlen(s); i++) return false;
switch (s[i]) { } // end of WriteStr
case '"': fputs("\\\"", Stream); break;
case '\\': fputs("\\\\", Stream); break; /***********************************************************************/
case '\t': fputs("\\t", Stream); break; /* Write a character to the Serialize file. */
case '\n': fputs("\\n", Stream); break; /***********************************************************************/
case '\r': fputs("\\r", Stream); break; bool JOUTFILE::WriteChr(const char c)
case '\b': fputs("\\b", Stream); break; {
case '\f': fputs("\\f", Stream); break; // This is temporary
default: fputc(c, Stream);
fputc(s[i], Stream); return false;
break; } // end of WriteChr
} // endswitch s[i]
/***********************************************************************/
fputc('"', Stream); /* Escape and Concatenate a string to the Serialize string. */
return false; /***********************************************************************/
} // end of Escape bool JOUTFILE::Escape(const char *s)
{
/* ------------------------- Class JOUTPRT --------------------------- */ // This is temporary
fputc('"', Stream);
/***********************************************************************/
/* Write a string to the Serialize pretty file. */ for (unsigned int i = 0; i < strlen(s); i++)
/***********************************************************************/ switch (s[i]) {
bool JOUTPRT::WriteStr(const char *s) case '"': fputs("\\\"", Stream); break;
{ case '\\': fputs("\\\\", Stream); break;
// This is temporary case '\t': fputs("\\t", Stream); break;
if (B) { case '\n': fputs("\\n", Stream); break;
fputs(EL, Stream); case '\r': fputs("\\r", Stream); break;
M--; case '\b': fputs("\\b", Stream); break;
case '\f': fputs("\\f", Stream); break;
for (int i = 0; i < M; i++) default:
fputc('\t', Stream); fputc(s[i], Stream);
break;
B = false; } // endswitch s[i]
} // endif B
fputc('"', Stream);
fputs(s, Stream); return false;
return false; } // end of Escape
} // end of WriteStr
/* ------------------------- Class JOUTPRT --------------------------- */
/***********************************************************************/
/* Write a character to the Serialize pretty file. */ /***********************************************************************/
/***********************************************************************/ /* Write a string to the Serialize pretty file. */
bool JOUTPRT::WriteChr(const char c) /***********************************************************************/
{ bool JOUTPRT::WriteStr(const char *s)
switch (c) { {
case ':': // This is temporary
fputs(": ", Stream); if (B) {
break; fputs(EL, Stream);
case '{': M--;
case '[':
#if 0 for (int i = 0; i < M; i++)
if (M) fputc('\t', Stream);
fputs(EL, Stream);
B = false;
for (int i = 0; i < M; i++) } // endif B
fputc('\t', Stream);
#endif // 0 fputs(s, Stream);
return false;
fputc(c, Stream); } // end of WriteStr
fputs(EL, Stream);
M++; /***********************************************************************/
/* Write a character to the Serialize pretty file. */
for (int i = 0; i < M; i++) /***********************************************************************/
fputc('\t', Stream); bool JOUTPRT::WriteChr(const char c)
{
break; switch (c) {
case '}': case ':':
case ']': fputs(": ", Stream);
M--; break;
fputs(EL, Stream); case '{':
case '[':
for (int i = 0; i < M; i++) #if 0
fputc('\t', Stream); if (M)
fputs(EL, Stream);
fputc(c, Stream);
B = true; for (int i = 0; i < M; i++)
break; fputc('\t', Stream);
case ',': #endif // 0
fputc(c, Stream);
fputs(EL, Stream); fputc(c, Stream);
fputs(EL, Stream);
for (int i = 0; i < M; i++) M++;
fputc('\t', Stream);
for (int i = 0; i < M; i++)
B = false; fputc('\t', Stream);
break;
default: break;
fputc(c, Stream); case '}':
} // endswitch c case ']':
M--;
return false; fputs(EL, Stream);
} // end of WriteChr
for (int i = 0; i < M; i++)
/* -------------------------- Class JOBJECT -------------------------- */ fputc('\t', Stream);
/***********************************************************************/ fputc(c, Stream);
/* Add a new pair to an Object. */ B = true;
/***********************************************************************/ break;
PJPR JOBJECT::AddPair(PGLOBAL g, PSZ key) case ',':
{ fputc(c, Stream);
PJPR jpp = new(g) JPAIR(key); fputs(EL, Stream);
if (Last) for (int i = 0; i < M; i++)
Last->Next = jpp; fputc('\t', Stream);
else
First = jpp; B = false;
break;
Last = jpp; default:
Size++; fputc(c, Stream);
return jpp; } // endswitch c
} // end of AddPair
return false;
/***********************************************************************/ } // end of WriteChr
/* Get the value corresponding to the given key. */
/***********************************************************************/ /* -------------------------- Class JOBJECT -------------------------- */
PJVAL JOBJECT::GetValue(const char* key)
{ /***********************************************************************/
for (PJPR jp = First; jp; jp = jp->Next) /* Add a new pair to an Object. */
if (!strcmp(jp->Key, key)) /***********************************************************************/
return jp->Val; PJPR JOBJECT::AddPair(PGLOBAL g, PSZ key)
{
return NULL; PJPR jpp = new(g) JPAIR(key);
} // end of GetValue;
if (Last)
/***********************************************************************/ Last->Next = jpp;
/* Return the text corresponding to all keys (XML like). */ else
/***********************************************************************/ First = jpp;
PSZ JOBJECT::GetText(PGLOBAL g)
{ Last = jpp;
char *p, *text = (char*)PlugSubAlloc(g, NULL, 0); Size++;
bool b = true; return jpp;
} // end of AddPair
if (!First)
return NULL; /***********************************************************************/
else for (PJPR jp = First; jp; jp = jp->Next) { /* Get the value corresponding to the given key. */
if (!(p = jp->Val->GetString())) /***********************************************************************/
p = "???"; PJVAL JOBJECT::GetValue(const char* key)
{
if (b) { for (PJPR jp = First; jp; jp = jp->Next)
strcpy(text, p); if (!strcmp(jp->Key, key))
b = false; return jp->Val;
} else
strcat(strcat(text, " "), p); return NULL;
} // end of GetValue;
} // endfor jp
/***********************************************************************/
PlugSubAlloc(g, NULL, strlen(text) + 1); /* Return the text corresponding to all keys (XML like). */
return text; /***********************************************************************/
} // end of GetValue; PSZ JOBJECT::GetText(PGLOBAL g)
{
/***********************************************************************/ char *p, *text = (char*)PlugSubAlloc(g, NULL, 0);
/* Set or add a value corresponding to the given key. */ bool b = true;
/***********************************************************************/
void JOBJECT::SetValue(PGLOBAL g, PJVAL jvp, PSZ key) if (!First)
{ return NULL;
PJPR jp; else for (PJPR jp = First; jp; jp = jp->Next) {
if (!(p = jp->Val->GetString()))
for (jp = First; jp; jp = jp->Next) p = "???";
if (!strcmp(jp->Key, key)) {
jp->Val = jvp; if (b) {
break; strcpy(text, p);
} // endif key b = false;
} else
if (!jp) { strcat(strcat(text, " "), p);
jp = AddPair(g, key);
jp->Val = jvp; } // endfor jp
} // endif jp
PlugSubAlloc(g, NULL, strlen(text) + 1);
} // end of SetValue return text;
} // end of GetValue;
/* -------------------------- Class JARRAY --------------------------- */
/***********************************************************************/
/***********************************************************************/ /* Set or add a value corresponding to the given key. */
/* Make the array of values from the values list. */ /***********************************************************************/
/***********************************************************************/ void JOBJECT::SetValue(PGLOBAL g, PJVAL jvp, PSZ key)
void JARRAY::InitArray(PGLOBAL g) {
{ PJPR jp;
int i;
PJVAL jvp; for (jp = First; jp; jp = jp->Next)
if (!strcmp(jp->Key, key)) {
for (Size = 0, jvp = First; jvp; jvp = jvp->Next) jp->Val = jvp;
if (!jvp->Del) break;
Size++; } // endif key
if (!Size) { if (!jp) {
return; jp = AddPair(g, key);
} else if (Size > Alloc) { jp->Val = jvp;
// No need to realloc after deleting values } // endif jp
Mvals = (PJVAL*)PlugSubAlloc(g, NULL, Size * sizeof(PJVAL));
Alloc = Size; } // end of SetValue
} // endif Size
/* -------------------------- Class JARRAY --------------------------- */
for (i = 0, jvp = First; jvp; jvp = jvp->Next)
if (!jvp->Del) /***********************************************************************/
Mvals[i++] = jvp; /* Make the array of values from the values list. */
/***********************************************************************/
} // end of InitArray void JARRAY::InitArray(PGLOBAL g)
{
/***********************************************************************/ int i;
/* Get the Nth value of an Array. */ PJVAL jvp;
/***********************************************************************/
PJVAL JARRAY::GetValue(int i) for (Size = 0, jvp = First; jvp; jvp = jvp->Next)
{ if (!jvp->Del)
if (Mvals && i >= 0 && i < Size) Size++;
return Mvals[i];
else if (!Size) {
return NULL; return;
} // end of GetValue } else if (Size > Alloc) {
// No need to realloc after deleting values
/***********************************************************************/ Mvals = (PJVAL*)PlugSubAlloc(g, NULL, Size * sizeof(PJVAL));
/* Add a Value to the Arrays Value list. */ Alloc = Size;
/***********************************************************************/ } // endif Size
PJVAL JARRAY::AddValue(PGLOBAL g, PJVAL jvp)
{ for (i = 0, jvp = First; jvp; jvp = jvp->Next)
if (!jvp) if (!jvp->Del)
jvp = new(g) JVALUE; Mvals[i++] = jvp;
if (Last) } // end of InitArray
Last->Next = jvp;
else /***********************************************************************/
First = jvp; /* Get the Nth value of an Array. */
/***********************************************************************/
Last = jvp; PJVAL JARRAY::GetValue(int i)
return jvp; {
} // end of AddValue if (Mvals && i >= 0 && i < Size)
return Mvals[i];
/***********************************************************************/ else
/* Add a Value to the Arrays Value list. */ return NULL;
/***********************************************************************/ } // end of GetValue
bool JARRAY::SetValue(PGLOBAL g, PJVAL jvp, int n)
{ /***********************************************************************/
int i = 0; /* Add a Value to the Arrays Value list. */
PJVAL jp, *jpp = &First; /***********************************************************************/
PJVAL JARRAY::AddValue(PGLOBAL g, PJVAL jvp)
for (i = 0, jp = First; i < n; i++, jp = *(jpp = &jp->Next)) {
if (!jp) if (!jvp)
*jpp = jp = new(g) JVALUE; jvp = new(g) JVALUE;
*jpp = jvp; if (Last)
jvp->Next = (jp ? jp->Next : NULL); Last->Next = jvp;
return false; else
} // end of SetValue First = jvp;
/***********************************************************************/ Last = jvp;
/* Delete a Value from the Arrays Value list. */ return jvp;
/***********************************************************************/ } // end of AddValue
bool JARRAY::DeleteValue(int n)
{ /***********************************************************************/
PJVAL jvp = GetValue(n); /* Add a Value to the Arrays Value list. */
/***********************************************************************/
if (jvp) { bool JARRAY::SetValue(PGLOBAL g, PJVAL jvp, int n)
jvp->Del = true; {
return false; int i = 0;
} else PJVAL jp, *jpp = &First;
return true;
for (i = 0, jp = First; i < n; i++, jp = *(jpp = &jp->Next))
} // end of DeleteValue if (!jp)
*jpp = jp = new(g) JVALUE;
/* -------------------------- Class JVALUE- -------------------------- */
*jpp = jvp;
/***********************************************************************/ jvp->Next = (jp ? jp->Next : NULL);
/* Constructor for a Value with a given string or numeric value. */ return false;
/***********************************************************************/ } // end of SetValue
JVALUE::JVALUE(PGLOBAL g, PVAL valp) : JSON()
{ /***********************************************************************/
Jsp = NULL; /* Delete a Value from the Arrays Value list. */
Value = AllocateValue(g, valp); /***********************************************************************/
Next = NULL; bool JARRAY::DeleteValue(int n)
Del = false; {
} // end of JVALUE constructor PJVAL jvp = GetValue(n);
/***********************************************************************/ if (jvp) {
/* Returns the type of the Value's value. */ jvp->Del = true;
/***********************************************************************/ return false;
JTYP JVALUE::GetValType(void) } else
{ return true;
if (Jsp)
return Jsp->GetType(); } // end of DeleteValue
else if (Value)
return (JTYP)Value->GetType(); /* -------------------------- Class JVALUE- -------------------------- */
else
return (JTYP)TYPE_VOID; /***********************************************************************/
/* Constructor for a Value with a given string or numeric value. */
} // end of GetValType /***********************************************************************/
JVALUE::JVALUE(PGLOBAL g, PVAL valp) : JSON()
/***********************************************************************/ {
/* Return the Value's Object value. */ Jsp = NULL;
/***********************************************************************/ Value = AllocateValue(g, valp);
PJOB JVALUE::GetObject(void) Next = NULL;
{ Del = false;
if (Jsp && Jsp->GetType() == TYPE_JOB) } // end of JVALUE constructor
return (PJOB)Jsp;
/***********************************************************************/
return NULL; /* Returns the type of the Value's value. */
} // end of GetObject /***********************************************************************/
JTYP JVALUE::GetValType(void)
/***********************************************************************/ {
/* Return the Value's Array value. */ if (Jsp)
/***********************************************************************/ return Jsp->GetType();
PJAR JVALUE::GetArray(void) else if (Value)
{ return (JTYP)Value->GetType();
if (Jsp && Jsp->GetType() == TYPE_JAR) else
return (PJAR)Jsp; return (JTYP)TYPE_VOID;
return NULL; } // end of GetValType
} // end of GetArray
/***********************************************************************/
/***********************************************************************/ /* Return the Value's Object value. */
/* Return the Value's Integer value. */ /***********************************************************************/
/***********************************************************************/ PJOB JVALUE::GetObject(void)
int JVALUE::GetInteger(void) {
{ if (Jsp && Jsp->GetType() == TYPE_JOB)
return (Value) ? Value->GetIntValue() : 0; return (PJOB)Jsp;
} // end of GetInteger
return NULL;
/***********************************************************************/ } // end of GetObject
/* Return the Value's Double value. */
/***********************************************************************/ /***********************************************************************/
double JVALUE::GetFloat(void) /* Return the Value's Array value. */
{ /***********************************************************************/
return (Value) ? Value->GetFloatValue() : 0.0; PJAR JVALUE::GetArray(void)
} // end of GetFloat {
if (Jsp && Jsp->GetType() == TYPE_JAR)
/***********************************************************************/ return (PJAR)Jsp;
/* Return the Value's String value. */
/***********************************************************************/ return NULL;
PSZ JVALUE::GetString(void) } // end of GetArray
{
char buf[32]; /***********************************************************************/
return (Value) ? Value->GetCharString(buf) : NULL; /* Return the Value's Integer value. */
} // end of GetString /***********************************************************************/
int JVALUE::GetInteger(void)
/***********************************************************************/ {
/* Set the Value's value as the given integer. */ return (Value) ? Value->GetIntValue() : 0;
/***********************************************************************/ } // end of GetInteger
void JVALUE::SetInteger(PGLOBAL g, int n)
{ /***********************************************************************/
Value = AllocateValue(g, &n, TYPE_INT); /* Return the Value's Double value. */
} // end of AddInteger /***********************************************************************/
double JVALUE::GetFloat(void)
/***********************************************************************/ {
/* Set the Value's value as the given DOUBLE. */ return (Value) ? Value->GetFloatValue() : 0.0;
/***********************************************************************/ } // end of GetFloat
void JVALUE::SetFloat(PGLOBAL g, double f)
{ /***********************************************************************/
Value = AllocateValue(g, &f, TYPE_DOUBLE, 6); /* Return the Value's String value. */
} // end of AddFloat /***********************************************************************/
PSZ JVALUE::GetString(void)
/***********************************************************************/ {
/* Set the Value's value as the given string. */ char buf[32];
/***********************************************************************/ return (Value) ? Value->GetCharString(buf) : NULL;
void JVALUE::SetString(PGLOBAL g, PSZ s) } // end of GetString
{
Value = AllocateValue(g, s, TYPE_STRING); /***********************************************************************/
} // end of AddFloat /* Set the Value's value as the given integer. */
/***********************************************************************/
void JVALUE::SetInteger(PGLOBAL g, int n)
{
Value = AllocateValue(g, &n, TYPE_INT);
} // end of AddInteger
/***********************************************************************/
/* Set the Value's value as the given DOUBLE. */
/***********************************************************************/
void JVALUE::SetFloat(PGLOBAL g, double f)
{
Value = AllocateValue(g, &f, TYPE_DOUBLE, 6);
} // end of AddFloat
/***********************************************************************/
/* Set the Value's value as the given string. */
/***********************************************************************/
void JVALUE::SetString(PGLOBAL g, PSZ s)
{
Value = AllocateValue(g, s, TYPE_STRING);
} // end of AddFloat
...@@ -44,9 +44,10 @@ DllExport void Json_Object_Grp_deinit(UDF_INIT*); ...@@ -44,9 +44,10 @@ DllExport void Json_Object_Grp_deinit(UDF_INIT*);
/***********************************************************************/ /***********************************************************************/
/* Allocate and initialise the memory area. */ /* Allocate and initialise the memory area. */
/***********************************************************************/ /***********************************************************************/
my_bool JsonInit(UDF_INIT *initid, char *message, unsigned long len) my_bool JsonInit(UDF_INIT *initid, char *message, unsigned long reslen,
unsigned long memlen)
{ {
PGLOBAL g = PlugInit(NULL, len); PGLOBAL g = PlugInit(NULL, memlen);
if (!g) { if (!g) {
strcpy(message, "Allocation error"); strcpy(message, "Allocation error");
...@@ -59,7 +60,7 @@ my_bool JsonInit(UDF_INIT *initid, char *message, unsigned long len) ...@@ -59,7 +60,7 @@ my_bool JsonInit(UDF_INIT *initid, char *message, unsigned long len)
initid->ptr = (char*)g; initid->ptr = (char*)g;
initid->maybe_null = false; initid->maybe_null = false;
initid->max_length = len - 512; initid->max_length = reslen;
return false; return false;
} // end of Json_Object_init } // end of Json_Object_init
...@@ -72,6 +73,92 @@ static my_bool IsJson(UDF_ARGS *args, int i) ...@@ -72,6 +73,92 @@ static my_bool IsJson(UDF_ARGS *args, int i)
!strnicmp(args->attributes[i], "Json_", 5)); !strnicmp(args->attributes[i], "Json_", 5));
} // end of IsJson } // end of IsJson
/***********************************************************************/
/* Calculate the reslen and memlen needed by a function. */
/***********************************************************************/
static my_bool CalcLen(UDF_ARGS *args, my_bool obj,
unsigned long& reslen, unsigned long& memlen)
{
unsigned long i, k;
reslen = args->arg_count + 2;
// Calculate the result max length
for (i = 0; i < args->arg_count; i++) {
if (obj) {
if (!(k = args->attribute_lengths[i]))
k = strlen(args->attributes[i]);
reslen += (k + 3); // For quotes and :
} // endif obj
switch (args->arg_type[i]) {
case STRING_RESULT:
if (IsJson(args, i))
reslen += args->lengths[i];
else
reslen += (args->lengths[i] + 1) * 2; // Pessimistic !
break;
case INT_RESULT:
reslen += 20;
break;
case REAL_RESULT:
reslen += 31;
break;
case DECIMAL_RESULT:
reslen += (args->lengths[i] + 7); // 6 decimals
break;
case TIME_RESULT:
case ROW_RESULT:
case IMPOSSIBLE_RESULT:
default:
// What should we do here ?
break;
} // endswitch arg_type
} // endfor i
// Calculate the amount of memory needed
memlen = 1024 + sizeof(JOUTSTR) + reslen;
for (i = 0; i < args->arg_count; i++) {
memlen += (args->lengths[i] + sizeof(JVALUE));
if (obj) {
if (!(k = args->attribute_lengths[i]))
k = strlen(args->attributes[i]);
memlen += (k + sizeof(JOBJECT) + sizeof(JPAIR));
} else
memlen += sizeof(JARRAY);
switch (args->arg_type[i]) {
case STRING_RESULT:
if (IsJson(args, i))
memlen += args->lengths[i] * 5; // Estimate parse memory
memlen += sizeof(TYPVAL<PSZ>);
break;
case INT_RESULT:
memlen += sizeof(TYPVAL<int>);
break;
case REAL_RESULT:
case DECIMAL_RESULT:
memlen += sizeof(TYPVAL<double>);
break;
case TIME_RESULT:
case ROW_RESULT:
case IMPOSSIBLE_RESULT:
default:
// What should we do here ?
break;
} // endswitch arg_type
} // endfor i
return false;
} // end of CalcLen
/***********************************************************************/ /***********************************************************************/
/* Make a zero terminated string from the passed argument. */ /* Make a zero terminated string from the passed argument. */
/***********************************************************************/ /***********************************************************************/
...@@ -131,25 +218,25 @@ static PSZ MakeKey(PGLOBAL g, UDF_ARGS *args, int i) ...@@ -131,25 +218,25 @@ static PSZ MakeKey(PGLOBAL g, UDF_ARGS *args, int i)
/***********************************************************************/ /***********************************************************************/
static PJVAL MakeValue(PGLOBAL g, UDF_ARGS *args, int i) static PJVAL MakeValue(PGLOBAL g, UDF_ARGS *args, int i)
{ {
char *str; char *sap = args->args[i];
PJVAL jvp = new(g) JVALUE; PJVAL jvp = new(g) JVALUE;
switch (args->arg_type[i]) { if (sap) switch (args->arg_type[i]) {
case STRING_RESULT: case STRING_RESULT:
if ((str = MakePSZ(g, args, i))) { if (args->lengths[i]) {
if (IsJson(args, i)) if (IsJson(args, i))
jvp->SetValue(ParseJson(g, str, strlen(str), 0)); jvp->SetValue(ParseJson(g, sap, args->lengths[i], 0));
else else
jvp->SetString(g, str); jvp->SetString(g, MakePSZ(g, args, i));
} // endif str } // endif str
break; break;
case INT_RESULT: case INT_RESULT:
jvp->SetInteger(g, *(int*)args->args[i]); jvp->SetInteger(g, *(int*)sap);
break; break;
case REAL_RESULT: case REAL_RESULT:
jvp->SetFloat(g, *(double*)args->args[i]); jvp->SetFloat(g, *(double*)sap);
break; break;
case DECIMAL_RESULT: case DECIMAL_RESULT:
jvp->SetFloat(g, atof(MakePSZ(g, args, i))); jvp->SetFloat(g, atof(MakePSZ(g, args, i)));
...@@ -169,12 +256,15 @@ static PJVAL MakeValue(PGLOBAL g, UDF_ARGS *args, int i) ...@@ -169,12 +256,15 @@ static PJVAL MakeValue(PGLOBAL g, UDF_ARGS *args, int i)
/***********************************************************************/ /***********************************************************************/
my_bool Json_Value_init(UDF_INIT *initid, UDF_ARGS *args, char *message) my_bool Json_Value_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ {
unsigned long reslen, memlen;
if (args->arg_count > 1) { if (args->arg_count > 1) {
strcpy(message, "Json_Value cannot accept more than 1 argument"); strcpy(message, "Json_Value cannot accept more than 1 argument");
return true; return true;
} // endif arg_count } else
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, message, 1024); return JsonInit(initid, message, reslen, memlen);
} // end of Json_Value_init } // end of Json_Value_init
char *Json_Value(UDF_INIT *initid, UDF_ARGS *args, char *result, char *Json_Value(UDF_INIT *initid, UDF_ARGS *args, char *result,
...@@ -204,7 +294,10 @@ void Json_Value_deinit(UDF_INIT* initid) ...@@ -204,7 +294,10 @@ void Json_Value_deinit(UDF_INIT* initid)
/***********************************************************************/ /***********************************************************************/
my_bool Json_Array_init(UDF_INIT *initid, UDF_ARGS *args, char *message) my_bool Json_Array_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ {
return JsonInit(initid, message, 8192); unsigned long reslen, memlen;
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, message, reslen, memlen);
} // end of Json_Array_init } // end of Json_Array_init
char *Json_Array(UDF_INIT *initid, UDF_ARGS *args, char *result, char *Json_Array(UDF_INIT *initid, UDF_ARGS *args, char *result,
...@@ -240,11 +333,14 @@ void Json_Array_deinit(UDF_INIT* initid) ...@@ -240,11 +333,14 @@ void Json_Array_deinit(UDF_INIT* initid)
/***********************************************************************/ /***********************************************************************/
my_bool Json_Object_init(UDF_INIT *initid, UDF_ARGS *args, char *message) my_bool Json_Object_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ {
return JsonInit(initid, message, 8192); unsigned long reslen, memlen;
CalcLen(args, true, reslen, memlen);
return JsonInit(initid, message, reslen, memlen);
} // end of Json_Object_init } // end of Json_Object_init
char *Json_Object(UDF_INIT *initid, UDF_ARGS *args, char *result, char *Json_Object(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error) unsigned long *res_length, char *is_null, char *error)
{ {
char *str; char *str;
uint i; uint i;
...@@ -274,10 +370,18 @@ void Json_Object_deinit(UDF_INIT* initid) ...@@ -274,10 +370,18 @@ void Json_Object_deinit(UDF_INIT* initid)
/***********************************************************************/ /***********************************************************************/
my_bool Json_Array_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message) my_bool Json_Array_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ {
unsigned long reslen, memlen, n = 10;
if (args->arg_count != 1) { if (args->arg_count != 1) {
strcpy(message, "Json_Array_Grp can only accept 1 argument"); strcpy(message, "Json_Array_Grp can only accept 1 argument");
return true; return true;
} else if (JsonInit(initid, message, 16384)) } else
CalcLen(args, false, reslen, memlen);
reslen *= n;
memlen *= n;
if (JsonInit(initid, message, reslen, memlen))
return true; return true;
PGLOBAL g = (PGLOBAL)initid->ptr; PGLOBAL g = (PGLOBAL)initid->ptr;
...@@ -330,10 +434,18 @@ void Json_Array_Grp_deinit(UDF_INIT* initid) ...@@ -330,10 +434,18 @@ void Json_Array_Grp_deinit(UDF_INIT* initid)
/***********************************************************************/ /***********************************************************************/
my_bool Json_Object_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message) my_bool Json_Object_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{ {
unsigned long reslen, memlen, n = 10;
if (args->arg_count != 2) { if (args->arg_count != 2) {
strcpy(message, "Json_Array_Grp can only accept 2 argument"); strcpy(message, "Json_Array_Grp can only accept 2 argument");
return true; return true;
} else if (JsonInit(initid, message, 16384)) } else
CalcLen(args, true, reslen, memlen);
reslen *= n;
memlen *= n;
if (JsonInit(initid, message, reslen, memlen))
return true; return true;
PGLOBAL g = (PGLOBAL)initid->ptr; PGLOBAL g = (PGLOBAL)initid->ptr;
......
...@@ -825,7 +825,9 @@ PJSON JSONCOL::GetRow(PGLOBAL g) ...@@ -825,7 +825,9 @@ PJSON JSONCOL::GetRow(PGLOBAL g)
PJSON nwr, row = Tjp->Row; PJSON nwr, row = Tjp->Row;
for (int i = 0; i < Nod-1 && row; i++) { for (int i = 0; i < Nod-1 && row; i++) {
switch (row->GetType()) { if (Nodes[i+1].Op == OP_XX)
break;
else switch (row->GetType()) {
case TYPE_JOB: case TYPE_JOB:
if (!Nodes[i].Key) if (!Nodes[i].Key)
// Expected Array was not there // Expected Array was not there
...@@ -932,7 +934,11 @@ void JSONCOL::WriteColumn(PGLOBAL g) ...@@ -932,7 +934,11 @@ void JSONCOL::WriteColumn(PGLOBAL g)
jsp = ParseJson(g, s, (int)strlen(s), 0); jsp = ParseJson(g, s, (int)strlen(s), 0);
if (arp) { if (arp) {
arp->AddValue(g, new(g) JVALUE(jsp)); if (Nod > 1 && Nodes[Nod-2].Rank)
arp->SetValue(g, new(g) JVALUE(jsp), Nodes[Nod-2].Rank-1);
else
arp->AddValue(g, new(g) JVALUE(jsp));
arp->InitArray(g); arp->InitArray(g);
} else if (objp) { } else if (objp) {
if (Nod > 1 && Nodes[Nod-2].Key) if (Nod > 1 && Nodes[Nod-2].Key)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment