JsonParserByLeo/Test/Other/Qwen3.8Max.mqh

1981 lines
48 KiB
MQL5
Raw Permalink Normal View History

2026-07-27 20:43:04 -05:00
//+------------------------------------------------------------------+
//| 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