mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1795 lines
		
	
	
	
		
			48 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1795 lines
		
	
	
	
		
			48 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*************** bson CPP Declares Source Code File (.H) ***************/
 | 
						|
/*  Name: bson.cpp   Version 1.0                                       */
 | 
						|
/*                                                                     */
 | 
						|
/*  (C) Copyright to the author Olivier BERTRAND          2020         */
 | 
						|
/*                                                                     */
 | 
						|
/*  This file contains the BJSON 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.  */
 | 
						|
/*  bson.h      is header containing the BSON classes declarations.    */
 | 
						|
/***********************************************************************/
 | 
						|
#include "global.h"
 | 
						|
#include "plgdbsem.h"
 | 
						|
#include "bson.h"
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Check macro.                                                       */
 | 
						|
/***********************************************************************/
 | 
						|
#if defined(_DEBUG)
 | 
						|
#define CheckType(X,Y) if (!X || X ->Type != Y) throw MSG(VALTYPE_NOMATCH);
 | 
						|
#else
 | 
						|
#define CheckType(X,Y)
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(_WIN32)
 | 
						|
#define EL  "\r\n"
 | 
						|
#else
 | 
						|
#define EL  "\n"
 | 
						|
#undef     SE_CATCH                  // Does not work for Linux
 | 
						|
#endif
 | 
						|
 | 
						|
int GetJsonDefPrec(void);
 | 
						|
 | 
						|
#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
 | 
						|
 | 
						|
/* --------------------------- Class BDOC ---------------------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  BDOC constructor.                                                  */
 | 
						|
/***********************************************************************/
 | 
						|
BDOC::BDOC(PGLOBAL G) : BJSON(G, NULL)
 | 
						|
{ 
 | 
						|
  jp = NULL;
 | 
						|
  s = NULL;
 | 
						|
  len = 0;
 | 
						|
  pretty = 3;
 | 
						|
  pty[0] = pty[1] = pty[2] = true;
 | 
						|
  comma = false;
 | 
						|
} // end of BDOC constructor
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Parse a json string.                                                */
 | 
						|
/* Note: when pretty is not known, the caller set pretty to 3.         */
 | 
						|
/***********************************************************************/
 | 
						|
PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng)
 | 
						|
{
 | 
						|
  size_t i;
 | 
						|
  bool  b = false;
 | 
						|
  PBVAL bvp = NULL;
 | 
						|
 | 
						|
  s = js;
 | 
						|
  len = lng;
 | 
						|
  xtrc(1, "BDOC::ParseJson: s=%.10s len=%zd\n", s, len);
 | 
						|
 | 
						|
  if (!s || !len) {
 | 
						|
    strcpy(g->Message, "Void JSON object");
 | 
						|
    return NULL;
 | 
						|
  } // endif s
 | 
						|
 | 
						|
  // Trying to guess the pretty format
 | 
						|
  if (s[0] == '[' && (s[1] == '\n' || (s[1] == '\r' && s[2] == '\n')))
 | 
						|
    pty[0] = false;
 | 
						|
 | 
						|
  try {
 | 
						|
    bvp = NewVal();
 | 
						|
    bvp->Type = TYPE_UNKNOWN;
 | 
						|
 | 
						|
    for (i = 0; i < len; i++)
 | 
						|
      switch (s[i]) {
 | 
						|
      case '[':
 | 
						|
        if (bvp->Type != TYPE_UNKNOWN)
 | 
						|
          bvp->To_Val = ParseAsArray(i);
 | 
						|
        else
 | 
						|
          bvp->To_Val = ParseArray(++i);
 | 
						|
 | 
						|
        bvp->Type = TYPE_JAR;
 | 
						|
        break;
 | 
						|
      case '{':
 | 
						|
        if (bvp->Type != TYPE_UNKNOWN) {
 | 
						|
          bvp->To_Val = ParseAsArray(i);
 | 
						|
          bvp->Type = TYPE_JAR;
 | 
						|
        } else {
 | 
						|
          bvp->To_Val = ParseObject(++i);
 | 
						|
          bvp->Type = TYPE_JOB;
 | 
						|
        } // endif Type
 | 
						|
 | 
						|
        break;
 | 
						|
      case ' ':
 | 
						|
      case '\t':
 | 
						|
      case '\n':
 | 
						|
      case '\r':
 | 
						|
        break;
 | 
						|
      case ',':
 | 
						|
        if (bvp->Type != TYPE_UNKNOWN && (pretty == 1 || pretty == 3)) {
 | 
						|
          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
 | 
						|
        /* fall through */
 | 
						|
      default:
 | 
						|
        if (bvp->Type != TYPE_UNKNOWN) {
 | 
						|
          bvp->To_Val = ParseAsArray(i);
 | 
						|
          bvp->Type = TYPE_JAR;
 | 
						|
        } else if ((bvp->To_Val = MOF(ParseValue(i, NewVal()))))
 | 
						|
          bvp->Type = TYPE_JVAL;
 | 
						|
        else
 | 
						|
          throw 4;
 | 
						|
 | 
						|
        break;
 | 
						|
      }; // endswitch s[i]
 | 
						|
 | 
						|
    if (bvp->Type == TYPE_UNKNOWN)
 | 
						|
      snprintf(g->Message, sizeof(g->Message), "Invalid Json string '%.*s'", MY_MIN((int)len, 50), s);
 | 
						|
    else if (pretty == 3) {
 | 
						|
      for (i = 0; i < 3; i++)
 | 
						|
        if (pty[i]) {
 | 
						|
          pretty = i;
 | 
						|
          break;
 | 
						|
        } // endif pty
 | 
						|
 | 
						|
    } // endif ptyp
 | 
						|
 | 
						|
  } catch (int n) {
 | 
						|
    if (trace(1))
 | 
						|
      htrc("Exception %d: %s\n", n, G->Message);
 | 
						|
    GetMsg(g);
 | 
						|
    bvp = NULL;
 | 
						|
  } catch (const char* msg) {
 | 
						|
    strcpy(g->Message, msg);
 | 
						|
    bvp = NULL;
 | 
						|
  } // end catch
 | 
						|
 | 
						|
  return bvp;
 | 
						|
} // end of ParseJson
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Parse several items as being in an array.                           */
 | 
						|
/***********************************************************************/
 | 
						|
OFFSET BDOC::ParseAsArray(size_t& i) {
 | 
						|
  if (pty[0] && (!pretty || pretty > 2)) {
 | 
						|
    OFFSET jsp;
 | 
						|
 | 
						|
    if ((jsp = ParseArray((i = 0))) && pretty == 3)
 | 
						|
      pretty = (pty[0]) ? 0 : 3;
 | 
						|
 | 
						|
    return jsp;
 | 
						|
  } else
 | 
						|
    strcpy(G->Message, "More than one item in file");
 | 
						|
 | 
						|
  return 0;
 | 
						|
} // end of ParseAsArray
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Parse a JSON Array.                                                 */
 | 
						|
/***********************************************************************/
 | 
						|
OFFSET BDOC::ParseArray(size_t& i)
 | 
						|
{
 | 
						|
  int   level = 0;
 | 
						|
  bool  b = (!i);
 | 
						|
  PBVAL vlp, firstvlp, lastvlp;
 | 
						|
 | 
						|
  vlp = firstvlp = lastvlp = NULL;
 | 
						|
 | 
						|
  for (; i < len; i++)
 | 
						|
    switch (s[i]) {
 | 
						|
    case ',':
 | 
						|
      if (level < 2) {
 | 
						|
        snprintf(G->Message, sizeof(G->Message), "Unexpected ',' near %.*s", (int) ARGS);
 | 
						|
        throw 1;
 | 
						|
      } else
 | 
						|
        level = 1;
 | 
						|
 | 
						|
      break;
 | 
						|
    case ']':
 | 
						|
      if (level == 1) {
 | 
						|
        snprintf(G->Message, sizeof(G->Message), "Unexpected ',]' near %.*s", (int) ARGS);
 | 
						|
        throw 1;
 | 
						|
      } // endif level
 | 
						|
 | 
						|
      return MOF(firstvlp);
 | 
						|
    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", (int) ARGS);
 | 
						|
        throw 1;
 | 
						|
      } else if (lastvlp) {
 | 
						|
        vlp = ParseValue(i, NewVal());
 | 
						|
        lastvlp->Next = MOF(vlp);
 | 
						|
        lastvlp = vlp;
 | 
						|
      } else
 | 
						|
        firstvlp = lastvlp = ParseValue(i, NewVal());
 | 
						|
 | 
						|
      level = (b) ? 1 : 2;
 | 
						|
      break;
 | 
						|
    }; // endswitch s[i]
 | 
						|
 | 
						|
  if (b) {
 | 
						|
    // Case of Pretty == 0
 | 
						|
    return MOF(firstvlp);
 | 
						|
  } // endif b
 | 
						|
 | 
						|
  throw ("Unexpected EOF in array");
 | 
						|
} // end of ParseArray
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Parse a JSON Object.                                                */
 | 
						|
