JsonParserByLeo/Src/JsonParser.mqh

980 lines
25 KiB
MQL5
Raw Permalink Normal View History

2026-06-03 14:16:03 -05:00
//+------------------------------------------------------------------+
2026-06-02 21:23:50 -05:00
//| JsonParser.mqh |
//| Copyright 2026, Niquel Mendoza. |
//| https://www.mql5.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, Niquel Mendoza."
#property link "https://www.mql5.com/"
#property strict
#ifndef JSONPARSERBYLEO_SRC_JSONPARSER_MQH
#define JSONPARSERBYLEO_SRC_JSONPARSER_MQH
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "JsonDefines.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
namespace TSN
{
2026-06-03 07:50:45 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
struct CJsonNode;
2026-06-02 21:23:50 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CJsonParser
{
2026-06-02 22:52:39 -05:00
public:
2026-06-02 21:23:50 -05:00
//---
2026-06-03 14:16:03 -05:00
long m_cinta[];
2026-06-02 21:23:50 -05:00
uchar m_json[];
//---
int m_cinta_pos;
2026-06-03 07:50:45 -05:00
2026-06-03 14:16:03 -05:00
//---
int m_len; // Tamaño a leer de m_json
int m_offset; // Desde donde compienza m_pos
2026-06-02 21:23:50 -05:00
2026-06-03 14:16:03 -05:00
private:
2026-06-02 21:23:50 -05:00
//---
2026-06-03 14:16:03 -05:00
int m_pos; // pos en json
int m_cinta_reserve;
2026-06-02 21:23:50 -05:00
//---
int m_stak_num[512];
int m_stak_pos[512];
char m_stak_state[512];
int m_stak_size;
int m_stak_curr;
int m_stak_curr_state;
//---
ENUM_TSN_JSON_LAST_ERR m_last_err;
uchar m_next;
2026-06-03 14:16:03 -05:00
//---
bool m_next_has_k;
2026-06-02 21:23:50 -05:00
//---
void ProccesDecimalPart(double val);
public:
2026-06-03 18:53:05 -05:00
CJsonParser(void) : m_cinta_reserve(0), m_len(0), m_offset(0) {}
2026-06-02 21:23:50 -05:00
~CJsonParser(void) {}
2026-06-03 07:50:45 -05:00
//---
2026-06-03 08:32:38 -05:00
// Para data raw se puede usar el json uchar directamtne
2026-06-03 12:20:23 -05:00
__forceinline void CalcLen() { m_len = ArraySize(m_json); }
2026-06-03 08:32:38 -05:00
inline void Assing(const string& json);
void AssingFile(const string& file_name, const bool comon_flag);
bool Parse();
2026-06-03 07:50:45 -05:00
//---
__forceinline ENUM_TSN_JSON_LAST_ERR LastErr() const { return m_last_err; }
2026-06-02 21:23:50 -05:00
//---
string Unescape(const int start, const int end) const;
2026-06-03 16:57:42 -05:00
int Unescape(const int start, const int end, uchar& res[]) const;
2026-06-02 21:23:50 -05:00
static int HexToDec(const uchar c);
2026-06-02 22:52:39 -05:00
2026-06-03 07:50:45 -05:00
//---
2026-06-02 22:52:39 -05:00
__forceinline int GetStep(const int idx) const;
2026-06-03 07:50:45 -05:00
__forceinline int GetStepPure(const int idx) const;
2026-06-03 18:53:05 -05:00
//---
void GetLastErrorLocation(int& col, int& line) const;
2026-06-03 07:50:45 -05:00
//---
void PrintCintaTypes() const;
//---
CJsonNode GetRoot();
2026-06-02 21:23:50 -05:00
};
2026-06-03 07:50:45 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-06-03 08:32:38 -05:00
inline void CJsonParser::Assing(const string& json)
2026-06-03 07:50:45 -05:00
{
m_len = StringToCharArray(json, m_json);
2026-06-03 08:32:38 -05:00
m_offset = 0;
2026-06-03 07:50:45 -05:00
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-06-03 08:32:38 -05:00
void CJsonParser::AssingFile(const string& file_name, const bool comon_flag)
2026-06-03 08:45:12 -05:00
{
2026-06-03 07:50:45 -05:00
//---
m_len = (int)FileLoad(file_name, m_json, (comon_flag ? FILE_COMMON : 0));
2026-06-03 08:32:38 -05:00
m_offset = 0;
2026-06-03 07:50:45 -05:00
//---
if(m_len >= 2)
{
// UTF16 BE
if(m_json[0] == 0xFF && m_json[1] == 0xFE)
{
const int n = (m_len - 2) >> 1;
for(int i = 0; i < n; i++)
m_json[i] = m_json[2 + (i * 2)]; // byte bajo (el char real)
m_len = ArrayResize(m_json, n);
}
// UTF16 LE
else
if(m_json[0] == 0xFE && m_json[1] == 0xFF)
{
const int n = (m_len - 2) >> 1;
for(int i = 0; i < n; i++)
m_json[i] = m_json[3 + (i * 2)]; // byte alto (invertido)
m_len = ArrayResize(m_json, n);
}
}
else
if(m_len >= 3 && m_json[0] == 0xEF && m_json[1] == 0xBB && m_json[2] == 0xBF)
{
// UTF-8 BOM
2026-06-03 08:32:38 -05:00
m_offset = 3; // simplemente saltear
2026-06-03 07:50:45 -05:00
}
//---
//Print(CharArrayToString(m_json));
}
2026-06-02 21:23:50 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#define TSN_JSON_NEXT \
while(m_pos < m_len) \
{ \
const uchar c = m_json[m_pos]; \
if(c < 33) \
{ \
m_pos++; \
continue; \
} \
2026-06-03 07:50:45 -05:00
if(c > JSON_MAX_VALUE_C) \
2026-06-02 21:23:50 -05:00
{ \
m_last_err = TSN_JSON_ERR_INVALID_CHAR; \
return false; \
} \
const uchar locked = m_next; \
m_next = g_table_json_tokens[c - 34]; \
const int f = g_json_to_f[m_next];\
if(f != 0 && (f & g_json_expected[m_stak_curr_state][locked]) == 0)\
{ \
m_last_err= TSN_JSON_ERR_MALFORDMED_JSON; \
return false; \
} \
break; \
}
//---
#define TSN_JSON_RESERVAR(N) \
if(m_cinta_pos + N > m_cinta_reserve) \
{ \
m_cinta_reserve += (m_cinta_reserve << 1) + N; \
if(ArrayResize(m_cinta, m_cinta_reserve, m_cinta_reserve) == -1) \
{ \
m_last_err=TSN_JSON_ERR_OVERFLOW_IN_CINTA_RESIZE; \
return false; \
} \
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CJsonParser::ProccesDecimalPart(double val)
{
//---
if(m_pos < m_len && m_json[m_pos] == '.') // Parte decimal
{
//---
m_pos++;
long frac_int = 0;
int frac_digits = 0;
//---
for(; m_pos < m_len; m_pos++)
{
const uchar c = m_json[m_pos];
if(IsNotDigit(c))
break;
frac_int = frac_int * 10 + (c - '0');
frac_digits++;
}
if(frac_digits <= 18)
val += frac_int * g_Exp10[frac_digits];
else
{
double frac = (double)frac_int;
for(int k = 0; k < frac_digits; k++)
frac *= 0.1;
val += frac;
}
}
//---
if(m_pos < m_len && (m_json[m_pos] == 'e' || m_json[m_pos] == 'E')) // e or E
{
//---
m_pos++;
int exp_sign = 1;
if(m_pos < m_len && m_json[m_pos] == '-')
{
exp_sign = -1;
m_pos++;
}
else
if(m_pos < m_len && m_json[m_pos] == '+')
{
m_pos++;
}
//---
int exp_val = 0;
for(; m_pos < m_len; m_pos++)
{
const uchar c = m_json[m_pos];
if(IsNotDigit(c))
break;
exp_val = exp_val * 10 + (c - '0');
}
//---
if(exp_val <= 18)
{
if(exp_sign == 1)
val *= g_Pow10[exp_val];
else
val *= g_Exp10[exp_val];
}
else
{
double p = 1.0;
for(int k = 0; k < exp_val; k++)
p *= 10.0;
if(exp_sign == 1)
val *= p;
else
val /= p;
}
}
//---
static BitInterpreter bit;
bit.double_value = val;
m_cinta[m_cinta_pos++] = JSON_VTYPE_REAL;
m_cinta[m_cinta_pos++] = bit.long_value;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-06-03 08:32:38 -05:00
bool CJsonParser::Parse()
2026-06-02 21:23:50 -05:00
{
2026-06-03 07:50:45 -05:00
//---
m_stak_size = 0;
m_stak_curr_state = -1;
m_stak_curr = -1;
m_next_has_k = false;
m_last_err = TSN_JSON_NOT_ERR;
m_next = TSN_JSON_TOK_INVALID;
2026-06-03 08:32:38 -05:00
m_pos = m_offset;
2026-06-03 07:50:45 -05:00
m_cinta_pos = 0;
2026-06-03 15:48:09 -05:00
const int expected = m_len * 2 + 128;
if(expected > m_cinta_reserve)
{
m_cinta_reserve = expected;
ArrayResize(m_cinta, m_cinta_reserve, m_cinta_reserve);
}
2026-06-03 07:50:45 -05:00
2026-06-02 21:23:50 -05:00
//--- Inicial
while(m_pos < m_len)
{
const uchar c = m_json[m_pos];
if(c < 33)
{
m_pos++;
continue;
}
2026-06-03 07:50:45 -05:00
if(c > JSON_MAX_VALUE_C)
2026-06-02 21:23:50 -05:00
{
m_last_err = TSN_JSON_ERR_INVALID_CHAR;
return false;
}
m_next = g_table_json_tokens[c - 34];
if(m_next < TSN_JSON_TOK_LLAVE_INI || m_next > TSN_JSON_TOK_COR_INI)
{
m_last_err = TSN_JSON_ERR_EXPECTED_OBJ_ARR;
return false;
}
break;
}
//--- Bucle
while(true)
{
switch(m_next)
{
case TSN_JSON_TOK_NUMBER:
{
//---
2026-06-03 12:20:23 -05:00
//TSN_JSON_RESERVAR(2)
2026-06-02 21:23:50 -05:00
//--- Parte 1...
long v = 0;
int sign = 1;
//--- Validamos signo
if(m_json[m_pos] == '-')
{
sign = -1;
m_pos++;
}
//---
while(m_pos < m_len)
{
const uchar ch = m_json[m_pos];
if(IsDigit(ch))
{
v = v * 10 + (ch - '0');
m_pos++;
}
else
if(ch == '.' || ch == 'e' || ch == 'E')
{
ProccesDecimalPart((double)v);
break;
}
else
{
m_cinta[m_cinta_pos++] = JSON_VTYPE_INTEGER;
m_cinta[m_cinta_pos++] = v * sign;
break; // Fin
}
}
//--- no hago el m_pos++ dado que ahora mismo estamo en el seg char
TSN_JSON_NEXT
break;
}
case TSN_JSON_TOK_STRING:
{
//---
2026-06-03 12:20:23 -05:00
//TSN_JSON_RESERVAR(2)
2026-06-02 21:23:50 -05:00
//---
const int start = ++m_pos;
if(m_next_has_k)
{
// Modifcamos nuestro m_next actual (esta en string TSN_JSON_TOK_STRING)
m_next = TSN_JSON_TOK_KEY;
m_cinta[m_cinta_pos] = JSON_VTYPE_KEY;
uint key_hash = 2166136261;
while(m_pos < m_len)
{
//---
2026-06-03 07:50:45 -05:00
if(m_json[m_pos] == '"')
{
//PrintFormat("Key: '%s'", CharArrayToString(m_json, start, ((m_pos - 1) - start) + 1));
m_cinta[m_cinta_pos++] |= long(key_hash) << TSN_JSON_BIT_STR_START_HASH;
m_cinta[m_cinta_pos++] = long(m_pos - 1) | long(start) << TSN_JSON_BIT_STR_START_END;
break;
}
//---
key_hash ^= uint(m_json[m_pos]);
key_hash *= 16777619;
2026-06-02 21:23:50 -05:00
//---
if(m_json[m_pos] == '\\')
{
m_pos += 2;
if(m_pos + 1 < m_len)
{
2026-06-03 07:50:45 -05:00
key_hash ^= uint(m_json[m_pos + 1]);
key_hash *= 16777619;
2026-06-02 21:23:50 -05:00
}
continue;
}
//---
m_pos++;
}
}
else
{
m_cinta[m_cinta_pos++] = JSON_VTYPE_STRING;
while(m_pos < m_len)
{
if(m_json[m_pos] == '\\')
{
m_pos += 2;
continue;
}
//---
if(m_json[m_pos] == '"')
{
m_cinta[m_cinta_pos++] = long(m_pos - 1) | long(start) << TSN_JSON_BIT_STR_START_END;
break;
}
//---
m_pos++;
}
}
//---
if(m_json[m_pos++] != '"')
{
m_last_err = TSN_JSON_ERR_STRING_NOT_CLOSED;
return false;
}
//---
TSN_JSON_NEXT
break;
}
case TSN_JSON_TOK_BOOL_TRUE:
{
2026-06-03 12:20:23 -05:00
//TSN_JSON_RESERVAR(1)
// t r u e W
// [-4] [-3] [-2] [-1] [0]
if((m_pos += 4) >= m_len || m_json[m_pos - 3] != 'r' || m_json[m_pos - 2] != 'u' || m_json[m_pos - 1] != 'e')
2026-06-02 21:23:50 -05:00
{
m_last_err = TSN_JSON_ERR_MALFORMED_TRUE;
return false;
}
2026-06-03 12:20:23 -05:00
// 2 | 1 << 8 = 258
// JSON_VTYPE_BOOLEAN | long(1) << TSN_JSON_BIT_START_ENDTYPE
m_cinta[m_cinta_pos++] = 258;
2026-06-02 21:23:50 -05:00
//---
TSN_JSON_NEXT
break;
}
case TSN_JSON_TOK_BOOL_FALSE:
{
2026-06-03 12:20:23 -05:00
//TSN_JSON_RESERVAR(1)
// f a l s e W
// [] [-4] [-3] [-2 ] [-1] [0]
if((m_pos += 5) >= m_len || m_json[m_pos - 4] != 'a' || m_json[m_pos - 3] != 'l'
|| m_json[m_pos - 2] != 's' || m_json[m_pos - 1] != 'e')
2026-06-02 21:23:50 -05:00
{
m_last_err = TSN_JSON_ERR_MALFORMED_FALSE;
return false;
}
m_cinta[m_cinta_pos++] = JSON_VTYPE_BOOLEAN;
//---
TSN_JSON_NEXT
break;
}
case TSN_JSON_TOK_NULL:
{
2026-06-03 12:20:23 -05:00
//TSN_JSON_RESERVAR(1)
// n u l l W
// [-4][-3][-2][-1][]
if((m_pos += 4) >= m_len || m_json[m_pos - 3] != 'u' || m_json[m_pos - 2] != 'l' || m_json[m_pos - 1] != 'l')
2026-06-02 21:23:50 -05:00
{
m_last_err = TSN_JSON_ERR_MALFORMED_NULL;
return false;
}
m_cinta[m_cinta_pos++] = JSON_VTYPE_NULL;
//---
TSN_JSON_NEXT
break;
}
case TSN_JSON_TOK_COMMA:
{
if(m_stak_curr_state == TSN_JSON_CTX_IN_OBJ)
{
m_next_has_k = true;
}
//---
m_stak_num[m_stak_curr]++;
//---
m_pos++;
//---
TSN_JSON_NEXT
break;
}
case TSN_JSON_TOK_LLAVE_INI:
{
2026-06-03 12:20:23 -05:00
//TSN_JSON_RESERVAR(1)
2026-06-02 21:23:50 -05:00
m_cinta[m_cinta_pos] = JSON_VTYPE_OBJ;
//---
m_next_has_k = true;
//---
m_stak_curr = m_stak_size++;
2026-06-02 22:52:39 -05:00
m_stak_curr_state = TSN_JSON_CTX_IN_OBJ;
m_stak_state[m_stak_curr] = TSN_JSON_CTX_IN_OBJ;
2026-06-02 21:23:50 -05:00
m_stak_num[m_stak_curr] = 0;
m_stak_pos[m_stak_curr] = m_cinta_pos++;
//---
2026-06-03 12:20:23 -05:00
m_cinta[m_cinta_pos++] = m_pos++;
2026-06-02 21:23:50 -05:00
//---
TSN_JSON_NEXT
//---
break;
}
case TSN_JSON_TOK_COR_INI:
{
2026-06-03 12:20:23 -05:00
//TSN_JSON_RESERVAR(1)
2026-06-02 22:52:39 -05:00
m_cinta[m_cinta_pos] = JSON_VTYPE_ARR;
2026-06-02 21:23:50 -05:00
//---
m_next_has_k = false;
//---
m_stak_curr = m_stak_size++;
2026-06-02 22:52:39 -05:00
m_stak_curr_state = TSN_JSON_CTX_IN_ARR;
m_stak_state[m_stak_curr] = TSN_JSON_CTX_IN_ARR;
2026-06-02 21:23:50 -05:00
m_stak_num[m_stak_curr] = 0;
m_stak_pos[m_stak_curr] = m_cinta_pos++;
//---
2026-06-03 12:20:23 -05:00
m_cinta[m_cinta_pos++] = m_pos++;
2026-06-02 21:23:50 -05:00
//---
TSN_JSON_NEXT
//---
break;
}
case TSN_JSON_TOK_LLAVE_END:
case TSN_JSON_TOK_COR_END:
{
2026-06-03 08:32:38 -05:00
//---
2026-06-03 18:53:05 -05:00
// 10 11 12 13
if(m_cinta_pos > m_stak_pos[m_stak_curr] + 2) // [a][a][v][c]
{
m_stak_num[m_stak_curr]++;
}
2026-06-03 08:32:38 -05:00
//---
2026-06-03 07:50:45 -05:00
const int lp = m_stak_pos[m_stak_curr];
2026-06-03 18:53:05 -05:00
m_cinta[lp] |= long(m_stak_num[m_stak_curr]) << TSN_JSON_BIT_START_ENDTYPE | long(m_cinta_pos - lp) << TSN_JSON_BIT_START_NUM_C;
2026-06-03 12:20:23 -05:00
m_cinta[lp + 1] |= long(m_pos) << TSN_JSON_BIT_END_T;
2026-06-02 21:23:50 -05:00
//---
m_stak_size = m_stak_curr--;
//---
if(m_stak_size == 0)
{
return true;
}
else
{
m_stak_curr_state = m_stak_state[m_stak_curr];
}
//---
m_pos++;
//---
TSN_JSON_NEXT
//---
break;
}
case TSN_JSON_TOK_FIN_KEY:
{
m_next_has_k = false;
//---
m_pos++;
//---
TSN_JSON_NEXT
//---
break;
}
default:
{
m_last_err = TSN_JSON_ERR_INVALID_CHAR;
return false;
}
}
}
//---
m_last_err = TSN_JSON_ERR_JSON_NOT_FINISH;
//---
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
static int CJsonParser::HexToDec(const uchar c)
{
if(c >= '0' && c <= '9')
return c - '0';
if(c >= 'a' && c <= 'f')
return c - 'a' + 10;
if(c >= 'A' && c <= 'F')
return c - 'A' + 10;
return 0;
}
2026-06-03 16:57:42 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CJsonParser::Unescape(const int start, const int end, uchar& res[]) const
{
//---
ArrayResize(res, (end - start) + 1);
int pos = 0;
2026-06-02 21:23:50 -05:00
2026-06-03 16:57:42 -05:00
//---
for(int i = start; i <= end; i++)
{
if(m_json[i] == '\\' && i + 1 <= end)
{
i++;
const uchar next = m_json[i];
switch(next)
{
case '"':
res[pos++] = '"';
break;
case '\\':
res[pos++] = '\\';
break;
case '/':
res[pos++] = '/';
break;
case 'b':
res[pos++] = '\x08';
break;
case 'f':
res[pos++] = '\f';
break;
case 'n':
res[pos++] = '\n';
break;
case 'r':
res[pos++] = '\r';
break;
case 't':
res[pos++] = '\t';
break;
case 'u':
{
if(i + 4 <= end)
{
const uint code = (HexToDec(m_json[i + 1]) << 12) |
(HexToDec(m_json[i + 2]) << 8) |
(HexToDec(m_json[i + 3]) << 4) |
HexToDec(m_json[i + 4]);
i += 4;
//--- encode to UTF-8
if(pos + 4 >= ArraySize(res))
ArrayResize(res, pos + 64);
if(code < 0x80)
{
res[pos++] = uchar(code);
}
else
if(code < 0x800)
{
res[pos++] = uchar(0xC0 | (code >> 6));
res[pos++] = uchar(0x80 | (code & 0x3F));
}
else
{
res[pos++] = uchar(0xE0 | (code >> 12));
res[pos++] = uchar(0x80 | ((code >> 6) & 0x3F));
res[pos++] = uchar(0x80 | (code & 0x3F));
}
}
else
res[pos++] = 'u';
break;
}
default:
res[pos++] = next;
break;
}
}
else
res[pos++] = m_json[i];
}
//---
return ArrayResize(res, pos);
}
2026-06-02 21:23:50 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string CJsonParser::Unescape(const int start, const int end) const
{
//---
string res = "";
StringSetLength(res, (end - start) + 1);
int pos = 0;
//---
for(int i = start; i <= end; i++)
{
if(m_json[i] == '\\' && i + 1 <= end)
{
i++;
const uchar next = m_json[i];
switch(next)
{
case '"':
res.SetChar(pos++, '"');
break;
case '\\':
res.SetChar(pos++, '\\');
break;
case '/':
res.SetChar(pos++, '/');
break;
case 'b':
res.SetChar(pos++, '\x08');
break;
case 'f':
res.SetChar(pos++, '\f');
break;
case 'n':
res.SetChar(pos++, '\n');
break;
case 'r':
res.SetChar(pos++, '\r');
break;
case 't':
res.SetChar(pos++, '\t');
break;
case 'u':
{
// \uFFFF
if(i + 4 <= end)
{
const int code = (HexToDec(m_json[i + 1]) << 12) |
(HexToDec(m_json[i + 2]) << 8) |
(HexToDec(m_json[i + 3]) << 4) |
HexToDec(m_json[i + 4]);
res.SetChar(pos++, (ushort)code);
i += 4;
}
else
res.SetChar(pos++, 'u');
break;
}
default:
res.SetChar(pos++, next);
break;
}
}
else
res.SetChar(pos++, m_json[i]);
}
//---
res.Truncate(pos);
//---
return res;
}
2026-06-02 22:52:39 -05:00
//+------------------------------------------------------------------+
2026-06-03 07:50:45 -05:00
//| |
2026-06-02 22:52:39 -05:00
//+------------------------------------------------------------------+
2026-06-03 07:50:45 -05:00
__forceinline int CJsonParser::GetStepPure(const int idx) const
2026-06-02 22:52:39 -05:00
{
2026-06-03 07:50:45 -05:00
const int tipo = int(m_cinta[idx] & B'1111');
switch(tipo)
2026-06-02 22:52:39 -05:00
{
case JSON_VTYPE_INTEGER:
return 2;
case JSON_VTYPE_REAL:
return 2;
2026-06-03 07:50:45 -05:00
case JSON_VTYPE_BOOLEAN:
return 1;
2026-06-02 22:52:39 -05:00
case JSON_VTYPE_STRING:
return 2;
2026-06-03 07:50:45 -05:00
case JSON_VTYPE_NULL:
return 1;
case JSON_VTYPE_ARR:
2026-06-03 12:20:23 -05:00
return 2;
2026-06-03 07:50:45 -05:00
case JSON_VTYPE_OBJ:
2026-06-03 12:20:23 -05:00
return 2;
2026-06-03 07:50:45 -05:00
case JSON_VTYPE_KEY:
return 2;
}
return 1;
}
//+------------------------------------------------------------------+
//| GetStep: posiciones que ocupa el nodo idx en la cinta |
//+------------------------------------------------------------------+
__forceinline int CJsonParser::GetStep(const int idx)
const
{
switch(int(m_cinta[idx] & 0xFF))
{
case JSON_VTYPE_INTEGER:
return 2;
case JSON_VTYPE_REAL:
return 2;
2026-06-02 22:52:39 -05:00
case JSON_VTYPE_BOOLEAN:
return 1;
2026-06-03 07:50:45 -05:00
case JSON_VTYPE_STRING:
return 2;
2026-06-02 22:52:39 -05:00
case JSON_VTYPE_NULL:
return 1;
case JSON_VTYPE_ARR:
2026-06-03 15:48:09 -05:00
return int(m_cinta[idx] >> TSN_JSON_BIT_START_NUM_C);
2026-06-02 22:52:39 -05:00
case JSON_VTYPE_OBJ:
2026-06-03 15:48:09 -05:00
return int(m_cinta[idx] >> TSN_JSON_BIT_START_NUM_C);
2026-06-02 22:52:39 -05:00
case JSON_VTYPE_KEY:
return 2;
}
return 1;
}
2026-06-03 07:50:45 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CJsonNode CJsonParser::GetRoot()
{
if(m_cinta_pos == 0)
return EMPTY_JSON_NODE;
return CJsonNode(&this, 0, GetStep(0));
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CJsonParser::PrintCintaTypes() const
{
int p = 0;
while(p < m_cinta_pos)
{
const ENUM_JSON_VTYPE tipo = ENUM_JSON_VTYPE(m_cinta[p] & 0xFF);
2026-06-03 15:48:09 -05:00
string text = "[" + (string)p + "] " + EnumToString(tipo) + " | ";
//---
switch(tipo)
{
case JSON_VTYPE_INTEGER:
text += "val=" + (string)m_cinta[p + 1];
break;
case JSON_VTYPE_REAL:
{
static BitInterpreter un;
un.long_value = m_cinta[p + 1];
text += "val=" + (string)un.double_value;
break;
}
case JSON_VTYPE_BOOLEAN:
text += "val=" + (string)(bool)((m_cinta[p] >> TSN_JSON_BIT_START_ENDTYPE) & 1);
break;
case JSON_VTYPE_STRING:
{
const int s = int(m_cinta[p + 1] >> TSN_JSON_BIT_STR_START_END);
const int e = int(m_cinta[p + 1] & 0xFFFFFFFF);
text += "start=" + (string)s + " end=" + (string)e + " val=\"" + CharArrayToString(m_json, s, (e - s) + 1) + "\"";
break;
}
case JSON_VTYPE_NULL:
text += "null";
break;
case JSON_VTYPE_ARR:
case JSON_VTYPE_OBJ:
{
const int count = int((m_cinta[p] >> TSN_JSON_BIT_START_ENDTYPE) & 0xFFFFFF);
const int num_c = int(m_cinta[p] >> TSN_JSON_BIT_START_NUM_C);
const int raw_s = int(m_cinta[p + 1] & 0xFFFFFFFF);
const int raw_e = int(m_cinta[p + 1] >> TSN_JSON_BIT_END_T);
text += "count=" + (string)count + " num_c=" + (string)num_c + " raw_start=" + (string)raw_s + " raw_end=" + (string)raw_e;
break;
}
case JSON_VTYPE_KEY:
{
const int s = int(m_cinta[p + 1] >> TSN_JSON_BIT_STR_START_END);
const int e = int(m_cinta[p + 1] & 0xFFFFFFFF);
const uint hash = uint(m_cinta[p] >> TSN_JSON_BIT_STR_START_HASH);
text += "hash=" + (string)hash + " key=\"" + CharArrayToString(m_json, s, (e - s) + 1) + "\"";
break;
}
}
Print(text);
2026-06-03 07:50:45 -05:00
p += GetStepPure(p);
}
}
2026-06-03 18:53:05 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CJsonParser::GetLastErrorLocation(int &col, int &line) const
{
col = 1;
line = 1;
//Print(CharArrayToString(m_json, 0, m_pos));
for(int i = 0; i <= m_pos && i < m_len; i++)
{
if(m_json[i] == '\n')
{
line++;
col = 1;
}
else
col++;
}
}
2026-06-03 07:50:45 -05:00
2026-06-02 21:23:50 -05:00
}
#endif // JSONPARSERBYLEO_SRC_JSONPARSER_MQH
2026-06-03 16:57:42 -05:00
//+------------------------------------------------------------------+