| //+------------------------------------------------------------------+
|
| //| 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
|
|
|