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