/***********************************************************************/
 | 
						|
OFFSET BDOC::ParseObject(size_t& i)
 | 
						|
{
 | 
						|
  OFFSET key;
 | 
						|
  int    level = 0;
 | 
						|
  PBPR   bpp, firstbpp, lastbpp;
 | 
						|
 | 
						|
  bpp = firstbpp = lastbpp = NULL;
 | 
						|
 | 
						|
  for (; i < len; i++)
 | 
						|
    switch (s[i]) {
 | 
						|
    case '"':
 | 
						|
      if (level < 2) {
 | 
						|
        key = ParseString(++i);
 | 
						|
        bpp = NewPair(key);
 | 
						|
 | 
						|
        if (lastbpp) {
 | 
						|
          lastbpp->Vlp.Next = MOF(bpp);
 | 
						|
          lastbpp = bpp;
 | 
						|
        } else 
 | 
						|
          firstbpp = lastbpp = bpp;
 | 
						|
 | 
						|
        level = 2;
 | 
						|
      } else {
 | 
						|
        snprintf(G->Message, sizeof(G->Message), "misplaced string near %.*s", (int) ARGS);
 | 
						|
        throw 2;
 | 
						|
      } // endif level
 | 
						|
 | 
						|
      break;
 | 
						|
    case ':':
 | 
						|
      if (level == 2) {
 | 
						|
        ParseValue(++i, GetVlp(lastbpp));
 | 
						|
        level = 3;
 | 
						|
      } else {
 | 
						|
        snprintf(G->Message, sizeof(G->Message), "Unexpected ':' near %.*s", (int) ARGS);
 | 
						|
        throw 2;
 | 
						|
      } // endif level
 | 
						|
 | 
						|
      break;
 | 
						|
    case ',':
 | 
						|
      if (level < 3) {
 | 
						|
        snprintf(G->Message, sizeof(G->Message), "Unexpected ',' near %.*s", (int) ARGS);
 | 
						|
        throw 2;
 | 
						|
      } else
 | 
						|
        level = 1;
 | 
						|
 | 
						|
      break;
 | 
						|
    case '}':
 | 
						|
      if (!(level == 0 || level == 3)) {
 | 
						|
        snprintf(G->Message, sizeof(G->Message), "Unexpected '}' near %.*s", (int) ARGS);
 | 
						|
        throw 2;
 | 
						|
      } // endif level
 | 
						|
 | 
						|
      return MOF(firstbpp);
 | 
						|
    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], (int) ARGS);
 | 
						|
      throw 2;
 | 
						|
    }; // endswitch s[i]
 | 
						|
 | 
						|
  strcpy(G->Message, "Unexpected EOF in Object");
 | 
						|
  throw 2;
 | 
						|
} // end of ParseObject
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Parse a JSON Value.                                                 */
 | 
						|
/***********************************************************************/
 | 
						|
PBVAL BDOC::ParseValue(size_t& i, PBVAL bvp)
 | 
						|
{
 | 
						|
  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 '[':
 | 
						|
    bvp->To_Val = ParseArray(++i);
 | 
						|
    bvp->Type = TYPE_JAR;
 | 
						|
    break;
 | 
						|
  case '{':
 | 
						|
    bvp->To_Val = ParseObject(++i);
 | 
						|
    bvp->Type = TYPE_JOB;
 | 
						|
    break;
 | 
						|
  case '"':
 | 
						|
    bvp->To_Val = ParseString(++i);
 | 
						|
    bvp->Type = TYPE_STRG;
 | 
						|
    break;
 | 
						|
  case 't':
 | 
						|
    if (!strncmp(s + i, "true", 4)) {
 | 
						|
      bvp->B = true;
 | 
						|
      bvp->Type = TYPE_BOOL;
 | 
						|
      i += 3;
 | 
						|
    } else
 | 
						|
      goto err;
 | 
						|
 | 
						|
    break;
 | 
						|
  case 'f':
 | 
						|
    if (!strncmp(s + i, "false", 5)) {
 | 
						|
      bvp->B = false;
 | 
						|
      bvp->Type = TYPE_BOOL;
 | 
						|
      i += 4;
 | 
						|
    } else
 | 
						|
      goto err;
 | 
						|
 | 
						|
    break;
 | 
						|
  case 'n':
 | 
						|
    if (!strncmp(s + i, "null", 4)) {
 | 
						|
      bvp->Type = TYPE_NULL;
 | 
						|
      i += 3;
 | 
						|
    } else
 | 
						|
      goto err;
 | 
						|
 | 
						|
    break;
 | 
						|
  case '-':
 | 
						|
  default:
 | 
						|
    if (s[i] == '-' || isdigit(s[i]))
 | 
						|
      ParseNumeric(i, bvp);
 | 
						|
    else
 | 
						|
      goto err;
 | 
						|
 | 
						|
  }; // endswitch s[i]
 | 
						|
 | 
						|
  return bvp;
 | 
						|
 | 
						|
err:
 | 
						|
  snprintf(G->Message, sizeof(G->Message), "Unexpected character '%c' near %.*s", s[i], (int) ARGS);
 | 
						|
  throw 3;
 | 
						|
} // end of ParseValue
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Unescape and parse a JSON string.                                  */
 | 
						|
/***********************************************************************/
 | 
						|
