2026-08-04 08:01:43 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| JsonSaxImp.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_JSONSAXIMP_MQH
|
|
|
|
|
#define JSONPARSERBYLEO_SRC_JSONSAXIMP_MQH
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#include "JsonParser.mqh"
|
|
|
|
|
#include "JsonSax.mqh"
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
namespace TSN
|
|
|
|
|
{
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#define JSONPARSERBYLEO_SAX_STR_START (0)
|
2026-08-04 09:07:11 -05:00
|
|
|
/* Notas de mi parte
|
|
|
|
|
Siempre cuando vuevea a llamar aseungramtne de agregar datos amenos un solo dato es lo minimo..
|
|
|
|
|
*/
|
2026-08-04 08:01:43 -05:00
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CJsonParserStream : public CJsonParser
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
ITsnJsonParserStream* m_in;
|
2026-08-04 09:02:31 -05:00
|
|
|
bool m_del_caller;
|
|
|
|
|
|
|
|
|
|
//---
|
2026-08-04 08:01:43 -05:00
|
|
|
uchar m_prev_c;
|
|
|
|
|
uint8_t m_in_n;
|
|
|
|
|
long m_mask;
|
|
|
|
|
long m_last_number;
|
|
|
|
|
double m_last_number_dbl;
|
|
|
|
|
|
|
|
|
|
//----
|
|
|
|
|
long m_sax_frac_int;
|
|
|
|
|
int m_sax_frac_digits;
|
|
|
|
|
|
|
|
|
|
public:
|
2026-08-04 09:02:31 -05:00
|
|
|
CJsonParserStream(void) : m_del_caller(false) {}
|
|
|
|
|
~CJsonParserStream(void);
|
2026-08-04 08:01:43 -05:00
|
|
|
|
|
|
|
|
//---
|
2026-08-04 09:02:31 -05:00
|
|
|
__forceinline int CurrentStack() const { return m_stak_curr + 1; }
|
|
|
|
|
__forceinline int CurrentStackState() const { return m_stak_curr_state; }
|
2026-08-04 08:01:43 -05:00
|
|
|
void KillParse();
|
|
|
|
|
|
2026-08-04 09:02:31 -05:00
|
|
|
//---
|
|
|
|
|
void SetCaller(ITsnJsonParserStream* caller, bool del);
|
|
|
|
|
void CheckLimpieza();
|
|
|
|
|
|
2026-08-04 08:01:43 -05:00
|
|
|
//---
|
|
|
|
|
bool ParseSreamSax();
|
|
|
|
|
};
|
|
|
|
|
|
2026-08-04 09:02:31 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
CJsonParserStream::~CJsonParserStream(void)
|
|
|
|
|
{
|
|
|
|
|
if(m_del_caller && CheckPointer(m_in) == POINTER_DYNAMIC)
|
|
|
|
|
delete m_in;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-04 08:01:43 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
// Al terminar solo lo poneres en tok invalid..
|
|
|
|
|
#define JSONPARSERBYLEO_SAX_ON_FINISH m_next=TSN_JSON_TOK_INVALID;
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
void CJsonParserStream::KillParse(void)
|
|
|
|
|
{
|
|
|
|
|
JSONPARSERBYLEO_SAX_ON_FINISH
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-04 09:02:31 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
void CJsonParserStream::SetCaller(ITsnJsonParserStream *caller, bool del)
|
|
|
|
|
{
|
|
|
|
|
m_del_caller = del;
|
|
|
|
|
m_in = caller;
|
|
|
|
|
m_in.MainPointer(&this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
void CJsonParserStream::CheckLimpieza(void)
|
|
|
|
|
{
|
|
|
|
|
// Revisamos el estado previo
|
|
|
|
|
// La idea ees ver si estamos en string SI no lo estabamos entonces es seguro retrazar el pos
|
|
|
|
|
if(((1 << m_next) & (TSN_JSON_F_KEY | TSN_JSON_F_STRING)) == 0)
|
|
|
|
|
{
|
|
|
|
|
m_pos = 0; // Reiniciamos el pos
|
|
|
|
|
// Entonces la idea es que la siguiente llama el que llame a esta clase
|
|
|
|
|
// Llente el array auqneusea conreserva pero hasta m_len
|
|
|
|
|
// Lo deal seria ejeuctar esto antes de cada relleneado
|
|
|
|
|
}
|
|
|
|
|
// No se puede..
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2026-08-26 19:48:01 -05:00
|
|
|
|
2026-08-04 08:01:43 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CJsonParserStream::ParseSreamSax(void)
|
|
|
|
|
{
|
|
|
|
|
//--- Inicial
|
|
|
|
|
if(m_next == TSN_JSON_TOK_INVALID)
|
|
|
|
|
{
|
2026-08-26 19:48:01 -05:00
|
|
|
// general
|
2026-08-04 08:01:43 -05:00
|
|
|
m_stak_curr = -1;
|
|
|
|
|
m_last_err = TSN_JSON_NOT_ERR;
|
|
|
|
|
m_pos = m_offset;
|
2026-08-26 19:48:01 -05:00
|
|
|
// numeros
|
|
|
|
|
m_last_number = 0;
|
|
|
|
|
m_mask = 0;
|
|
|
|
|
//dbl
|
|
|
|
|
m_in_n = 0;
|
|
|
|
|
// extra
|
2026-08-04 08:01:43 -05:00
|
|
|
m_stak_pos[JSONPARSERBYLEO_SAX_STR_START] = -1; // string y keys
|
|
|
|
|
|
2026-08-04 09:02:31 -05:00
|
|
|
//---
|
|
|
|
|
m_in.OnStartDocument();
|
|
|
|
|
|
2026-08-04 08:01:43 -05:00
|
|
|
//--- Inicial
|
|
|
|
|
const uchar _f_c = m_raw[m_pos];
|
|
|
|
|
if(_f_c == '{')
|
|
|
|
|
{
|
|
|
|
|
m_next = TSN_JSON_TOK_LLAVE_INI;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
if(_f_c == '[')
|
|
|
|
|
{
|
|
|
|
|
m_next = TSN_JSON_TOK_COR_INI;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_pos++;
|
|
|
|
|
while(true)
|
|
|
|
|
{
|
|
|
|
|
const uchar _f__c = m_raw[m_pos];
|
|
|
|
|
if(_f__c < 33)
|
|
|
|
|
{
|
|
|
|
|
m_pos++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(_f__c == '{')
|
|
|
|
|
{
|
|
|
|
|
m_next = TSN_JSON_TOK_LLAVE_INI;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
if(_f__c == '[')
|
|
|
|
|
{
|
|
|
|
|
m_next = TSN_JSON_TOK_COR_INI;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_next = TSN_JSON_TOK_INVALID;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--- Bucle
|
|
|
|
|
while(true)
|
|
|
|
|
{
|
|
|
|
|
switch(m_next)
|
|
|
|
|
{
|
2026-08-26 19:48:01 -05:00
|
|
|
case TSN_JSON_TOK_NUMBER_NEG:
|
2026-08-04 08:01:43 -05:00
|
|
|
{
|
|
|
|
|
//---
|
2026-08-26 19:48:01 -05:00
|
|
|
// m_last_number=0 ya viene a 0
|
|
|
|
|
m_mask = -1; // solo cambiamos la mascara
|
|
|
|
|
m_next = TSN_JSON_TOK_NUMBER;
|
2026-08-04 08:01:43 -05:00
|
|
|
|
|
|
|
|
//---
|
2026-08-26 19:48:01 -05:00
|
|
|
if(++m_pos >= m_len) // Ahora en numero de lo contraio a la siguiente..
|
|
|
|
|
return true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2026-08-04 08:01:43 -05:00
|
|
|
|
2026-08-26 19:48:01 -05:00
|
|
|
//---
|
|
|
|
|
case TSN_JSON_TOK_NUMBER:
|
|
|
|
|
{
|
2026-08-04 08:01:43 -05:00
|
|
|
//---
|
2026-08-26 19:48:01 -05:00
|
|
|
uchar ch = m_raw[m_pos] ^ '0';
|
2026-08-04 08:01:43 -05:00
|
|
|
|
2026-08-26 19:48:01 -05:00
|
|
|
//--- bucle principal
|
2026-08-04 08:01:43 -05:00
|
|
|
while(true)
|
|
|
|
|
{
|
|
|
|
|
m_last_number = (m_last_number << 3) + (m_last_number << 1) + ch;
|
|
|
|
|
m_pos++;
|
|
|
|
|
if(m_pos >= m_len)
|
2026-08-26 19:48:01 -05:00
|
|
|
return true;
|
2026-08-04 08:01:43 -05:00
|
|
|
ch = m_raw[m_pos] ^ '0';
|
|
|
|
|
if(ch < 10)
|
|
|
|
|
continue;
|
|
|
|
|
else
|
2026-08-26 19:48:01 -05:00
|
|
|
if(ch == 30 || (ch | 0x20) == 117)
|
2026-08-04 08:01:43 -05:00
|
|
|
{
|
|
|
|
|
m_prev_c = ch;
|
|
|
|
|
m_last_number_dbl = double(m_last_number);
|
|
|
|
|
m_next = TSN_JSON_TOK_SAX_DBL;
|
2026-08-26 19:48:01 -05:00
|
|
|
// dbl ya reincia ..
|
2026-08-04 08:01:43 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_in.OnInteger((m_last_number ^ m_mask) - m_mask);
|
|
|
|
|
m_next = TSN_JSON_TOK_SAX_NO_NEXT_KEY;
|
2026-08-26 19:48:01 -05:00
|
|
|
// reiniciamos
|
|
|
|
|
m_last_number = 0;
|
|
|
|
|
m_mask = 0;
|
|
|
|
|
break;
|
2026-08-04 08:01:43 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--- no hago el m_pos++ dado que ahora mismo estamo en el seg char
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
case TSN_JSON_TOK_STRING:
|
|
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
//TSN_JSON_RESERVAR(2)
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(m_stak_pos[JSONPARSERBYLEO_SAX_STR_START] == -1)
|
|
|
|
|
{
|
|
|
|
|
m_stak_pos[JSONPARSERBYLEO_SAX_STR_START] = ++m_pos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--- Char por char
|
2026-08-04 09:02:31 -05:00
|
|
|
while(true)
|
2026-08-04 08:01:43 -05:00
|
|
|
{
|
2026-08-04 09:02:31 -05:00
|
|
|
//---
|
|
|
|
|
if(m_pos >= m_len)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-04 08:01:43 -05:00
|
|
|
//---
|
|
|
|
|
const uchar c = m_raw[m_pos];
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(c == '\\')
|
|
|
|
|
{
|
|
|
|
|
m_pos += 2;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if(c == '"')
|
|
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
const int start = m_stak_pos[JSONPARSERBYLEO_SAX_STR_START];
|
|
|
|
|
m_in.OnString(start, m_pos - start);
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_stak_pos[JSONPARSERBYLEO_SAX_STR_START] = -1;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_pos++;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_next = TSN_JSON_TOK_SAX_NO_NEXT_KEY;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_pos++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
// No enconto nada.. entonces.. sale noma vovemos luego
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TSN_JSON_TOK_BOOL_TRUE:
|
|
|
|
|
{
|
|
|
|
|
//TSN_JSON_RESERVAR(1)
|
|
|
|
|
// t r u e W
|
|
|
|
|
// [-4] [-3] [-2] [-1] [0]
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(m_pos + 5 < m_len)
|
|
|
|
|
{
|
|
|
|
|
m_pos += 4; // Aumentamos y continuamos
|
2026-08-04 09:29:06 -05:00
|
|
|
m_in.OnBool(true);
|
2026-08-04 08:01:43 -05:00
|
|
|
m_next = TSN_JSON_TOK_SAX_NO_NEXT_KEY;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TSN_JSON_TOK_BOOL_FALSE:
|
|
|
|
|
{
|
|
|
|
|
//TSN_JSON_RESERVAR(1)
|
|
|
|
|
// f a l s e W
|
|
|
|
|
// [] [-4] [-3] [-2 ] [-1] [0]
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(m_pos + 6 < m_len)
|
|
|
|
|
{
|
|
|
|
|
m_pos += 5; // Aumentamos y continuamos
|
2026-08-04 09:29:06 -05:00
|
|
|
m_in.OnBool(false);
|
2026-08-04 08:01:43 -05:00
|
|
|
m_next = TSN_JSON_TOK_SAX_NO_NEXT_KEY;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TSN_JSON_TOK_NULL:
|
|
|
|
|
{
|
|
|
|
|
//TSN_JSON_RESERVAR(1)
|
|
|
|
|
// n u l l W
|
|
|
|
|
// [-4][-3][-2][-1][]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
// Solo si hay 5 chars mas si no no hacemo snada
|
|
|
|
|
if(m_pos + 5 < m_len)
|
|
|
|
|
{
|
|
|
|
|
m_pos += 4; // Aumentamos y continuamos
|
|
|
|
|
m_in.OnNull();
|
|
|
|
|
m_next = TSN_JSON_TOK_SAX_NO_NEXT_KEY;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TSN_JSON_TOK_COMMA:
|
|
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
m_pos++;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(m_stak_curr_state == TSN_JSON_CTX_IN_OBJ)
|
|
|
|
|
m_next = TSN_JSON_TOK_SAX_FIND_KEY;
|
|
|
|
|
else
|
|
|
|
|
m_next = TSN_JSON_TOK_SAX_COM_KEY;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TSN_JSON_TOK_LLAVE_INI:
|
|
|
|
|
{
|
|
|
|
|
//_--
|
|
|
|
|
m_in.OnStartObj();
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_stak_curr++;
|
2026-08-04 09:02:31 -05:00
|
|
|
m_stak_state[m_stak_curr] = TSN_JSON_CTX_IN_OBJ;
|
|
|
|
|
m_stak_curr_state = TSN_JSON_CTX_IN_OBJ;
|
2026-08-04 08:01:43 -05:00
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_pos++;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_next = TSN_JSON_TOK_SAX_LLAVE_INI;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TSN_JSON_TOK_COR_INI:
|
|
|
|
|
{
|
|
|
|
|
//_--
|
|
|
|
|
m_in.OnStartArr();
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_stak_curr++;
|
2026-08-04 09:02:31 -05:00
|
|
|
m_stak_state[m_stak_curr] = TSN_JSON_CTX_IN_ARR;
|
|
|
|
|
m_stak_curr_state = TSN_JSON_CTX_IN_ARR;
|
2026-08-04 08:01:43 -05:00
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_pos++;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_next = TSN_JSON_TOK_SAX_COR_INI;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TSN_JSON_TOK_LLAVE_END:
|
|
|
|
|
{
|
2026-08-04 09:02:31 -05:00
|
|
|
//---
|
|
|
|
|
m_stak_curr--;
|
|
|
|
|
|
2026-08-04 08:01:43 -05:00
|
|
|
//---
|
|
|
|
|
m_in.OnEndObJ();
|
|
|
|
|
|
|
|
|
|
//---
|
2026-08-04 09:02:31 -05:00
|
|
|
if(m_stak_curr < 0) // termino
|
2026-08-04 08:01:43 -05:00
|
|
|
{
|
|
|
|
|
m_in.OnEndDocument();
|
|
|
|
|
JSONPARSERBYLEO_SAX_ON_FINISH
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-04 09:02:31 -05:00
|
|
|
//---
|
|
|
|
|
m_stak_curr_state = m_stak_state[m_stak_curr];
|
|
|
|
|
|
2026-08-04 08:01:43 -05:00
|
|
|
//---
|
|
|
|
|
m_pos++;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_next = TSN_JSON_TOK_SAX_NO_NEXT_KEY;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TSN_JSON_TOK_COR_END:
|
|
|
|
|
{
|
2026-08-04 09:02:31 -05:00
|
|
|
//---
|
|
|
|
|
m_stak_curr--;
|
|
|
|
|
|
2026-08-04 08:01:43 -05:00
|
|
|
//---
|
|
|
|
|
m_in.OnEndArr();
|
|
|
|
|
|
|
|
|
|
//---
|
2026-08-04 09:02:31 -05:00
|
|
|
if(m_stak_curr < 0) // termino
|
2026-08-04 08:01:43 -05:00
|
|
|
{
|
|
|
|
|
m_in.OnEndDocument();
|
|
|
|
|
JSONPARSERBYLEO_SAX_ON_FINISH
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-04 09:02:31 -05:00
|
|
|
//---
|
|
|
|
|
m_stak_curr_state = m_stak_state[m_stak_curr];
|
|
|
|
|
|
2026-08-04 08:01:43 -05:00
|
|
|
//---
|
|
|
|
|
m_pos++;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_next = TSN_JSON_TOK_SAX_NO_NEXT_KEY;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case TSN_JSON_TOK_KEY:
|
|
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
if(m_stak_pos[JSONPARSERBYLEO_SAX_STR_START] == -1)
|
|
|
|
|
{
|
|
|
|
|
m_stak_pos[JSONPARSERBYLEO_SAX_STR_START] = ++m_pos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--- Char por char
|
2026-08-04 09:02:31 -05:00
|
|
|
while(true)
|
2026-08-04 08:01:43 -05:00
|
|
|
{
|
2026-08-04 09:02:31 -05:00
|
|
|
//---
|
|
|
|
|
if(m_pos >= m_len)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-04 08:01:43 -05:00
|
|
|
//---
|
|
|
|
|
const uchar c = m_raw[m_pos];
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(c == '\\')
|
|
|
|
|
{
|
|
|
|
|
m_pos += 2;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if(c == '"')
|
|
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
const int start = m_stak_pos[JSONPARSERBYLEO_SAX_STR_START];
|
|
|
|
|
m_in.OnKey(start, m_pos - start);
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_stak_pos[JSONPARSERBYLEO_SAX_STR_START] = -1;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_pos++;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_next = TSN_JSON_TOK_SAX_DOS_PUNTOS;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_pos++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case TSN_JSON_TOK_INVALID:
|
|
|
|
|
{
|
|
|
|
|
m_last_err = TSN_JSON_ERR_INVALID_CHAR;
|
|
|
|
|
JSONPARSERBYLEO_SAX_ON_FINISH
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case TSN_JSON_TOK_SAX_NO_NEXT_KEY:
|
|
|
|
|
{
|
|
|
|
|
while(true)
|
|
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
if(m_pos >= m_len)
|
|
|
|
|
return true; // esperando mas ...
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const uchar _c = m_raw[m_pos];
|
|
|
|
|
if(_c < 33)
|
|
|
|
|
{
|
|
|
|
|
m_pos++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_next = g_table_json_tokens[_c];
|
|
|
|
|
if(((1 << m_next) & m_stak_curr_state) == 0)
|
|
|
|
|
{
|
|
|
|
|
JSONPARSERBYLEO_SAX_ON_FINISH
|
|
|
|
|
m_last_err = TSN_JSON_ERR_MALFORDMED_JSON;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
case TSN_JSON_TOK_SAX_LLAVE_INI:
|
|
|
|
|
{
|
|
|
|
|
while(true)
|
|
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
if(m_pos >= m_len)
|
|
|
|
|
return true; // esperando mas ...
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const uchar _c = m_raw[m_pos];
|
|
|
|
|
if(_c == '"')
|
|
|
|
|
{
|
|
|
|
|
m_next = TSN_JSON_TOK_KEY;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if(_c == '}')
|
|
|
|
|
{
|
|
|
|
|
m_next = TSN_JSON_TOK_LLAVE_END;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
m_pos++;
|
|
|
|
|
}
|
2026-08-04 09:02:31 -05:00
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
break;
|
2026-08-04 08:01:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
case TSN_JSON_TOK_SAX_COR_INI:
|
|
|
|
|
{
|
|
|
|
|
while(true)
|
|
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
if(m_pos >= m_len)
|
|
|
|
|
return true; // esperando mas ...
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const uchar _c = m_raw[m_pos];
|
|
|
|
|
if(_c < 33)
|
|
|
|
|
{
|
|
|
|
|
m_pos++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
m_next = g_table_json_tokens[_c];
|
|
|
|
|
if(((1 << m_next) & TSN_JSON_F_VAL_COR) == 0)
|
|
|
|
|
{
|
|
|
|
|
JSONPARSERBYLEO_SAX_ON_FINISH
|
|
|
|
|
m_last_err = TSN_JSON_ERR_MALFORDMED_JSON;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case TSN_JSON_TOK_SAX_FIND_KEY:
|
|
|
|
|
{
|
|
|
|
|
while(true)
|
|
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
if(m_pos >= m_len)
|
|
|
|
|
return true; // esperando mas ...
|
|
|
|
|
//---
|
|
|
|
|
if(m_raw[m_pos] == '"')
|
|
|
|
|
{
|
|
|
|
|
m_next = TSN_JSON_TOK_KEY;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
m_pos++;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case TSN_JSON_TOK_SAX_COM_KEY:
|
|
|
|
|
{
|
|
|
|
|
while(true)
|
|
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
if(m_pos >= m_len)
|
|
|
|
|
return true; // esperando mas ...
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const uchar _c = m_raw[m_pos];
|
|
|
|
|
if(_c < 33)
|
|
|
|
|
{
|
|
|
|
|
m_pos++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
m_next = g_table_json_tokens[_c];
|
|
|
|
|
if(((1 << m_next) & TSN_JSON_F_ALL_I_VAL) == 0)
|
|
|
|
|
{
|
|
|
|
|
m_last_err = TSN_JSON_ERR_MALFORDMED_JSON;
|
|
|
|
|
JSONPARSERBYLEO_SAX_ON_FINISH
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
case TSN_JSON_TOK_SAX_DBL:
|
|
|
|
|
{
|
|
|
|
|
// Comentarios para que no te pierdas
|
|
|
|
|
// En si la tenica a usar es como ir lockeradno o teneinedo estaods con reuso de varialbes
|
|
|
|
|
// m_prev_c continee el ultimo char.. lo uso priemro para poder evitar una lectura de array mas
|
|
|
|
|
// y luego lo utilizo mas adalante para no vover a ver si m_pos e E\e
|
|
|
|
|
// Dado que podria no entrar si eso pasa
|
|
|
|
|
// Ahora otras vairalevbs presents son m_in_n esta es como mi avarialbe de estado
|
|
|
|
|
// La uso para ver en que fase estoy
|
|
|
|
|
// Luego tmabien se reusa m_last_number en el E\e para ver si tenia signo o no
|
|
|
|
|
// Aqui si neceisto persistencia.. por eso reutilizo esa varialbe..
|
|
|
|
|
if(m_prev_c == 30)
|
|
|
|
|
{
|
2026-08-26 19:48:01 -05:00
|
|
|
if(m_in_n == 0) // etapa inicial 0
|
2026-08-04 08:01:43 -05:00
|
|
|
{
|
2026-08-26 19:48:01 -05:00
|
|
|
m_in_n++; // 1
|
2026-08-04 08:01:43 -05:00
|
|
|
m_pos++;
|
|
|
|
|
m_sax_frac_int = 0;
|
|
|
|
|
m_sax_frac_digits = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
while(true)
|
|
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
if(m_pos >= m_len)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const uchar c = m_raw[m_pos] ^ '0';
|
|
|
|
|
if(c > 9)
|
|
|
|
|
{
|
2026-08-26 19:48:01 -05:00
|
|
|
m_in_n = 0; // Vuelta en 0 (ahora para procesar lod giitos)
|
2026-08-04 08:01:43 -05:00
|
|
|
m_prev_c = 0; // Ahora ya no podra ingresar a este if
|
|
|
|
|
m_last_number_dbl += m_sax_frac_int * g_Exp10[m_sax_frac_digits];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_sax_frac_int = (m_sax_frac_int << 3) + (m_sax_frac_int << 1) + c;
|
|
|
|
|
m_sax_frac_digits++;
|
|
|
|
|
m_pos++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
// Pasamos con un char extra..
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--- Ahora procesamos E
|
|
|
|
|
if(m_prev_c == 15 || (m_raw[m_pos] | 0x20) == 'e') // e or E
|
|
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
switch(m_in_n)
|
|
|
|
|
{
|
2026-08-26 19:48:01 -05:00
|
|
|
case 0:
|
2026-08-04 08:01:43 -05:00
|
|
|
{
|
2026-08-26 19:48:01 -05:00
|
|
|
m_in_n++; // 1
|
2026-08-04 08:01:43 -05:00
|
|
|
m_prev_c = 15;
|
|
|
|
|
m_pos++;
|
|
|
|
|
if(m_pos >= m_len)
|
|
|
|
|
return true; // Salimos
|
|
|
|
|
// Cae al siguiente
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-26 19:48:01 -05:00
|
|
|
case 1:
|
2026-08-04 08:01:43 -05:00
|
|
|
{
|
2026-08-26 19:48:01 -05:00
|
|
|
m_in_n++; // 2
|
2026-08-04 08:01:43 -05:00
|
|
|
m_last_number = 1; // bool exp_sign = true;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const uchar _c = m_raw[m_pos];
|
|
|
|
|
if(_c == '-')
|
|
|
|
|
{
|
|
|
|
|
m_last_number = 0; // exp_sign = false;
|
|
|
|
|
m_pos++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
if(_c == '+')
|
|
|
|
|
{
|
|
|
|
|
m_pos++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(m_pos >= m_len)
|
|
|
|
|
return true;
|
|
|
|
|
// Cae al siguiente
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-26 19:48:01 -05:00
|
|
|
case 2:
|
2026-08-04 08:01:43 -05:00
|
|
|
{
|
2026-08-26 19:48:01 -05:00
|
|
|
m_in_n++; // 3
|
2026-08-04 08:01:43 -05:00
|
|
|
m_sax_frac_int = 0;
|
|
|
|
|
// Cae al siguiente
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-26 19:48:01 -05:00
|
|
|
case 3:
|
2026-08-04 08:01:43 -05:00
|
|
|
{
|
|
|
|
|
while(true)
|
|
|
|
|
{
|
|
|
|
|
const uchar _c = m_raw[m_pos] ^ '0';
|
|
|
|
|
if(_c < 9)
|
|
|
|
|
{
|
2026-08-26 19:48:01 -05:00
|
|
|
m_last_number_dbl *= m_last_number ? g_Pow10[m_sax_frac_int] : g_Exp10[m_sax_frac_int];
|
2026-08-04 08:01:43 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_sax_frac_int = (m_sax_frac_int << 3) + (m_sax_frac_int << 1) + _c;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_pos++;
|
|
|
|
|
if(m_pos >= m_len)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
break; // Sale esta vez si..
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
JSONPARSERBYLEO_SAX_ON_FINISH
|
|
|
|
|
m_last_err = TSN_JSON_ERR_INVALID_STATE_IN_PARSE_DOUBLE_E;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-26 19:48:01 -05:00
|
|
|
//--- Reinicio base
|
2026-08-04 08:01:43 -05:00
|
|
|
m_in_n = 0;
|
|
|
|
|
|
|
|
|
|
//---
|
2026-08-28 08:28:32 -05:00
|
|
|
TsnBitInterprete bit;
|
2026-08-04 08:01:43 -05:00
|
|
|
bit.double_value = m_last_number_dbl;
|
|
|
|
|
bit.long_value ^= (m_mask & (1LL << 63));
|
|
|
|
|
m_in.OnReal(bit.double_value);
|
|
|
|
|
|
2026-08-26 19:48:01 -05:00
|
|
|
//---
|
|
|
|
|
m_last_number = 0; // reiniciamos (pude haber sido 1)
|
|
|
|
|
m_mask = 0; // tambien a 0
|
2026-08-04 08:01:43 -05:00
|
|
|
//---
|
|
|
|
|
m_next = TSN_JSON_TOK_SAX_NO_NEXT_KEY;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case TSN_JSON_TOK_SAX_DOS_PUNTOS:
|
|
|
|
|
{
|
|
|
|
|
//--- Find :
|
|
|
|
|
while(true)
|
|
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
if(m_pos >= m_len)
|
|
|
|
|
return true; // luego
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(m_raw[m_pos] == ':')
|
2026-08-04 09:02:31 -05:00
|
|
|
{
|
|
|
|
|
//---
|
|
|
|
|
m_pos++; // Luego del
|
|
|
|
|
|
|
|
|
|
//--- Buscamos valor
|
|
|
|
|
m_next = TSN_JSON_TOK_SAX_COM_KEY;
|
2026-08-04 08:01:43 -05:00
|
|
|
break;
|
2026-08-04 09:02:31 -05:00
|
|
|
}
|
2026-08-04 08:01:43 -05:00
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_pos++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
m_last_err = TSN_JSON_ERR_INVALID_CHAR;
|
|
|
|
|
JSONPARSERBYLEO_SAX_ON_FINISH
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif // JSONPARSERBYLEO_SRC_JSONSAXIMP_MQH
|
|
|
|
|
//+------------------------------------------------------------------+
|