mariadb/storage/connect/json.cpp
Mikhail Chalov 2ff01e763e Fix insecure use of strcpy, strcat and sprintf in Connect
Old style C functions `strcpy()`, `strcat()` and `sprintf()` are vulnerable to
security issues due to lacking memory boundary checks. Replace these in the
Connect storage engine with safe new and/or custom functions such as
`snprintf()` `safe_strcpy()` and `safe_strcat()`.

With this change FlawFinder and other static security analyzers report 287
fewer findings.

All new code of the whole pull request, including one or several files that are
either new files or modified ones, are contributed under the BSD-new license. I
am contributing on behalf of my employer Amazon Web Services, Inc.
2023-05-12 15:37:00 +01:00

2065 lines
55 KiB
C++

/*************** json CPP Declares Source Code File (.H) ***************/
/* Name: json.cpp Version 1.6 */
/* */
/* (C) Copyright to the author Olivier BERTRAND 2014 - 2021 */
/* */
/* This file contains the JSON classes functions. */
/***********************************************************************/
/***********************************************************************/
/* Include relevant sections of the MariaDB header file. */
/***********************************************************************/
#include <my_global.h>
#include <m_string.h>
/***********************************************************************/
/* Include application header files: */
/* global.h is header containing all global declarations. */
/* plgdbsem.h is header containing the DB application declarations. */
/* xjson.h is header containing the JSON classes declarations. */
/***********************************************************************/
#include "global.h"
#include "plgdbsem.h"
#include "json.h"
#define ARGS MY_MIN(24,(int)len-i),s+MY_MAX(i-3,0)
#if defined(_WIN32)
#define EL "\r\n"
#else
#define EL "\n"
#undef SE_CATCH // Does not work for Linux
#endif
#if defined(SE_CATCH)
/**************************************************************************/
/* This is the support of catching C interrupts to prevent crashes. */
/**************************************************************************/
#include <eh.h>
class SE_Exception {
public:
SE_Exception(unsigned int n, PEXCEPTION_RECORD p) : nSE(n), eRec(p) {}
~SE_Exception() {}
unsigned int nSE;
PEXCEPTION_RECORD eRec;
}; // end of class SE_Exception
void trans_func(unsigned int u, _EXCEPTION_POINTERS* pExp)
{
throw SE_Exception(u, pExp->ExceptionRecord);
} // end of trans_func
char *GetExceptionDesc(PGLOBAL g, unsigned int e);
#endif // SE_CATCH
char *GetJsonNull(void);
int GetDefaultPrec(void);
int PrepareColist(char*);
/***********************************************************************/
/* IsNum: check whether this string is all digits. */
/***********************************************************************/
bool IsNum(PSZ s)
{
char* p = s;
if (*p == '-')
p++;
if (*p == ']')
return false;
else for (; *p; p++)
if (*p == ']')
break;
else if (!isdigit(*p))
return false;
return true;
} // end of IsNum
/***********************************************************************/
/* IsArray: check whether this is a Mongo array path. */
/***********************************************************************/
bool IsArray(PSZ s)
{
char* p = s;
if (!p || !*p)
return false;
else for (; *p; p++)
if (*p == '.')
break;
else if (!isdigit(*p))
return false;
return true;
} // end of IsArray
/***********************************************************************/
/* NextChr: return the first found '[' or Sep pointer. */
/***********************************************************************/
char* NextChr(PSZ s, char sep)
{
char* p1 = strchr(s, '[');
char* p2 = strchr(s, sep);
if (!p2)
return p1;
else if (p1)
return MY_MIN(p1, p2);
return p2;
} // end of NextChr
/***********************************************************************/
/* Stringified: check that this column is in the stringified list. */
/***********************************************************************/
bool Stringified(PCSZ strfy, char *colname)
{
if (strfy) {
char *p, colist[512];
int n;
strncpy(colist, strfy, sizeof(colist) - 1);
n = PrepareColist(colist);
for (p = colist; n && p; p += (strlen(p) + 1), n--)
if (!stricmp(p, colname))
return true;
} // endif strfy
return false;
} // end of Stringified
#if 0
/***********************************************************************/
/* 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
#endif // 0
/***********************************************************************/
/* Parse a json string. */
/* Note: when pretty is not known, the caller set pretty to 3. */
/***********************************************************************/
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;
PJDOC jdp = NULL;
if (trace(1))
htrc("ParseJson: s=%.10s len=%zd\n", s, len);
if (!s || !len) {
snprintf(g->Message, sizeof(g->Message), "Void JSON object");
return NULL;
} 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 {
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
snprintf(g->Message, sizeof(g->Message), "Unexpected ',' (pretty=%d)", pretty);
throw 3;
case '(':
b = true;
break;
case ')':
if (b) {
b = false;
break;
} // endif b
/* falls through */
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)
snprintf(g->Message, sizeof(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) {
snprintf(g->Message, sizeof(g->Message), "%s", 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 !!!!!
jdp->dfp = GetDefaultPrec();
if (!jsp) {
snprintf(g->Message, sizeof(g->Message), "Null json tree");
throw 1;
} else if (!fn) {
// Serialize to a string
jp = new(g) JOUTSTR(g);
b = pretty == 1;
} else {
if (!(fs = fopen(fn, "wb"))) {
snprintf(g->Message, sizeof(g->Message), MSG(OPEN_MODE_ERROR) ": %s",
"w", (int)errno, fn, strerror(errno));
throw 2;
} else if (pretty >= 2) {
// Serialize to a pretty file
jp = new(g)JOUTPRT(g, fs);
} else {
// Serialize to a flat file
b = true;
jp = new(g)JOUTFILE(g, fs, pretty);
} // endif's
} // endif's
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:
snprintf(g->Message, sizeof(g->Message), "Invalid json tree");
} // endswitch Type
if (fs) {
fputs(EL, fs);
fclose(fs);
if(err) {
str = NULL;
} else {
snprintf(g->Message, sizeof(g->Message), "Ok");
str = g->Message;
}
} else if (!err) {
str = ((JOUTSTR*)jp)->Strp;
jp->WriteChr('\0');
PlugSubAlloc(g, NULL, ((JOUTSTR*)jp)->N);
} else {
if (!g->Message[0])
snprintf(g->Message, sizeof(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) {
snprintf(g->Message, sizeof(g->Message), "%s", 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)
{
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]
WriteChr('"');
} else
WriteStr("null");
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
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]
fputc('"', Stream);
} else
fputs("null", 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 JDOC::ParseAsArray(PGLOBAL g, int& i, int pretty, int *ptyp)
{
if (pty[0] && (!pretty || pretty > 2)) {
PJAR jsp;
if ((jsp = ParseArray(g, (i = 0))) && ptyp && pretty == 3)
*ptyp = (pty[0]) ? 0 : 3;
return jsp;
} else
snprintf(g->Message, sizeof(g->Message), "More than one item in file");
return NULL;
} // end of ParseAsArray
/***********************************************************************/
/* Parse a JSON Array. */
/***********************************************************************/
PJAR JDOC::ParseArray(PGLOBAL g, int& i)
{
int level = 0;
bool b = (!i);
PJAR jarp = new(g) JARRAY;
for (; i < len; i++)
switch (s[i]) {
case ',':
if (level < 2) {
snprintf(g->Message, sizeof(g->Message), "Unexpected ',' near %.*s",ARGS);
throw 1;
} else
level = 1;
break;
case ']':
if (level == 1) {
snprintf(g->Message, sizeof(g->Message), "Unexpected ',]' near %.*s", ARGS);
throw 1;
} // endif level
jarp->InitArray(g);
return jarp;
case '\n':
if (!b)
pty[0] = pty[1] = false;
case '\r':
case ' ':
case '\t':
break;
default:
if (level == 2) {
snprintf(g->Message, sizeof(g->Message), "Unexpected value near %.*s", ARGS);
throw 1;
} else
jarp->AddArrayValue(g, ParseValue(g, i));
level = (b) ? 1 : 2;
break;
}; // endswitch s[i]
if (b) {
// Case of Pretty == 0
jarp->InitArray(g);
return jarp;
} // endif b
throw ("Unexpected EOF in array");
} // end of ParseArray
/***********************************************************************/
/* Parse a JSON Object. */
/***********************************************************************/
PJOB JDOC::ParseObject(PGLOBAL g, int& i)
{
PSZ key;
int level = -1;
PJOB jobp = new(g) JOBJECT;
PJPR jpp = NULL;
for (; i < len; i++)
switch (s[i]) {
case '"':
if (level < 2) {
key = ParseString(g, ++i);
jpp = jobp->AddPair(g, key);
level = 1;
} else {
snprintf(g->Message, sizeof(g->Message), "misplaced string near %.*s", ARGS);
throw 2;
} // endif level
break;
case ':':
if (level == 1) {
jpp->Val = ParseValue(g, ++i);
level = 2;
} else {
snprintf(g->Message, sizeof(g->Message), "Unexpected ':' near %.*s", ARGS);
throw 2;
} // endif level
break;
case ',':
if (level < 2) {
snprintf(g->Message, sizeof(g->Message), "Unexpected ',' near %.*s", ARGS);
throw 2;
} else
level = 0;
break;
case '}':
if (level == 0 || level == 1) {
snprintf(g->Message, sizeof(g->Message), "Unexpected '}' near %.*s", ARGS);
throw 2;
} // endif level
return jobp;
case '\n':
pty[0] = pty[1] = false;
case '\r':
case ' ':
case '\t':
break;
default:
snprintf(g->Message, sizeof(g->Message), "Unexpected character '%c' near %.*s",
s[i], ARGS);
throw 2;
}; // endswitch s[i]
snprintf(g->Message, sizeof(g->Message), "Unexpected EOF in Object");
throw 2;
} // end of ParseObject
/***********************************************************************/
/* Parse a JSON Value. */
/***********************************************************************/
PJVAL JDOC::ParseValue(PGLOBAL g, int& i)
{
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
suite:
switch (s[i]) {
case '[':
jvp->Jsp = ParseArray(g, ++i);
jvp->DataType = TYPE_JSON;
break;
case '{':
jvp->Jsp = ParseObject(g, ++i);
jvp->DataType = TYPE_JSON;
break;
case '"':
// jvp->Val = AllocVal(g, TYPE_STRG);
jvp->Strp = ParseString(g, ++i);
jvp->DataType = TYPE_STRG;
break;
case 't':
if (!strncmp(s + i, "true", 4)) {
// jvp->Val = AllocVal(g, TYPE_BOOL);
jvp->B = true;
jvp->DataType = TYPE_BOOL;
i += 3;
} else
goto err;
break;
case 'f':
if (!strncmp(s + i, "false", 5)) {
// jvp->Val = AllocVal(g, TYPE_BOOL);
jvp->B = false;
jvp->DataType = TYPE_BOOL;
i += 4;
} else
goto err;
break;
case 'n':
if (!strncmp(s + i, "null", 4)) {
jvp->DataType = TYPE_NULL;
i += 3;
} else
goto err;
break;
case '-':
default:
if (s[i] == '-' || isdigit(s[i]))
ParseNumeric(g, i, jvp);
else
goto err;
}; // endswitch s[i]
return jvp;
err:
snprintf(g->Message, sizeof(g->Message), "Unexpected character '%c' near %.*s", s[i], ARGS);
throw 3;
} // end of ParseValue
/***********************************************************************/
/* Unescape and parse a JSON string. */
/***********************************************************************/
char *JDOC::ParseString(PGLOBAL g, int& i)
{
uchar *p;
int n = 0;
// Be sure of memory availability
if (((size_t)len + 1 - i) > ((PPOOLHEADER)g->Sarea)->FreeBlk)
throw("ParseString: Out of memory");
// The size to allocate is not known yet
p = (uchar*)PlugSubAlloc(g, NULL, 0);
for (; i < len; i++)
switch (s[i]) {
case '"':
p[n++] = 0;
PlugSubAlloc(g, NULL, n);
return (char*)p;
case '\\':
if (++i < len) {
if (s[i] == 'u') {
if (len - i > 5) {
// if (charset == utf8) {
char xs[5];
uint hex;
xs[0] = s[++i];
xs[1] = s[++i];
xs[2] = s[++i];
xs[3] = s[++i];
xs[4] = 0;
hex = strtoul(xs, NULL, 16);
if (hex < 0x80) {
p[n] = (uchar)hex;
} else if (hex < 0x800) {
p[n++] = (uchar)(0xC0 | (hex >> 6));
p[n] = (uchar)(0x80 | (hex & 0x3F));
} else if (hex < 0x10000) {
p[n++] = (uchar)(0xE0 | (hex >> 12));
p[n++] = (uchar)(0x80 | ((hex >> 6) & 0x3f));
p[n] = (uchar)(0x80 | (hex & 0x3f));
} else
p[n] = '?';
#if 0
} else {
char xs[3];
UINT hex;
i += 2;
xs[0] = s[++i];
xs[1] = s[++i];
xs[2] = 0;
hex = strtoul(xs, NULL, 16);
p[n] = (char)hex;
} // endif charset
#endif // 0
} else
goto err;
} else switch(s[i]) {
case 't': p[n] = '\t'; break;
case 'n': p[n] = '\n'; break;
case 'r': p[n] = '\r'; break;
case 'b': p[n] = '\b'; break;
case 'f': p[n] = '\f'; break;
default: p[n] = s[i]; break;
} // endswitch
n++;
} else
goto err;
break;
default:
p[n++] = s[i];
break;
}; // endswitch s[i]
err:
throw("Unexpected EOF in String");
} // end of ParseString
/***********************************************************************/
/* Parse a JSON numeric value. */
/***********************************************************************/
void JDOC::ParseNumeric(PGLOBAL g, int& i, PJVAL vlp)
{
char buf[50];
int n = 0;
short nd = 0;
bool has_dot = false;
bool has_e = false;
bool found_digit = false;
//PVL vlp = NULL;
for (; i < len; i++) {
switch (s[i]) {
case '.':
if (!found_digit || has_dot || has_e)
goto err;
has_dot = true;
break;
case 'e':
case 'E':
if (!found_digit || has_e)
goto err;
has_e = true;
found_digit = false;
break;
case '+':
if (!has_e)
goto err;
// fall through
case '-':
if (found_digit)
goto err;
break;
default:
if (isdigit(s[i])) {
if (has_dot && !has_e)
nd++; // Number of decimals
found_digit = true;
} else
goto fin;
}; // endswitch s[i]
buf[n++] = s[i];
} // endfor i
fin:
if (found_digit) {
buf[n] = 0;
if (has_dot || has_e) {
double dv = strtod(buf, NULL);
// vlp = AllocVal(g, TYPE_DBL);
vlp->F = dv;
vlp->Nd = nd;
vlp->DataType = TYPE_DBL;
} else {
long long iv = strtoll(buf, NULL, 10);
if (iv > INT_MAX32 || iv < INT_MIN32) {
// vlp = AllocVal(g, TYPE_BINT);
vlp->LLn = iv;
vlp->DataType = TYPE_BINT;
} else {
// vlp = AllocVal(g, TYPE_INTG);
vlp->N = (int)iv;
vlp->DataType = TYPE_INTG;
} // endif iv
} // endif has
i--; // Unstack following character
return;
} else
throw("No digit found");
err:
throw("Unexpected EOF in number");
} // end of ParseNumeric
/***********************************************************************/
/* Serialize a JSON Array. */
/***********************************************************************/
bool JDOC::SerializeArray(PJAR jarp, bool b)
{
bool first = true;
if (b) {
if (js->Prty()) {
if (js->WriteChr('['))
return true;
else if (js->Prty() == 1 && (js->WriteStr(EL) || js->WriteChr('\t')))
return true;
} // 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(jarp->GetArrayValue(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 JDOC::SerializeObject(PJOB jobp)
{
bool first = true;
if (js->WriteChr('{'))
return true;
for (PJPR pair = jobp->GetFirst(); 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(pair->Val))
return true;
} // endfor i
return js->WriteChr('}');
} // end of SerializeObject
/***********************************************************************/
/* Serialize a JSON Value. */
/***********************************************************************/
bool JDOC::SerializeValue(PJVAL jvp)
{
char buf[64];
PJAR jap;
PJOB jop;
//PVL vlp;
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 (jvp->DataType) {
case TYPE_BOOL:
return js->WriteStr(jvp->B ? "true" : "false");
case TYPE_STRG:
case TYPE_DTM:
return js->Escape(jvp->Strp);
case TYPE_INTG:
snprintf(buf, sizeof(buf), "%d", jvp->N);
return js->WriteStr(buf);
case TYPE_BINT:
snprintf(buf, sizeof(buf), "%lld", jvp->LLn);
return js->WriteStr(buf);
case TYPE_DBL: // dfp to limit to the default number of decimals
snprintf(buf, sizeof(buf), "%.*f", MY_MIN(jvp->Nd, dfp), jvp->F);
return js->WriteStr(buf);
case TYPE_NULL:
return js->WriteStr("null");
default:
return js->WriteStr("???"); // TODO
} // endswitch Type
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) {
int n = 0;
for (PJPR jpp = First; jpp; jpp = jpp->Next)
// If b return only non null pairs
if (!b || jpp->Val && !jpp->Val->IsNull())
n++;
return n;
} // end of GetSize
/***********************************************************************/
/* Add a new pair to an Object. */
/***********************************************************************/
PJPR JOBJECT::AddPair(PGLOBAL g, PCSZ key)
{
PJPR jpp = (PJPR)PlugSubAlloc(g, NULL, sizeof(JPAIR));
jpp->Key = key;
jpp->Next = NULL;
jpp->Val = NULL;
if (Last)
Last->Next = jpp;
else
First = jpp;
Last = jpp;
return jpp;
} // end of AddPair
/***********************************************************************/
/* Return all keys as an array. */
/***********************************************************************/
PJAR JOBJECT::GetKeyList(PGLOBAL g)
{
PJAR jarp = new(g) JARRAY();
for (PJPR jpp = First; jpp; jpp = jpp->Next)
jarp->AddArrayValue(g, new(g) JVALUE(g, jpp->Key));
jarp->InitArray(g);
return jarp;
} // end of GetKeyList
/***********************************************************************/
/* Return all values as an array. */
/***********************************************************************/
PJAR JOBJECT::GetValList(PGLOBAL g)
{
PJAR jarp = new(g) JARRAY();
for (PJPR jpp = First; jpp; jpp = jpp->Next)
jarp->AddArrayValue(g, jpp->Val);
jarp->InitArray(g);
return jarp;
} // end of GetValList
/***********************************************************************/
/* Get the value corresponding to the given key. */
/***********************************************************************/
PJVAL JOBJECT::GetKeyValue(const char* key)
{
for (PJPR jp = First; jp; jp = jp->Next)
if (!strcmp(jp->Key, key))
return jp->Val;
return NULL;
} // end of GetValue;
/***********************************************************************/
/* Return the text corresponding to all keys (XML like). */
/***********************************************************************/
PSZ JOBJECT::GetText(PGLOBAL g, PSTRG text)
{
if (First) {
bool b;
if (!text) {
text = new(g) STRING(g, 256);
b = true;
} else {
if (text->GetLastChar() != ' ')
text->Append(' ');
b = false;
} // endif text
if (b && !First->Next && !strcmp(First->Key, "$date")) {
int i;
PSZ s;
First->Val->GetText(g, text);
s = text->GetStr();
i = (s[1] == '-' ? 2 : 1);
if (IsNum(s + i)) {
// Date is in milliseconds
int j = text->GetLength();
if (j >= 4 + i) {
s[j - 3] = 0; // Change it to seconds
text->SetLength((uint)strlen(s));
} else
text->Set(" 0");
} // endif text
} else for (PJPR jp = First; jp; jp = jp->Next) {
jp->Val->GetText(g, text);
if (jp->Next)
text->Append(' ');
} // endfor jp
if (b) {
text->Trim();
return text->GetStr();
} // endif b
} // endif First
return NULL;
} // end of GetText;
/***********************************************************************/
/* Merge two objects. */
/***********************************************************************/
bool JOBJECT::Merge(PGLOBAL g, PJSON jsp)
{
if (jsp->GetType() != TYPE_JOB) {
snprintf(g->Message, sizeof(g->Message), "Second argument is not an object");
return true;
} // endif Type
PJOB jobp = (PJOB)jsp;
for (PJPR jpp = jobp->First; jpp; jpp = jpp->Next)
SetKeyValue(g, jpp->Val, jpp->Key);
return false;
} // end of Marge;
/***********************************************************************/
/* Set or add a value corresponding to the given key. */
/***********************************************************************/
void JOBJECT::SetKeyValue(PGLOBAL g, PJVAL jvp, PCSZ key)
{
PJPR jp;
for (jp = First; jp; jp = jp->Next)
if (!strcmp(jp->Key, key)) {
jp->Val = jvp;
break;
} // endif key
if (!jp) {
jp = AddPair(g, key);
jp->Val = jvp;
} // endif jp
} // end of SetValue
/***********************************************************************/
/* Delete a value corresponding to the given key. */
/***********************************************************************/
void JOBJECT::DeleteKey(PCSZ key)
{
PJPR jp, *pjp = &First;
for (jp = First; jp; jp = jp->Next)
if (!strcmp(jp->Key, key)) {
*pjp = jp->Next;
break;
} else
pjp = &jp->Next;
} // end of DeleteKey
/***********************************************************************/
/* True if void or if all members are nulls. */
/***********************************************************************/
bool JOBJECT::IsNull(void)
{
for (PJPR jp = First; jp; jp = jp->Next)
if (!jp->Val->IsNull())
return false;
return true;
} // end of IsNull
/* -------------------------- 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. */
/***********************************************************************/
int JARRAY::GetSize(bool b)
{
if (b) {
// Return only non null values
int n = 0;
for (PJVAL jvp = First; jvp; jvp = jvp->Next)
if (!jvp->IsNull())
n++;
return n;
} else
return Size;
} // end of GetSize
/***********************************************************************/
/* Make the array of values from the values list. */
/***********************************************************************/
void JARRAY::InitArray(PGLOBAL g)
{
int i;
PJVAL jvp, *pjvp = &First;
for (Size = 0, jvp = First; jvp; jvp = jvp->Next)
if (!jvp->Del)
Size++;
if (Size > Alloc) {
// No need to realloc after deleting values
Mvals = (PJVAL*)PlugSubAlloc(g, NULL, Size * sizeof(PJVAL));
Alloc = Size;
} // 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;
} // end of InitArray
/***********************************************************************/
/* Get the Nth value of an Array. */
/***********************************************************************/
PJVAL JARRAY::GetArrayValue(int i)
{
if (Mvals && i >= 0 && i < Size)
return Mvals[i];
else if (Mvals && i < 0 && i >= -Size)
return Mvals[Size + i];
else
return NULL;
} // end of GetValue
/***********************************************************************/
/* Add a Value to the Array Value list. */
/***********************************************************************/
PJVAL JARRAY::AddArrayValue(PGLOBAL g, PJVAL jvp, int *x)
{
if (!jvp)
jvp = new(g) JVALUE;
if (x) {
int i = 0, n = *x;
PJVAL jp, *jpp = &First;
for (jp = First; jp && i < n; i++, jp = *(jpp = &jp->Next));
(*jpp) = jvp;
if (!(jvp->Next = jp))
Last = 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
return jvp;
} // end of AddValue
/***********************************************************************/
/* Merge two arrays. */
/***********************************************************************/
bool JARRAY::Merge(PGLOBAL g, PJSON jsp)
{
if (jsp->GetType() != TYPE_JAR) {
snprintf(g->Message, sizeof(g->Message), "Second argument is not an array");
return true;
} // endif Type
PJAR arp = (PJAR)jsp;
for (int i = 0; i < arp->size(); i++)
AddArrayValue(g, arp->GetArrayValue(i));
InitArray(g);
return false;
} // end of Merge
/***********************************************************************/
/* Set the nth Value of the Array Value list or add it. */
/***********************************************************************/
void JARRAY::SetArrayValue(PGLOBAL g, PJVAL jvp, int n)
{
int i = 0;
PJVAL jp, *jpp = &First;
for (jp = First; i < n; i++, jp = *(jpp = &jp->Next))
if (!jp)
*jpp = jp = new(g) JVALUE;
*jpp = jvp;
jvp->Next = (jp ? jp->Next : NULL);
} // end of SetValue
/***********************************************************************/
/* Return the text corresponding to all values. */
/***********************************************************************/
PSZ JARRAY::GetText(PGLOBAL g, PSTRG text)
{
if (First) {
bool b;
PJVAL jp;
if (!text) {
text = new(g) STRING(g, 256);
b = true;
} else {
if (text->GetLastChar() != ' ')
text->Append(" (");
else
text->Append('(');
b = false;
}
for (jp = First; jp; jp = jp->Next) {
jp->GetText(g, text);
if (jp->Next)
text->Append(", ");
else if (!b)
text->Append(')');
} // endfor jp
if (b) {
text->Trim();
return text->GetStr();
} // endif b
} // endif First
return NULL;
} // end of GetText;
/***********************************************************************/
/* Delete a Value from the Arrays Value list. */
/***********************************************************************/
bool JARRAY::DeleteValue(int n)
{
PJVAL jvp = GetArrayValue(n);
if (jvp) {
jvp->Del = true;
return false;
} else
return true;
} // end of DeleteValue
/***********************************************************************/
/* True if void or if all members are nulls. */
/***********************************************************************/
bool JARRAY::IsNull(void)
{
for (int i = 0; i < Size; i++)
if (!Mvals[i]->IsNull())
return false;
return true;
} // end of IsNull
/* -------------------------- Class JVALUE- -------------------------- */
/***********************************************************************/
/* Constructor for a JVALUE. */
/***********************************************************************/
JVALUE::JVALUE(PJSON jsp) : JSON()
{
if (jsp && jsp->GetType() == TYPE_JVAL) {
PJVAL jvp = (PJVAL)jsp;
// Val = ((PJVAL)jsp)->GetVal();
if (jvp->DataType == TYPE_JSON) {
Jsp = jvp->GetJsp();
DataType = TYPE_JSON;
Nd = 0;
} else {
LLn = jvp->LLn; // Must be LLn on 32 bit machines
Nd = jvp->Nd;
DataType = jvp->DataType;
} // endelse Jsp
} else {
Jsp = jsp;
// Val = NULL;
DataType = Jsp ? TYPE_JSON : TYPE_NULL;
Nd = 0;
} // endif Type
Next = NULL;
Del = false;
Type = TYPE_JVAL;
} // end of JVALUE constructor
#if 0
/***********************************************************************/
/* Constructor for a JVALUE with a given string or numeric value. */
/***********************************************************************/
JVALUE::JVALUE(PGLOBAL g, PVL vlp) : JSON()
{
Jsp = NULL;
Val = vlp;
Next = NULL;
Del = false;
Type = TYPE_JVAL;
} // end of JVALUE constructor
#endif // 0
/***********************************************************************/
/* Constructor for a JVALUE 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
/***********************************************************************/
/* Constructor for a given string. */
/***********************************************************************/
JVALUE::JVALUE(PGLOBAL g, PCSZ strp) : JSON()
{
Jsp = NULL;
//Val = AllocVal(g, TYPE_STRG);
Strp = (char*)strp;
DataType = TYPE_STRG;
Nd = 0;
Next = NULL;
Del = false;
Type = TYPE_JVAL;
} // end of JVALUE constructor
/***********************************************************************/
/* Set or reset all Jvalue members. */
/***********************************************************************/
void JVALUE::Clear(void)
{
Jsp = NULL;
Next = NULL;
Type = TYPE_JVAL;
Del = false;
Nd = 0;
DataType = TYPE_NULL;
} // end of Clear
/***********************************************************************/
/* Returns the type of the Value's value. */
/***********************************************************************/
JTYP JVALUE::GetValType(void)
{
if (DataType == TYPE_JSON)
return Jsp->GetType();
//else if (Val)
// return Val->Type;
else
return DataType;
} // end of GetValType
/***********************************************************************/
/* Return the Value's Object value. */
/***********************************************************************/
PJOB JVALUE::GetObject(void)
{
if (DataType == TYPE_JSON && Jsp->GetType() == TYPE_JOB)
return (PJOB)Jsp;
return NULL;
} // end of GetObject
/***********************************************************************/
/* Return the Value's Array value. */
/***********************************************************************/
PJAR JVALUE::GetArray(void)
{
if (DataType == TYPE_JSON && Jsp->GetType() == TYPE_JAR)
return (PJAR)Jsp;
return NULL;
} // end of GetArray
/***********************************************************************/
/* Return the Value's as a Value class. */
/***********************************************************************/
PVAL JVALUE::GetValue(PGLOBAL g)
{
PVAL valp = NULL;
if (DataType != TYPE_JSON)
if (DataType == TYPE_STRG)
valp = AllocateValue(g, Strp, DataType, Nd);
else
valp = AllocateValue(g, &LLn, DataType, Nd);
return valp;
} // end of GetValue
/***********************************************************************/
/* Return the Value's Integer value. */
/***********************************************************************/
int JVALUE::GetInteger(void) {
int n;
switch (DataType) {
case TYPE_INTG: n = N; break;
case TYPE_DBL: n = (int)F; break;
case TYPE_DTM:
case TYPE_STRG: n = atoi(Strp); break;
case TYPE_BOOL: n = (B) ? 1 : 0; break;
case TYPE_BINT: n = (int)LLn; break;
default:
n = 0;
} // endswitch Type
return n;
} // end of GetInteger
/***********************************************************************/
/* Return the Value's Big integer value. */
/***********************************************************************/
long long JVALUE::GetBigint(void)
{
long long lln;
switch (DataType) {
case TYPE_BINT: lln = LLn; break;
case TYPE_INTG: lln = (long long)N; break;
case TYPE_DBL: lln = (long long)F; break;
case TYPE_DTM:
case TYPE_STRG: lln = atoll(Strp); break;
case TYPE_BOOL: lln = (B) ? 1 : 0; break;
default:
lln = 0;
} // endswitch Type
return lln;
} // end of GetBigint
/***********************************************************************/
/* Return the Value's Double value. */
/***********************************************************************/
double JVALUE::GetFloat(void)
{
double d;
switch (DataType) {
case TYPE_DBL: d = F; break;
case TYPE_BINT: d = (double)LLn; break;
case TYPE_INTG: d = (double)N; break;
case TYPE_DTM:
case TYPE_STRG: d = atof(Strp); break;
case TYPE_BOOL: d = (B) ? 1.0 : 0.0; break;
default:
d = 0.0;
} // endswitch Type
return d;
} // end of GetFloat
/***********************************************************************/
/* Return the Value's String value. */
/***********************************************************************/
PSZ JVALUE::GetString(PGLOBAL g, char *buff)
{
char buf[32];
char *p = (buff) ? buff : buf;
switch (DataType) {
case TYPE_DTM:
case TYPE_STRG:
p = Strp;
break;
case TYPE_INTG:
sprintf(p, "%d", N);
break;
case TYPE_BINT:
sprintf(p, "%lld", LLn);
break;
case TYPE_DBL:
sprintf(p, "%.*lf", Nd, F);
break;
case TYPE_BOOL:
p = (char*)((B) ? "true" : "false");
break;
case TYPE_NULL:
p = (char*)"null";
break;
default:
p = NULL;
} // endswitch Type
return (p == buf) ? (char*)PlugDup(g, buf) : p;
} // end of GetString
/***********************************************************************/
/* Return the Value's String value. */
/***********************************************************************/
PSZ JVALUE::GetText(PGLOBAL g, PSTRG text)
{
if (DataType == TYPE_JSON)
return Jsp->GetText(g, text);
char buff[32];
PSZ s = (DataType == TYPE_NULL) ? NULL : GetString(g, buff);
if (s)
text->Append(s);
else if (GetJsonNull())
text->Append(GetJsonNull());
return NULL;
} // end of GetText
void JVALUE::SetValue(PJSON jsp)
{
if (DataType == TYPE_JSON && jsp->GetType() == TYPE_JVAL) {
Jsp = jsp->GetJsp();
Nd = ((PJVAL)jsp)->Nd;
DataType = ((PJVAL)jsp)->DataType;
// Val = ((PJVAL)jsp)->GetVal();
} else {
Jsp = jsp;
DataType = TYPE_JSON;
} // endif Type
} // end of SetValue;
void JVALUE::SetValue(PGLOBAL g, PVAL valp)
{
//if (!Val)
// Val = AllocVal(g, TYPE_VAL);
if (!valp || valp->IsNull()) {
DataType = TYPE_NULL;
} else switch (valp->GetType()) {
case TYPE_DATE:
if (((DTVAL*)valp)->IsFormatted())
Strp = PlugDup(g, valp->GetCharValue());
else {
char buf[32];
Strp = PlugDup(g, valp->GetCharString(buf));
} // endif Formatted
DataType = TYPE_DTM;
break;
case TYPE_STRING:
Strp = PlugDup(g, valp->GetCharValue());
DataType = TYPE_STRG;
break;
case TYPE_DOUBLE:
case TYPE_DECIM:
F = valp->GetFloatValue();
if (IsTypeNum(valp->GetType()))
Nd = valp->GetValPrec();
DataType = TYPE_DBL;
break;
case TYPE_TINY:
B = valp->GetTinyValue() != 0;
DataType = TYPE_BOOL;
case TYPE_INT:
N = valp->GetIntValue();
DataType = TYPE_INTG;
break;
case TYPE_BIGINT:
LLn = valp->GetBigintValue();
DataType = TYPE_BINT;
break;
default:
snprintf(g->Message, sizeof(g->Message), "Unsupported typ %d\n", valp->GetType());
throw(777);
} // endswitch Type
} // end of SetValue
/***********************************************************************/
/* Set the Value's value as the given integer. */
/***********************************************************************/
void JVALUE::SetInteger(PGLOBAL g, int n)
{
N = n;
DataType = TYPE_INTG;
} // end of SetInteger
/***********************************************************************/
/* Set the Value's Boolean value as a tiny integer. */
/***********************************************************************/
void JVALUE::SetBool(PGLOBAL g, bool b)
{
B = b;
DataType = TYPE_BOOL;
} // end of SetTiny
/***********************************************************************/
/* Set the Value's value as the given big integer. */
/***********************************************************************/
void JVALUE::SetBigint(PGLOBAL g, long long ll)
{
LLn = ll;
DataType = TYPE_BINT;
} // end of SetBigint
/***********************************************************************/
/* Set the Value's value as the given DOUBLE. */
/***********************************************************************/
void JVALUE::SetFloat(PGLOBAL g, double f)
{
F = f;
Nd = GetDefaultPrec();
DataType = TYPE_DBL;
} // end of SetFloat
/***********************************************************************/
/* Set the Value's value as the given string. */
/***********************************************************************/
void JVALUE::SetString(PGLOBAL g, PSZ s, int ci)
{
Strp = s;
Nd = ci;
DataType = TYPE_STRG;
} // end of SetString
/***********************************************************************/
/* True when its JSON or normal value is null. */
/***********************************************************************/
bool JVALUE::IsNull(void)
{
return (DataType == TYPE_JSON) ? Jsp->IsNull() : DataType == TYPE_NULL;
} // 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 = 0;
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->Mvals = (PJVAL*)MakeOff(Base, jarp->Mvals);
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->DataType == TYPE_JSON)
jvp->Jsp = (PJSON)MoffJson(jvp->Jsp);
else if (jvp->DataType == TYPE_STRG)
jvp->Strp = (PSZ)MakeOff(Base, (jvp->Strp));
// 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
#if 0
/***********************************************************************/
/* 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
#endif // 0
/***********************************************************************/
/* 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((long long)jarp) JARRAY(0);
if (jarp->First) {
jarp->Mvals = (PJVAL*)MakePtr(Base, (size_t)jarp->Mvals);
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((long long)jobp) JOBJECT(0);
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((long long)jvp) JVALUE(0);
if (!jvp->Del) {
if (jvp->DataType == TYPE_JSON)
jvp->Jsp = (PJSON)MptrJson(jvp->Jsp);
else if (jvp->DataType == TYPE_STRG)
jvp->Strp = (PSZ)MakePtr(Base, (size_t)jvp->Strp);
// 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
#if 0
/***********************************************************************/
/* 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
#endif // 0