OFFSET BDOC::ParseString(size_t& 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*)BsonSubAlloc(0);
 | 
						|
 | 
						|
  for (; i < len; i++)
 | 
						|
    switch (s[i]) {
 | 
						|
    case '"':
 | 
						|
      p[n++] = 0;
 | 
						|
      BsonSubAlloc(n);
 | 
						|
      return MOF(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 BDOC::ParseNumeric(size_t& i, PBVAL vlp)
 | 
						|
{
 | 
						|
  char  buf[50];
 | 
						|
  int   n = 0;
 | 
						|
  short nd = 0;
 | 
						|
  bool  has_dot = false;
 | 
						|
  bool  has_e = false;
 | 
						|
  bool  found_digit = false;
 | 
						|
 | 
						|
  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 = atof(buf);
 | 
						|
 | 
						|
      if (nd >= 6 || dv > FLT_MAX || dv < FLT_MIN) {
 | 
						|
        double* dvp = (double*)PlugSubAlloc(G, NULL, sizeof(double));
 | 
						|
 | 
						|
        *dvp = dv;
 | 
						|
        vlp->To_Val = MOF(dvp);
 | 
						|
        vlp->Type = TYPE_DBL;
 | 
						|
      } else {
 | 
						|
        vlp->F = (float)dv;
 | 
						|
        vlp->Type = TYPE_FLOAT;
 | 
						|
      } // endif nd
 | 
						|
 | 
						|
      vlp->Nd = MY_MIN(nd, 16);
 | 
						|
    } else {
 | 
						|
      longlong iv = strtoll(buf, NULL, 10);
 | 
						|
 | 
						|
      if (iv > INT_MAX32 || iv < INT_MIN32) {
 | 
						|
        longlong *llp = (longlong*)PlugSubAlloc(G, NULL, sizeof(longlong));
 | 
						|
 | 
						|
        *llp = iv;
 | 
						|
        vlp->To_Val = MOF(llp);
 | 
						|
        vlp->Type = TYPE_BINT;
 | 
						|
      } else {
 | 
						|
        vlp->N = (int)iv;
 | 
						|
        vlp->Type = 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 BJSON document tree:                                    */
 | 
						|
/***********************************************************************/
 | 
						|
PSZ BDOC::Serialize(PGLOBAL g, PBVAL bvp, char* fn, int pretty)
 | 
						|
{
 | 
						|
  PSZ   str = NULL;
 | 
						|
  bool  b = false, err = true;
 | 
						|
  FILE* fs = NULL;
 | 
						|
 | 
						|
  G->Message[0] = 0;
 | 
						|
 | 
						|
  try {
 | 
						|
    if (!bvp) {
 | 
						|
      safe_strcpy(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
 | 
						|
 | 
						|
    switch (bvp->Type) {
 | 
						|
    case TYPE_JAR:
 | 
						|
      err = SerializeArray(bvp->To_Val, b);
 | 
						|
      break;
 | 
						|
    case TYPE_JOB:
 | 
						|
      err = ((b && jp->Prty()) && jp->WriteChr('\t'));
 | 
						|
      err |= SerializeObject(bvp->To_Val);
 | 
						|
      break;
 | 
						|
    case TYPE_JVAL:
 | 
						|
      err = SerializeValue(MVP(bvp->To_Val));
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      err = SerializeValue(bvp, true);
 | 
						|
    } // endswitch Type
 | 
						|
 | 
						|
    if (fs) {
 | 
						|
      fputs(EL, fs);
 | 
						|
      fclose(fs);
 | 
						|
      str = (err) ? NULL : strcpy(g->Message, "Ok");
 | 
						|
    } else if (!err) {
 | 
						|
      str = ((JOUTSTR*)jp)->Strp;
 | 
						|
      jp->WriteChr('\0');
 | 
						|
      PlugSubAlloc(g, NULL, ((JOUTSTR*)jp)->N);
 | 
						|
    } else if (G->Message[0])
 | 
						|
        strcpy(g->Message, "Error in Serialize");
 | 
						|
      else
 | 
						|
        GetMsg(g);
 | 
						|
 | 
						|
  } catch (int n) {
 | 
						|
    if (trace(1))
 | 
						|
      htrc("Exception %d: %s\n", n, G->Message);
 | 
						|
    GetMsg(g);
 | 
						|
    str = NULL;
 | 
						|
  } catch (const char* msg) {
 | 
						|
    strcpy(g->Message, msg);
 | 
						|
    str = NULL;
 | 
						|
  } // end catch
 | 
						|
 | 
						|
  return str;
 | 
						|
} // end of Serialize
 | 
						|
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Serialize a JSON Array.                                             */
 | 
						|
/***********************************************************************/
 | 
						|
bool BDOC::SerializeArray(OFFSET arp, bool b)
 | 
						|
{
 | 
						|
  bool  first = true;
 | 
						|
  PBVAL vp = MVP(arp);
 | 
						|
 | 
						|
  if (b) {
 | 
						|
    if (jp->Prty()) {
 | 
						|
      if (jp->WriteChr('['))
 | 
						|
        return true;
 | 
						|
      else if (jp->Prty() == 1 && (jp->WriteStr(EL) || jp->WriteChr('\t')))
 | 
						|
        return true;
 | 
						|
 | 
						|
    } // endif Prty
 | 
						|
 | 
						|
  } else if (jp->WriteChr('['))
 | 
						|
    return true;
 | 
						|
 | 
						|
  for (; vp; vp = MVP(vp->Next)) {
 | 
						|
    if (first)
 | 
						|
      first = false;
 | 
						|
    else if ((!b || jp->Prty()) && jp->WriteChr(','))
 | 
						|
      return true;
 | 
						|
    else if (b) {
 | 
						|
      if (jp->Prty() < 2 && jp->WriteStr(EL))
 | 
						|
        return true;
 | 
						|
      else if (jp->Prty() == 1 && jp->WriteChr('\t'))
 | 
						|
        return true;
 | 
						|
 | 
						|
    } // endif b
 | 
						|
 | 
						|
    if (SerializeValue(vp))
 | 
						|
      return true;
 | 
						|
 | 
						|
  } // endfor vp
 | 
						|
 | 
						|
  if (b && jp->Prty() == 1 && jp->WriteStr(EL))
 | 
						|
    return true;
 | 
						|
 | 
						|
  return ((!b || jp->Prty()) && jp->WriteChr(']'));
 | 
						|
} // end of SerializeArray
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Serialize a JSON Object.                                            */
 | 
						|
/***********************************************************************/
 | 
						|
bool BDOC::SerializeObject(OFFSET obp)
 | 
						|
{
 | 
						|
  bool first = true;
 | 
						|
  PBPR prp = MPP(obp);
 | 
						|
 | 
						|
  if (jp->WriteChr('{'))
 | 
						|
    return true;
 | 
						|
 | 
						|
  for (; prp; prp = GetNext(prp)) {
 | 
						|
    if (first)
 | 
						|
      first = false;
 | 
						|
    else if (jp->WriteChr(','))
 | 
						|
      return true;
 | 
						|
 | 
						|
    if (jp->WriteChr('"') ||
 | 
						|
      jp->WriteStr(MZP(prp->Key)) ||
 | 
						|
      jp->WriteChr('"') ||
 | 
						|
      jp->WriteChr(':') ||
 | 
						|
      SerializeValue(GetVlp(prp)))
 | 
						|
      return true;
 | 
						|
 | 
						|
  } // endfor i
 | 
						|
 | 
						|
  return jp->WriteChr('}');
 | 
						|
} // end of SerializeObject
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Serialize a JSON Value.                                             */
 | 
						|
/***********************************************************************/
 | 
						|
bool BDOC::SerializeValue(PBVAL jvp, bool b)
 | 
						|
{
 | 
						|
  char buf[64];
 | 
						|
 | 
						|
  if (jvp) switch (jvp->Type) {
 | 
						|
  case TYPE_JAR:
 | 
						|
    return SerializeArray(jvp->To_Val, false);
 | 
						|
  case TYPE_JOB:
 | 
						|
    return SerializeObject(jvp->To_Val);
 | 
						|
  case TYPE_BOOL:
 | 
						|
    return jp->WriteStr(jvp->B ? "true" : "false");
 | 
						|
  case TYPE_STRG:
 | 
						|
  case TYPE_DTM:
 | 
						|
    if (b) {
 | 
						|
      return jp->WriteStr(MZP(jvp->To_Val));
 | 
						|
    } else
 | 
						|
      return jp->Escape(MZP(jvp->To_Val));
 | 
						|
 | 
						|
  case TYPE_INTG:
 | 
						|
    snprintf(buf, sizeof(buf), "%d", jvp->N);
 | 
						|
    return jp->WriteStr(buf);
 | 
						|
  case TYPE_BINT:
 | 
						|
    snprintf(buf, sizeof(buf), "%lld", *(longlong*)MakePtr(Base, jvp->To_Val));
 | 
						|
    return jp->WriteStr(buf);
 | 
						|
  case TYPE_FLOAT:
 | 
						|
    snprintf(buf, sizeof(buf), "%.*f", jvp->Nd, jvp->F);
 | 
						|
    return jp->WriteStr(buf);
 | 
						|
  case TYPE_DBL:
 | 
						|
    snprintf(buf, sizeof(buf), "%.*lf", jvp->Nd, *(double*)MakePtr(Base, jvp->To_Val));
 | 
						|
    return jp->WriteStr(buf);
 | 
						|
  case TYPE_NULL:
 | 
						|
    return jp->WriteStr("null");
 | 
						|
  case TYPE_JVAL:
 | 
						|
    return SerializeValue(MVP(jvp->To_Val));
 | 
						|
  default:
 | 
						|
    return jp->WriteStr("???");   // TODO
 | 
						|
  } // endswitch Type
 | 
						|
 | 
						|
  return  jp->WriteStr("null");
 | 
						|
} // end of SerializeValue
 | 
						|
 | 
						|
/* --------------------------- Class BJSON --------------------------- */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/*  Program for sub-allocating Bjson structures.                       */
 | 
						|
/***********************************************************************/
 | 
						|
void* BJSON::BsonSubAlloc(size_t size)
 | 
						|
{
 | 
						|
  PPOOLHEADER pph;                           /* Points on area header. */
 | 
						|
  void* memp = G->Sarea;
 | 
						|
 | 
						|
  size = ((size + 3) / 4) * 4;       /* Round up size to multiple of 4 */
 | 
						|
  pph = (PPOOLHEADER)memp;
 | 
						|
 | 
						|
  xtrc(16, "SubAlloc in %p size=%zd used=%zd free=%zd\n",
 | 
						|
    memp, size, pph->To_Free, pph->FreeBlk);
 | 
						|
 | 
						|
  if (size > pph->FreeBlk) {   /* Not enough memory left in pool */
 | 
						|
    snprintf(G->Message, sizeof(G->Message),
 | 
						|
      "Not enough memory for request of %zd (used=%zd free=%zd)",
 | 
						|
      size, pph->To_Free, pph->FreeBlk);
 | 
						|
    xtrc(1, "BsonSubAlloc: %s\n", G->Message);
 | 
						|
 | 
						|
    if (Throw)
 | 
						|
      throw(1234);
 | 
						|
    else
 | 
						|
      return NULL;
 | 
						|
 | 
						|
  } /* endif size OS32 code */
 | 
						|
 | 
						|
  // Do the suballocation the simplest way
 | 
						|
  memp = MakePtr(memp, pph->To_Free); /* Points to suballocated block  */
 | 
						|
  pph->To_Free += size;               /* New offset of pool free block */
 | 
						|
  pph->FreeBlk -= size;               /* New size   of pool free block */
 | 
						|
  xtrc(16, "Done memp=%p used=%zd free=%zd\n",
 | 
						|
    memp, pph->To_Free, pph->FreeBlk);
 | 
						|
  return memp;
 | 
						|
} // end of BsonSubAlloc
 | 
						|
 | 
						|
/*********************************************************************************/
 | 
						|
/*  Program for SubSet re-initialization of the memory pool.                     */
 | 
						|
/*********************************************************************************/
 | 
						|
PSZ BJSON::NewStr(PSZ str)
 | 
						|
{
 | 
						|
  if (str) {
 | 
						|
    PSZ sm = (PSZ)BsonSubAlloc(strlen(str) + 1);
 | 
						|
 | 
						|
    strcpy(sm, str);
 | 
						|
    return sm;
 | 
						|
  } else
 | 
						|
    return NULL;
 | 
						|
 | 
						|
} // end of NewStr
 | 
						|
 | 
						|
/*********************************************************************************/
 | 
						|
/*  Program for SubSet re-initialization of the memory pool.                     */
 | 
						|
/*********************************************************************************/
 | 
						|
void BJSON::SubSet(bool b)
 | 
						|
{
 | 
						|
  PPOOLHEADER pph = (PPOOLHEADER)G->Sarea;
 | 
						|
 | 
						|
  pph->To_Free = (G->Saved_Size) ? G->Saved_Size : sizeof(POOLHEADER);
 | 
						|
  pph->FreeBlk = G->Sarea_Size - pph->To_Free;
 | 
						|
 | 
						|
  if (b)
 | 
						|
    G->Saved_Size = 0;
 | 
						|
 | 
						|
} // end of SubSet
 | 
						|
 | 
						|
/*********************************************************************************/
 | 
						|
/*  Set the beginning of suballocations.                                         */
 | 
						|
/*********************************************************************************/
 | 
						|
void BJSON::MemSet(size_t size)
 | 
						|
{
 | 
						|
  PPOOLHEADER pph = (PPOOLHEADER)G->Sarea;
 | 
						|
 | 
						|
  pph->To_Free = size + sizeof(POOLHEADER);
 | 
						|
  pph->FreeBlk = G->Sarea_Size - pph->To_Free;
 | 
						|
} // end of MemSet
 | 
						|
 | 
						|
  /* ------------------------ Bobject functions ------------------------ */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Set a pair vlp to some PVAL values.                                 */
 | 
						|
/***********************************************************************/
 | 
						|
void BJSON::SetPairValue(PBPR brp, PBVAL bvp)
 | 
						|
{
 | 
						|
  if (bvp) {
 | 
						|
    brp->Vlp.To_Val = bvp->To_Val;
 | 
						|
    brp->Vlp.Nd = bvp->Nd;
 | 
						|
    brp->Vlp.Type = bvp->Type;
 | 
						|
  } else {
 | 
						|
    brp->Vlp.To_Val = 0;
 | 
						|
    brp->Vlp.Nd = 0;
 | 
						|
    brp->Vlp.Type = TYPE_NULL;
 | 
						|
  } // endif bvp
 | 
						|
 | 
						|
} // end of SetPairValue
 | 
						|
 | 
						|
  /***********************************************************************/
 | 
						|
/* Sub-allocate and initialize a BPAIR.                                */
 | 
						|
/***********************************************************************/
 | 
						|
PBPR BJSON::NewPair(OFFSET key, int type)
 | 
						|
{
 | 
						|
  PBPR bpp = (PBPR)BsonSubAlloc(sizeof(BPAIR));
 | 
						|
 | 
						|
  bpp->Key = key;
 | 
						|
  bpp->Vlp.Type = type;
 | 
						|
  bpp->Vlp.To_Val = 0;
 | 
						|
  bpp->Vlp.Nd = 0;
 | 
						|
  bpp->Vlp.Next = 0;
 | 
						|
  return bpp;
 | 
						|
} // end of SubAllocPair
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Return the number of pairs in this object.                          */
 | 
						|
/***********************************************************************/
 | 
						|
int BJSON::GetObjectSize(PBVAL bop, bool b)
 | 
						|
{
 | 
						|
  CheckType(bop, TYPE_JOB);
 | 
						|
  int n = 0;
 | 
						|
 | 
						|
  for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
 | 
						|
    // If b return only non null pairs
 | 
						|
    if (!b || (brp->Vlp.To_Val && brp->Vlp.Type != TYPE_NULL))
 | 
						|
      n++;
 | 
						|
 | 
						|
  return n;
 | 
						|
} // end of GetObjectSize
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Add a new pair to an Object and return it.                          */
 | 
						|
/***********************************************************************/
 | 
						|
PBVAL BJSON::AddPair(PBVAL bop, PSZ key, int type)
 | 
						|
{
 | 
						|
  CheckType(bop, TYPE_JOB);
 | 
						|
  PBPR   brp;
 | 
						|
  OFFSET nrp = NewPair(key, type);
 | 
						|
 | 
						|
  if (bop->To_Val) {
 | 
						|
    for (brp = GetObject(bop); brp->Vlp.Next; brp = GetNext(brp));
 | 
						|
 | 
						|
    brp->Vlp.Next = nrp;
 | 
						|
  } else
 | 
						|
    bop->To_Val = nrp;
 | 
						|
 | 
						|
  bop->Nd++;
 | 
						|
  return GetVlp(MPP(nrp));
 | 
						|
} // end of AddPair
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Return all object keys as an array.                                 */
 | 
						|
/***********************************************************************/
 | 
						|
PBVAL BJSON::GetKeyList(PBVAL bop)
 | 
						|
{
 | 
						|
  CheckType(bop, TYPE_JOB);
 | 
						|
  PBVAL arp = NewVal(TYPE_JAR);
 | 
						|
 | 
						|
  for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
 | 
						|
    AddArrayValue(arp, MOF(SubAllocVal(brp->Key, TYPE_STRG)));
 | 
						|
 | 
						|
  return arp;
 | 
						|
} // end of GetKeyList
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Return all object values as an array.                               */
 | 
						|
/***********************************************************************/
 | 
						|
PBVAL BJSON::GetObjectValList(PBVAL bop)
 | 
						|
{
 | 
						|
  CheckType(bop, TYPE_JOB);
 | 
						|
  PBVAL arp = NewVal(TYPE_JAR);
 | 
						|
 | 
						|
  for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
 | 
						|
    AddArrayValue(arp, DupVal(GetVlp(brp)));
 | 
						|
 | 
						|
  return arp;
 | 
						|
} // end of GetObjectValList
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Get the value corresponding to the given key.                       */
 | 
						|
/***********************************************************************/
 | 
						|
PBVAL BJSON::GetKeyValue(PBVAL bop, PSZ key)
 | 
						|
{
 | 
						|
  CheckType(bop, TYPE_JOB);
 | 
						|
 | 
						|
  for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
 | 
						|
    if (!strcmp(GetKey(brp), key))
 | 
						|
      return GetVlp(brp);
 | 
						|
 | 
						|
  return NULL;
 | 
						|
} // end of GetKeyValue;
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Return the text corresponding to all keys (XML like).               */
 | 
						|
/***********************************************************************/
 | 
						|
PSZ BJSON::GetObjectText(PGLOBAL g, PBVAL bop, PSTRG text)
 | 
						|
{
 | 
						|
  CheckType(bop, TYPE_JOB);
 | 
						|
  PBPR brp = GetObject(bop);
 | 
						|
 | 
						|
  if (brp) {
 | 
						|
    bool b;
 | 
						|
 | 
						|
    if (!text) {
 | 
						|
      text = new(g) STRING(g, 256);
 | 
						|
      b = true;
 | 
						|
    } else {
 | 
						|
      if (text->GetLastChar() != ' ')
 | 
						|
        text->Append(' ');
 | 
						|
 | 
						|
      b = false;
 | 
						|
    }	// endif text
 | 
						|
 | 
						|
    if (b && !brp->Vlp.Next && !strcmp(MZP(brp->Key), "$date")) {
 | 
						|
      int i;
 | 
						|
      PSZ s;
 | 
						|
 | 
						|
      GetValueText(g, GetVlp(brp), 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 (; brp; brp = GetNext(brp)) {
 | 
						|
      GetValueText(g, GetVlp(brp), text);
 | 
						|
 | 
						|
      if (brp->Vlp.Next)
 | 
						|
        text->Append(' ');
 | 
						|
 | 
						|
    }	// endfor brp
 | 
						|
 | 
						|
    if (b) {
 | 
						|
      text->Trim();
 | 
						|
      return text->GetStr();
 | 
						|
    }	// endif b
 | 
						|
 | 
						|
  } // endif bop
 | 
						|
 | 
						|
  return NULL;
 | 
						|
} // end of GetObjectText;
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Set or add a value corresponding to the given key.                  */
 | 
						|
/***********************************************************************/
 | 
						|
void BJSON::SetKeyValue(PBVAL bop, OFFSET bvp, PSZ key)
 | 
						|
{
 | 
						|
  CheckType(bop, TYPE_JOB);
 | 
						|
  PBPR brp, prp = NULL;
 | 
						|
 | 
						|
  if (bop->To_Val) {
 | 
						|
    for (brp = GetObject(bop); brp; brp = GetNext(brp))
 | 
						|
      if (!strcmp(GetKey(brp), key))
 | 
						|
        break;
 | 
						|
      else
 | 
						|
        prp = brp;
 | 
						|
 | 
						|
    if (!brp)
 | 
						|
      brp = MPP(prp->Vlp.Next = NewPair(key));
 | 
						|
 | 
						|
  } else
 | 
						|
    brp = MPP(bop->To_Val = NewPair(key));
 | 
						|
 | 
						|
  SetPairValue(brp, MVP(bvp));
 | 
						|
  bop->Nd++;
 | 
						|
} // end of SetKeyValue
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Merge two objects.                                                  */
 | 
						|
/***********************************************************************/
 | 
						|
PBVAL BJSON::MergeObject(PBVAL bop1, PBVAL bop2)
 | 
						|
{
 | 
						|
  CheckType(bop1, TYPE_JOB);
 | 
						|
  CheckType(bop2, TYPE_JOB);
 | 
						|
 | 
						|
  if (bop1->To_Val)
 | 
						|
    for (PBPR brp = GetObject(bop2); brp; brp = GetNext(brp))
 | 
						|
      SetKeyValue(bop1, GetVlp(brp), GetKey(brp));
 | 
						|
 | 
						|
  else {
 | 
						|
    bop1->To_Val = bop2->To_Val;
 | 
						|
    bop1->Nd = bop2->Nd;
 | 
						|
  } // endelse To_Val
 | 
						|
 | 
						|
  return bop1;
 | 
						|
} // end of MergeObject;
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Delete a value corresponding to the given key.                      */
 | 
						|
/***********************************************************************/
 | 
						|
bool BJSON::DeleteKey(PBVAL bop, PCSZ key)
 | 
						|
{
 | 
						|
  CheckType(bop, TYPE_JOB);
 | 
						|
  PBPR brp, pbrp = NULL;
 | 
						|
 | 
						|
  for (brp = GetObject(bop); brp; brp = GetNext(brp))
 | 
						|
    if (!strcmp(MZP(brp->Key), key)) {
 | 
						|
      if (pbrp) {
 | 
						|
        pbrp->Vlp.Next = brp->Vlp.Next;
 | 
						|
      } else
 | 
						|
        bop->To_Val = brp->Vlp.Next;
 | 
						|
 | 
						|
      bop->Nd--;
 | 
						|
      return true;;
 | 
						|
    } else
 | 
						|
      pbrp = brp;
 | 
						|
 | 
						|
  return false;
 | 
						|
} // end of DeleteKey
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* True if void or if all members are nulls.                           */
 | 
						|
/***********************************************************************/
 | 
						|
bool BJSON::IsObjectNull(PBVAL bop)
 | 
						|
{
 | 
						|
  CheckType(bop, TYPE_JOB);
 | 
						|
 | 
						|
  for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
 | 
						|
    if (brp->Vlp.To_Val && brp->Vlp.Type != TYPE_NULL)
 | 
						|
      return false;
 | 
						|
 | 
						|
  return true;
 | 
						|
} // end of IsObjectNull
 | 
						|
 | 
						|
/* ------------------------- Barray functions ------------------------ */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Return the number of values in this object.                         */
 | 
						|
/***********************************************************************/
 | 
						|
int BJSON::GetArraySize(PBVAL bap, bool b)
 | 
						|
{
 | 
						|
  CheckType(bap, TYPE_JAR);
 | 
						|
  int n = 0;
 | 
						|
 | 
						|
  for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp))
 | 
						|
    //  If b, return only non null values
 | 
						|
    if (!b || bvp->Type != TYPE_NULL)
 | 
						|
      n++;
 | 
						|
 | 
						|
  return n;
 | 
						|
} // end of GetArraySize
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Get the Nth value of an Array.                                      */
 | 
						|
/***********************************************************************/
 | 
						|
PBVAL BJSON::GetArrayValue(PBVAL bap, int n)
 | 
						|
{
 | 
						|
  CheckType(bap, TYPE_JAR);
 | 
						|
  int i = 0;
 | 
						|
 | 
						|
  if (n < 0)
 | 
						|
    n += GetArraySize(bap);
 | 
						|
 | 
						|
  for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp), i++)
 | 
						|
    if (i == n)
 | 
						|
      return bvp;
 | 
						|
 | 
						|
  return NULL;
 | 
						|
} // end of GetArrayValue
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Add a Value to the Array Value list.                                */
 | 
						|
/***********************************************************************/
 | 
						|
void BJSON::AddArrayValue(PBVAL bap, OFFSET nbv, int* x)
 | 
						|
{
 | 
						|
  CheckType(bap, TYPE_JAR);
 | 
						|
  int   i = 0;
 | 
						|
  PBVAL bvp, lbp = NULL;
 | 
						|
 | 
						|
  if (!nbv)
 | 
						|
    nbv = MOF(NewVal());
 | 
						|
 | 
						|
  for (bvp = GetArray(bap); bvp; bvp = GetNext(bvp), i++)
 | 
						|
    if (x && i == *x)
 | 
						|
      break;
 | 
						|
    else
 | 
						|
      lbp = bvp;
 | 
						|
 | 
						|
  if (lbp) {
 | 
						|
    MVP(nbv)->Next = lbp->Next;
 | 
						|
    lbp->Next = nbv;
 | 
						|
  } else {
 | 
						|
    MVP(nbv)->Next = bap->To_Val;
 | 
						|
    bap->To_Val = nbv;
 | 
						|
  } // endif lbp
 | 
						|
 | 
						|
  bap->Nd++;
 | 
						|
} // end of AddArrayValue
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Merge two arrays.                                                   */
 | 
						|
/***********************************************************************/
 | 
						|
void BJSON::MergeArray(PBVAL bap1, PBVAL bap2)
 | 
						|
{
 | 
						|
  CheckType(bap1, TYPE_JAR);
 | 
						|
  CheckType(bap2, TYPE_JAR);
 | 
						|
 | 
						|
  if (bap1->To_Val) {
 | 
						|
    for (PBVAL bvp = GetArray(bap2); bvp; bvp = GetNext(bvp))
 | 
						|
      AddArrayValue(bap1, MOF(DupVal(bvp)));
 | 
						|
 | 
						|
  } else {
 | 
						|
    bap1->To_Val = bap2->To_Val;
 | 
						|
    bap1->Nd = bap2->Nd;
 | 
						|
  } // endif To_Val
 | 
						|
 | 
						|
} // end of MergeArray
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Set the nth Value of the Array Value list or add it.                */
 | 
						|
/***********************************************************************/
 | 
						|
void BJSON::SetArrayValue(PBVAL bap, PBVAL nvp, int n)
 | 
						|
{
 | 
						|
  CheckType(bap, TYPE_JAR);
 | 
						|
  int   i = 0;
 | 
						|
  PBVAL bvp = NULL;
 | 
						|
 | 
						|
  for (bvp = GetArray(bap); i < n; i++, bvp = bvp ? GetNext(bvp) : NULL)
 | 
						|
    if (!bvp)
 | 
						|
      AddArrayValue(bap, NewVal());
 | 
						|
 | 
						|
  if (!bvp)
 | 
						|
    AddArrayValue(bap, MOF(nvp));
 | 
						|
  else
 | 
						|
    SetValueVal(bvp, nvp);
 | 
						|
 | 
						|
} // end of SetValue
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Return the text corresponding to all values.                        */
 | 
						|
/***********************************************************************/
 | 
						|
PSZ BJSON::GetArrayText(PGLOBAL g, PBVAL bap, PSTRG text)
 | 
						|
{
 | 
						|
  CheckType(bap, TYPE_JAR);
 | 
						|
 | 
						|
  if (bap->To_Val) {
 | 
						|
    bool  b;
 | 
						|
 | 
						|
    if (!text) {
 | 
						|
      text = new(g) STRING(g, 256);
 | 
						|
      b = true;
 | 
						|
    } else {
 | 
						|
      if (text->GetLastChar() != ' ')
 | 
						|
        text->Append(" (");
 | 
						|
      else
 | 
						|
        text->Append('(');
 | 
						|
 | 
						|
      b = false;
 | 
						|
    } // endif text
 | 
						|
 | 
						|
    for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp)) {
 | 
						|
      GetValueText(g, bvp, text);
 | 
						|
 | 
						|
      if (bvp->Next)
 | 
						|
        text->Append(", ");
 | 
						|
      else if (!b)
 | 
						|
        text->Append(')');
 | 
						|
 | 
						|
    }	// endfor bvp
 | 
						|
 | 
						|
    if (b) {
 | 
						|
      text->Trim();
 | 
						|
      return text->GetStr();
 | 
						|
    }	// endif b
 | 
						|
 | 
						|
  } // endif To_Val
 | 
						|
 | 
						|
  return NULL;
 | 
						|
} // end of GetText;
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Delete a Value from the Arrays Value list.                          */
 | 
						|
/***********************************************************************/
 | 
						|
bool BJSON::DeleteValue(PBVAL bap, int n)
 | 
						|
{
 | 
						|
  CheckType(bap, TYPE_JAR);
 | 
						|
  int   i = 0;
 | 
						|
  PBVAL bvp, pvp = NULL;
 | 
						|
 | 
						|
  for (bvp = GetArray(bap); bvp; i++, bvp = GetNext(bvp))
 | 
						|
    if (i == n) {
 | 
						|
      if (pvp)
 | 
						|
        pvp->Next = bvp->Next;
 | 
						|
      else
 | 
						|
        bap->To_Val = bvp->Next;
 | 
						|
 | 
						|
      bap->Nd--;
 | 
						|
      return true;;
 | 
						|
    } else
 | 
						|
      pvp = bvp;
 | 
						|
 | 
						|
  return false;
 | 
						|
} // end of DeleteValue
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* True if void or if all members are nulls.                           */
 | 
						|
/***********************************************************************/
 | 
						|
bool BJSON::IsArrayNull(PBVAL bap)
 | 
						|
{
 | 
						|
  CheckType(bap, TYPE_JAR);
 | 
						|
 | 
						|
  for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp))
 | 
						|
    if (bvp->Type != TYPE_NULL)
 | 
						|
      return false;
 | 
						|
 | 
						|
  return true;
 | 
						|
} // end of IsNull
 | 
						|
 | 
						|
