forked from nique_372/JsonParserByLeo
904 lines
24 KiB
MQL5
904 lines
24 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| 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_JSONSAX_JSONSAXIMP_MQH
| |
#define JSONPARSERBYLEO_SRC_JSONSAX_JSONSAXIMP_MQH
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
#include "..\\JsonCore\\JsonParser.mqh"
| |
#include "JsonSax.mqh"
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
namespace TSN
| |
{
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
#define JSONPARSERBYLEO_SAX_STR_START (0)
| |
/* Notas de mi parte
| |
Siempre cuando vuevea a llamar aseungramtne de agregar datos amenos un solo dato es lo minimo..
| |
*/
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
class CJsonParserStream : public CBaseLanFormat
| |
{
| |
private:
| |
//--- Del parsing en si
| |
ushort m_stak_state[JSONPARSERBYLEO_MAX_STACK];
| |
int m_stak_curr;
| |
ushort m_stak_curr_state;
| |
| |
//---
| |
ENUM_TSN_JSON_LAST_ERR m_last_err;
| |
| |
//--- hook
| |
ITsnJsonParserStream* m_in;
| |
bool m_del_caller;
| |
| |
//--- parsing de numeros
| |
uint8_t m_in_n; // estado en decimal parse
| |
long m_last_i; // ultimo numero entero
| |
long m_mask; // mascara (pos o neg)
| |
| |
// estas se resetean solas
| |
int m_sax_frac_dc; // incio del dc \ si el ex epo luego del E\e es neg
| |
int m_sax_frac_expo; // esponente del numero rea
| |
int m_total_dig; // total de digitos de la aprte entera y fraccionaria
| |
uchar m_ch; // caracter actual
| |
uchar m_fci; // primer caracter numerico (Esto para el lz y ov)
| |
int m_sax_frac_exponente_f; // exponente parse (fuill numero luego del E\e)
| |
uchar m_prev_c; // loceo
| |
| |
//--- start (inicio de string o \ numero )
| |
int m_start;
| |
| |
//--- fijos (true\false\null)
| |
uint m_tok_fixed; // token actual (max 4bytes)
| |
uchar m_sc; // sh actual (empieza en 0)
| |
| |
| |
public:
| |
CJsonParserStream(void);
| |
~CJsonParserStream(void);
| |
| |
| |
//---
| |
__forceinline ENUM_TSN_JSON_LAST_ERR LastErr() const { return m_last_err; }
| |
| |
//---
| |
__forceinline int CurrentStack() const { return m_stak_curr + 1; }
| |
__forceinline ushort CurrentStackState() const { return m_stak_curr_state; }
| |
void KillParse();
| |
| |
//---
| |
void SetCaller(ITsnJsonParserStream* caller, bool del);
| |
void CheckLimpieza();
| |
| |
//---
| |
bool ParseSreamSax();
| |
};
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
CJsonParserStream::CJsonParserStream(void)
| |
: m_del_caller(false)
| |
{
| |
m_next = TSN_JSON_TOK_INVALID;
| |
m_pos = 0; // offset inicial
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
CJsonParserStream::~CJsonParserStream(void)
| |
{
| |
if(m_del_caller && CheckPointer(m_in) == POINTER_DYNAMIC)
| |
delete m_in;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
// Al terminar solo lo poneres en tok invalid..
| |
//---
| |
#define JSONPARSERBYLEO_SAX_ON_FINISH_P m_next=TSN_JSON_TOK_INVALID;
| |
| |
| |
#define JSONPARSERBYLEO_SAX_ON_FINISH_CORR \
| |
m_in.OnEndDocument(); \
| |
JSONPARSERBYLEO_SAX_ON_FINISH_P
| |
| |
//---
| |
#define JSONPARSERBYLEO_SAX_ON_FINISH_ERR \
| |
m_in.OnError(); \
| |
JSONPARSERBYLEO_SAX_ON_FINISH_P
| |
| |
//---
| |
#define JSONPARSERBYLEO_SAX_ITER_INT \
| |
STRCONV_TOV_ALG(m_last_i, m_ch) \
| |
if(++m_pos >= m_len) \
| |
return true; \
| |
if((m_ch = m_raw[m_pos] ^ '0') > 9) \
| |
break; \
| |
| |
//---
| |
#define JSONPARSERBYLEO_SAX_ITER_INT_UNROLLED_8 \
| |
JSONPARSERBYLEO_SAX_ITER_INT \
| |
JSONPARSERBYLEO_SAX_ITER_INT \
| |
JSONPARSERBYLEO_SAX_ITER_INT \
| |
JSONPARSERBYLEO_SAX_ITER_INT \
| |
JSONPARSERBYLEO_SAX_ITER_INT \
| |
JSONPARSERBYLEO_SAX_ITER_INT \
| |
JSONPARSERBYLEO_SAX_ITER_INT \
| |
JSONPARSERBYLEO_SAX_ITER_INT
| |
| |
//---
| |
#define JSONPARSERBYLEO_SAX_ITER_INT_SKIP \
| |
while(true) \
| |
{ \
| |
if(++m_pos >= m_len) \
| |
return true; \
| |
if((m_ch = m_raw[m_pos] ^ '0') > 9) \
| |
break; \
| |
} \
| |
| |
| |
//---
| |
#define JSONPARSERBYLEO_SAX_ITER_INT_UNROLLED_19 \
| |
JSONPARSERBYLEO_SAX_ITER_INT_UNROLLED_8 \
| |
JSONPARSERBYLEO_SAX_ITER_INT_UNROLLED_8 \
| |
JSONPARSERBYLEO_SAX_ITER_INT \
| |
JSONPARSERBYLEO_SAX_ITER_INT \
| |
JSONPARSERBYLEO_SAX_ITER_INT
| |
| |
//---
| |
#define JSONSAX_IMP_FIXED(TOKS_NUM, VALID, ERROR, EVENT) \
| |
while(++m_pos < m_len && m_sc < ((TOKS_NUM) << 3)) \
| |
{ \
| |
m_tok_fixed |= (uint)m_raw[m_pos] << (m_sc); \
| |
m_sc += 8; \
| |
} \
| |
if(m_sc == ((TOKS_NUM) << 3)) \
| |
{ \
| |
if(m_tok_fixed != VALID) \
| |
{ \
| |
m_last_err=ERROR; \
| |
JSONPARSERBYLEO_SAX_ON_FINISH_ERR \
| |
return false; \
| |
} \
| |
EVENT; \
| |
m_next = TSN_JSON_TOK_SAX_NO_NEXT_KEY; \
| |
m_sc = 0; \
| |
m_tok_fixed = 0; \
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
void CJsonParserStream::KillParse(void)
| |
{
| |
m_next = TSN_JSON_TOK_INVALID; // sin nada en medio
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
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 = m_offset; // Reiniciamos el pos
| |
m_len = 0; // toca llenar dado que ahora es 0
| |
// 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..
| |
}
| |
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
// NOTA minimo intrudcion un byte.. por cada calling no menos...
| |
bool CJsonParserStream::ParseSreamSax(void)
| |
{
| |
//--- Inicial
| |
if(m_next == TSN_JSON_TOK_INVALID)
| |
{
| |
//---
| |
// general
| |
m_stak_curr = -1;
| |
m_last_err = TSN_JSON_NOT_ERR;
| |
m_pos = m_offset;
| |
// numeros
| |
m_last_i = 0;
| |
m_mask = 0;
| |
//dbl
| |
m_in_n = 0;
| |
// extra
| |
m_start = -1; // string y keys
| |
// fijos
| |
m_tok_fixed = 0;
| |
m_sc = 0;
| |
| |
//---
| |
m_in.OnStartDocument();
| |
| |
//--- Inicial
| |
//Print(m_pos);
| |
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_next = TSN_JSON_TOK_SAX_SLOW_PATH_FIND;
| |
if(++m_pos >= m_len)
| |
return true; // falta
| |
}
| |
}
| |
| |
//--- Bucle
| |
while(true)
| |
{
| |
switch(m_next)
| |
{
| |
case TSN_JSON_TOK_NUMBER_NEG:
| |
{
| |
//---
| |
// m_last_i=0 ya viene a 0
| |
m_mask = -1; // solo cambiamos la mascara
| |
m_start = m_pos;
| |
| |
//---
| |
if(++m_pos >= m_len) // Ahora en numero de lo contraio a la siguiente..}
| |
{
| |
m_next = TSN_JSON_TOK_NUMBER;
| |
return true;
| |
}
| |
// Si hay aun valor cae aqui...
| |
}
| |
| |
//---
| |
case TSN_JSON_TOK_NUMBER:
| |
{
| |
//---
| |
m_ch = m_raw[m_pos] ^ '0';
| |
| |
//---
| |
if(m_start == -1)
| |
{
| |
m_start = m_pos;
| |
m_fci = m_ch;
| |
}
| |
| |
//---
| |
while(m_ch < 10) // solo si es menor a 10
| |
{
| |
JSONPARSERBYLEO_SAX_ITER_INT_UNROLLED_19
| |
//--- aca ya no tiene sentido acomular ov seguro .... asi que saltamos noma
| |
JSONPARSERBYLEO_SAX_ITER_INT_SKIP
| |
break;
| |
}
| |
| |
//--- lz
| |
// si el valor inicial es 0 pero .. por alguna razon hay dos digitos que se procesaron...
| |
m_total_dig = (m_pos - m_start + int(m_mask));
| |
if(m_fci == 0 && m_total_dig > 1)
| |
{
| |
m_last_err = TSN_JSON_ERR_LEADING_ZEROS;
| |
JSONPARSERBYLEO_SAX_ON_FINISH_ERR
| |
return false;
| |
}
| |
| |
//--- final
| |
if(STRCONV_DECX_CH_IS_DEC(m_ch))
| |
{
| |
m_prev_c = m_ch;
| |
m_next = TSN_JSON_TOK_SAX_DBL;
| |
}
| |
else
| |
{
| |
if(m_total_dig > 19 || m_last_i < 0) // overflow
| |
m_in.OnBigInteger(m_start, m_total_dig);
| |
else
| |
m_in.OnInteger((m_last_i ^ m_mask) - m_mask);
| |
| |
//--- terminamos
| |
m_next = TSN_JSON_TOK_SAX_NO_NEXT_KEY;
| |
m_last_i = 0;
| |
m_mask = 0;
| |
m_start = -1;
| |
}
| |
//--- no hago el m_pos++ dado que ahora mismo estamo en el seg char
| |
break;
| |
}
| |
| |
//---
| |
case TSN_JSON_TOK_STRING:
| |
{
| |
//---
| |
if(m_start == -1)
| |
m_start = ++m_pos;
| |
| |
//--- Char por char
| |
while(true)
| |
{
| |
//---
| |
if(m_pos >= m_len)
| |
return true;
| |
| |
//---
| |
const uchar c = m_raw[m_pos];
| |
| |
//---
| |
if(c == '\\')
| |
{
| |
m_pos += 2;
| |
continue;
| |
}
| |
if(c == '"')
| |
{
| |
//---
| |
const int start = m_start;
| |
m_in.OnString(start, m_pos - start);
| |
| |
//---
| |
m_start = -1;
| |
m_pos++;
| |
m_next = TSN_JSON_TOK_SAX_NO_NEXT_KEY;
| |
break;
| |
}
| |
| |
//---
| |
m_pos++;
| |
}
| |
//---
| |
break;
| |
}
| |
case TSN_JSON_TOK_BOOL_TRUE:
| |
{
| |
//--- el primer t ya se cuenta como valido solo los isuigntes
| |
JSONSAX_IMP_FIXED(3, TSNJSON_VAL_TRUE, TSN_JSON_ERR_MALFORMED_TRUE, m_in.OnBool(true))
| |
break;
| |
}
| |
case TSN_JSON_TOK_BOOL_FALSE:
| |
{
| |
//---
| |
JSONSAX_IMP_FIXED(4, TSNJSON_VAL_FALSE, TSN_JSON_ERR_MALFORMED_FALSE, m_in.OnBool(false))
| |
break;
| |
}
| |
case TSN_JSON_TOK_NULL:
| |
{
| |
//---
| |
JSONSAX_IMP_FIXED(3, TSNJSON_VAL_NULL, TSN_JSON_ERR_MALFORMED_NULL, m_in.OnNull())
| |
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++;
| |
m_stak_state[m_stak_curr] = TSN_JSON_CTX_IN_OBJ;
| |
m_stak_curr_state = TSN_JSON_CTX_IN_OBJ;
| |
| |
//---
| |
m_pos++;
| |
| |
//---
| |
m_next = TSN_JSON_TOK_SAX_LLAVE_INI;
| |
| |
//---
| |
break;
| |
}
| |
case TSN_JSON_TOK_COR_INI:
| |
{
| |
//_--
| |
m_in.OnStartArr();
| |
| |
//---
| |
m_stak_curr++;
| |
m_stak_state[m_stak_curr] = TSN_JSON_CTX_IN_ARR;
| |
m_stak_curr_state = TSN_JSON_CTX_IN_ARR;
| |
| |
//---
| |
m_pos++;
| |
m_next = TSN_JSON_TOK_SAX_COR_INI;
| |
| |
//---
| |
break;
| |
}
| |
case TSN_JSON_TOK_LLAVE_END:
| |
{
| |
//---
| |
m_stak_curr--;
| |
| |
//---
| |
m_in.OnEndObJ();
| |
| |
//---
| |
if(m_stak_curr < 0) // termino
| |
{
| |
JSONPARSERBYLEO_SAX_ON_FINISH_CORR
| |
return true;
| |
}
| |
| |
//---
| |
m_stak_curr_state = m_stak_state[m_stak_curr];
| |
m_pos++;
| |
m_next = TSN_JSON_TOK_SAX_NO_NEXT_KEY;
| |
| |
//---
| |
break;
| |
}
| |
case TSN_JSON_TOK_COR_END:
| |
{
| |
//---
| |
m_stak_curr--;
| |
| |
//---
| |
m_in.OnEndArr();
| |
| |
//---
| |
if(m_stak_curr < 0) // termino
| |
{
| |
m_in.OnEndDocument();
| |
JSONPARSERBYLEO_SAX_ON_FINISH_CORR
| |
return true;
| |
}
| |
| |
//---
| |
m_stak_curr_state = m_stak_state[m_stak_curr];
| |
m_pos++;
| |
m_next = TSN_JSON_TOK_SAX_NO_NEXT_KEY;
| |
| |
//---
| |
break;
| |
}
| |
case TSN_JSON_TOK_KEY:
| |
{
| |
//---
| |
if(m_start == -1)
| |
m_start = ++m_pos;
| |
| |
//--- Char por char
| |
while(true)
| |
{
| |
//---
| |
if(m_pos >= m_len)
| |
return true;
| |
| |
//---
| |
const uchar c = m_raw[m_pos];
| |
if(c == '\\')
| |
{
| |
m_pos += 2;
| |
continue;
| |
}
| |
if(c == '"')
| |
{
| |
//---
| |
const int start = m_start;
| |
m_in.OnKey(start, m_pos - start);
| |
| |
//---
| |
m_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_ERR
| |
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)
| |
{
| |
m_last_err = TSN_JSON_ERR_MALFORDMED_JSON_AFTER_VAL;
| |
JSONPARSERBYLEO_SAX_ON_FINISH_ERR
| |
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++;
| |
}
| |
break;
| |
}
| |
| |
//---
| |
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)
| |
{
| |
m_last_err = TSN_JSON_ERR_MALFORDMED_JSON_AFTER_COR_INI;
| |
JSONPARSERBYLEO_SAX_ON_FINISH_ERR
| |
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_FIND_VAL;
| |
JSONPARSERBYLEO_SAX_ON_FINISH_ERR
| |
return false;
| |
}
| |
break;
| |
}
| |
break;
| |
}
| |
| |
//---
| |
case TSN_JSON_TOK_SAX_DBL:
| |
{
| |
//---
| |
if(m_prev_c == 30)
| |
{
| |
if(m_in_n == 0) // etapa inicial 0
| |
{
| |
m_in_n++; // 1
| |
m_pos++;
| |
m_sax_frac_expo = 0; // exponenet actual
| |
m_sax_frac_dc = m_pos; // inicio de la parte dc imal
| |
}
| |
| |
//---
| |
while(true)
| |
{
| |
//---
| |
if(m_pos >= m_len)
| |
return true;
| |
| |
//---
| |
m_ch = m_raw[m_pos] ^ '0';
| |
if(m_ch > 9)
| |
{
| |
m_in_n = 0; // Vuelta en 0 (ahora para procesar lod giitos)
| |
m_prev_c = 0; // Ahora ya no podra ingresar a este if
| |
| |
//---
| |
m_sax_frac_dc = (m_pos - m_sax_frac_dc);
| |
| |
//---
| |
m_sax_frac_expo -= m_sax_frac_dc;
| |
m_total_dig += m_sax_frac_dc;
| |
break;
| |
}
| |
| |
//---
| |
m_last_i = (m_last_i << 3) + (m_last_i << 1) + m_ch;
| |
m_pos++;
| |
}
| |
}
| |
| |
//--- Ahora procesamos E
| |
if(m_prev_c == 15 || (m_ch | 0x20) == 117) // e or E
| |
{
| |
//---
| |
switch(m_in_n)
| |
{
| |
case 0: // Saltamos el E\e
| |
{
| |
m_in_n++; // 1
| |
m_prev_c = 15;
| |
| |
//---
| |
if(++m_pos >= m_len)
| |
return true; // Salimos
| |
// Cae al siguiente
| |
}
| |
case 1:
| |
{
| |
m_in_n++; // 2
| |
// por defecto positivo asi que el siguinete le resta
| |
| |
//---
| |
m_sax_frac_dc = 1; // positivo
| |
m_ch = m_raw[m_pos] ^ '0';
| |
| |
//---
| |
if(m_ch > 9)
| |
{
| |
if(m_ch == ('-' ^ '0'))
| |
m_sax_frac_dc = 0;
| |
| |
//---
| |
m_ch = UCHAR_MAX;
| |
| |
//---
| |
if(++m_pos >= m_len)
| |
return true;
| |
}
| |
| |
//---
| |
// Cae al siguiente
| |
}
| |
case 2:
| |
{
| |
m_in_n++; // 3
| |
m_sax_frac_exponente_f = 0;
| |
//---
| |
// Cae al siguiente
| |
}
| |
case 3:
| |
{
| |
//--- en caso sea uchar max (tema de signo entonces volvemos..)
| |
if(m_ch == UCHAR_MAX)
| |
m_ch = m_raw[m_pos] ^ '0';
| |
| |
//---
| |
while(true)
| |
{
| |
if(m_ch > 9)
| |
{
| |
// si ex positivo lo sumamos.. si es negativo seria -x + -x (suma.. de negativos)
| |
m_sax_frac_expo += m_sax_frac_dc ? m_sax_frac_exponente_f : -m_sax_frac_exponente_f;
| |
break;
| |
}
| |
| |
//---
| |
m_sax_frac_exponente_f = (m_sax_frac_exponente_f << 3) + (m_sax_frac_exponente_f << 1) + m_ch;
| |
| |
//---
| |
m_pos++;
| |
if(m_pos >= m_len)
| |
{
| |
m_ch = UCHAR_MAX; // valido aun sigamos.
| |
return true;
| |
}
| |
| |
//---
| |
m_ch = m_raw[m_pos] ^ '0'; // si guiente
| |
}
| |
break; // Sale esta vez si..
| |
}
| |
| |
//---
| |
default:
| |
{
| |
m_last_err = TSN_JSON_ERR_INVALID_STATE_IN_PARSE_DOUBLE_E;
| |
JSONPARSERBYLEO_SAX_ON_FINISH_ERR
| |
return false;
| |
}
| |
}
| |
}
| |
| |
//--- Reinicio base
| |
m_in_n = 0;
| |
| |
//---
| |
if(STRCONV_DOUBLE_SAFE_DBL(m_total_dig, m_sax_frac_expo)) // limite seguro para esto
| |
{
| |
TsnBitInterprete bit;
| |
bit.double_value = STRCONV_TO_DOUBLE_ALG(m_sax_frac_expo, m_last_i);
| |
bit.long_value ^= (m_mask & (1LL << 63)); // a neg
| |
m_in.OnReal(bit.double_value);
| |
}
| |
else // perdida de preciscion le damos al callbackd que decida que hacer si big decimal o lo qeu el quiera..
| |
{
| |
m_in.OnBigDecimal(m_start, (m_pos - m_start));
| |
}
| |
| |
//---
| |
m_start = -1; // si o si dado uqe lo guardamos
| |
m_last_i = 0; // reiniciamos (pude haber sido 1)
| |
m_mask = 0; // tambien a 0
| |
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] == ':')
| |
{
| |
//---
| |
m_pos++; // Luego del
| |
| |
//--- Buscamos valor
| |
m_next = TSN_JSON_TOK_SAX_COM_KEY;
| |
break;
| |
}
| |
| |
//---
| |
m_pos++;
| |
}
| |
| |
//---
| |
break;
| |
}
| |
| |
//--- cae a slow path para contrue el inicio
| |
case TSN_JSON_TOK_SAX_SLOW_PATH_FIND:
| |
{
| |
//---
| |
m_ch = m_raw[m_pos];
| |
while(m_ch < 33)
| |
{
| |
if(++m_pos >= m_len)
| |
return true;
| |
m_ch = m_raw[m_pos];
| |
}
| |
| |
//---
| |
if(m_ch == '}')
| |
{
| |
m_next = TSN_JSON_TOK_LLAVE_INI;
| |
continue;
| |
}
| |
else
| |
if(m_ch == ']')
| |
{
| |
m_next = TSN_JSON_TOK_COR_INI;
| |
continue;
| |
}
| |
}
| |
| |
//--- invalid token
| |
default:
| |
{
| |
m_last_err = TSN_JSON_ERR_INVALID_CHAR;
| |
JSONPARSERBYLEO_SAX_ON_FINISH_ERR
| |
return false;
| |
}
| |
}
| |
}
| |
//---
| |
return true;
| |
}
| |
}
| |
#endif // JSONPARSERBYLEO_SRC_JSONSAX_JSONSAXIMP_MQH
| |
//+------------------------------------------------------------------+
|