mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 02:46:29 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			2066 lines
		
	
	
	
		
			55 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			2066 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)
 | |
| 
 | |
| #define EL "\n"
 | |
| #if !defined(_WIN32)
 | |
| #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;
 | |
|     break;
 | |
|   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
 | 