/* ------------------------- Bvalue functions ------------------------ */
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Sub-allocate and clear a BVAL.                                      */
 | 
						|
/***********************************************************************/
 | 
						|
PBVAL BJSON::NewVal(int type)
 | 
						|
{
 | 
						|
  PBVAL bvp = (PBVAL)BsonSubAlloc(sizeof(BVAL));
 | 
						|
 | 
						|
  bvp->To_Val = 0;
 | 
						|
  bvp->Nd = 0;
 | 
						|
  bvp->Type = type;
 | 
						|
  bvp->Next = 0;
 | 
						|
  return bvp;
 | 
						|
} // end of SubAllocVal
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Sub-allocate and initialize a BVAL as type.                         */
 | 
						|
/***********************************************************************/
 | 
						|
PBVAL BJSON::SubAllocVal(OFFSET toval, int type, short nd)
 | 
						|
{
 | 
						|
  PBVAL bvp = NewVal(type);
 | 
						|
 | 
						|
  bvp->To_Val = toval;
 | 
						|
  bvp->Nd = nd;
 | 
						|
  return bvp;
 | 
						|
} // end of SubAllocVal
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Sub-allocate and initialize a BVAL as string.                       */
 | 
						|
/***********************************************************************/
 | 
						|
PBVAL BJSON::SubAllocStr(OFFSET toval, short nd)
 | 
						|
{
 | 
						|
  PBVAL bvp = NewVal(TYPE_STRG);
 | 
						|
 | 
						|
  bvp->To_Val = toval;
 | 
						|
  bvp->Nd = nd;
 | 
						|
  return bvp;
 | 
						|
} // end of SubAllocStr
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Allocate a BVALUE with a given string or numeric value.             */
 | 
						|
