1981 lines
48 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| Qwen3.8Max.mqh |
| |||
//| Copyright 2026, Niquel Mendoza. |
| |||
//| https://www.mql5.com/ |
| |||
//+------------------------------------------------------------------+
| |||
#property copyright "Copyright 2026, Niquel Mendoza."
| |||
#property link "https://www.mql5.com/"
| |||
#property strict
| |||
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| |
| |||
//+------------------------------------------------------------------+
| |||
// Same prompt claude\mql5 lite
| |||
/*
| |||
1. ITERACION
| |||
Tengo errores:
| |||
wrong parameters count Qwen3.8Max.mqh 1753 17
| |||
built-in: string DoubleToString(double,int) Qwen3.8Max.mqh 1753 17
| |||
implicit conversion from 'unknown' to 'string' Qwen3.8Max.mqh 1753 17
| |||
wrong parameters count Qwen3.8Max.mqh 1784 13
| |||
built-in: double StringToDouble(const string) Qwen3.8Max.mqh 1784 13
| |||
cannot convert parameter 'CJson&' to 'CJson*' Qwen3.8Max.mqh 1825 22
| |||
wrong parameters count, 2 passed, but 0 requires Qwen3.8Max.mqh 1825 14
| |||
could be one of 3 function(s) Qwen3.8Max.mqh 1825 14
| |||
implicit JsonRef::JsonRef(const JsonRef&) Qwen3.8Max.mqh 92 8
| |||
JsonRef::JsonRef(CJson*,int) Qwen3.8Max.mqh 104 4
| |||
JsonRef::JsonRef() Qwen3.8Max.mqh 98 4
| |||
cannot convert parameter 'CJson&' to 'CJson*' Qwen3.8Max.mqh 1830 22
| |||
wrong parameters count, 2 passed, but 0 requires Qwen3.8Max.mqh 1830 14
| |||
could be one of 3 function(s) Qwen3.8Max.mqh 1830 14
| |||
implicit JsonRef::JsonRef(const JsonRef&) Qwen3.8Max.mqh 92 8
| |||
JsonRef::JsonRef(CJson*,int) Qwen3.8Max.mqh 104 4
| |||
JsonRef::JsonRef() Qwen3.8Max.mqh 98 4
| |||
6 errors, 1 warnings 6 1
| |||
| |||
Los corregir todos yo ire dejando comentarios..
| |||
| |||
2. Iteracion
| |||
Al probarlo da error ni siuieqera funciona
| |||
2026.07.27 19:52:46.618 Qwen3.8Max (EURUSD,M1) false
| |||
2026.07.27 19:52:46.618 Qwen3.8Max (EURUSD,M1) array out of range in 'Qwen3.8Max.mqh' (1695,40)
| |||
| |||
Bueno lo tengo
| |||
2026.07.27 20:05:30.350 Qwen3.8Max (EURUSD,M1) false
| |||
2026.07.27 20:05:30.350 Qwen3.8Max (EURUSD,M1) JSON error: Invalid escape sequence pos=220961 line=6031 col=28
| |||
| |||
| |||
BUeno conitnuare otro dia con qwen me canse ya con glm.. hoy... ..
| |||
| |||
*/
| |||
| |||
//// Code ai start..
| |||
//+------------------------------------------------------------------+
| |||
//| High Performance JSON Parser for MQL5 |
| |||
//| Pure MQL5, no DLL, no external libraries |
| |||
//+------------------------------------------------------------------+
| |||
#ifndef JSON_MQH
| |||
#define JSON_MQH
| |||
| |||
#define JSON_CP_UTF8 65001
| |||
#define JSON_FNV_INIT ((uint)0x811C9DC5)
| |||
#define JSON_FNV_PRIME ((uint)16777619)
| |||
#define JSON_FLAG_KEY_DECODED 1
| |||
#define JSON_FLAG_VAL_DECODED 2
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Error codes |
| |||
//+------------------------------------------------------------------+
| |||
enum ENUM_JSON_ERROR
| |||
{
| |||
JSON_OK = 0,
| |||
JSON_UNKNOWN_ERROR,
| |||
JSON_UNEXPECTED_CHARACTER,
| |||
JSON_UNEXPECTED_END,
| |||
JSON_INVALID_NUMBER,
| |||
JSON_INVALID_STRING,
| |||
JSON_INVALID_ESCAPE,
| |||
JSON_INVALID_UNICODE,
| |||
JSON_EXPECTED_COLON,
| |||
JSON_EXPECTED_COMMA,
| |||
JSON_EXPECTED_OBJECT,
| |||
JSON_EXPECTED_ARRAY,
| |||
JSON_EXPECTED_KEY,
| |||
JSON_EXPECTED_VALUE,
| |||
JSON_INVALID_LITERAL,
| |||
JSON_MAX_DEPTH,
| |||
JSON_MEMORY_ERROR,
| |||
JSON_TRAILING_DATA
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Node types |
| |||
//+------------------------------------------------------------------+
| |||
enum ENUM_JSON_TYPE
| |||
{
| |||
JSON_NONE = -1,
| |||
JSON_NULL = 0,
| |||
JSON_BOOL = 1,
| |||
JSON_NUMBER = 2,
| |||
JSON_STRING = 3,
| |||
JSON_ARRAY = 4,
| |||
JSON_OBJECT = 5
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Parser states |
| |||
//+------------------------------------------------------------------+
| |||
enum ENUM_JSON_STATE
| |||
{
| |||
JSON_STATE_OBJ_KEY_OR_END = 0,
| |||
JSON_STATE_OBJ_KEY = 1,
| |||
JSON_STATE_OBJ_COLON = 2,
| |||
JSON_STATE_OBJ_VALUE = 3,
| |||
JSON_STATE_OBJ_COMMA_OR_END = 4,
| |||
JSON_STATE_ARRAY_VALUE_OR_END = 5,
| |||
JSON_STATE_ARRAY_VALUE = 6,
| |||
JSON_STATE_ARRAY_COMMA_OR_END = 7
| |||
};
| |||
| |||
class CJson;
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Lightweight reference to a JSON node |
| |||
//+------------------------------------------------------------------+
| |||
struct JsonRef
| |||
{
| |||
public:
| |||
CJson *json;
| |||
int node;
| |||
| |||
JsonRef()
| |||
{
| |||
json = NULL;
| |||
node = -1;
| |||
}
| |||
| |||
JsonRef(CJson *j, int n)
| |||
{
| |||
json = j;
| |||
node = n;
| |||
}
| |||
| |||
JsonRef operator[](const string key); // quite el & por "implicit conversion from 'string' to 'int' Qwen3.8Max.mq5 28 23"
| |||
JsonRef operator[](const int index);
| |||
| |||
bool Exists();
| |||
int Type();
| |||
int Size();
| |||
| |||
double ToDouble();
| |||
long ToInteger();
| |||
bool ToBool();
| |||
string ToString();
| |||
| |||
bool IsObject();
| |||
bool IsArray();
| |||
bool IsString();
| |||
bool IsNumber();
| |||
bool IsBool();
| |||
bool IsNull();
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Internal node |
| |||
//+------------------------------------------------------------------+
| |||
struct JsonNode
| |||
{
| |||
public:
| |||
uchar type;
| |||
uchar flags;
| |||
int parent;
| |||
int first_child;
| |||
int last_child;
| |||
int next_sibling;
| |||
int child_count;
| |||
| |||
int key_start;
| |||
int key_len;
| |||
uint key_hash;
| |||
| |||
int val_start;
| |||
int val_len;
| |||
| |||
double num;
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Main JSON parser class |
| |||
//+------------------------------------------------------------------+
| |||
class CJson
| |||
{
| |||
public:
| |||
// Public input buffer. Fill it directly for best performance.
| |||
uchar Buffer[];
| |||
| |||
// If InputSize >= 0, parser uses only InputSize bytes from Buffer.
| |||
// If InputSize < 0, parser uses ArraySize(Buffer).
| |||
int InputSize;
| |||
| |||
// Maximum nested container depth.
| |||
int MaxDepth;
| |||
| |||
// Build hash index for object member lookup.
| |||
bool UseHashIndex;
| |||
| |||
// Minimum number of object members before building hash index.
| |||
int HashThreshold;
| |||
| |||
protected:
| |||
int m_size;
| |||
int m_root;
| |||
| |||
ENUM_JSON_ERROR m_error;
| |||
int m_error_pos;
| |||
| |||
int m_node_used;
| |||
JsonNode m_nodes[];
| |||
| |||
int m_children[];
| |||
| |||
uchar m_pool[];
| |||
int m_pool_used;
| |||
| |||
int m_stack[];
| |||
uchar m_state[];
| |||
int m_stack_used;
| |||
| |||
int m_member_count;
| |||
| |||
int m_hash_size;
| |||
int m_hash_mask;
| |||
int m_hash_parent[];
| |||
uint m_hash_key[];
| |||
int m_hash_node[];
| |||
| |||
int m_pending_key_start;
| |||
int m_pending_key_len;
| |||
uint m_pending_key_hash;
| |||
uchar m_pending_flags;
| |||
bool m_pending_valid;
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| Small helpers |
| |||
//+---------------------------------------------------------------+
| |||
int Resolve(int node) const
| |||
{
| |||
return(node < 0 ? m_root : node);
| |||
}
| |||
| |||
bool SetError(ENUM_JSON_ERROR code, int pos)
| |||
{
| |||
m_error = code;
| |||
m_error_pos = pos;
| |||
return(false);
| |||
}
| |||
| |||
void SkipWs(int &pos)
| |||
{
| |||
while(pos < m_size)
| |||
{
| |||
uchar c = Buffer[pos];
| |||
if(c != 0x20 && c != 0x09 && c != 0x0A && c != 0x0D)
| |||
break;
| |||
pos++;
| |||
}
| |||
}
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| Memory helpers |
| |||
//+---------------------------------------------------------------+
| |||
bool EnsureNodes(int count, int pos)
| |||
{
| |||
int cap = ArraySize(m_nodes);
| |||
if(count <= cap)
| |||
return(true);
| |||
| |||
int new_cap = cap * 2;
| |||
if(new_cap < count)
| |||
new_cap = count;
| |||
if(new_cap < 1024)
| |||
new_cap = 1024;
| |||
| |||
if(ArrayResize(m_nodes, new_cap, new_cap + 4096) < 0)
| |||
return(SetError(JSON_MEMORY_ERROR, pos));
| |||
| |||
return(true);
| |||
}
| |||
| |||
bool EnsureStack(int count, int pos)
| |||
{
| |||
int cap = ArraySize(m_stack);
| |||
if(count <= cap)
| |||
return(true);
| |||
| |||
int new_cap = cap * 2;
| |||
if(new_cap < count)
| |||
new_cap = count;
| |||
if(new_cap < 64)
| |||
new_cap = 64;
| |||
| |||
if(ArrayResize(m_stack, new_cap, new_cap + 256) < 0)
| |||
return(SetError(JSON_MEMORY_ERROR, pos));
| |||
| |||
if(ArrayResize(m_state, new_cap, new_cap + 256) < 0)
| |||
return(SetError(JSON_MEMORY_ERROR, pos));
| |||
| |||
return(true);
| |||
}
| |||
| |||
bool EnsurePool(int add, int pos)
| |||
{
| |||
int cap = ArraySize(m_pool);
| |||
if(m_pool_used + add <= cap)
| |||
return(true);
| |||
| |||
int new_cap = cap * 2;
| |||
if(new_cap < m_pool_used + add)
| |||
new_cap = m_pool_used + add;
| |||
if(new_cap < 1024)
| |||
new_cap = 1024;
| |||
| |||
if(ArrayResize(m_pool, new_cap, new_cap + 4096) < 0)
| |||
return(SetError(JSON_MEMORY_ERROR, pos));
| |||
| |||
return(true);
| |||
}
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| Pool and hashing helpers |
| |||
//+---------------------------------------------------------------+
| |||
bool AppendPoolByte(uchar b, uint &h, int pos)
| |||
{
| |||
if(!EnsurePool(1, pos))
| |||
return(false);
| |||
| |||
m_pool[m_pool_used++] = b;
| |||
h = ((h ^ b) * JSON_FNV_PRIME);
| |||
return(true);
| |||
}
| |||
| |||
bool AppendPoolUtf8(uint cp, uint &h, int pos)
| |||
{
| |||
if(cp < 0x80)
| |||
return(AppendPoolByte((uchar)cp, h, pos));
| |||
| |||
if(cp < 0x800)
| |||
{
| |||
if(!AppendPoolByte((uchar)(0xC0 | (cp >> 6)), h, pos))
| |||
return(false);
| |||
return(AppendPoolByte((uchar)(0x80 | (cp & 0x3F)), h, pos));
| |||
}
| |||
| |||
if(cp < 0x10000)
| |||
{
| |||
if(!AppendPoolByte((uchar)(0xE0 | (cp >> 12)), h, pos))
| |||
return(false);
| |||
if(!AppendPoolByte((uchar)(0x80 | ((cp >> 6) & 0x3F)), h, pos))
| |||
return(false);
| |||
return(AppendPoolByte((uchar)(0x80 | (cp & 0x3F)), h, pos));
| |||
}
| |||
| |||
if(cp <= 0x10FFFF)
| |||
{
| |||
if(!AppendPoolByte((uchar)(0xF0 | (cp >> 18)), h, pos))
| |||
return(false);
| |||
if(!AppendPoolByte((uchar)(0x80 | ((cp >> 12) & 0x3F)), h, pos))
| |||
return(false);
| |||
if(!AppendPoolByte((uchar)(0x80 | ((cp >> 6) & 0x3F)), h, pos))
| |||
return(false);
| |||
return(AppendPoolByte((uchar)(0x80 | (cp & 0x3F)), h, pos));
| |||
}
| |||
| |||
return(SetError(JSON_INVALID_UNICODE, pos));
| |||
}
| |||
| |||
bool ParseHex4(int &cur, uint &val)
| |||
{
| |||
if(cur + 4 > m_size)
| |||
return(SetError(JSON_INVALID_UNICODE, cur));
| |||
| |||
val = 0;
| |||
| |||
for(int i = 0; i < 4; i++)
| |||
{
| |||
uchar c = Buffer[cur];
| |||
int hv;
| |||
| |||
if(c >= 0x30 && c <= 0x39)
| |||
hv = c - 0x30;
| |||
else if(c >= 0x41 && c <= 0x46)
| |||
hv = c - 0x41 + 10;
| |||
else if(c >= 0x61 && c <= 0x66)
| |||
hv = c - 0x61 + 10;
| |||
else
| |||
return(SetError(JSON_INVALID_UNICODE, cur));
| |||
| |||
val = (val << 4) | (uint)hv;
| |||
cur++;
| |||
}
| |||
| |||
return(true);
| |||
}
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| String parser |
| |||
//+---------------------------------------------------------------+
| |||
bool ParseStringSlow(int start,
| |||
int p,
| |||
uint h,
| |||
int &pos,
| |||
int &out_start,
| |||
int &out_len,
| |||
bool &out_decoded,
| |||
uint &out_hash)
| |||
{
| |||
int pool_start = m_pool_used;
| |||
| |||
int n = p - start;
| |||
if(n > 0)
| |||
{
| |||
if(!EnsurePool(n, start))
| |||
return(false);
| |||
| |||
int base = m_pool_used;
| |||
for(int i = 0; i < n; i++)
| |||
m_pool[base + i] = Buffer[start + i];
| |||
| |||
m_pool_used += n;
| |||
}
| |||
| |||
int cur = p;
| |||
| |||
while(cur < m_size)
| |||
{
| |||
int run = cur;
| |||
| |||
while(run < m_size)
| |||
{
| |||
uchar c = Buffer[run];
| |||
if(c == 0x22 || c == 0x5C || c < 0x20)
| |||
break;
| |||
run++;
| |||
}
| |||
| |||
int rn = run - cur;
| |||
if(rn > 0)
| |||
{
| |||
if(!EnsurePool(rn, cur))
| |||
return(false);
| |||
| |||
int base = m_pool_used;
| |||
for(int i = 0; i < rn; i++)
| |||
{
| |||
uchar b = Buffer[cur + i];
| |||
m_pool[base + i] = b;
| |||
h = ((h ^ b) * JSON_FNV_PRIME);
| |||
}
| |||
| |||
m_pool_used += rn;
| |||
cur = run;
| |||
}
| |||
| |||
if(cur >= m_size)
| |||
return(SetError(JSON_UNEXPECTED_END, pos));
| |||
| |||
uchar c = Buffer[cur];
| |||
| |||
if(c == 0x22)
| |||
{
| |||
out_start = pool_start;
| |||
out_len = m_pool_used - pool_start;
| |||
out_decoded = true;
| |||
out_hash = h;
| |||
pos = cur + 1;
| |||
return(true);
| |||
}
| |||
| |||
if(c < 0x20)
| |||
return(SetError(JSON_INVALID_STRING, cur));
| |||
| |||
// c == backslash
| |||
cur++;
| |||
if(cur >= m_size)
| |||
return(SetError(JSON_UNEXPECTED_END, cur));
| |||
| |||
uchar e = Buffer[cur];
| |||
| |||
switch(e)
| |||
{
| |||
case 0x22: // \"
| |||
if(!AppendPoolByte(0x22, h, cur))
| |||
return(false);
| |||
cur++;
| |||
break;
| |||
| |||
case 0x5C: // \\
| |||
if(!AppendPoolByte(0x5C, h, cur))
| |||
return(false);
| |||
cur++;
| |||
break;
| |||
| |||
case 0x2F: // \/
| |||
if(!AppendPoolByte(0x2F, h, cur))
| |||
return(false);
| |||
cur++;
| |||
break;
| |||
| |||
case 0x62: // \b
| |||
if(!AppendPoolByte(0x08, h, cur))
| |||
return(false);
| |||
cur++;
| |||
break;
| |||
| |||
case 0x66: // \f
| |||
if(!AppendPoolByte(0x0C, h, cur))
| |||
return(false);
| |||
cur++;
| |||
break;
| |||
| |||
case 0x6E: // \n
| |||
if(!AppendPoolByte(0x0A, h, cur))
| |||
return(false);
| |||
cur++;
| |||
break;
| |||
| |||
case 0x72: // \r
| |||
if(!AppendPoolByte(0x0D, h, cur))
| |||
return(false);
| |||
cur++;
| |||
break;
| |||
| |||
case 0x74: // \t
| |||
if(!AppendPoolByte(0x09, h, cur))
| |||
return(false);
| |||
cur++;
| |||
break;
| |||
| |||
case 0x75: // \uXXXX
| |||
{
| |||
cur++;
| |||
uint cp;
| |||
if(!ParseHex4(cur, cp))
| |||
return(false);
| |||
| |||
if(cp >= 0xD800 && cp <= 0xDBFF)
| |||
{
| |||
if(cur + 6 <= m_size && Buffer[cur] == 0x5C && Buffer[cur + 1] == 0x75)
| |||
{
| |||
cur += 2;
| |||
uint low;
| |||
if(!ParseHex4(cur, low))
| |||
return(false);
| |||
| |||
if(low >= 0xDC00 && low <= 0xDFFF)
| |||
cp = 0x10000 + ((cp - 0xD800) << 10) + (low - 0xDC00);
| |||
else
| |||
return(SetError(JSON_INVALID_UNICODE, cur));
| |||
}
| |||
else
| |||
{
| |||
return(SetError(JSON_INVALID_UNICODE, cur));
| |||
}
| |||
}
| |||
else if(cp >= 0xDC00 && cp <= 0xDFFF)
| |||
{
| |||
return(SetError(JSON_INVALID_UNICODE, cur));
| |||
}
| |||
| |||
if(!AppendPoolUtf8(cp, h, cur))
| |||
return(false);
| |||
| |||
break;
| |||
}
| |||
| |||
default:
| |||
return(SetError(JSON_INVALID_ESCAPE, cur));
| |||
}
| |||
}
| |||
| |||
return(SetError(JSON_UNEXPECTED_END, pos));
| |||
}
| |||
| |||
bool ParseStringToken(int &pos,
| |||
int &out_start,
| |||
int &out_len,
| |||
bool &out_decoded,
| |||
uint &out_hash)
| |||
{
| |||
if(pos >= m_size || Buffer[pos] != 0x22)
| |||
return(SetError(JSON_INVALID_STRING, pos));
| |||
| |||
int start = pos + 1;
| |||
int p = start;
| |||
uint h = JSON_FNV_INIT;
| |||
| |||
while(p < m_size)
| |||
{
| |||
uchar c = Buffer[p];
| |||
| |||
if(c == 0x22)
| |||
{
| |||
out_start = start;
| |||
out_len = p - start;
| |||
out_decoded = false;
| |||
out_hash = h;
| |||
pos = p + 1;
| |||
return(true);
| |||
}
| |||
| |||
if(c == 0x5C)
| |||
return(ParseStringSlow(start, p, h, pos, out_start, out_len, out_decoded, out_hash));
| |||
| |||
if(c < 0x20)
| |||
return(SetError(JSON_INVALID_STRING, p));
| |||
| |||
h = ((h ^ c) * JSON_FNV_PRIME);
| |||
p++;
| |||
}
| |||
| |||
return(SetError(JSON_UNEXPECTED_END, pos));
| |||
}
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| Number parser |
| |||
//+---------------------------------------------------------------+
| |||
bool ParseNumberToken(int &pos, double &val)
| |||
{
| |||
int start = pos;
| |||
bool neg = false;
| |||
| |||
if(pos < m_size && Buffer[pos] == 0x2D)
| |||
{
| |||
neg = true;
| |||
pos++;
| |||
}
| |||
| |||
if(pos >= m_size)
| |||
return(SetError(JSON_INVALID_NUMBER, start));
| |||
| |||
uchar c = Buffer[pos];
| |||
double intpart = 0.0;
| |||
| |||
if(c == 0x30)
| |||
{
| |||
pos++;
| |||
if(pos < m_size && Buffer[pos] >= 0x30 && Buffer[pos] <= 0x39)
| |||
return(SetError(JSON_INVALID_NUMBER, pos));
| |||
}
| |||
else if(c >= 0x31 && c <= 0x39)
| |||
{
| |||
while(pos < m_size)
| |||
{
| |||
uchar d = Buffer[pos];
| |||
if(d < 0x30 || d > 0x39)
| |||
break;
| |||
| |||
intpart = intpart * 10.0 + (double)(d - 0x30);
| |||
pos++;
| |||
}
| |||
}
| |||
else
| |||
{
| |||
return(SetError(JSON_INVALID_NUMBER, pos));
| |||
}
| |||
| |||
if(pos < m_size && Buffer[pos] == 0x2E)
| |||
{
| |||
pos++;
| |||
| |||
if(pos >= m_size || Buffer[pos] < 0x30 || Buffer[pos] > 0x39)
| |||
return(SetError(JSON_INVALID_NUMBER, pos));
| |||
| |||
double frac = 0.0;
| |||
double scale = 0.1;
| |||
| |||
while(pos < m_size)
| |||
{
| |||
uchar d = Buffer[pos];
| |||
if(d < 0x30 || d > 0x39)
| |||
break;
| |||
| |||
frac += (double)(d - 0x30) * scale;
| |||
scale *= 0.1;
| |||
pos++;
| |||
}
| |||
| |||
intpart += frac;
| |||
}
| |||
| |||
int exp = 0;
| |||
bool exp_neg = false;
| |||
| |||
if(pos < m_size && (Buffer[pos] == 0x65 || Buffer[pos] == 0x45))
| |||
{
| |||
pos++;
| |||
| |||
if(pos < m_size && (Buffer[pos] == 0x2B || Buffer[pos] == 0x2D))
| |||
{
| |||
exp_neg = (Buffer[pos] == 0x2D);
| |||
pos++;
| |||
}
| |||
| |||
if(pos >= m_size || Buffer[pos] < 0x30 || Buffer[pos] > 0x39)
| |||
return(SetError(JSON_INVALID_NUMBER, pos));
| |||
| |||
while(pos < m_size)
| |||
{
| |||
uchar d = Buffer[pos];
| |||
if(d < 0x30 || d > 0x39)
| |||
break;
| |||
| |||
if(exp < 100000)
| |||
exp = exp * 10 + (d - 0x30);
| |||
| |||
pos++;
| |||
}
| |||
}
| |||
| |||
val = neg ? -intpart : intpart;
| |||
| |||
if(exp != 0)
| |||
{
| |||
int e = exp;
| |||
if(e > 308)
| |||
e = 308;
| |||
| |||
double de = (double)e;
| |||
val *= MathPow(10.0, exp_neg ? -de : de);
| |||
}
| |||
| |||
return(true);
| |||
}
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| Node construction helpers |
| |||
//+---------------------------------------------------------------+
| |||
int NewNode(uchar type, int parent, int pos)
| |||
{
| |||
if(!EnsureNodes(m_node_used + 1, pos))
| |||
return(-1);
| |||
| |||
int idx = m_node_used++;
| |||
| |||
m_nodes[idx].type = type;
| |||
m_nodes[idx].flags = 0;
| |||
m_nodes[idx].parent = parent;
| |||
m_nodes[idx].first_child = -1;
| |||
m_nodes[idx].last_child = -1;
| |||
m_nodes[idx].next_sibling = -1;
| |||
m_nodes[idx].child_count = 0;
| |||
| |||
m_nodes[idx].key_start = 0;
| |||
m_nodes[idx].key_len = 0;
| |||
m_nodes[idx].key_hash = 0;
| |||
| |||
m_nodes[idx].val_start = 0;
| |||
m_nodes[idx].val_len = 0;
| |||
| |||
m_nodes[idx].num = 0.0;
| |||
| |||
return(idx);
| |||
}
| |||
| |||
bool AssignPendingKey(int node, int parent, int pos)
| |||
{
| |||
if(parent < 0)
| |||
{
| |||
m_pending_valid = false;
| |||
return(true);
| |||
}
| |||
| |||
if(m_nodes[parent].type != (uchar)JSON_OBJECT)
| |||
{
| |||
m_pending_valid = false;
| |||
return(true);
| |||
}
| |||
| |||
if(!m_pending_valid)
| |||
return(SetError(JSON_EXPECTED_KEY, pos));
| |||
| |||
m_nodes[node].key_start = m_pending_key_start;
| |||
m_nodes[node].key_len = m_pending_key_len;
| |||
m_nodes[node].key_hash = m_pending_key_hash;
| |||
| |||
if((m_pending_flags & JSON_FLAG_KEY_DECODED) != 0)
| |||
m_nodes[node].flags = (uchar)(m_nodes[node].flags | JSON_FLAG_KEY_DECODED);
| |||
| |||
m_pending_valid = false;
| |||
return(true);
| |||
}
| |||
| |||
void AddChild(int parent, int child)
| |||
{
| |||
if(parent < 0)
| |||
return;
| |||
| |||
if(m_nodes[parent].first_child < 0)
| |||
{
| |||
m_nodes[parent].first_child = child;
| |||
}
| |||
else
| |||
{
| |||
m_nodes[m_nodes[parent].last_child].next_sibling = child;
| |||
}
| |||
| |||
m_nodes[parent].last_child = child;
| |||
m_nodes[parent].child_count++;
| |||
| |||
if(m_nodes[parent].type == (uchar)JSON_OBJECT)
| |||
m_member_count++;
| |||
}
| |||
| |||
bool PushStack(int node, uchar state, int pos)
| |||
{
| |||
if(m_stack_used >= MaxDepth)
| |||
return(SetError(JSON_MAX_DEPTH, pos));
| |||
| |||
if(!EnsureStack(m_stack_used + 1, pos))
| |||
return(false);
| |||
| |||
m_stack[m_stack_used] = node;
| |||
m_state[m_stack_used] = state;
| |||
m_stack_used++;
| |||
| |||
return(true);
| |||
}
| |||
| |||
bool ParseObjectKey(int &pos)
| |||
{
| |||
int s, l;
| |||
bool dec;
| |||
uint h;
| |||
| |||
if(!ParseStringToken(pos, s, l, dec, h))
| |||
return(false);
| |||
| |||
m_pending_key_start = s;
| |||
m_pending_key_len = l;
| |||
m_pending_key_hash = h;
| |||
m_pending_flags = dec ? (uchar)JSON_FLAG_KEY_DECODED : 0;
| |||
m_pending_valid = true;
| |||
| |||
return(true);
| |||
}
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| Create a value node at current position |
| |||
//+---------------------------------------------------------------+
| |||
bool CreateValueNode(int &pos, int parent, int &out_node)
| |||
{
| |||
if(pos >= m_size)
| |||
return(SetError(JSON_UNEXPECTED_END, pos));
| |||
| |||
uchar c = Buffer[pos];
| |||
| |||
// Object
| |||
if(c == 0x7B)
| |||
{
| |||
int node = NewNode((uchar)JSON_OBJECT, parent, pos);
| |||
if(node < 0)
| |||
return(false);
| |||
| |||
if(!AssignPendingKey(node, parent, pos))
| |||
return(false);
| |||
| |||
AddChild(parent, node);
| |||
pos++;
| |||
| |||
if(!PushStack(node, (uchar)JSON_STATE_OBJ_KEY_OR_END, pos))
| |||
return(false);
| |||
| |||
out_node = node;
| |||
return(true);
| |||
}
| |||
| |||
// Array
| |||
if(c == 0x5B)
| |||
{
| |||
int node = NewNode((uchar)JSON_ARRAY, parent, pos);
| |||
if(node < 0)
| |||
return(false);
| |||
| |||
if(!AssignPendingKey(node, parent, pos))
| |||
return(false);
| |||
| |||
AddChild(parent, node);
| |||
pos++;
| |||
| |||
if(!PushStack(node, (uchar)JSON_STATE_ARRAY_VALUE_OR_END, pos))
| |||
return(false);
| |||
| |||
out_node = node;
| |||
return(true);
| |||
}
| |||
| |||
// String
| |||
if(c == 0x22)
| |||
{
| |||
int s, l;
| |||
bool dec;
| |||
uint h;
| |||
| |||
if(!ParseStringToken(pos, s, l, dec, h))
| |||
return(false);
| |||
| |||
int node = NewNode((uchar)JSON_STRING, parent, pos);
| |||
if(node < 0)
| |||
return(false);
| |||
| |||
if(!AssignPendingKey(node, parent, pos))
| |||
return(false);
| |||
| |||
m_nodes[node].val_start = s;
| |||
m_nodes[node].val_len = l;
| |||
| |||
if(dec)
| |||
m_nodes[node].flags = (uchar)(m_nodes[node].flags | JSON_FLAG_VAL_DECODED);
| |||
| |||
AddChild(parent, node);
| |||
| |||
out_node = node;
| |||
return(true);
| |||
}
| |||
| |||
// true
| |||
if(c == 0x74)
| |||
{
| |||
if(pos + 4 > m_size ||
| |||
Buffer[pos + 1] != 0x72 ||
| |||
Buffer[pos + 2] != 0x75 ||
| |||
Buffer[pos + 3] != 0x65)
| |||
{
| |||
return(SetError(JSON_INVALID_LITERAL, pos));
| |||
}
| |||
| |||
int node = NewNode((uchar)JSON_BOOL, parent, pos);
| |||
if(node < 0)
| |||
return(false);
| |||
| |||
if(!AssignPendingKey(node, parent, pos))
| |||
return(false);
| |||
| |||
m_nodes[node].num = 1.0;
| |||
AddChild(parent, node);
| |||
| |||
pos += 4;
| |||
out_node = node;
| |||
return(true);
| |||
}
| |||
| |||
// false
| |||
if(c == 0x66)
| |||
{
| |||
if(pos + 5 > m_size ||
| |||
Buffer[pos + 1] != 0x61 ||
| |||
Buffer[pos + 2] != 0x6C ||
| |||
Buffer[pos + 3] != 0x73 ||
| |||
Buffer[pos + 4] != 0x65)
| |||
{
| |||
return(SetError(JSON_INVALID_LITERAL, pos));
| |||
}
| |||
| |||
int node = NewNode((uchar)JSON_BOOL, parent, pos);
| |||
if(node < 0)
| |||
return(false);
| |||
| |||
if(!AssignPendingKey(node, parent, pos))
| |||
return(false);
| |||
| |||
m_nodes[node].num = 0.0;
| |||
AddChild(parent, node);
| |||
| |||
pos += 5;
| |||
out_node = node;
| |||
return(true);
| |||
}
| |||
| |||
// null
| |||
if(c == 0x6E)
| |||
{
| |||
if(pos + 4 > m_size ||
| |||
Buffer[pos + 1] != 0x75 ||
| |||
Buffer[pos + 2] != 0x6C ||
| |||
Buffer[pos + 3] != 0x6C)
| |||
{
| |||
return(SetError(JSON_INVALID_LITERAL, pos));
| |||
}
| |||
| |||
int node = NewNode((uchar)JSON_NULL, parent, pos);
| |||
if(node < 0)
| |||
return(false);
| |||
| |||
if(!AssignPendingKey(node, parent, pos))
| |||
return(false);
| |||
| |||
m_nodes[node].num = 0.0;
| |||
AddChild(parent, node);
| |||
| |||
pos += 4;
| |||
out_node = node;
| |||
return(true);
| |||
}
| |||
| |||
// Number
| |||
if(c == 0x2D || (c >= 0x30 && c <= 0x39))
| |||
{
| |||
double v;
| |||
if(!ParseNumberToken(pos, v))
| |||
return(false);
| |||
| |||
int node = NewNode((uchar)JSON_NUMBER, parent, pos);
| |||
if(node < 0)
| |||
return(false);
| |||
| |||
if(!AssignPendingKey(node, parent, pos))
| |||
return(false);
| |||
| |||
m_nodes[node].num = v;
| |||
AddChild(parent, node);
| |||
| |||
out_node = node;
| |||
return(true);
| |||
}
| |||
| |||
return(SetError(JSON_UNEXPECTED_CHARACTER, pos));
| |||
}
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| Build contiguous child index |
| |||
//+---------------------------------------------------------------+
| |||
bool BuildChildren(int pos)
| |||
{
| |||
int total = 0;
| |||
| |||
for(int i = 0; i < m_node_used; i++)
| |||
{
| |||
m_nodes[i].last_child = total;
| |||
total += m_nodes[i].child_count;
| |||
}
| |||
| |||
if(total == 0)
| |||
{
| |||
ArrayFree(m_children);
| |||
| |||
for(int i = 0; i < m_node_used; i++)
| |||
m_nodes[i].first_child = 0;
| |||
| |||
return(true);
| |||
}
| |||
| |||
if(ArrayResize(m_children, total, total + 1024) < 0)
| |||
return(SetError(JSON_MEMORY_ERROR, pos));
| |||
| |||
for(int i = 0; i < m_node_used; i++)
| |||
{
| |||
int offset = m_nodes[i].last_child;
| |||
int child = m_nodes[i].first_child;
| |||
int idx = 0;
| |||
| |||
while(child != -1)
| |||
{
| |||
m_children[offset + idx] = child;
| |||
child = m_nodes[child].next_sibling;
| |||
idx++;
| |||
}
| |||
| |||
m_nodes[i].first_child = offset;
| |||
m_nodes[i].last_child = -1;
| |||
}
| |||
| |||
return(true);
| |||
}
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| Hash helpers |
| |||
//+---------------------------------------------------------------+
| |||
uint HashMix(int parent, uint key_hash) const
| |||
{
| |||
uint h = key_hash ^ ((uint)parent * (uint)0x9E3779B9);
| |||
h ^= (h >> 16);
| |||
h *= (uint)0x85EBCA6B;
| |||
h ^= (h >> 13);
| |||
h *= (uint)0xC2B2AE35;
| |||
h ^= (h >> 16);
| |||
return(h);
| |||
}
| |||
| |||
uint HashBytes(uchar &data[], int len) const
| |||
{
| |||
uint h = JSON_FNV_INIT;
| |||
| |||
for(int i = 0; i < len; i++)
| |||
h = ((h ^ data[i]) * JSON_FNV_PRIME);
| |||
| |||
return(h);
| |||
}
| |||
| |||
bool KeyEquals(int node, uchar &key[], int len, uint hash)
| |||
{
| |||
if(node < 0 || node >= m_node_used)
| |||
return(false);
| |||
| |||
if(m_nodes[node].key_len != len)
| |||
return(false);
| |||
| |||
if(m_nodes[node].key_hash != hash)
| |||
return(false);
| |||
| |||
if(len == 0)
| |||
return(true);
| |||
| |||
int start = m_nodes[node].key_start;
| |||
| |||
if((m_nodes[node].flags & JSON_FLAG_KEY_DECODED) != 0)
| |||
{
| |||
for(int i = 0; i < len; i++)
| |||
{
| |||
if(m_pool[start + i] != key[i])
| |||
return(false);
| |||
}
| |||
}
| |||
else
| |||
{
| |||
for(int i = 0; i < len; i++)
| |||
{
| |||
if(Buffer[start + i] != key[i])
| |||
return(false);
| |||
}
| |||
}
| |||
| |||
return(true);
| |||
}
| |||
| |||
void InsertHash(int parent, uint key_hash, int node)
| |||
{
| |||
if(m_hash_size <= 0)
| |||
return;
| |||
| |||
uint pos = HashMix(parent, key_hash) & (uint)m_hash_mask;
| |||
int scanned = 0;
| |||
| |||
while(m_hash_parent[pos] != -1 && scanned < m_hash_size)
| |||
{
| |||
pos = (pos + 1) & (uint)m_hash_mask;
| |||
scanned++;
| |||
}
| |||
| |||
if(scanned >= m_hash_size)
| |||
return;
| |||
| |||
m_hash_parent[pos] = parent;
| |||
m_hash_key[pos] = key_hash;
| |||
m_hash_node[pos] = node;
| |||
}
| |||
| |||
bool BuildHash(int pos)
| |||
{
| |||
m_hash_size = 0;
| |||
m_hash_mask = 0;
| |||
| |||
if(m_member_count <= 0)
| |||
return(true);
| |||
| |||
int target = m_member_count * 2;
| |||
if(target <= 0)
| |||
target = 0x40000000;
| |||
if(target < 16)
| |||
target = 16;
| |||
| |||
int table_size = 1;
| |||
while(table_size < target && table_size < 0x40000000)
| |||
table_size <<= 1;
| |||
| |||
if(ArrayResize(m_hash_parent, table_size, table_size + 1024) < 0)
| |||
return(SetError(JSON_MEMORY_ERROR, pos));
| |||
| |||
if(ArrayResize(m_hash_key, table_size, table_size + 1024) < 0)
| |||
return(SetError(JSON_MEMORY_ERROR, pos));
| |||
| |||
if(ArrayResize(m_hash_node, table_size, table_size + 1024) < 0)
| |||
return(SetError(JSON_MEMORY_ERROR, pos));
| |||
| |||
for(int i = 0; i < table_size; i++)
| |||
m_hash_parent[i] = -1;
| |||
| |||
m_hash_size = table_size;
| |||
m_hash_mask = table_size - 1;
| |||
| |||
for(int i = 0; i < m_node_used; i++)
| |||
{
| |||
int p = m_nodes[i].parent;
| |||
if(p >= 0 && m_nodes[p].type == (uchar)JSON_OBJECT)
| |||
InsertHash(p, m_nodes[i].key_hash, i);
| |||
}
| |||
| |||
return(true);
| |||
}
| |||
| |||
public:
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| Reset / Clear |
| |||
//+---------------------------------------------------------------+
| |||
void Reset()
| |||
{
| |||
m_size = 0;
| |||
m_root = -1;
| |||
| |||
m_error = JSON_OK;
| |||
m_error_pos = -1;
| |||
| |||
m_node_used = 0;
| |||
m_pool_used = 0;
| |||
m_stack_used = 0;
| |||
| |||
m_member_count = 0;
| |||
| |||
m_hash_size = 0;
| |||
m_hash_mask = 0;
| |||
| |||
m_pending_key_start = 0;
| |||
m_pending_key_len = 0;
| |||
m_pending_key_hash = 0;
| |||
m_pending_flags = 0;
| |||
m_pending_valid = false;
| |||
}
| |||
| |||
void Clear()
| |||
{
| |||
ArrayFree(m_nodes);
| |||
ArrayFree(m_children);
| |||
ArrayFree(m_pool);
| |||
ArrayFree(m_stack);
| |||
ArrayFree(m_state);
| |||
| |||
ArrayFree(m_hash_parent);
| |||
ArrayFree(m_hash_key);
| |||
ArrayFree(m_hash_node);
| |||
| |||
Reset();
| |||
}
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| Constructor / Destructor |
| |||
//+---------------------------------------------------------------+
| |||
CJson()
| |||
{
| |||
InputSize = -1;
| |||
MaxDepth = 1024;
| |||
UseHashIndex = true;
| |||
HashThreshold = 16;
| |||
| |||
Reset();
| |||
}
| |||
| |||
~CJson()
| |||
{
| |||
Clear();
| |||
}
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| Main parse function |
| |||
//+---------------------------------------------------------------+
| |||
bool Parse()
| |||
{
| |||
Reset();
| |||
| |||
if(MaxDepth <= 0)
| |||
MaxDepth = 1024;
| |||
| |||
if(HashThreshold < 0)
| |||
HashThreshold = 0;
| |||
| |||
ArraySetAsSeries(Buffer, false);
| |||
| |||
int buf_size = ArraySize(Buffer);
| |||
| |||
if(InputSize >= 0)
| |||
m_size = (InputSize < buf_size ? InputSize : buf_size);
| |||
else
| |||
m_size = buf_size;
| |||
| |||
if(m_size < 0)
| |||
m_size = 0;
| |||
| |||
int pos = 0;
| |||
| |||
// Optional UTF-8 BOM.
| |||
if(m_size >= 3 && Buffer[0] == 0xEF && Buffer[1] == 0xBB && Buffer[2] == 0xBF)
| |||
pos = 3;
| |||
| |||
SkipWs(pos);
| |||
| |||
if(pos >= m_size)
| |||
return(SetError(JSON_UNEXPECTED_END, pos));
| |||
| |||
int root;
| |||
if(!CreateValueNode(pos, -1, root))
| |||
return(false);
| |||
| |||
m_root = root;
| |||
| |||
while(m_stack_used > 0)
| |||
{
| |||
int si = m_stack_used - 1;
| |||
int node = m_stack[si];
| |||
uchar st = m_state[si];
| |||
| |||
if(st == (uchar)JSON_STATE_OBJ_KEY_OR_END)
| |||
{
| |||
SkipWs(pos);
| |||
if(pos >= m_size)
| |||
return(SetError(JSON_UNEXPECTED_END, pos));
| |||
| |||
uchar c = Buffer[pos];
| |||
| |||
if(c == 0x7D)
| |||
{
| |||
pos++;
| |||
m_stack_used--;
| |||
continue;
| |||
}
| |||
| |||
if(c != 0x22)
| |||
return(SetError(JSON_EXPECTED_KEY, pos));
| |||
| |||
if(!ParseObjectKey(pos))
| |||
return(false);
| |||
| |||
m_state[si] = (uchar)JSON_STATE_OBJ_COLON;
| |||
}
| |||
else if(st == (uchar)JSON_STATE_OBJ_KEY)
| |||
{
| |||
SkipWs(pos);
| |||
if(pos >= m_size)
| |||
return(SetError(JSON_UNEXPECTED_END, pos));
| |||
| |||
uchar c = Buffer[pos];
| |||
| |||
if(c != 0x22)
| |||
return(SetError(JSON_EXPECTED_KEY, pos));
| |||
| |||
if(!ParseObjectKey(pos))
| |||
return(false);
| |||
| |||
m_state[si] = (uchar)JSON_STATE_OBJ_COLON;
| |||
}
| |||
else if(st == (uchar)JSON_STATE_OBJ_COLON)
| |||
{
| |||
SkipWs(pos);
| |||
if(pos >= m_size)
| |||
return(SetError(JSON_UNEXPECTED_END, pos));
| |||
| |||
if(Buffer[pos] != 0x3A)
| |||
return(SetError(JSON_EXPECTED_COLON, pos));
| |||
| |||
pos++;
| |||
m_state[si] = (uchar)JSON_STATE_OBJ_VALUE;
| |||
}
| |||
else if(st == (uchar)JSON_STATE_OBJ_VALUE)
| |||
{
| |||
SkipWs(pos);
| |||
if(pos >= m_size)
| |||
return(SetError(JSON_UNEXPECTED_END, pos));
| |||
| |||
m_state[si] = (uchar)JSON_STATE_OBJ_COMMA_OR_END;
| |||
| |||
int child;
| |||
if(!CreateValueNode(pos, node, child))
| |||
return(false);
| |||
}
| |||
else if(st == (uchar)JSON_STATE_OBJ_COMMA_OR_END)
| |||
{
| |||
SkipWs(pos);
| |||
if(pos >= m_size)
| |||
return(SetError(JSON_UNEXPECTED_END, pos));
| |||
| |||
uchar c = Buffer[pos];
| |||
| |||
if(c == 0x2C)
| |||
{
| |||
pos++;
| |||
m_state[si] = (uchar)JSON_STATE_OBJ_KEY;
| |||
}
| |||
else if(c == 0x7D)
| |||
{
| |||
pos++;
| |||
m_stack_used--;
| |||
}
| |||
else
| |||
{
| |||
return(SetError(JSON_EXPECTED_COMMA, pos));
| |||
}
| |||
}
| |||
else if(st == (uchar)JSON_STATE_ARRAY_VALUE_OR_END)
| |||
{
| |||
SkipWs(pos);
| |||
if(pos >= m_size)
| |||
return(SetError(JSON_UNEXPECTED_END, pos));
| |||
| |||
uchar c = Buffer[pos];
| |||
| |||
if(c == 0x5D)
| |||
{
| |||
pos++;
| |||
m_stack_used--;
| |||
continue;
| |||
}
| |||
| |||
m_state[si] = (uchar)JSON_STATE_ARRAY_COMMA_OR_END;
| |||
| |||
int child;
| |||
if(!CreateValueNode(pos, node, child))
| |||
return(false);
| |||
}
| |||
else if(st == (uchar)JSON_STATE_ARRAY_VALUE)
| |||
{
| |||
SkipWs(pos);
| |||
if(pos >= m_size)
| |||
return(SetError(JSON_UNEXPECTED_END, pos));
| |||
| |||
uchar c = Buffer[pos];
| |||
| |||
if(c == 0x5D)
| |||
return(SetError(JSON_EXPECTED_VALUE, pos));
| |||
| |||
m_state[si] = (uchar)JSON_STATE_ARRAY_COMMA_OR_END;
| |||
| |||
int child;
| |||
if(!CreateValueNode(pos, node, child))
| |||
return(false);
| |||
}
| |||
else if(st == (uchar)JSON_STATE_ARRAY_COMMA_OR_END)
| |||
{
| |||
SkipWs(pos);
| |||
if(pos >= m_size)
| |||
return(SetError(JSON_UNEXPECTED_END, pos));
| |||
| |||
uchar c = Buffer[pos];
| |||
| |||
if(c == 0x2C)
| |||
{
| |||
pos++;
| |||
m_state[si] = (uchar)JSON_STATE_ARRAY_VALUE;
| |||
}
| |||
else if(c == 0x5D)
| |||
{
| |||
pos++;
| |||
m_stack_used--;
| |||
}
| |||
else
| |||
{
| |||
return(SetError(JSON_EXPECTED_COMMA, pos));
| |||
}
| |||
}
| |||
else
| |||
{
| |||
return(SetError(JSON_UNKNOWN_ERROR, pos));
| |||
}
| |||
}
| |||
| |||
SkipWs(pos);
| |||
| |||
if(pos != m_size)
| |||
return(SetError(JSON_TRAILING_DATA, pos));
| |||
| |||
if(!BuildChildren(pos))
| |||
return(false);
| |||
| |||
if(UseHashIndex && m_member_count >= HashThreshold)
| |||
{
| |||
if(!BuildHash(pos))
| |||
return(false);
| |||
}
| |||
else
| |||
{
| |||
m_hash_size = 0;
| |||
}
| |||
| |||
return(true);
| |||
}
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| Error API |
| |||
//+---------------------------------------------------------------+
| |||
ENUM_JSON_ERROR GetError() const
| |||
{
| |||
return(m_error);
| |||
}
| |||
| |||
bool HasError() const
| |||
{
| |||
return(m_error != JSON_OK);
| |||
}
| |||
| |||
string GetErrorMessage() const
| |||
{
| |||
switch(m_error)
| |||
{
| |||
case JSON_OK: return("OK");
| |||
case JSON_UNKNOWN_ERROR: return("Unknown error");
| |||
case JSON_UNEXPECTED_CHARACTER: return("Unexpected character");
| |||
case JSON_UNEXPECTED_END: return("Unexpected end of input");
| |||
case JSON_INVALID_NUMBER: return("Invalid number");
| |||
case JSON_INVALID_STRING: return("Invalid string");
| |||
case JSON_INVALID_ESCAPE: return("Invalid escape sequence");
| |||
case JSON_INVALID_UNICODE: return("Invalid unicode sequence");
| |||
case JSON_EXPECTED_COLON: return("Expected colon");
| |||
case JSON_EXPECTED_COMMA: return("Expected comma");
| |||
case JSON_EXPECTED_OBJECT: return("Expected object");
| |||
case JSON_EXPECTED_ARRAY: return("Expected array");
| |||
case JSON_EXPECTED_KEY: return("Expected object key");
| |||
case JSON_EXPECTED_VALUE: return("Expected value");
| |||
case JSON_INVALID_LITERAL: return("Invalid literal");
| |||
case JSON_MAX_DEPTH: return("Maximum depth exceeded");
| |||
case JSON_MEMORY_ERROR: return("Memory allocation error");
| |||
case JSON_TRAILING_DATA: return("Trailing data after JSON document");
| |||
}
| |||
| |||
return("Unknown error");
| |||
}
| |||
| |||
int GetErrorPosition() const
| |||
{
| |||
return(m_error_pos);
| |||
}
| |||
| |||
int GetLine() const
| |||
{
| |||
if(m_error_pos < 0)
| |||
return(0);
| |||
| |||
int limit = m_error_pos;
| |||
if(limit > m_size)
| |||
limit = m_size;
| |||
| |||
int line = 1;
| |||
| |||
for(int i = 0; i < limit; i++)
| |||
{
| |||
if(Buffer[i] == 0x0A)
| |||
line++;
| |||
}
| |||
| |||
return(line);
| |||
}
| |||
| |||
int GetColumn() const
| |||
{
| |||
if(m_error_pos < 0)
| |||
return(0);
| |||
| |||
int limit = m_error_pos;
| |||
if(limit > m_size)
| |||
limit = m_size;
| |||
| |||
int col = 1;
| |||
| |||
for(int i = limit - 1; i >= 0; i--)
| |||
{
| |||
if(Buffer[i] == 0x0A)
| |||
break;
| |||
| |||
col++;
| |||
}
| |||
| |||
return(col);
| |||
}
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| Basic node API |
| |||
//+---------------------------------------------------------------+
| |||
int Root() const
| |||
{
| |||
return(m_root);
| |||
}
| |||
| |||
bool Exists(int node = -1)
| |||
{
| |||
int n = Resolve(node);
| |||
return(n >= 0 && n < m_node_used);
| |||
}
| |||
| |||
ENUM_JSON_TYPE GetType(int node = -1)
| |||
{
| |||
int n = Resolve(node);
| |||
| |||
if(n < 0 || n >= m_node_used)
| |||
return(JSON_NONE);
| |||
| |||
return((ENUM_JSON_TYPE)m_nodes[n].type);
| |||
}
| |||
| |||
bool IsObject(int node = -1)
| |||
{
| |||
return(GetType(node) == JSON_OBJECT);
| |||
}
| |||
| |||
bool IsArray(int node = -1)
| |||
{
| |||
return(GetType(node) == JSON_ARRAY);
| |||
}
| |||
| |||
bool IsString(int node = -1)
| |||
{
| |||
return(GetType(node) == JSON_STRING);
| |||
}
| |||
| |||
bool IsNumber(int node = -1)
| |||
{
| |||
return(GetType(node) == JSON_NUMBER);
| |||
}
| |||
| |||
bool IsBool(int node = -1)
| |||
{
| |||
return(GetType(node) == JSON_BOOL);
| |||
}
| |||
| |||
bool IsNull(int node = -1)
| |||
{
| |||
return(GetType(node) == JSON_NULL);
| |||
}
| |||
| |||
int Size(int node = -1)
| |||
{
| |||
int n = Resolve(node);
| |||
| |||
if(n < 0 || n >= m_node_used)
| |||
return(0);
| |||
| |||
uchar t = m_nodes[n].type;
| |||
| |||
if(t == (uchar)JSON_OBJECT || t == (uchar)JSON_ARRAY)
| |||
return(m_nodes[n].child_count);
| |||
| |||
return(0);
| |||
}
| |||
| |||
int Count(int node = -1)
| |||
{
| |||
return(Size(node));
| |||
}
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| Child access |
| |||
//+---------------------------------------------------------------+
| |||
int GetChild(int parent, int index)
| |||
{
| |||
int p = (parent < 0 ? m_root : parent);
| |||
| |||
if(p < 0 || p >= m_node_used)
| |||
return(-1);
| |||
| |||
uchar t = m_nodes[p].type;
| |||
| |||
if(t != (uchar)JSON_OBJECT && t != (uchar)JSON_ARRAY)
| |||
return(-1);
| |||
| |||
if(index < 0 || index >= m_nodes[p].child_count)
| |||
return(-1);
| |||
| |||
return(m_children[m_nodes[p].first_child + index]);
| |||
}
| |||
| |||
int FindChild(int parent, uchar &key[], int key_len)
| |||
{
| |||
int p = (parent < 0 ? m_root : parent);
| |||
| |||
if(p < 0 || p >= m_node_used)
| |||
return(-1);
| |||
| |||
if(m_nodes[p].type != (uchar)JSON_OBJECT)
| |||
return(-1);
| |||
| |||
if(key_len < 0)
| |||
return(-1);
| |||
| |||
uint qhash = HashBytes(key, key_len);
| |||
| |||
if(m_hash_size > 0)
| |||
{
| |||
uint pos = HashMix(p, qhash) & (uint)m_hash_mask;
| |||
int scanned = 0;
| |||
| |||
while(m_hash_parent[pos] != -1 && scanned < m_hash_size)
| |||
{
| |||
if(m_hash_parent[pos] == p && m_hash_key[pos] == qhash)
| |||
{
| |||
int child = m_hash_node[pos];
| |||
if(KeyEquals(child, key, key_len, qhash))
| |||
return(child);
| |||
}
| |||
| |||
pos = (pos + 1) & (uint)m_hash_mask;
| |||
scanned++;
| |||
}
| |||
| |||
return(-1);
| |||
}
| |||
| |||
int offset = m_nodes[p].first_child;
| |||
int count = m_nodes[p].child_count;
| |||
| |||
for(int i = 0; i < count; i++)
| |||
{
| |||
int child = m_children[offset + i];
| |||
if(KeyEquals(child, key, key_len, qhash))
| |||
return(child);
| |||
}
| |||
| |||
return(-1);
| |||
}
| |||
| |||
int FindChild(int parent, const string &key)
| |||
{
| |||
uchar bytes[];
| |||
int len = StringToCharArray(key, bytes, 0, -1, JSON_CP_UTF8);
| |||
| |||
if(len < 0)
| |||
{
| |||
len = StringToCharArray(key, bytes);
| |||
if(len < 0)
| |||
return(-1);
| |||
}
| |||
| |||
if(len > 0 && bytes[len - 1] == 0)
| |||
len--;
| |||
| |||
return(FindChild(parent, bytes, len));
| |||
}
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| Key and value access |
| |||
//+---------------------------------------------------------------+
| |||
string GetKey(int node)
| |||
{
| |||
if(node < 0 || node >= m_node_used)
| |||
return("");
| |||
| |||
int parent = m_nodes[node].parent;
| |||
| |||
if(parent < 0 || parent >= m_node_used)
| |||
return("");
| |||
| |||
if(m_nodes[parent].type != (uchar)JSON_OBJECT)
| |||
return("");
| |||
| |||
int len = m_nodes[node].key_len;
| |||
| |||
if(len <= 0)
| |||
return("");
| |||
| |||
int start = m_nodes[node].key_start;
| |||
| |||
if((m_nodes[node].flags & JSON_FLAG_KEY_DECODED) != 0)
| |||
return(CharArrayToString(m_pool, start, len, JSON_CP_UTF8));
| |||
| |||
return(CharArrayToString(Buffer, start, len, JSON_CP_UTF8));
| |||
}
| |||
| |||
string GetString(int node = -1)
| |||
{
| |||
int n = Resolve(node);
| |||
| |||
if(n < 0 || n >= m_node_used)
| |||
return("");
| |||
| |||
uchar t = m_nodes[n].type;
| |||
| |||
if(t == (uchar)JSON_STRING)
| |||
{
| |||
int len = m_nodes[n].val_len;
| |||
| |||
if(len <= 0)
| |||
return("");
| |||
| |||
int start = m_nodes[n].val_start;
| |||
| |||
if((m_nodes[n].flags & JSON_FLAG_VAL_DECODED) != 0)
| |||
return(CharArrayToString(m_pool, start, len, JSON_CP_UTF8));
| |||
| |||
return(CharArrayToString(Buffer, start, len, JSON_CP_UTF8));
| |||
}
| |||
| |||
// [CORRECION POR NIQUE](DOUBLE TO STRING NO TIENE UN 3 PARAMETRO)
| |||
// VERSION ORIGINAL: DoubleToString(m_nodes[n].num, 16, false)
| |||
// Correcion:
| |||
if(t == (uchar)JSON_NUMBER)
| |||
return(DoubleToString(m_nodes[n].num, 16));
| |||
| |||
if(t == (uchar)JSON_BOOL)
| |||
return(m_nodes[n].num != 0.0 ? "true" : "false");
| |||
| |||
if(t == (uchar)JSON_NULL)
| |||
return("null");
| |||
| |||
return("");
| |||
}
| |||
| |||
double GetDouble(int node = -1)
| |||
{
| |||
int n = Resolve(node);
| |||
| |||
if(n < 0 || n >= m_node_used)
| |||
return(0.0);
| |||
| |||
uchar t = m_nodes[n].type;
| |||
| |||
if(t == (uchar)JSON_NUMBER)
| |||
return(m_nodes[n].num);
| |||
| |||
if(t == (uchar)JSON_BOOL)
| |||
return(m_nodes[n].num);
| |||
| |||
if(t == (uchar)JSON_STRING)
| |||
{
| |||
string s = GetString(n);
| |||
// CORRECION POR NIQUE_372
| |||
// SOLO RECIBE 1 PARAMETRO NO 2.. ORIGINAL "StringToDouble(s, v)" (infiero que se pasa por referncia..)
| |||
// Correcion:
| |||
return StringToDouble(s);
| |||
}
| |||
| |||
return(0.0);
| |||
}
| |||
| |||
long GetInteger(int node = -1)
| |||
{
| |||
return((long)GetDouble(node));
| |||
}
| |||
| |||
bool GetBool(int node = -1)
| |||
{
| |||
int n = Resolve(node);
| |||
| |||
if(n < 0 || n >= m_node_used)
| |||
return(false);
| |||
| |||
uchar t = m_nodes[n].type;
| |||
| |||
if(t == (uchar)JSON_BOOL)
| |||
return(m_nodes[n].num != 0.0);
| |||
| |||
if(t == (uchar)JSON_NUMBER)
| |||
return(m_nodes[n].num != 0.0);
| |||
| |||
if(t == (uchar)JSON_STRING)
| |||
{
| |||
string s = GetString(n);
| |||
return(s == "true" || s == "1");
| |||
}
| |||
| |||
return(false);
| |||
}
| |||
| |||
//+---------------------------------------------------------------+
| |||
//| Convenient root access |
| |||
//+---------------------------------------------------------------+
| |||
JsonRef operator[](const string key)
| |||
{
| |||
// ORIGINAL: return(JsonRef(this, FindChild(m_root, key)));
| |||
// CORRECION POR NIQUE (THIS ES REF NO PTR)
| |||
return(JsonRef(&this, FindChild(m_root, key)));
| |||
}
| |||
| |||
JsonRef operator[](const int index)
| |||
{
| |||
// ORIGINAL: return(JsonRef(this, GetChild(m_root, index)));
| |||
// CORRECION POR NIQUE (THIS ES REF NO PTR)
| |||
return(JsonRef(&this, GetChild(m_root, index)));
| |||
}
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| JsonRef implementation |
| |||
//+------------------------------------------------------------------+
| |||
JsonRef JsonRef::operator[](const string key) // qyuite el & por ese error que mencione
| |||
{
| |||
if(json == NULL || node < 0)
| |||
return(JsonRef());
| |||
| |||
return(JsonRef(json, json.FindChild(node, key)));
| |||
}
| |||
| |||
JsonRef JsonRef::operator[](const int index)
| |||
{
| |||
if(json == NULL || node < 0)
| |||
return(JsonRef());
| |||
| |||
return(JsonRef(json, json.GetChild(node, index)));
| |||
}
| |||
| |||
bool JsonRef::Exists()
| |||
{
| |||
if(json == NULL || node < 0)
| |||
return(false);
| |||
| |||
return(json.Exists(node));
| |||
}
| |||
| |||
int JsonRef::Type()
| |||
{
| |||
if(json == NULL || node < 0)
| |||
return(JSON_NONE);
| |||
| |||
return(json.GetType(node));
| |||
}
| |||
| |||
int JsonRef::Size()
| |||
{
| |||
if(json == NULL || node < 0)
| |||
return(0);
| |||
| |||
return(json.Size(node));
| |||
}
| |||
| |||
double JsonRef::ToDouble()
| |||
{
| |||
if(json == NULL || node < 0)
| |||
return(0.0);
| |||
| |||
return(json.GetDouble(node));
| |||
}
| |||
| |||
long JsonRef::ToInteger()
| |||
{
| |||
if(json == NULL || node < 0)
| |||
return(0);
| |||
| |||
return(json.GetInteger(node));
| |||
}
| |||
| |||
bool JsonRef::ToBool()
| |||
{
| |||
if(json == NULL || node < 0)
| |||
return(false);
| |||
| |||
return(json.GetBool(node));
| |||
}
| |||
| |||
string JsonRef::ToString()
| |||
{
| |||
if(json == NULL || node < 0)
| |||
return("");
| |||
| |||
return(json.GetString(node));
| |||
}
| |||
| |||
bool JsonRef::IsObject()
| |||
{
| |||
return(Type() == JSON_OBJECT);
| |||
}
| |||
| |||
bool JsonRef::IsArray()
| |||
{
| |||
return(Type() == JSON_ARRAY);
| |||
}
| |||
| |||
bool JsonRef::IsString()
| |||
{
| |||
return(Type() == JSON_STRING);
| |||
}
| |||
| |||
bool JsonRef::IsNumber()
| |||
{
| |||
return(Type() == JSON_NUMBER);
| |||
}
| |||
| |||
bool JsonRef::IsBool()
| |||
{
| |||
return(Type() == JSON_BOOL);
| |||
}
| |||
| |||
bool JsonRef::IsNull()
| |||
{
| |||
return(Type() == JSON_NULL);
| |||
}
| |||
| |||
#endif
| |||
|