/***********************************************************************/
 | 
						|
PBVAL BJSON::NewVal(PVAL valp)
 | 
						|
{
 | 
						|
  PBVAL vlp = NewVal();
 | 
						|
 | 
						|
  SetValue(vlp, valp);
 | 
						|
  return vlp;
 | 
						|
} // end of SubAllocVal
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Sub-allocate and initialize a BVAL from another BVAL.               */
 | 
						|
/***********************************************************************/
 | 
						|
PBVAL BJSON::DupVal(PBVAL bvlp)
 | 
						|
{
 | 
						|
  if (bvlp) {
 | 
						|
    PBVAL bvp = NewVal();
 | 
						|
 | 
						|
    *bvp = *bvlp;
 | 
						|
    bvp->Next = 0;
 | 
						|
    return bvp;
 | 
						|
  } else
 | 
						|
    return NULL;
 | 
						|
 | 
						|
} // end of DupVal
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Return the size of value's value.                                   */
 | 
						|
/***********************************************************************/
 | 
						|
int BJSON::GetSize(PBVAL vlp, bool b)
 | 
						|
{
 | 
						|
  switch (vlp->Type) {
 | 
						|
  case TYPE_JAR:
 | 
						|
    return GetArraySize(vlp);
 | 
						|
  case TYPE_JOB:
 | 
						|
    return GetObjectSize(vlp);
 | 
						|
  default:
 | 
						|
    return 1;
 | 
						|
  } // enswitch Type
 | 
						|
 | 
						|
} // end of GetSize
 | 
						|
 | 
						|
PBVAL BJSON::GetBson(PBVAL bvp)
 | 
						|
{ 
 | 
						|
  PBVAL bp = NULL;
 | 
						|
 | 
						|
  switch (bvp->Type) {
 | 
						|
    case TYPE_JAR:
 | 
						|
      bp = MVP(bvp->To_Val);
 | 
						|
      break;
 | 
						|
    case TYPE_JOB:
 | 
						|
      bp = GetVlp(MPP(bvp->To_Val));
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      bp = bvp;
 | 
						|
      break;
 | 
						|
  } // endswitch Type
 | 
						|
 | 
						|
  return bp;
 | 
						|
} // end of GetBson
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Return the Value's as a Value struct.                               */
 | 
						|
/***********************************************************************/
 | 
						|
PVAL BJSON::GetValue(PGLOBAL g, PBVAL vp)
 | 
						|
{
 | 
						|
  double d;
 | 
						|
  PVAL   valp;
 | 
						|
  PBVAL  vlp = vp->Type == TYPE_JVAL ? MVP(vp->To_Val) : vp;
 | 
						|
 | 
						|
  switch (vlp->Type) {
 | 
						|
    case TYPE_STRG:
 | 
						|
    case TYPE_DBL:
 | 
						|
    case TYPE_BINT:
 | 
						|
      valp = AllocateValue(g, MP(vlp->To_Val), vlp->Type, vlp->Nd);
 | 
						|
      break;
 | 
						|
    case TYPE_INTG:
 | 
						|
    case TYPE_BOOL:
 | 
						|
      valp = AllocateValue(g, vlp, vlp->Type);
 | 
						|
      break;
 | 
						|
    case TYPE_FLOAT:
 | 
						|
      d = (double)vlp->F;
 | 
						|
      valp = AllocateValue(g, &d, TYPE_DOUBLE, vlp->Nd);
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      valp = NULL;
 | 
						|
      break;
 | 
						|
  } // endswitch Type
 | 
						|
 | 
						|
  return valp;
 | 
						|
} // end of GetValue
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Return the Value's Integer value.                                   */
 | 
						|
/***********************************************************************/
 | 
						|
int BJSON::GetInteger(PBVAL vp) {
 | 
						|
  int   n;
 | 
						|
  PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
 | 
						|
 | 
						|
  switch (vlp->Type) {
 | 
						|
  case TYPE_INTG:
 | 
						|
    n = vlp->N;
 | 
						|
    break;
 | 
						|
  case TYPE_FLOAT:
 | 
						|
    n = (int)vlp->F;
 | 
						|
    break;
 | 
						|
  case TYPE_DTM:
 | 
						|
  case TYPE_STRG:
 | 
						|
    n = atoi(MZP(vlp->To_Val));
 | 
						|
    break;
 | 
						|
  case TYPE_BOOL:
 | 
						|
    n = (vlp->B) ? 1 : 0;
 | 
						|
    break;
 | 
						|
  case TYPE_BINT: 
 | 
						|
    n = (int)*(longlong*)MP(vlp->To_Val);
 | 
						|
    break;
 | 
						|
  case TYPE_DBL:
 | 
						|
    n = (int)*(double*)MP(vlp->To_Val);
 | 
						|
    break;
 | 
						|
  default:
 | 
						|
    n = 0;
 | 
						|
  } // endswitch Type
 | 
						|
 | 
						|
  return n;
 | 
						|
} // end of GetInteger
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Return the Value's Big integer value.                               */
 | 
						|
/***********************************************************************/
 | 
						|
longlong BJSON::GetBigint(PBVAL vp) {
 | 
						|
  longlong lln;
 | 
						|
  PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
 | 
						|
 | 
						|
  switch (vlp->Type) {
 | 
						|
  case TYPE_BINT: 
 | 
						|
    lln = *(longlong*)MP(vlp->To_Val);
 | 
						|
    break;
 | 
						|
  case TYPE_INTG: 
 | 
						|
    lln = (longlong)vlp->N;
 | 
						|
    break;
 | 
						|
  case TYPE_FLOAT: 
 | 
						|
    lln = (longlong)vlp->F;
 | 
						|
    break;
 | 
						|
  case TYPE_DBL:
 | 
						|
    lln = (longlong)*(double*)MP(vlp->To_Val);
 | 
						|
    break;
 | 
						|
  case TYPE_DTM:
 | 
						|
  case TYPE_STRG: 
 | 
						|
    lln = atoll(MZP(vlp->To_Val));
 | 
						|
    break;
 | 
						|
  case TYPE_BOOL:
 | 
						|
    lln = (vlp->B) ? 1 : 0;
 | 
						|
    break;
 | 
						|
  default:
 | 
						|
    lln = 0;
 | 
						|
  } // endswitch Type
 | 
						|
 | 
						|
  return lln;
 | 
						|
} // end of GetBigint
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Return the Value's Double value.                                    */
 | 
						|
/***********************************************************************/
 | 
						|
double BJSON::GetDouble(PBVAL vp)
 | 
						|
{
 | 
						|
  double d;
 | 
						|
  PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
 | 
						|
 | 
						|
  switch (vlp->Type) {
 | 
						|
    case TYPE_DBL:
 | 
						|
      d = *(double*)MP(vlp->To_Val);
 | 
						|
      break;
 | 
						|
    case TYPE_BINT:
 | 
						|
      d = (double)*(longlong*)MP(vlp->To_Val);
 | 
						|
      break;
 | 
						|
    case TYPE_INTG:
 | 
						|
      d = (double)vlp->N;
 | 
						|
      break;
 | 
						|
    case TYPE_FLOAT:
 | 
						|
      d = (double)vlp->F;
 | 
						|
      break;
 | 
						|
    case TYPE_DTM:
 | 
						|
    case TYPE_STRG:
 | 
						|
      d = atof(MZP(vlp->To_Val));
 | 
						|
      break;
 | 
						|
    case TYPE_BOOL:
 | 
						|
      d = (vlp->B) ? 1.0 : 0.0;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      d = 0.0;
 | 
						|
  } // endswitch Type
 | 
						|
 | 
						|
  return d;
 | 
						|
} // end of GetDouble
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Return the Value's String value.                                    */
 | 
						|
/***********************************************************************/
 | 
						|
PSZ BJSON::GetString(PBVAL vp, char* buff)
 | 
						|
{
 | 
						|
  char  buf[32];
 | 
						|
  char* p = (buff) ? buff : buf;
 | 
						|
  PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
 | 
						|
 | 
						|
  switch (vlp->Type) {
 | 
						|
  case TYPE_DTM:
 | 
						|
  case TYPE_STRG:
 | 
						|
    p = MZP(vlp->To_Val);
 | 
						|
    break;
 | 
						|
  case TYPE_INTG:
 | 
						|
    sprintf(p, "%d", vlp->N);
 | 
						|
    break;
 | 
						|
  case TYPE_FLOAT:
 | 
						|
    sprintf(p, "%.*f", vlp->Nd, vlp->F);
 | 
						|
    break;
 | 
						|
  case TYPE_BINT:
 | 
						|
    sprintf(p, "%lld", *(longlong*)MP(vlp->To_Val));
 | 
						|
    break;
 | 
						|
  case TYPE_DBL:
 | 
						|
    sprintf(p, "%.*lf", vlp->Nd, *(double*)MP(vlp->To_Val));
 | 
						|
    break;
 | 
						|
  case TYPE_BOOL:
 | 
						|
    p = (PSZ)((vlp->B) ? "true" : "false");
 | 
						|
    break;
 | 
						|
  case TYPE_NULL:
 | 
						|
    p = (PSZ)"null";
 | 
						|
    break;
 | 
						|
  default:
 | 
						|
    p = NULL;
 | 
						|
  } // endswitch Type
 | 
						|
 | 
						|
  return (p == buf) ? (PSZ)PlugDup(G, buf) : p;
 | 
						|
} // end of GetString
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Return the Value's String value.                                    */
 | 
						|
/***********************************************************************/
 | 
						|
PSZ BJSON::GetValueText(PGLOBAL g, PBVAL vlp, PSTRG text)
 | 
						|
{
 | 
						|
  if (vlp->Type == TYPE_JOB)
 | 
						|
    return GetObjectText(g, vlp, text);
 | 
						|
  else if (vlp->Type == TYPE_JAR)
 | 
						|
    return GetArrayText(g, vlp, text);
 | 
						|
 | 
						|
  char buff[32];
 | 
						|
  PSZ  s = (vlp->Type == TYPE_NULL) ? NULL : GetString(vlp, buff);
 | 
						|
 | 
						|
  if (s)
 | 
						|
    text->Append(s);
 | 
						|
  else if (GetJsonNull())
 | 
						|
    text->Append(GetJsonNull());
 | 
						|
 | 
						|
  return NULL;
 | 
						|
} // end of GetText
 | 
						|
 | 
						|
void BJSON::SetValueObj(PBVAL vlp, PBVAL bop)
 | 
						|
{
 | 
						|
  CheckType(bop, TYPE_JOB);
 | 
						|
  vlp->To_Val = bop->To_Val;
 | 
						|
  vlp->Nd = bop->Nd;
 | 
						|
  vlp->Type = TYPE_JOB;
 | 
						|
} // end of SetValueObj;
 | 
						|
 | 
						|
void BJSON::SetValueArr(PBVAL vlp, PBVAL bap)
 | 
						|
{
 | 
						|
  CheckType(bap, TYPE_JAR);
 | 
						|
  vlp->To_Val = bap->To_Val;
 | 
						|
  vlp->Nd = bap->Nd;
 | 
						|
  vlp->Type = TYPE_JAR;
 | 
						|
} // end of SetValue;
 | 
						|
 | 
						|
void BJSON::SetValueVal(PBVAL vlp, PBVAL vp)
 | 
						|
{
 | 
						|
  vlp->To_Val = vp->To_Val;
 | 
						|
  vlp->Nd = vp->Nd;
 | 
						|
  vlp->Type = vp->Type;
 | 
						|
} // end of SetValue;
 | 
						|
 | 
						|
PBVAL BJSON::SetValue(PBVAL vlp, PVAL valp)
 | 
						|
{
 | 
						|
  if (!vlp)
 | 
						|
    vlp = NewVal();
 | 
						|
 | 
						|
  if (!valp || valp->IsNull()) {
 | 
						|
    vlp->Type = TYPE_NULL;
 | 
						|
  } else switch (valp->GetType()) {
 | 
						|
    case TYPE_DATE:
 | 
						|
      if (((DTVAL*)valp)->IsFormatted())
 | 
						|
        vlp->To_Val = DupStr(valp->GetCharValue());
 | 
						|
      else {
 | 
						|
        char buf[32];
 | 
						|
 | 
						|
        vlp->To_Val = DupStr(valp->GetCharString(buf));
 | 
						|
      }	// endif Formatted
 | 
						|
 | 
						|
      vlp->Type = TYPE_DTM;
 | 
						|
      break;
 | 
						|
    case TYPE_STRING:
 | 
						|
      vlp->To_Val = DupStr(valp->GetCharValue());
 | 
						|
      vlp->Type = TYPE_STRG;
 | 
						|
      break;
 | 
						|
    case TYPE_DOUBLE:
 | 
						|
    case TYPE_DECIM:
 | 
						|
    { double d = valp->GetFloatValue();
 | 
						|
      int    nd = (IsTypeNum(valp->GetType())) ? valp->GetValPrec() : 0;
 | 
						|
 | 
						|
      if (nd > 0 && nd <= 6 && d >= FLT_MIN && d <= FLT_MAX) {
 | 
						|
        vlp->F = (float)valp->GetFloatValue();
 | 
						|
        vlp->Type = TYPE_FLOAT;
 | 
						|
      } else {
 | 
						|
        double* dp = (double*)BsonSubAlloc(sizeof(double));
 | 
						|
 | 
						|
        *dp = d;
 | 
						|
        vlp->To_Val = MOF(dp);
 | 
						|
        vlp->Type = TYPE_DBL;
 | 
						|
      } // endif Nd
 | 
						|
 | 
						|
      vlp->Nd = MY_MIN(nd, 16);
 | 
						|
    } break;
 | 
						|
    case TYPE_TINY:
 | 
						|
      vlp->B = valp->GetTinyValue() != 0;
 | 
						|
      vlp->Type = TYPE_BOOL;
 | 
						|
      break;
 | 
						|
    case TYPE_INT:
 | 
						|
      vlp->N = valp->GetIntValue();
 | 
						|
      vlp->Type = TYPE_INTG;
 | 
						|
      break;
 | 
						|
    case TYPE_BIGINT:
 | 
						|
      if (valp->GetBigintValue() >= INT_MIN32 &&
 | 
						|
        valp->GetBigintValue() <= INT_MAX32) {
 | 
						|
        vlp->N = valp->GetIntValue();
 | 
						|
        vlp->Type = TYPE_INTG;
 | 
						|
      } else {
 | 
						|
        longlong* llp = (longlong*)BsonSubAlloc(sizeof(longlong));
 | 
						|
 | 
						|
        *llp = valp->GetBigintValue();
 | 
						|
        vlp->To_Val = MOF(llp);
 | 
						|
        vlp->Type = TYPE_BINT;
 | 
						|
      } // endif BigintValue
 | 
						|
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      snprintf(G->Message, sizeof(G->Message), "Unsupported typ %d\n", valp->GetType());
 | 
						|
      throw(777);
 | 
						|
  } // endswitch Type
 | 
						|
 | 
						|
  return vlp;
 | 
						|
} // end of SetValue
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Set the Value's value as the given integer.                         */
 | 
						|
/***********************************************************************/
 | 
						|
void BJSON::SetInteger(PBVAL vlp, int n)
 | 
						|
{
 | 
						|
  vlp->N = n;
 | 
						|
  vlp->Type = TYPE_INTG;
 | 
						|
} // end of SetInteger
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Set the Value's Boolean value as a tiny integer.                    */
 | 
						|
/***********************************************************************/
 | 
						|
void BJSON::SetBool(PBVAL vlp, bool b)
 | 
						|
{
 | 
						|
  vlp->B = b;
 | 
						|
  vlp->Type = TYPE_BOOL;
 | 
						|
} // end of SetTiny
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Set the Value's value as the given big integer.                     */
 | 
						|
/***********************************************************************/
 | 
						|
void BJSON::SetBigint(PBVAL vlp, longlong ll)
 | 
						|
{
 | 
						|
  if (ll >= INT_MIN32 && ll <= INT_MAX32) {
 | 
						|
    vlp->N = (int)ll;
 | 
						|
    vlp->Type = TYPE_INTG;
 | 
						|
  } else {
 | 
						|
    longlong* llp = (longlong*)PlugSubAlloc(G, NULL, sizeof(longlong));
 | 
						|
 | 
						|
    *llp = ll;
 | 
						|
    vlp->To_Val = MOF(llp);
 | 
						|
    vlp->Type = TYPE_BINT;
 | 
						|
  } // endif ll
 | 
						|
 | 
						|
} // end of SetBigint
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Set the Value's value as the given DOUBLE.                          */
 | 
						|
/***********************************************************************/
 | 
						|
void BJSON::SetFloat(PBVAL vlp, double d, int prec)
 | 
						|
{
 | 
						|
  int nd = MY_MIN((prec < 0) ? GetJsonDefPrec() : prec, 16);
 | 
						|
 | 
						|
  if (nd < 6 && d >= FLT_MIN && d <= FLT_MAX) {
 | 
						|
    vlp->F = (float)d;
 | 
						|
    vlp->Type = TYPE_FLOAT;
 | 
						|
  } else {
 | 
						|
    double* dp = (double*)BsonSubAlloc(sizeof(double));
 | 
						|
 | 
						|
    *dp = d;
 | 
						|
    vlp->To_Val = MOF(dp);
 | 
						|
    vlp->Type = TYPE_DBL;
 | 
						|
  } // endif nd
 | 
						|
 | 
						|
  vlp->Nd = nd;
 | 
						|
} // end of SetFloat
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* Set the Value's value as the given DOUBLE representation.                          */
 | 
						|
/***********************************************************************/
 | 
						|
void BJSON::SetFloat(PBVAL vlp, PSZ s)
 | 
						|
{
 | 
						|
  char  *p = strchr(s, '.');
 | 
						|
  int    nd = 0;
 | 
						|
  double d = atof(s);
 | 
						|
 | 
						|
  if (p) {
 | 
						|
    for (++p; isdigit(*p); nd++, p++);
 | 
						|
    for (--p; *p == '0'; nd--, p--);
 | 
						|
  } // endif p
 | 
						|
 | 
						|
  SetFloat(vlp, d, nd);
 | 
						|
} // end of SetFloat
 | 
						|
 | 
						|
 /***********************************************************************/
 | 
						|
/* Set the Value's value as the given string.                          */
 | 
						|
/***********************************************************************/
 | 
						|
void BJSON::SetString(PBVAL vlp, PSZ s, int ci)
 | 
						|
{
 | 
						|
  vlp->To_Val = MOF(s);
 | 
						|
  vlp->Nd = ci;
 | 
						|
  vlp->Type = TYPE_STRG;
 | 
						|
} // end of SetString
 | 
						|
 | 
						|
/***********************************************************************/
 | 
						|
/* True when its JSON or normal value is null.                         */
 | 
						|
/***********************************************************************/
 | 
						|
bool BJSON::IsValueNull(PBVAL vlp)
 | 
						|
{
 | 
						|
  bool b;
 | 
						|
 | 
						|
  switch (vlp->Type) {
 | 
						|
  case TYPE_NULL:
 | 
						|
    b = true;
 | 
						|
    break;
 | 
						|
  case TYPE_JOB:
 | 
						|
    b = IsObjectNull(vlp);
 | 
						|
    break;
 | 
						|
  case TYPE_JAR:
 | 
						|
    b = IsArrayNull(vlp);
 | 
						|
    break;
 | 
						|
  default:
 | 
						|
    b = false;
 | 
						|
  } // endswitch Type
 | 
						|
 | 
						|
  return b;
 | 
						|
  } // end of IsNull
 |