2026-07-24 07:27:55 -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
/ / + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
//| |
//+------------------------------------------------------------------+
2026-10-03 17:00:34 -05:00
# include "JsonDefines.mqh"
2026-07-19 13:56:15 -05:00
# include <TSN\\BSFL\\Dom.mqh>
2026-06-02 21:23:50 -05:00
2026-08-03 09:31:58 -05:00
//---
# ifdef JSONPARSERBYLEO_DLL
# include "DLL\\Main.mqh"
# endif // JSONPARSERBYLEO_DLL
2026-06-02 21:23:50 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
namespace TSN
{
2026-06-03 07:50:45 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-06-09 14:15:41 -05:00
//#define JSONPARSERBYLEO_DESACTIVE_SWAR
2026-06-03 07:50:45 -05:00
2026-06-02 21:23:50 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-07-19 07:41:52 -05:00
class CJsonParser : public CBaseStructuredLan
2026-06-02 21:23:50 -05:00
{
2026-08-04 08:01:50 -05:00
protected :
2026-06-02 21:23:50 -05:00
//---
2026-08-27 13:56:43 -05:00
uint m_stak_num [ JSONPARSERBYLEO_MAX_STACK ] ;
int m_stak_pos [ JSONPARSERBYLEO_MAX_STACK ] ;
ushort m_stak_state [ JSONPARSERBYLEO_MAX_STACK ] ;
2026-06-02 21:23:50 -05:00
int m_stak_curr ;
2026-08-02 16:49:10 -05:00
ushort m_stak_curr_state ;
2026-06-02 21:23:50 -05:00
2026-08-03 09:31:58 -05:00
//---
# ifdef JSONPARSERBYLEO_DLL
int m_index [ ] ;
int m_index_r ;
# endif // JSONPARSERBYLEO_DLL
2026-06-02 21:23:50 -05:00
//---
ENUM_TSN_JSON_LAST_ERR m_last_err ;
2026-07-19 07:41:52 -05:00
//---
int CalcRegType ( const string & file_name ) override final ;
2026-09-30 07:39:54 -05:00
2026-06-02 21:23:50 -05:00
public :
2026-08-03 09:31:58 -05:00
CJsonParser ( void ) ;
2026-06-02 21:23:50 -05:00
~ CJsonParser ( void ) { }
2026-10-01 08:25:33 -05:00
//--- Parse + Correct padding
2026-06-03 08:32:38 -05:00
// Para data raw se puede usar el json uchar directamtne
2026-06-21 21:51:52 -05:00
bool AutoParseByFileExt ( const int file_ext_type ) ;
2026-09-18 14:11:09 -05:00
void CorrectPadding ( ) ;
2026-08-03 09:31:58 -05:00
# ifdef JSONPARSERBYLEO_DLL
2026-09-18 14:11:09 -05:00
void CorrectPaddingSimd ( ) ;
2026-08-03 09:31:58 -05:00
# endif // JSONPARSERBYLEO_DLL
2026-06-03 07:50:45 -05:00
2026-06-18 09:48:36 -05:00
//---
bool Parse ( ) ;
2026-08-03 09:31:58 -05:00
# ifdef JSONPARSERBYLEO_DLL
2026-09-18 14:11:09 -05:00
__forceinline bool ParseSimd ( ) ;
2026-08-03 09:31:58 -05:00
# endif // JSONPARSERBYLEO_DLL
2026-09-18 14:11:09 -05:00
2026-10-01 08:25:33 -05:00
//--- Errores
2026-06-03 07:50:45 -05:00
__forceinline ENUM_TSN_JSON_LAST_ERR LastErr ( ) const { return m_last_err ; }
2026-09-30 07:39:54 -05:00
void CatchErr ( ) ;
2026-10-03 17:00:34 -05:00
void ErrorInfo ( const string header = " " ) ;
2026-06-03 07:50:45 -05:00
2026-10-01 08:25:33 -05:00
//--- Step
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
2026-10-01 08:25:33 -05:00
//--- Info
2026-06-18 08:36:18 -05:00
void PrintCintaTypes ( const int start , const int num ) const ;
2026-06-03 07:50:45 -05:00
2026-07-26 16:46:05 -05:00
//--- Comparacion
// keys
bool KeysEqual ( const ulong key_hash_fnv1a64 , const int curr ) const ;
bool KeysEqual ( const string & str , const int curr ) const ;
// strings
2026-06-20 13:57:50 -05:00
bool StrEquals ( const string & str , const int curr ) const ;
2026-07-28 21:39:04 -05:00
2026-10-01 08:25:33 -05:00
//--- Clean node
2026-07-10 07:17:28 -05:00
string CleanNode ( int i , const int end ) const ;
2026-07-15 17:58:56 -05:00
int CleanNode ( int i , const int end , uchar & out [ ] , int k , bool ajustar_arr ) const ;
2026-07-10 07:17:28 -05:00
2026-10-01 08:25:33 -05:00
//--- Extra (node-use)
2026-06-20 13:57:50 -05:00
bool NodeHashing ( int curr , const int obj_count , const int bend , int & table_pos ) ;
2026-10-01 08:25:33 -05:00
bool SerializeToDom ( CDomNodeBase * root , CDomNodeManager * manager , int cur , const int end ) ;
2026-07-11 16:31:27 -05:00
2026-10-01 08:25:33 -05:00
//--- Array
2026-09-30 07:39:54 -05:00
template < typename T >
void ToArray ( int cur , T & out_arr [ ] , const int end ) const ;
template < typename T >
bool ExistInArray ( int cur , const T val , const uint flags , const int end ) const ;
template < typename T >
bool ExistInArrayHomogeneo ( int cur , const T val , const int end ) const ;
2026-10-01 08:25:33 -05:00
2026-10-01 13:36:22 -05:00
//--- Make
2026-10-01 08:25:33 -05:00
// uso en get value o exatcion
static bool MakeString ( const uchar & in [ ] , int i , int len , string & res ) ;
static int MakeUArray ( const uchar & in [ ] , int i , int len , uchar & res [ ] , int pos = 0 ) ;
static bool MakeKeyHashFNV1A64 ( const uchar & in [ ] , int & i , int len , ulong & hash ) ;
static bool EscapePointer ( const string & in , int & p , int len , ulong & hash ) ;
2026-10-03 17:00:34 -05:00
//---
static void PrintError ( const string & header , const uchar & buf [ ] , const int len ,
int col , int line , ENUM_TSN_JSON_LAST_ERR err , string & salida , bool print = true ) ;
2026-10-01 08:25:33 -05:00
//---
CJsonNode GetRoot ( ) ;
2026-07-26 16:46:05 -05:00
//--- Tablas generales
2026-09-30 07:39:54 -05:00
static const string s_dtype_to_str [ JSON_VTYPE_TOTAL ] ;
static const char s_slots_size_arrobj ;
2026-07-26 16:46:05 -05:00
} ;
2026-08-03 09:31:58 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CJsonParser : : CJsonParser ( void )
{
2026-08-04 09:02:31 -05:00
m_next = TSN_JSON_TOK_INVALID ;
2026-08-03 09:31:58 -05:00
# ifdef JSONPARSERBYLEO_DLL
m_index_r = ArrayResize ( m_index , 256 , 256 ) ;
# endif // JSONPARSERBYLEO_DLL
}
2026-07-26 16:46:05 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-09-30 07:39:54 -05:00
const string CJsonParser : : s_dtype_to_str [ JSON_VTYPE_TOTAL ] =
2026-07-26 16:46:05 -05:00
{
" " ,
" " ,
" " ,
2026-09-30 07:39:54 -05:00
" ulong " ,
2026-07-26 16:46:05 -05:00
" long " ,
" double " ,
" bool " ,
" string " ,
" "
} ;
2026-09-30 07:39:54 -05:00
const char CJsonParser : : s_slots_size_arrobj = 2 ;
2026-06-02 21:23:50 -05:00
2026-09-18 14:11:09 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
# ifdef JSONPARSERBYLEO_DLL
void CJsonParser::CorrectPaddingSimd ( )
{
//---
const int new_len = m_len + 64 ;
ArrayResize ( m_raw , new_len ) ;
//---
int i = m_len ;
m_raw [ i + + ] = ' ' ;
m_raw [ i + + ] = ' ^ ' ; // para cor ini para que falle bien..
// esto es para el caso de " no cerrado o { asi tal cual.. entonces ahi
// porzariamos a econnotrar un "" el cual ya lo manejaria y seria invalido
m_raw [ i + + ] = ' " ' ;
m_raw [ i + + ] = ' ' ;
m_raw [ i + + ] = ' " ' ;
// esto es para el key... los dos primeors eran para que no de fuera de rango en index..
// en caso tengos un { asi tal cual... ecnontrar una key... pero luego le sigue : pero ahora pondmores
// , asi que == ':' fallaria retornando false, lo neceismtos dado que , se procesa como estrucuutra en la dll
m_raw [ i + + ] = ' , ' ;
//---
for ( ; i < new_len ; i + + )
m_raw [ i ] = ' ' ; // vacio
//--- Reservamos
if ( m_len > m_cinta_reserve )
{
2026-09-25 08:00:04 -05:00
m_cinta_reserve = m_len ;
2026-09-18 14:11:09 -05:00
ArrayResize ( m_cinta , m_len ) ;
}
//---
2026-09-25 08:00:04 -05:00
if ( m_len > m_index_r )
2026-09-18 14:11:09 -05:00
{
2026-09-25 08:00:04 -05:00
m_index_r = m_len ;
2026-09-18 14:11:09 -05:00
ArrayResize ( m_index , m_index_r ) ;
}
}
# endif // JSONPARSERBYLEO_DLL
//+------------------------------------------------------------------+
void CJsonParser::CorrectPadding ( )
{
//---
2026-09-30 07:39:54 -05:00
//const int new_len = ;
2026-09-25 08:00:04 -05:00
ArrayResize ( m_raw , m_len + 11 ) ;
2026-09-18 14:11:09 -05:00
//--- Rellenamos
// esto es por el escapado. caso borde donde el json su ultimo char sea \ y avanze ++
// entonces con esto apaleamos eso..
m_raw [ m_len ] = ' ' ;
// este caracter es invalido por lo que en casos donde haya [ (sin mas asi tal cual)
// como no tenemos chekeos de rango entonces se tompara con este daond un error de malformacion
m_raw [ m_len + 1 ] = ' ^ ' ;
m_raw [ m_len + 2 ] = ' " ' ;
// justo luego 8 caracteres
m_raw [ m_len + 3 ] = ' \n ' ; // en una key invalida cargara a paritr de aqui 7 caracterres mas..
m_raw [ m_len + 4 ] = ' " ' ; // esto para poder encontrar el cierre de key... aparte en asm
// un token " asi suelto no es valido asi que daria error en caso haya un ; asi no mas.. sin \n (lo enocnr)
// igual por el padding pero luego avnazar a " pero este como tal no es token valido
2026-10-03 11:47:17 -05:00
// invalidos para que sigmoas si un valor esta fuera de rango como un string o algo asi
// falle aqui....
m_raw [ m_len + 5 ] = ' ^ ' ; //
2026-10-02 22:01:54 -05:00
m_raw [ m_len + 6 ] = ' ^ ' ;
m_raw [ m_len + 7 ] = ' ^ ' ;
m_raw [ m_len + 8 ] = ' ^ ' ;
m_raw [ m_len + 9 ] = ' ^ ' ;
m_raw [ m_len + 10 ] = ' ^ ' ;
2026-09-18 14:11:09 -05:00
//--- Reservamos
if ( m_len > m_cinta_reserve )
{
m_cinta_reserve = m_len ;
ArrayResize ( m_cinta , m_len ) ;
}
}
2026-06-20 13:57:50 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CJsonParser::NodeHashing ( int curr , const int obj_count , const int bend , int & table_pos )
{
2026-09-23 15:25:08 -05:00
//--- inicial
BASESPARSERSLAN_START_NODE_HASH ( table_pos , curr )
2026-06-20 13:57:50 -05:00
//---
m_tables [ table_pos ] . table_size = obj_count ; // Numero de objetos
2026-09-23 15:25:08 -05:00
//---
2026-06-28 18:47:50 -05:00
m_pfh . MaxValSeed ( m_max_att + + ) ;
2026-09-25 08:00:04 -05:00
m_pfh . InitAlg ( obj_count , 0.70 , TSN_NODEBASEREAD_MIN_JIT_VALUES_TO_HASH_MIN ) ;
2026-06-20 13:57:50 -05:00
//---
2026-06-21 20:08:59 -05:00
ArrayResize ( m_tables [ table_pos ] . pos_arr , obj_count ) ;
2026-06-20 13:57:50 -05:00
//--- Obtnemos las posiciones de incio
2026-06-24 17:20:42 -05:00
ulong keys_h [ ] ;
2026-06-28 18:47:50 -05:00
int posiciones [ ] ;
2026-06-24 17:20:42 -05:00
ArrayResize ( keys_h , obj_count ) ;
2026-06-28 18:47:50 -05:00
ArrayResize ( posiciones , obj_count ) ;
2026-06-24 17:20:42 -05:00
int pos_c = 0 ;
2026-06-28 18:47:50 -05:00
curr + = 2 ; // Ahora en key
2026-06-24 17:20:42 -05:00
//---
2026-06-20 13:57:50 -05:00
while ( curr < bend )
{
2026-09-25 08:00:04 -05:00
const long v = m_cinta [ curr ] ;
if ( int ( v & TSN_SBL_BIT_MASK_TYPE ) ! = JSON_VTYPE_KEY )
2026-06-20 13:57:50 -05:00
{
curr + = GetStep ( curr ) ;
continue ;
}
//---
2026-06-24 17:20:42 -05:00
m_tables [ table_pos ] . pos_arr [ pos_c ] = curr ; // Assing
2026-06-20 13:57:50 -05:00
//---
2026-06-28 18:47:50 -05:00
ulong key_hash = FNV_OFFSET_BASIS ;
2026-09-25 08:00:04 -05:00
int i = int ( v > > TSN_SBL_BIT_STR_START ) ; // len
const int len = i + int ( ( v > > TSN_SBL_BIT_STR_LEN ) & TSN_SBL_BIT_STR_MASK_LEN ) ; // len
2026-06-20 13:57:50 -05:00
2026-06-24 17:20:42 -05:00
//--- Hash 64
2026-09-25 08:00:04 -05:00
while ( i < len )
2026-06-24 17:20:42 -05:00
{
2026-07-19 07:41:52 -05:00
key_hash ^ = m_raw [ i ] ;
2026-06-28 18:47:50 -05:00
key_hash * = FNV_PRIME ;
2026-09-25 08:00:04 -05:00
i + + ;
2026-06-24 17:20:42 -05:00
}
2026-09-25 08:00:04 -05:00
2026-07-19 07:41:52 -05:00
// PrintFormat("Hash para %s = %I64u", CharArrayToString(m_raw, int(m_cinta[curr] >> TSN_SBL_BIT_STR_START),
// int((m_cinta[curr] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN)), key_hash);
2026-06-20 13:57:50 -05:00
2026-06-24 17:20:42 -05:00
//---
2026-06-28 18:47:50 -05:00
keys_h [ pos_c ] = key_hash ;
posiciones [ pos_c ] = pos_c ;
pos_c + + ;
2026-06-20 13:57:50 -05:00
//---
2026-06-24 17:20:42 -05:00
curr + + ; // salta KEY
curr + = GetStep ( curr ) ; // salta VAL
}
2026-06-20 13:57:50 -05:00
2026-07-28 21:39:04 -05:00
// Cacheado
2026-06-28 18:47:50 -05:00
const int fn = m_pfh . m_final_table_size ;
2026-07-28 21:39:04 -05:00
//--- Last
m_tables [ table_pos ] . final_table_l = m_pfh . m_final_table_size_last ;
m_tables [ table_pos ] . bucket_l = m_pfh . m_buckets_size_last ;
2026-06-28 18:47:50 -05:00
// Iniciamos..
ArrayResize ( m_tables [ table_pos ] . pos_index , fn ) ;
2026-09-25 08:00:04 -05:00
//ArrayInitialize(m_tables[table_pos].pos_index, -1); no hace falta el que nos indica valides es key hash si key hash es invalido o no machte no llega aqui
//---
2026-06-28 18:47:50 -05:00
ArrayResize ( m_tables [ table_pos ] . key_hash , fn ) ;
ArrayInitialize ( m_tables [ table_pos ] . key_hash , 0ULL ) ;
2026-06-20 13:57:50 -05:00
//---
2026-09-25 08:00:04 -05:00
if ( m_pfh . RunWValue ( keys_h , posiciones , m_tables [ table_pos ] . seeds , m_tables [ table_pos ] . pos_index , m_tables [ table_pos ] . key_hash ) )
return true ;
//----
m_tables_size - - ; // pop
return false ;
2026-06-20 13:57:50 -05:00
}
2026-06-24 17:20:42 -05:00
2026-07-19 07:41:52 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CJsonParser::CalcRegType ( const string & file_name )
{
return ( int ) JPBL_HashExt ( file_name ) ;
}
2026-07-26 16:46:05 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CJsonParser::KeysEqual ( const string & str , const int curr ) const
{
//---
const int start = int ( m_cinta [ curr ] > > TSN_SBL_BIT_STR_START ) ;
const int len = int ( ( m_cinta [ curr ] > > TSN_SBL_BIT_STR_LEN ) & TSN_SBL_BIT_STR_MASK_LEN ) ;
const int l = StringLen ( str ) ;
//---
if ( l ! = len )
return false ;
//---
for ( int i = 0 ; i < l ; i + + )
if ( str [ i ] ! = m_raw [ start + i ] )
return false ;
//---
return true ;
}
//+------------------------------------------------------------------+
bool CJsonParser::KeysEqual ( const ulong key_hash_fnv1a64 , const int curr ) const
{
const int start = int ( m_cinta [ curr ] > > TSN_SBL_BIT_STR_START ) ;
const int len = int ( ( m_cinta [ curr ] > > TSN_SBL_BIT_STR_LEN ) & TSN_SBL_BIT_STR_MASK_LEN ) ;
ulong hash = FNV_OFFSET_BASIS ;
for ( int i = start ; i < ( start + len ) ; i + + )
{
hash ^ = m_raw [ i ] ;
hash * = FNV_PRIME ;
}
return hash = = key_hash_fnv1a64 ;
}
2026-06-20 13:57:50 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CJsonParser::StrEquals ( const string & str , const int curr ) const
{
//---
// m_cinta[m_cinta_pos++] = long(m_pos - 1) | long(start) << TSN_JSON_BIT_STR_START_END;
2026-07-19 07:41:52 -05:00
const int start = int ( m_cinta [ curr ] > > TSN_SBL_BIT_STR_START ) ;
const int len = int ( ( m_cinta [ curr ] > > TSN_SBL_BIT_STR_LEN ) & TSN_SBL_BIT_STR_MASK_LEN ) ;
//PrintFormat("Exact = '%s', other = '%s'", CharArrayToString(m_raw, start, len), str);
2026-06-20 14:18:38 -05:00
2026-06-20 13:57:50 -05:00
const int l = StringLen ( str ) ;
//---
2026-06-20 14:18:38 -05:00
if ( l ! = len )
2026-06-20 13:57:50 -05:00
return false ;
for ( int i = 0 ; i < l ; i + + )
{
2026-07-19 07:41:52 -05:00
if ( str [ i ] ! = m_raw [ start + i ] )
2026-06-20 13:57:50 -05:00
return false ;
}
return true ;
}
2026-06-23 08:02:37 -05:00
2026-07-10 07:17:28 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string CJsonParser::CleanNode ( int i , const int end ) const
{
//---
string str ;
int k = 0 ;
2026-09-18 14:11:09 -05:00
StringInit ( str , ( end - i ) + 1 , ' ' ) ;
2026-07-10 07:17:28 -05:00
// "\"\""
//---
bool in = false ;
for ( i ; i < = end ; i + + )
{
2026-07-19 07:41:52 -05:00
const uchar c = m_raw [ i ] ;
2026-07-10 07:17:28 -05:00
//---
if ( in )
{
str .SetChar ( k + + , c ) ;
if ( c = = ' \\ ' )
{
2026-07-19 07:41:52 -05:00
str .SetChar ( k + + , m_raw [ + + i ] ) ;
2026-07-10 07:17:28 -05:00
continue ;
}
in = ( c ! = ' " ' ) ;
}
else
{
if ( c < 33 )
continue ;
str .SetChar ( k + + , c ) ;
in = ( c = = ' " ' ) ;
}
}
//--
StringSetLength ( str , k ) ;
return str ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-07-15 17:58:56 -05:00
int CJsonParser::CleanNode ( int i , const int end , uchar & out [ ] , int k , bool ajustar_arr ) const
2026-07-10 07:17:28 -05:00
{
//---
2026-07-15 16:03:07 -05:00
const int needed = ( end - i ) + 1 ;
const int rsize = ArraySize ( out ) ;
const int e = needed + k ;
if ( rsize < = e )
{
ArrayResize ( out , rsize + e ) ;
}
2026-07-10 07:17:28 -05:00
//---
bool in = false ;
for ( i ; i < = end ; i + + )
{
2026-07-19 07:41:52 -05:00
const uchar c = m_raw [ i ] ;
2026-07-10 07:17:28 -05:00
//---
if ( in )
{
out [ k + + ] = c ;
if ( c = = ' \\ ' )
{
2026-07-19 07:41:52 -05:00
out [ k + + ] = m_raw [ + + i ] ;
2026-07-10 07:17:28 -05:00
continue ;
}
in = ( c ! = ' " ' ) ;
}
else
{
if ( c < 33 )
continue ;
out [ k + + ] = c ;
in = ( c = = ' " ' ) ;
}
}
//--
2026-07-15 17:58:56 -05:00
if ( ajustar_arr ) // Ajustamos exacto
ArrayResize ( out , k ) ;
2026-07-17 15:07:22 -05:00
//--
2026-07-15 16:03:07 -05:00
return k - ( e - needed ) ;
2026-07-10 07:17:28 -05:00
}
2026-06-18 09:48:36 -05:00
2026-06-21 21:51:52 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CJsonParser::AutoParseByFileExt ( const int file_ext_type )
{
switch ( file_ext_type )
{
2026-07-19 07:41:52 -05:00
case TSN_SLF_RAW_FILE :
2026-06-21 21:51:52 -05:00
{
2026-07-19 07:41:52 -05:00
CorrectPadding ( ) ; // Auto
2026-06-21 21:51:52 -05:00
return Parse ( ) ;
}
2026-07-19 07:41:52 -05:00
case TSN_SLF_RAW_EMBEBED :
2026-06-21 21:51:52 -05:00
{
2026-07-19 07:41:52 -05:00
return m_cinta_pos > 0 & & m_len > 0 ;
2026-06-21 21:51:52 -05:00
}
default :
{
m_last_err = TSN_JSON_ERR_INVALID_EXT_FILE ;
m_pos = 0 ;
return false ;
}
}
}
2026-06-18 09:48:36 -05:00
2026-06-02 21:23:50 -05:00
//+------------------------------------------------------------------+
2026-08-02 16:49:10 -05:00
//| Macros de avanze |
2026-06-02 21:23:50 -05:00
//+------------------------------------------------------------------+
2026-09-18 14:11:09 -05:00
//---
# define TSN_JSON_AUMENT m_stak_num [ m_stak_curr ] + + ;
2026-08-03 09:31:58 -05:00
//--- Se usa solo al incio de un llave ini validos " y }
2026-09-30 07:39:54 -05:00
# define TSN_JSON_NEXT_LLAVE_INI \
while(true) \
{ \
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-10-02 22:01:54 -05:00
//--- Generico
// Luego de un valor siempre , o su fin
// 1 en la tabl to token es INVALID (dara error..de malformed..)
// Este se usa luego de un valor.. la idea es que luego de un valor "" numero t\f\n ] }
// tiene que haber o un }] o en todo caso , de continuacino solo eso...
# define TSN_JSON_NEXT_NO_NEXT_KEY \
uchar _c = m_raw[m_pos]; \
while(_c < 33) { _c = m_raw[++m_pos]; } \
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; \
return false; \
2026-10-03 11:47:17 -05:00
}
2026-10-02 22:01:54 -05:00
2026-06-09 14:15:41 -05:00
2026-06-20 13:57:50 -05:00
//--- Luego de una coma en array
// Luego de una , y KEY siempre siempre valor
2026-09-30 07:39:54 -05:00
# define TSN_JSON_NEXT_VALUE_COMM_KEY \
uchar _c; \
while((_c=m_raw[++m_pos])<33) {} \
m_next = g_table_json_tokens[_c]; \
if(((1 << m_next) & TSN_JSON_F_ALL_I_VAL) == 0) \
{ \
2026-09-18 14:11:09 -05:00
m_last_err= TSN_JSON_ERR_MALFORDMED_JSON_FIND_VAL; \
2026-09-30 07:39:54 -05:00
return false; \
}
2026-08-03 09:31:58 -05:00
2026-08-26 19:48:01 -05:00
//+------------------------------------------------------------------+
2026-09-30 07:39:54 -05:00
//| Parseo de numeros |
2026-08-26 19:48:01 -05:00
//+------------------------------------------------------------------+
2026-09-30 07:39:54 -05:00
//--- make string
# define JSONPARSERBYLEO_NUM_MAKE_STRING m_cinta [ m_cinta_pos + + ] = JSON_VTYPE_STRING \
| long(m_pos - start) << TSN_SBL_BIT_STR_LEN \
| long(start) << TSN_SBL_BIT_STR_START;
2026-08-02 12:33:47 -05:00
//+------------------------------------------------------------------+
2026-08-03 15:01:11 -05:00
//| Parse con simd |
2026-08-02 12:33:47 -05:00
//+------------------------------------------------------------------+
2026-08-03 09:31:58 -05:00
# ifdef JSONPARSERBYLEO_DLL
2026-09-18 14:11:09 -05:00
__forceinline bool CJsonParser::ParseSimd ( )
2026-06-02 21:23:50 -05:00
{
2026-08-03 15:01:11 -05:00
//--- Iniciales
2026-06-03 07:50:45 -05:00
m_last_err = TSN_JSON_NOT_ERR ;
2026-07-12 18:24:34 -05:00
m_tables_size = 0 ;
2026-09-18 14:11:09 -05:00
return JsonParserResolve ( m_raw ,
m_cinta ,
m_index ,
m_len ,
m_offset ,
( int & ) m_last_err ,
m_cinta_pos ,
m_pos
) ;
2026-08-02 16:49:10 -05:00
}
2026-08-03 09:31:58 -05:00
# endif // JSONPARSERBYLEO_DLL
2026-08-03 15:01:11 -05:00
2026-08-26 19:48:01 -05:00
2026-08-02 16:49:10 -05:00
//+------------------------------------------------------------------+
2026-08-03 15:01:11 -05:00
//| Parse normal |
2026-08-02 16:49:10 -05:00
//+------------------------------------------------------------------+
bool CJsonParser::Parse ( )
{
//---
m_stak_curr = -1 ;
m_last_err = TSN_JSON_NOT_ERR ;
m_pos = m_offset ;
m_cinta_pos = 0 ;
m_tables_size = 0 ;
//--- 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-02 16:49:10 -05:00
{
2026-09-30 07:39:54 -05:00
//--- solo 3 varaibles nada mas en general (garantizado)
long v = 0 ;
const int start = m_pos ;
uchar ch = m_raw [ + + m_pos ] ^ ' 0 ' ;
2026-08-02 16:49:10 -05:00
//---
2026-09-30 07:39:54 -05:00
switch ( 0 )
{
default : // scope con psoiblidad de break.
{
//--- primera iteracion sin cheking
2026-10-02 22:01:54 -05:00
DOMBASEUTIL_PARSE_NUM_U1 ( v )
2026-09-30 07:39:54 -05:00
//--- Interesante: sigue siendo cero pero me pide mas digitios ?¿
if ( ! v )
{
m_last_err = TSN_JSON_ERR_LEADING_ZEROS ;
m_next = TSN_JSON_TOK_INVALID ;
continue ;
}
//--- 19 iteraciones maximo
2026-10-02 22:01:54 -05:00
DOMBASEUTIL_PARSE_NUM_UNROLLED_17 ( v )
2026-10-01 13:36:22 -05:00
STRCONV_TOV_ALG ( v , ch )
2026-09-30 07:39:54 -05:00
if ( ( ch = m_raw [ + + m_pos ] ^ ' 0 ' ) > 9 )
{
if ( v > 0 )
break ;
}
else // aun es valido asi que seguimos saltando el numero completo (parte entera) (pero ya sabmeos que es invalido)
{
2026-10-02 22:01:54 -05:00
DOMBASEUTIL_NUM_SKIP_NUMBER
2026-09-30 07:39:54 -05:00
}
//--- revismoos si es dec, si lo es saltamos la parte dec
2026-10-02 22:01:54 -05:00
if ( STRCONV_DECX_CH_IS_DEC ( ch ) )
break ;
2026-09-30 07:39:54 -05:00
//--- pasamos a str y ya no caemos abajo de aqui:
JSONPARSERBYLEO_NUM_MAKE_STRING
TSN_JSON_AUMENT
TSN_JSON_NEXT_NO_NEXT_KEY
continue ; // esto aplica a nivel de while
}
}
//--- vemos si decimal
2026-10-02 22:01:54 -05:00
if ( STRCONV_DECX_CH_IS_DEC ( ch ) )
2026-09-30 07:39:54 -05:00
{
long exponente = 0 ; // exponente
int digitos = m_pos - start ; // digitos que se van acomulando (parte ent + dec)
2026-10-02 22:01:54 -05:00
if ( STRCONV_DECX_CH_IS_PDEC ( ch ) )
2026-09-30 07:39:54 -05:00
{
int ds = + + m_pos ; // inicio
if ( ( ch = m_raw [ m_pos ] ^ ' 0 ' ) > 9 )
{
m_last_err = TSN_JSON_ERR_EXPECTED_NUMBER_AFECTER_DECIMALP ;
return false ;
}
while ( true )
{
2026-10-02 22:01:54 -05:00
//DOMBASEUTIL_NUM_PROCCES_FIRST_DEC(v, ch, m_pos, ds, digitos)
DOMBASEUTIL_PARSE_NUM_UNROLLED_18 ( v )
DOMBASEUTIL_NUM_SKIP_NUMBER
2026-09-30 07:39:54 -05:00
break ;
}
//---
ds = ( m_pos - ds ) ; // numero de digitos de la parte decimal
digitos + = ds ;
exponente - = ds ;
}
2026-10-02 22:01:54 -05:00
if ( STRCONV_DECX_CH_IS_E ( ch ) ) //
2026-09-30 07:39:54 -05:00
{
bool exp_positivo = true ;
ch = m_raw [ + + m_pos ] ^ ' 0 ' ;
if ( ch > 9 )
{
2026-10-02 22:01:54 -05:00
if ( STRCONV_DECX_CH_IS_MINUS ( ch ) )
2026-09-30 07:39:54 -05:00
exp_positivo = false ;
if ( ( ch = m_raw [ + + m_pos ] ^ ' 0 ' ) > 9 )
{
m_last_err = TSN_JSON_ERR_EXPECTED_NUMBER_AFECTER_EXP ;
return false ; // sale
}
}
int expo = 0 ;
while ( true ) // siguimos acomulando en v
{
2026-10-02 22:01:54 -05:00
DOMBASEUTIL_PARSE_NUM_U1 ( expo )
2026-09-30 07:39:54 -05:00
if ( expo = = 0 ) // leading zeros.. ahora mismo aun hay digitos pero el primero es 0..
{
2026-10-02 22:01:54 -05:00
DOMBASEUTIL_PARSE_SKIP_LZ
2026-09-30 07:39:54 -05:00
} // pos apunta al curr no cero ch ya tiene su valor en caso sea 00000x (no numero) sale..
2026-10-02 22:01:54 -05:00
DOMBASEUTIL_PARSE_NUM_UNROLLED_8 ( expo )
STRCONV_TOV_ALG ( expo , ch )
2026-09-30 07:39:54 -05:00
if ( ( ch = m_raw [ + + m_pos ] ^ ' 0 ' ) > 9 ) // 10cimo digito
{
2026-10-02 22:01:54 -05:00
if ( expo > 0 ) // es valido
2026-09-30 07:39:54 -05:00
break ; // no ov
}
else // sigue saltamos todo lo que hya
{
2026-10-02 22:01:54 -05:00
DOMBASEUTIL_NUM_SKIP_NUMBER
2026-09-30 07:39:54 -05:00
}
expo = INT_MAX ;
2026-10-02 22:01:54 -05:00
break ;
2026-09-30 07:39:54 -05:00
}
exponente + = exp_positivo ? expo : - expo ;
}
2026-10-02 22:01:54 -05:00
//--- 1 dado que start incluye el -
if ( STRCONV_DOUBLE_SAFE_DBL_P ( digitos , exponente , 1 ) )
2026-09-30 07:39:54 -05:00
{
TsnBitInterprete bit ;
2026-10-02 22:01:54 -05:00
bit . double_value = - STRCONV_TO_DOUBLE_ALG ( exponente , v ) ;
2026-09-30 07:39:54 -05:00
m_cinta [ m_cinta_pos + + ] = JSON_VTYPE_REAL ;
m_cinta [ m_cinta_pos + + ] = bit . long_value ;
}
else // make_string: numero grande o que ya no se peude representar con precision (a string)
{
JSONPARSERBYLEO_NUM_MAKE_STRING
}
}
else
{
m_cinta [ m_cinta_pos + + ] = JSON_VTYPE_INTEGER ;
m_cinta [ m_cinta_pos + + ] = - v ;
}
2026-08-02 16:49:10 -05:00
//---
2026-09-18 14:11:09 -05:00
TSN_JSON_AUMENT
2026-08-26 19:48:01 -05:00
TSN_JSON_NEXT_NO_NEXT_KEY
break ;
}
2026-08-02 16:49:10 -05:00
2026-08-26 19:48:01 -05:00
//---
2026-09-30 07:39:54 -05:00
case TSN_JSON_TOK_NUMBER :
2026-08-26 19:48:01 -05:00
{
//---
2026-09-30 07:39:54 -05:00
ulong v = 0 ;
const int start = m_pos ;
uchar ch = m_raw [ start ] ^ ' 0 ' ;
const uchar fc = ch ;
2026-08-02 16:49:10 -05:00
2026-09-30 07:39:54 -05:00
//---
switch ( 0 )
{
default : // scope con psoiblidad de break.
{
//---
2026-10-02 22:01:54 -05:00
DOMBASEUTIL_PARSE_NUM_U1 ( v )
2026-09-30 07:39:54 -05:00
if ( ! v )
{
m_last_err = TSN_JSON_ERR_LEADING_ZEROS ;
m_next = TSN_JSON_TOK_INVALID ;
continue ;
}
//--- 19 iteraciones maximo
2026-10-02 22:01:54 -05:00
DOMBASEUTIL_PARSE_NUM_UNROLLED_18 ( v )
2026-10-01 13:36:22 -05:00
STRCONV_TOV_ALG ( v , ch )
2026-09-30 07:39:54 -05:00
if ( ( ch = m_raw [ + + m_pos ] ^ ' 0 ' ) > 9 )
{
if ( fc = = 1 & & v > LONG_MAX )
break ;
}
else // aun es valido asi que seguimos saltando el numero completo (parte entera) (pero ya sabmeos que es invalido)
{
2026-10-02 22:01:54 -05:00
DOMBASEUTIL_NUM_SKIP_NUMBER
2026-09-30 07:39:54 -05:00
}
2026-10-02 22:01:54 -05:00
//--- revismoos si es dec, si es asi lo mandamos para la funcion dec aqui solo big integer
if ( STRCONV_DECX_CH_IS_DEC ( ch ) )
break ;
2026-09-30 07:39:54 -05:00
//--- pasamos a str y ya no caemos abajo de aqui:
JSONPARSERBYLEO_NUM_MAKE_STRING
TSN_JSON_AUMENT
TSN_JSON_NEXT_NO_NEXT_KEY
continue ; // esto aplica a nivel de while
}
}
//--- vemos si decimal
2026-10-02 22:01:54 -05:00
if ( STRCONV_DECX_CH_IS_DEC ( ch ) ) // v por lo tanto llega bien aqui como entero unsigned valido
2026-09-30 07:39:54 -05:00
{
long exponente = 0 ; // exponente
int digitos = m_pos - start ; // digitos que se van acomulando (parte ent + dec)
2026-10-02 22:01:54 -05:00
if ( STRCONV_DECX_CH_IS_PDEC ( ch ) ) // punto decimal (tomar precuacion aqui si v puede dar overflow y voltear no hay chekeo)
2026-09-30 07:39:54 -05:00
{
2026-10-02 22:01:54 -05:00
int ds = + + m_pos ;
2026-09-30 07:39:54 -05:00
if ( ( ch = m_raw [ m_pos ] ^ ' 0 ' ) > 9 )
{
m_last_err = TSN_JSON_ERR_EXPECTED_NUMBER_AFECTER_DECIMALP ;
return false ;
}
while ( true )
{
2026-10-02 22:01:54 -05:00
//DOMBASEUTIL_NUM_PROCCES_FIRST_DEC(v, ch, m_pos, ds, digitos)
DOMBASEUTIL_PARSE_NUM_UNROLLED_18 ( v )
DOMBASEUTIL_NUM_SKIP_NUMBER
2026-09-30 07:39:54 -05:00
break ;
}
//---
ds = ( m_pos - ds ) ; // numero de digitos de la parte decimal
digitos + = ds ;
exponente - = ds ;
}
2026-10-02 22:01:54 -05:00
if ( STRCONV_DECX_CH_IS_E ( ch ) ) //
2026-09-30 07:39:54 -05:00
{
bool exp_positivo = true ;
ch = m_raw [ + + m_pos ] ^ ' 0 ' ;
if ( ch > 9 )
{
2026-10-02 22:01:54 -05:00
if ( STRCONV_DECX_CH_IS_MINUS ( ch ) )
2026-09-30 07:39:54 -05:00
exp_positivo = false ;
if ( ( ch = m_raw [ + + m_pos ] ^ ' 0 ' ) > 9 )
{
m_last_err = TSN_JSON_ERR_EXPECTED_NUMBER_AFECTER_EXP ;
return false ; // sale
}
}
int expo = 0 ;
2026-10-02 22:01:54 -05:00
while ( true )
2026-09-30 07:39:54 -05:00
{
2026-10-02 22:01:54 -05:00
DOMBASEUTIL_PARSE_NUM_U1 ( expo )
2026-09-30 07:39:54 -05:00
if ( expo = = 0 ) // leading zeros.. ahora mismo aun hay digitos pero el primero es 0..
{
2026-10-02 22:01:54 -05:00
DOMBASEUTIL_PARSE_SKIP_LZ
2026-09-30 07:39:54 -05:00
} // pos apunta al curr no cero ch ya tiene su valor en caso sea 00000x (no numero) sale..
2026-10-02 22:01:54 -05:00
DOMBASEUTIL_PARSE_NUM_UNROLLED_8 ( expo )
STRCONV_TOV_ALG ( expo , ch )
2026-09-30 07:39:54 -05:00
if ( ( ch = m_raw [ + + m_pos ] ^ ' 0 ' ) > 9 ) // 10cimo digito
{
2026-10-02 22:01:54 -05:00
if ( expo > 0 ) // es valido
2026-09-30 07:39:54 -05:00
break ; // no ov
}
else // sigue saltamos todo lo que hya
{
2026-10-02 22:01:54 -05:00
DOMBASEUTIL_NUM_SKIP_NUMBER
2026-09-30 07:39:54 -05:00
}
expo = INT_MAX ;
2026-10-02 22:01:54 -05:00
break ;
2026-09-30 07:39:54 -05:00
}
exponente + = exp_positivo ? expo : - expo ;
}
2026-10-02 22:01:54 -05:00
//---
if ( STRCONV_DOUBLE_SAFE_DBL ( digitos , exponente ) )
2026-09-30 07:39:54 -05:00
{
TsnBitInterprete bit ;
2026-10-02 22:01:54 -05:00
bit . double_value = STRCONV_TO_DOUBLE_ALG ( exponente , v ) ;
2026-09-30 07:39:54 -05:00
m_cinta [ m_cinta_pos + + ] = JSON_VTYPE_REAL ;
m_cinta [ m_cinta_pos + + ] = bit . long_value ;
}
2026-10-02 22:01:54 -05:00
else
2026-09-30 07:39:54 -05:00
{
JSONPARSERBYLEO_NUM_MAKE_STRING
}
}
else
{
m_cinta [ m_cinta_pos + + ] = JSON_VTYPE_UINTEGER ;
m_cinta [ m_cinta_pos + + ] = ( long ) v ;
}
//---
2026-09-18 14:11:09 -05:00
TSN_JSON_AUMENT
2026-08-02 16:49:10 -05:00
TSN_JSON_NEXT_NO_NEXT_KEY
break ;
}
//---
case TSN_JSON_TOK_STRING :
{
//---
const int start = + + m_pos ;
//---
# ifndef JSONPARSERBYLEO_DESACTIVE_SWAR
//--- Pase inicial 8 en 8
while ( true )
{
// PrintFormat("Analizando: '%s'", CharArrayToString(m_raw, m_pos, 8));
const ulong chunk = ( ulong ) m_raw [ m_pos ]
| ( ulong ) m_raw [ m_pos + 1 ] < < 8
| ( ulong ) m_raw [ m_pos + 2 ] < < 16
| ( ulong ) m_raw [ m_pos + 3 ] < < 24
| ( ulong ) m_raw [ m_pos + 4 ] < < 32
| ( ulong ) m_raw [ m_pos + 5 ] < < 40
| ( ulong ) m_raw [ m_pos + 6 ] < < 48
| ( ulong ) m_raw [ m_pos + 7 ] < < 56 ;
//---
const ulong x_bs = chunk ^ TSNTABLES_SWAR_MASK_BACK_SLASH ;
ulong has_bs = TSNTABLES_SWAR_HAS ( x_bs ) ;
const ulong x_qt = chunk ^ TSNTABLES_SWAR_MASK_COMILLA ;
const ulong has_qt = TSNTABLES_SWAR_HAS ( x_qt ) ;
//---
if ( ( has_bs | has_qt ) = = 0 ) // Caso comun. .. ninguno de los dos.. continuamos..
{
m_pos + = 8 ;
continue ;
}
//---
if ( has_bs = = 0 ) // Si not iene bs (pero confirmamos que no es 0)
// Entonces no tirne bs pero si qt salimos de una..
{
2026-08-27 13:40:38 -05:00
const ulong flag_real = TSNTABLES_BIT_DEJAR_SOLO_MINUS_SIG_BYTE ( has_qt ) ;
2026-08-02 16:49:10 -05:00
//---
2026-08-27 13:40:38 -05:00
m_pos + = TSNTABLES_CTZ_64_GET_BYTE ( flag_real ) ;
2026-08-02 16:49:10 -05:00
m_cinta [ m_cinta_pos + + ] = JSON_VTYPE_STRING
| long ( m_pos - start ) < < TSN_SBL_BIT_STR_LEN
| long ( start ) < < TSN_SBL_BIT_STR_START ;
m_pos + + ; // Luego del "
break ;
}
//--- Hay bs si o si pero tambien puede haber "
const uchar compacted_bs = TSNTABLES_COMPACT_UL ( has_bs ) ;
const uchar prev = ( ( ( compacted_bs < < 1 ) | TSNTABLES_MASK_IMPARES ) - compacted_bs ) ^ TSNTABLES_MASK_IMPARES ;
const uchar escaped = prev ^ compacted_bs ;
//---
const uchar compacted_qt = TSNTABLES_COMPACT_UL ( has_qt ) ;
const uchar qt_final = compacted_qt & ~ escaped ;
//Print("nada");
//---
2026-09-18 14:11:09 -05:00
if ( qt_final ) // Hay un qt real de cierre
2026-08-02 16:49:10 -05:00
{
2026-09-18 14:11:09 -05:00
//---
2026-08-02 16:49:10 -05:00
// Avanzamos y cerramos..
2026-08-27 13:40:38 -05:00
m_pos + = g_tsntables_table_ctz_i8 [ qt_final ] ;
2026-08-02 16:49:10 -05:00
m_cinta [ m_cinta_pos + + ] = JSON_VTYPE_STRING
| long ( m_pos - start ) < < TSN_SBL_BIT_STR_LEN
| long ( start ) < < TSN_SBL_BIT_STR_START ;
2026-09-18 14:11:09 -05:00
//---
m_pos + + ;
2026-08-02 16:49:10 -05:00
break ;
}
else
{
m_pos + = 8 ;
// Print(CharToString(m_raw[m_pos]));
// escape
if ( ( ( prev & compacted_bs ) > > 7U ) ! = 0 ) // Overflow el ultimo char es \ y el siguiente escapa
{
//Print("siuu");
m_pos + + ; // Uno mas.. luego del currend
}
}
}
# else // JSONPARSERBYLEO_DESACTIVE_SWAR
//--- Char por char
2026-09-30 07:39:54 -05:00
while ( true )
2026-08-02 16:49:10 -05:00
{
const uchar c = m_raw [ m_pos ] ;
if ( c = = ' \\ ' )
{
m_pos + = 2 ;
continue ;
}
if ( c = = ' " ' )
{
// STRING 1 slot: [tipo(4)|len(28low)|start(32high)]
m_cinta [ m_cinta_pos + + ] = JSON_VTYPE_STRING | long ( m_pos - start ) < < TSN_SBL_BIT_STR_LEN |
long ( start ) < < TSN_SBL_BIT_STR_START ;
m_pos + + ;
break ;
}
m_pos + + ;
}
# endif // JSONPARSERBYLEO_DESACTIVE_SWAR
//---
2026-09-18 14:11:09 -05:00
TSN_JSON_AUMENT
2026-08-02 16:49:10 -05:00
TSN_JSON_NEXT_NO_NEXT_KEY
//---
break ;
}
2026-09-30 07:39:54 -05:00
case TSN_JSON_TOK_BOOL_TRUE :
2026-08-02 16:49:10 -05:00
{
2026-10-03 11:47:17 -05:00
const uint k = ( uint ) m_raw [ + + m_pos ] | ( uint ) m_raw [ + + m_pos ] < < 8 | ( uint ) m_raw [ + + m_pos ] < < 16 ;
if ( k ! = TSNJSON_VAL_TRUE )
2026-09-30 07:39:54 -05:00
return false ;
2026-08-02 16:49:10 -05:00
2026-09-30 07:39:54 -05:00
//---
m_pos + + ;
m_cinta [ m_cinta_pos + + ] = ( JSON_VTYPE_BOOLEAN | 1L L < < 4 ) ;
2026-08-02 16:49:10 -05:00
//---
2026-09-18 14:11:09 -05:00
TSN_JSON_AUMENT
2026-08-02 16:49:10 -05:00
TSN_JSON_NEXT_NO_NEXT_KEY
break ;
}
2026-09-30 07:39:54 -05:00
case TSN_JSON_TOK_BOOL_FALSE :
2026-08-02 16:49:10 -05:00
{
2026-10-03 11:47:17 -05:00
//const uint k = (uint)m_raw[++m_pos] | (uint)m_raw[++m_pos] << 8 | (uint)m_raw[++m_pos] << 16 | (uint)m_raw[++m_pos] << 24;
2026-09-30 07:39:54 -05:00
if ( m_raw [ + + m_pos ] ! = ' a ' | | m_raw [ + + m_pos ] ! = ' l ' | | m_raw [ + + m_pos ] ! = ' s ' | | m_raw [ + + m_pos ] ! = ' e ' )
return false ;
//---
m_pos + + ;
2026-08-02 16:49:10 -05:00
m_cinta [ m_cinta_pos + + ] = JSON_VTYPE_BOOLEAN ;
//---
2026-09-18 14:11:09 -05:00
TSN_JSON_AUMENT
2026-08-02 16:49:10 -05:00
TSN_JSON_NEXT_NO_NEXT_KEY
break ;
}
case TSN_JSON_TOK_NULL :
{
2026-10-03 11:47:17 -05:00
const uint k = ( uint ) m_raw [ + + m_pos ] | ( uint ) m_raw [ + + m_pos ] < < 8 | ( uint ) m_raw [ + + m_pos ] < < 16 ;
if ( k ! = TSNJSON_VAL_NULL )
2026-09-30 07:39:54 -05:00
return false ;
2026-08-02 16:49:10 -05:00
//---
2026-09-30 07:39:54 -05:00
m_pos + + ;
2026-08-02 16:49:10 -05:00
m_cinta [ m_cinta_pos + + ] = JSON_VTYPE_NULL ;
//---
2026-09-18 14:11:09 -05:00
TSN_JSON_AUMENT
2026-08-02 16:49:10 -05:00
TSN_JSON_NEXT_NO_NEXT_KEY
break ;
}
2026-09-30 07:39:54 -05:00
case TSN_JSON_TOK_COMMA :
2026-08-02 16:49:10 -05:00
{
//---
if ( m_stak_curr_state = = TSN_JSON_CTX_IN_OBJ )
{
2026-09-30 07:39:54 -05:00
while ( m_raw [ + + m_pos ] ! = ' " ' ) { }
m_next = TSN_JSON_TOK_KEY ;
2026-08-02 16:49:10 -05:00
}
else
{
TSN_JSON_NEXT_VALUE_COMM_KEY
}
break ;
}
case TSN_JSON_TOK_LLAVE_INI :
{
//TSN_JSON_RESERVAR(1)
m_cinta [ m_cinta_pos ] = JSON_VTYPE_OBJ ;
//---
m_stak_curr + + ;
m_stak_curr_state = TSN_JSON_CTX_IN_OBJ ;
m_stak_state [ m_stak_curr ] = TSN_JSON_CTX_IN_OBJ ;
m_stak_num [ m_stak_curr ] = 0 ;
m_stak_pos [ m_stak_curr ] = m_cinta_pos + + ;
//---
m_cinta [ m_cinta_pos + + ] = m_pos + + ;
//---
TSN_JSON_NEXT_LLAVE_INI
//---
break ;
}
case TSN_JSON_TOK_COR_INI :
{
m_cinta [ m_cinta_pos ] = JSON_VTYPE_ARR ;
//---
m_stak_curr + + ;
m_stak_curr_state = TSN_JSON_CTX_IN_ARR ;
m_stak_state [ m_stak_curr ] = TSN_JSON_CTX_IN_ARR ;
m_stak_num [ m_stak_curr ] = 0 ;
m_stak_pos [ m_stak_curr ] = m_cinta_pos + + ;
//---
m_cinta [ m_cinta_pos + + ] = m_pos + + ;
//---
2026-10-02 22:01:54 -05:00
uchar _c = m_raw [ m_pos ] ;
while ( _c < 33 )
_c = m_raw [ + + m_pos ] ;
2026-08-02 16:49:10 -05:00
2026-10-02 22:01:54 -05:00
//---
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 ;
return false ;
}
2026-10-03 11:47:17 -05:00
2026-08-02 16:49:10 -05:00
//---
break ;
}
case TSN_JSON_TOK_LLAVE_END :
case TSN_JSON_TOK_COR_END :
{
//---
const int lp = m_stak_pos [ m_stak_curr ] ;
m_cinta [ lp ] | = long ( m_stak_num [ m_stak_curr ] ) < < TSN_SBL_BIT_START_NUM_EL | long ( m_cinta_pos - lp ) < < TSN_SBL_BIT_START_NUM_C ;
m_cinta [ lp + 1 ] | = long ( m_pos ) < < TSN_JSON_BIT_END_T ;
//---
if ( - - m_stak_curr < 0 )
return true ;
//---
m_stak_curr_state = m_stak_state [ m_stak_curr ] ;
//---
m_pos + + ;
//---
2026-09-18 14:11:09 -05:00
TSN_JSON_AUMENT
2026-08-02 16:49:10 -05:00
TSN_JSON_NEXT_NO_NEXT_KEY
//---
break ;
}
case TSN_JSON_TOK_KEY :
{
const int start = + + m_pos ;
//---
2026-10-03 11:47:17 -05:00
# ifdef JSONPARSERBYLEO_ACTIVE_SWAR_KEYS
2026-08-02 16:49:10 -05:00
//--- Pase inicial 8 en 8
while ( true )
{
// "asdasdasd".........."
// PrintFormat("Analizando: '%s'", CharArrayToString(m_raw, m_pos, 8));
const ulong chunk = ( ulong ) m_raw [ m_pos ]
| ( ulong ) m_raw [ m_pos + 1 ] < < 8
| ( ulong ) m_raw [ m_pos + 2 ] < < 16
| ( ulong ) m_raw [ m_pos + 3 ] < < 24
| ( ulong ) m_raw [ m_pos + 4 ] < < 32
| ( ulong ) m_raw [ m_pos + 5 ] < < 40
| ( ulong ) m_raw [ m_pos + 6 ] < < 48
| ( ulong ) m_raw [ m_pos + 7 ] < < 56 ;
//---
# ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS
const ulong x_bs = chunk ^ TSNTABLES_SWAR_MASK_BACK_SLASH ;
ulong has_bs = TSNTABLES_SWAR_HAS ( x_bs ) ;
# endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS
const ulong x_qt = chunk ^ TSNTABLES_SWAR_MASK_COMILLA ;
const ulong has_qt = TSNTABLES_SWAR_HAS ( x_qt ) ;
//---
# ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS
if ( ( has_bs | has_qt ) = = 0 ) // Caso comun. .. ninguno de los dos.. continuamos..
{
m_pos + = 8 ;
continue ;
}
# else // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS
if ( has_qt = = 0 ) // Caso comun. .. ninguno de los dos.. continuamos..
{
m_pos + = 8 ;
continue ;
}
2026-09-18 14:11:09 -05:00
# endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS
2026-08-02 16:49:10 -05:00
//---
# ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS
if ( has_bs = = 0 ) // Si not iene bs (pero confirmamos que no es 0)
// Entonces no tirne bs pero si qt salimos de una..
{
# endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS
2026-08-27 13:40:38 -05:00
const ulong flag_real = TSNTABLES_BIT_DEJAR_SOLO_MINUS_SIG_BYTE ( has_qt ) ;
2026-08-02 16:49:10 -05:00
//---
2026-08-27 13:40:38 -05:00
m_pos + = TSNTABLES_CTZ_64_GET_BYTE ( flag_real ) ;
2026-08-02 16:49:10 -05:00
m_cinta [ m_cinta_pos + + ] = JSON_VTYPE_KEY
| long ( m_pos - start ) < < TSN_SBL_BIT_STR_LEN
| long ( start ) < < TSN_SBL_BIT_STR_START ;
m_pos + + ; // Luego del "
break ;
# ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS
}
//---
const uchar compacted_bs = TSNTABLES_COMPACT_UL ( has_bs ) ;
const uchar prev = ( ( ( compacted_bs < < 1 ) | TSNTABLES_MASK_IMPARES ) - compacted_bs ) ^ TSNTABLES_MASK_IMPARES ;
const uchar escaped = prev ^ compacted_bs ;
//---
const uchar compacted_qt = TSNTABLES_COMPACT_UL ( has_qt ) ;
const uchar qt_final = compacted_qt & ~ escaped ;
2026-06-20 13:57:50 -05:00
//---
2026-09-18 14:11:09 -05:00
if ( qt_final ) // Hay un qt real de cierre
2026-06-20 13:57:50 -05:00
{
2026-09-18 14:11:09 -05:00
//---
2026-07-12 18:46:58 -05:00
// Avanzamos y cerramos..
2026-08-27 13:40:38 -05:00
m_pos + = g_tsntables_table_ctz_i8 [ qt_final ] ;
2026-07-12 18:46:58 -05:00
m_cinta [ m_cinta_pos + + ] = JSON_VTYPE_STRING
2026-07-19 07:41:52 -05:00
| long ( m_pos - start ) < < TSN_SBL_BIT_STR_LEN
| long ( start ) < < TSN_SBL_BIT_STR_START ;
2026-06-20 13:57:50 -05:00
m_pos + + ; // Luego del "
2026-07-12 18:46:58 -05:00
break ;
2026-06-20 13:57:50 -05:00
}
2026-07-12 18:46:58 -05:00
else
{
m_pos + = 8 ;
2026-07-19 07:41:52 -05:00
// Print(CharToString(m_raw[m_pos]));
2026-08-02 16:49:10 -05:00
if ( ( ( prev & compacted_bs ) > > 7U ) ! = 0 ) // Overflow el ultimo char es \ y el siguiente escapa
2026-07-12 18:46:58 -05:00
{
//Print("siuu");
m_pos + + ; // Uno mas.. luego del currend
}
}
2026-06-27 07:49:32 -05:00
# endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS
2026-06-20 13:57:50 -05:00
}
2026-07-12 18:24:34 -05:00
# else // JSONPARSERBYLEO_ACTIVE_SWAR_KEYS
2026-06-20 13:57:50 -05:00
//--- Char por char
2026-10-03 11:47:17 -05:00
# ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS
2026-06-20 13:57:50 -05:00
while ( true )
{
2026-07-19 07:41:52 -05:00
const uchar c = m_raw [ m_pos ] ;
2026-06-20 13:57:50 -05:00
if ( c = = ' \\ ' )
{
m_pos + = 2 ;
continue ;
}
if ( c = = ' " ' )
{
2026-09-18 14:11:09 -05:00
//---
2026-06-20 14:18:38 -05:00
m_cinta [ m_cinta_pos + + ] = JSON_VTYPE_KEY
2026-07-19 07:41:52 -05:00
| long ( m_pos - start ) < < TSN_SBL_BIT_STR_LEN
| long ( start ) < < TSN_SBL_BIT_STR_START ;
2026-06-20 13:57:50 -05:00
m_pos + + ;
break ;
}
2026-10-03 11:47:17 -05:00
m_pos + + ;
2026-06-04 17:26:20 -05:00
}
2026-10-03 11:47:17 -05:00
# else // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS*/
//---
while ( m_raw [ m_pos ] ! = ' " ' )
m_pos + + ;
2026-10-03 17:00:34 -05:00
2026-10-03 11:47:17 -05:00
//---
m_cinta [ m_cinta_pos + + ] = JSON_VTYPE_KEY
| long ( m_pos - start ) < < TSN_SBL_BIT_STR_LEN
| long ( start ) < < TSN_SBL_BIT_STR_START ;
m_pos + + ;
# endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS
2026-07-12 18:24:34 -05:00
# endif // JSONPARSERBYLEO_ACTIVE_SWAR_KEYS
2026-06-04 17:26:20 -05:00
2026-06-20 13:57:50 -05:00
//--- Find :
2026-06-14 15:51:39 -05:00
while ( true )
2026-06-04 17:26:20 -05:00
{
2026-06-14 15:51:39 -05:00
//---
2026-07-19 07:41:52 -05:00
if ( m_raw [ m_pos ] = = ' : ' )
2026-06-14 15:51:39 -05:00
break ;
2026-06-04 17:26:20 -05:00
2026-06-14 15:51:39 -05:00
//---
2026-06-20 13:57:50 -05:00
m_pos + + ;
2026-06-14 15:51:39 -05:00
if ( m_pos > = m_len )
{
m_last_err = TSN_JSON_ERR_MALFODERD_KEY_EXPECTED_DOS_PUNTOS ;
return false ;
}
2026-06-04 17:26:20 -05:00
}
//--- Buscamos valor
2026-06-20 13:57:50 -05:00
TSN_JSON_NEXT_VALUE_COMM_KEY
2026-06-02 21:23:50 -05:00
//---
break ;
}
default :
return false ;
}
}
}
2026-06-20 13:57:50 -05:00
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-09-30 07:39:54 -05:00
switch ( int ( m_cinta [ idx ] & TSN_SBL_BIT_MASK_TYPE ) )
2026-06-02 22:52:39 -05:00
{
2026-07-19 07:41:52 -05:00
case JSON_VTYPE_KEY :
return 1 ;
case JSON_VTYPE_OBJ :
case JSON_VTYPE_ARR :
2026-09-30 07:39:54 -05:00
case JSON_VTYPE_UINTEGER :
2026-06-02 22:52:39 -05:00
case JSON_VTYPE_INTEGER :
case JSON_VTYPE_REAL :
return 2 ;
2026-06-03 07:50:45 -05:00
case JSON_VTYPE_BOOLEAN :
2026-06-02 22:52:39 -05:00
case JSON_VTYPE_STRING :
2026-06-03 07:50:45 -05:00
case JSON_VTYPE_NULL :
return 1 ;
2026-09-23 15:25:08 -05:00
default :
return 1 ;
2026-06-03 07:50:45 -05:00
}
}
//+------------------------------------------------------------------+
//| GetStep: posiciones que ocupa el nodo idx en la cinta |
//+------------------------------------------------------------------+
__forceinline int CJsonParser::GetStep ( const int idx )
const
{
2026-08-28 11:16:09 -05:00
switch ( int ( m_cinta [ idx ] & TSN_SBL_BIT_MASK_TYPE ) )
2026-06-03 07:50:45 -05:00
{
2026-07-19 07:41:52 -05:00
case JSON_VTYPE_KEY :
return 1 ;
case JSON_VTYPE_OBJ :
case JSON_VTYPE_ARR :
return int ( m_cinta [ idx ] > > TSN_SBL_BIT_START_NUM_C ) ;
2026-09-30 07:39:54 -05:00
case JSON_VTYPE_UINTEGER :
2026-06-03 07:50:45 -05:00
case JSON_VTYPE_INTEGER :
case JSON_VTYPE_REAL :
return 2 ;
2026-06-02 22:52:39 -05:00
case JSON_VTYPE_BOOLEAN :
2026-06-03 07:50:45 -05:00
case JSON_VTYPE_STRING :
2026-06-02 22:52:39 -05:00
case JSON_VTYPE_NULL :
return 1 ;
2026-09-23 15:25:08 -05:00
default :
return 1 ;
2026-06-02 22:52:39 -05:00
}
}
2026-06-03 07:50:45 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CJsonNode CJsonParser::GetRoot ( )
{
if ( m_cinta_pos = = 0 )
2026-07-26 16:46:05 -05:00
return CJsonNode : : EMPTY_NODE ;
2026-06-03 07:50:45 -05:00
return CJsonNode ( & this , 0 , GetStep ( 0 ) ) ;
}
//+------------------------------------------------------------------+
//| |
2026-07-19 13:56:15 -05:00
//+------------------------------------------------------------------+
2026-10-01 08:25:33 -05:00
bool CJsonParser::SerializeToDom ( CDomNodeBase * root , CDomNodeManager * manager , int cur , const int end )
2026-07-19 13:56:15 -05:00
{
//--- Temp
2026-10-01 08:25:33 -05:00
m_last_err = TSN_JSON_NOT_ERR ;
2026-07-19 13:56:15 -05:00
CDomNodeBase * prev_value ; // valolr qeu devuelve key
2026-08-27 13:56:43 -05:00
CDomNodeBase * current_container [ JSONPARSERBYLEO_MAX_STACK ] ; // contenedor
int current_ends [ JSONPARSERBYLEO_MAX_STACK ] ;
2026-07-19 13:56:15 -05:00
int sp = 0 ;
//--- Inicial
const int c = int ( ( m_cinta [ cur ] > > TSN_SBL_BIT_START_NUM_EL ) & TSN_SBL_BIT_MASK_NUM_EL ) ;
if ( ( m_cinta [ cur ] & TSN_SBL_BIT_MASK_TYPE ) = = JSON_VTYPE_OBJ )
root . NewObj ( c ) ;
else
root . NewArr ( c ) ;
2026-07-19 15:11:32 -05:00
2026-07-19 13:56:15 -05:00
//---
current_container [ 0 ] = root ;
current_ends [ sp ] = end ;
//---
cur + = 2 ;
//--- It
while ( true )
{
//--- Check
2026-07-21 10:38:19 -05:00
while ( cur > = current_ends [ sp ] )
2026-07-19 13:56:15 -05:00
{
sp - - ; // Nivel menos
2026-07-19 15:11:32 -05:00
//Print("sp luego: ", sp);
if ( sp < 0 )
2026-10-01 08:25:33 -05:00
return true ;
2026-07-19 13:56:15 -05:00
}
//---
const ENUM_JSON_VTYPE tipo = ENUM_JSON_VTYPE ( m_cinta [ cur ] & TSN_SBL_BIT_MASK_TYPE ) ;
2026-07-19 15:11:32 -05:00
//Print(EnumToString(tipo), " | ", cur, " | " , sp);
2026-07-19 13:56:15 -05:00
//---
switch ( tipo )
{
case JSON_VTYPE_KEY :
{
const int s = int ( m_cinta [ cur ] > > TSN_SBL_BIT_STR_START ) ;
const int slen = int ( ( m_cinta [ cur ] > > TSN_SBL_BIT_STR_LEN ) & TSN_SBL_BIT_STR_MASK_LEN ) ;
2026-07-23 16:13:49 -05:00
# ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS
2026-07-19 13:56:15 -05:00
const string str = Unescape ( s , s + slen - 1 ) ;
2026-07-23 16:13:49 -05:00
# else
const string str = CharArrayToString ( m_raw , s , slen ) ;
# endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS
2026-07-21 10:38:19 -05:00
prev_value = current_container [ sp ] [ str ] ;
2026-07-19 13:56:15 -05:00
break ;
}
case JSON_VTYPE_OBJ :
{
2026-07-21 10:38:19 -05:00
const int count = ( int ( ( m_cinta [ cur ] > > TSN_SBL_BIT_START_NUM_EL ) & TSN_SBL_BIT_MASK_NUM_EL ) ) < < 1 ;
2026-07-19 13:56:15 -05:00
if ( current_container [ sp ] . m_type = = JSON_VTYPE_ARR ) // [{}]
{
const int lock = sp + + ;
2026-07-19 15:11:32 -05:00
current_container [ sp ] = new CDomNodeBase ( manager ) ;
2026-07-19 13:56:15 -05:00
current_container [ sp ] . NewObj ( count ) ;
current_container [ lock ] . AddItem ( current_container [ sp ] ) ;
}
else // {key:{}}
{
sp + + ;
prev_value . NewObj ( count ) ;
current_container [ sp ] = prev_value ;
}
current_ends [ sp ] = cur + int ( m_cinta [ cur ] > > TSN_SBL_BIT_START_NUM_C ) ;
break ;
}
case JSON_VTYPE_ARR :
{
const int count = int ( ( m_cinta [ cur ] > > TSN_SBL_BIT_START_NUM_EL ) & TSN_SBL_BIT_MASK_NUM_EL ) ;
if ( current_container [ sp ] . m_type = = JSON_VTYPE_ARR )
{
const int lock = sp + + ;
2026-07-19 15:11:32 -05:00
current_container [ sp ] = new CDomNodeBase ( manager ) ;
2026-07-19 13:56:15 -05:00
current_container [ sp ] . NewArr ( count ) ;
current_container [ lock ] . AddItem ( current_container [ sp ] ) ;
}
else // {key:[]}
{
sp + + ;
prev_value . NewArr ( count ) ;
current_container [ sp ] = prev_value ;
}
current_ends [ sp ] = cur + int ( m_cinta [ cur ] > > TSN_SBL_BIT_START_NUM_C ) ;
break ;
}
2026-09-30 07:39:54 -05:00
case JSON_VTYPE_UINTEGER :
{
if ( current_container [ sp ] . m_type = = JSON_VTYPE_ARR )
current_container [ sp ] . AddItem ( new CDomNodeBase ( manager , ulong ( m_cinta [ cur + 1 ] ) ) ) ;
else
prev_value = ( ulong ) m_cinta [ cur + 1 ] ;
break ;
}
2026-07-19 13:56:15 -05:00
case JSON_VTYPE_INTEGER :
{
if ( current_container [ sp ] . m_type = = JSON_VTYPE_ARR )
2026-07-24 08:54:26 -05:00
current_container [ sp ] . AddItem ( new CDomNodeBase ( manager , m_cinta [ cur + 1 ] ) ) ;
2026-07-19 13:56:15 -05:00
else
prev_value = m_cinta [ cur + 1 ] ;
break ;
}
case JSON_VTYPE_REAL :
{
2026-08-28 08:28:32 -05:00
TsnBitInterprete un ;
2026-07-19 13:56:15 -05:00
un . long_value = m_cinta [ cur + 1 ] ;
//---
if ( current_container [ sp ] . m_type = = JSON_VTYPE_ARR )
2026-07-24 08:54:26 -05:00
current_container [ sp ] . AddItem ( new CDomNodeBase ( manager , un . double_value ) ) ;
2026-07-19 13:56:15 -05:00
else
prev_value = un . double_value ;
break ;
}
case JSON_VTYPE_BOOLEAN :
{
const bool v = ( ( m_cinta [ cur ] > > TSN_SBL_BIT_START_ENDTYPE ) & 1 ) ! = 0 ;
//---
if ( current_container [ sp ] . m_type = = JSON_VTYPE_ARR )
2026-07-24 08:54:26 -05:00
current_container [ sp ] . AddItem ( new CDomNodeBase ( manager , v ) ) ;
2026-07-19 13:56:15 -05:00
else
prev_value = v ;
break ;
}
case JSON_VTYPE_STRING :
{
const int s = int ( m_cinta [ cur ] > > TSN_SBL_BIT_STR_START ) ;
const int slen = int ( ( m_cinta [ cur ] > > TSN_SBL_BIT_STR_LEN ) & TSN_SBL_BIT_STR_MASK_LEN ) ;
//---
if ( current_container [ sp ] . m_type = = JSON_VTYPE_ARR )
2026-10-01 08:25:33 -05:00
{
CDomNodeBase * ptr = new CDomNodeBase ( TSN_SBL_BASE_TYPE_STR , manager ) ;
current_container [ sp ] . AddItem ( ptr ) ; // lo agregamos
const int idx = ptr . m_v . ix ;
if ( ! MakeString ( m_raw , s , slen , manager . m_string_stack [ idx ] ) )
{
m_last_err = TSN_JSON_ERR_IN_MATERIALIZE_STRING_PARSE_ERR ;
return false ;
}
}
2026-07-19 13:56:15 -05:00
else
2026-10-01 08:25:33 -05:00
{
prev_value . Type ( TSN_SBL_BASE_TYPE_STR ) ; // lo hacemos string
const int idx = prev_value . m_v . ix ;
if ( ! MakeString ( m_raw , s , slen , manager . m_string_stack [ idx ] ) )
{
m_last_err = TSN_JSON_ERR_IN_MATERIALIZE_STRING_PARSE_ERR ;
return false ;
}
}
2026-07-19 13:56:15 -05:00
break ;
}
case JSON_VTYPE_NULL :
{
//---
if ( current_container [ sp ] . m_type = = JSON_VTYPE_ARR )
2026-07-19 15:11:32 -05:00
current_container [ sp ] . AddItem ( new CDomNodeBase ( manager ) ) ;
2026-07-19 13:56:15 -05:00
else
prev_value . m_type = JSON_VTYPE_NULL ;
break ;
}
default :
break ;
}
//---
cur + = GetStepPure ( cur ) ;
}
2026-10-01 08:25:33 -05:00
//---
return false ;
2026-07-19 13:56:15 -05:00
}
//+------------------------------------------------------------------+
//| |
2026-06-03 07:50:45 -05:00
//+------------------------------------------------------------------+
2026-06-18 08:36:18 -05:00
void CJsonParser::PrintCintaTypes ( const int start , const int num ) const
2026-06-03 07:50:45 -05:00
{
2026-06-18 08:36:18 -05:00
//---
int p = fmax ( start , 0 ) ;
const int end = ( num = = WHOLE_ARRAY | | ( p + num ) > m_cinta_pos ) ? m_cinta_pos : ( p + num ) ;
2026-10-01 08:25:33 -05:00
//---
string str ;
string text ;
StringReserve ( text , 256 ) ; // algo razonable.
2026-06-18 08:36:18 -05:00
//---
while ( p < end )
2026-06-03 07:50:45 -05:00
{
2026-07-19 07:41:52 -05:00
const ENUM_JSON_VTYPE tipo = ENUM_JSON_VTYPE ( m_cinta [ p ] & TSN_SBL_BIT_MASK_TYPE ) ;
2026-10-01 08:25:33 -05:00
text = " [ " + ( string ) p + " ] " + EnumToString ( tipo ) + " | " ;
2026-06-03 15:48:09 -05:00
//---
switch ( tipo )
{
2026-07-19 07:41:52 -05:00
case JSON_VTYPE_KEY :
{
const int s = int ( m_cinta [ p ] > > TSN_SBL_BIT_STR_START ) ;
const int slen = int ( ( m_cinta [ p ] > > TSN_SBL_BIT_STR_LEN ) & TSN_SBL_BIT_STR_MASK_LEN ) ;
2026-07-23 16:13:49 -05:00
//---
2026-10-01 08:25:33 -05:00
if ( MakeString ( m_raw , s , slen , str ) )
text + = " start= " + ( string ) s + " len= " + ( string ) slen + " val= \" " + str + " \" " ;
else
text + = " start= " + ( string ) s + " len= " + ( string ) slen + " val=Invalid " ;
2026-07-19 07:41:52 -05:00
break ;
}
case JSON_VTYPE_OBJ :
case JSON_VTYPE_ARR :
{
const int count = int ( ( m_cinta [ p ] > > TSN_SBL_BIT_START_NUM_EL ) & TSN_SBL_BIT_MASK_NUM_EL ) ;
const int num_c = int ( m_cinta [ p ] > > TSN_SBL_BIT_START_NUM_C ) ;
2026-09-30 07:39:54 -05:00
const int raw_s = int ( m_cinta [ p + 1 ] & TSN_JSON_BIT_RAW_MASK_S ) ;
2026-07-19 07:41:52 -05:00
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 ;
}
2026-09-30 07:39:54 -05:00
case JSON_VTYPE_UINTEGER :
{
text + = " val= " + CValueToBuffer : : ULLToStr ( ulong ( m_cinta [ p + 1 ] ) ) ;
break ;
}
2026-06-03 15:48:09 -05:00
case JSON_VTYPE_INTEGER :
2026-07-19 07:41:52 -05:00
{
2026-06-03 15:48:09 -05:00
text + = " val= " + ( string ) m_cinta [ p + 1 ] ;
break ;
2026-07-19 07:41:52 -05:00
}
2026-06-03 15:48:09 -05:00
case JSON_VTYPE_REAL :
2026-06-04 17:26:20 -05:00
{
2026-08-28 08:28:32 -05:00
TsnBitInterprete un ;
2026-06-04 17:26:20 -05:00
un . long_value = m_cinta [ p + 1 ] ;
text + = " val= " + ( string ) un . double_value ;
break ;
}
2026-06-03 15:48:09 -05:00
case JSON_VTYPE_BOOLEAN :
2026-07-19 07:41:52 -05:00
text + = " val= " + ( string ) ( bool ) ( ( m_cinta [ p ] > > TSN_SBL_BIT_START_ENDTYPE ) & 1 ) ;
2026-06-03 15:48:09 -05:00
break ;
case JSON_VTYPE_STRING :
2026-06-04 17:26:20 -05:00
{
2026-07-19 07:41:52 -05:00
const int s = int ( m_cinta [ p ] > > TSN_SBL_BIT_STR_START ) ;
const int slen = int ( ( m_cinta [ p ] > > TSN_SBL_BIT_STR_LEN ) & TSN_SBL_BIT_STR_MASK_LEN ) ;
2026-10-01 08:25:33 -05:00
//---
if ( MakeString ( m_raw , s , slen , str ) )
text + = " start= " + ( string ) s + " len= " + ( string ) slen + " val= \" " + str + " \" " ;
else
text + = " start= " + ( string ) s + " len= " + ( string ) slen + " val=Invalid " ;
2026-06-04 17:26:20 -05:00
break ;
}
2026-06-03 15:48:09 -05:00
case JSON_VTYPE_NULL :
text + = " null " ;
break ;
2026-09-23 15:25:08 -05:00
//---
default :
break ;
2026-06-03 15:48:09 -05:00
}
Print ( text ) ;
2026-06-03 07:50:45 -05:00
p + = GetStepPure ( p ) ;
}
}
2026-10-01 08:25:33 -05:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-10-03 17:00:34 -05:00
static void CJsonParser::PrintError ( const string & header , const uchar & buf [ ] , const int len ,
int col , int line , ENUM_TSN_JSON_LAST_ERR err , string & salida , bool print = true )
2026-10-01 08:25:33 -05:00
{
//---
2026-10-03 17:00:34 -05:00
string out = " " ;
out .Reserve ( 256 ) ;
2026-10-01 08:25:33 -05:00
//---
2026-10-03 17:00:34 -05:00
if ( header .Length ( ) )
out + = " [ " + header + " ] \n " ;
2026-10-01 08:25:33 -05:00
//---
2026-10-03 17:00:34 -05:00
out + = StringFormat ( " JSON error at line %d, col %d: \n " , line , col ) ;
2026-10-01 08:25:33 -05:00
//---
2026-10-03 17:00:34 -05:00
switch ( err )
2026-10-01 08:25:33 -05:00
{
case TSN_JSON_ERR_INVALID_EXT_FILE :
2026-10-03 17:00:34 -05:00
out + = " Invalid file extension por JsonParserByLeo " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_INVALID_CHAR :
2026-10-03 17:00:34 -05:00
out + = " Invalid character found in json " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_MALFORDMED_JSON_AFTER_VAL :
2026-10-03 17:00:34 -05:00
out + = " Invalid character find in json, finding comma or context close (], }) " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_MALFORDMED_JSON_AFTER_COR_INI :
2026-10-03 17:00:34 -05:00
out + = " Invalid character find in json, finding valid value after '[' " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_MALFORDMED_JSON_FIND_VAL :
2026-10-03 17:00:34 -05:00
out + = " Invalid character find in json, finding valid value " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_MALFODERD_KEY_EXPECTED_DOS_PUNTOS :
2026-10-03 17:00:34 -05:00
out + = " Invalid JSON key, One of two errors: \" Expected a ':' after a JSON key \" or \" Malformed JSON while searching for characters. \" " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_MALFOMED_LEN_SUPERADO :
2026-10-03 17:00:34 -05:00
out + = " Len has superated, but json are not closed, malformed json " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_JSON_NOT_FINISH :
2026-10-03 17:00:34 -05:00
out + = " Json read has finish but not closed in ] or }, malformed json " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_LEADING_ZEROS :
2026-10-03 17:00:34 -05:00
out + = " A number in JSON notation cannot have leading zeros. " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_EXPECTED_NUMBER_AFECTER_EXP :
2026-10-03 17:00:34 -05:00
out + = " A number was expected after the 'E' exponent; an invalid character was found. " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_EXPECTED_NUMBER_AFECTER_DECIMALP :
2026-10-03 17:00:34 -05:00
out + = " A numeric value was expected after the decimal point. " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_MALFORMED_TRUE :
2026-10-03 17:00:34 -05:00
out + = " Malformed 'true' in json " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_MALFORMED_FALSE :
2026-10-03 17:00:34 -05:00
out + = " Malformed 'false' in json " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_MALFORMED_NULL :
2026-10-03 17:00:34 -05:00
out + = " Malformed 'null' in json " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_IN_MATERIALIZE_STRING_PARSE_ERR :
2026-10-03 17:00:34 -05:00
out + = " Error materializing string; possible causes include an invalid escape character or a malformed \\ u sequence. " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_OVERFLOW_IN_STACK :
2026-10-03 17:00:34 -05:00
out + = " Overflow for maxium stack " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_NOT_STRUCUTURAL_CHARS_FOUND :
2026-10-03 17:00:34 -05:00
out + = " Not structural character found in this json ({ | } | [ | ] | : | ,) " ;
2026-10-01 08:25:33 -05:00
break ;
case TSN_JSON_ERR_INVALID_STATE_IN_PARSE_DOUBLE_E :
2026-10-03 17:00:34 -05:00
out + = " Invalid state for Json Sax Parsing, in parse double value " ;
2026-10-01 08:25:33 -05:00
break ;
//---
default :
2026-10-03 17:00:34 -05:00
out + = " Unknow error " ;
2026-10-01 08:25:33 -05:00
break ;
}
//---
2026-10-03 17:00:34 -05:00
CParserErrFormat : : Format ( len , buf , line , col , out , salida ) ;
//---
if ( print )
Print ( salida ) ;
}
//+------------------------------------------------------------------+
// Solo a que tener cuidado con true\false\null
// aparte tok invalid tambien dado que este ultimo retorna false
void CJsonParser::CatchErr ( )
{
//---
if ( m_pos > = m_len )
m_pos = m_len - 1 ;
//---
if ( m_last_err ! = TSN_JSON_NOT_ERR )
return ; // ya tiene valor no hace falta
//---
switch ( m_next )
2026-10-01 08:25:33 -05:00
{
2026-10-03 17:00:34 -05:00
case TSN_JSON_TOK_BOOL_TRUE :
m_last_err = TSN_JSON_ERR_MALFORMED_TRUE ;
break ;
case TSN_JSON_TOK_BOOL_FALSE :
m_last_err = TSN_JSON_ERR_MALFORMED_FALSE ;
break ;
case TSN_JSON_TOK_NULL :
m_last_err = TSN_JSON_ERR_MALFORMED_NULL ;
break ;
default :
{
if ( m_next = = TSN_JSON_TOK_INVALID )
m_last_err = TSN_JSON_ERR_INVALID_CHAR ;
break ;
}
2026-10-01 08:25:33 -05:00
}
}
2026-07-11 16:31:27 -05:00
2026-09-30 07:39:54 -05:00
//+------------------------------------------------------------------+
2026-10-03 17:00:34 -05:00
void CJsonParser : : ErrorInfo ( const string header = " " )
{
//---
CatchErr ( ) ;
//---
if ( m_last_err = = TSN_JSON_NOT_ERR )
return ;
//---
int col , line ;
GetLastErrorLocation ( col , line ) ;
//---
string out = " " ;
PrintError ( header , m_raw , m_len , col , line , m_last_err , out ) ;
}
//+------------------------------------------------------------------+
2026-09-30 07:39:54 -05:00
//| Arrays helpers para evitar la resolcuino de ctx en todo mommento |
//+------------------------------------------------------------------+
template < typename T >
void CJsonParser : : ToArray ( int cur , T & out_arr [ ] , const int end ) const
{
//---
int k = 0 ;
switch ( int ( m_cinta [ cur ] & TSN_SBL_BIT_MASK_TYPE ) )
{
case JSON_VTYPE_UINTEGER :
{
while ( cur < end )
{
out_arr [ k + + ] = T ( ulong ( m_cinta [ cur + 1 ] ) ) ;
cur + = 2 ;
}
break ;
}
case JSON_VTYPE_INTEGER :
{
while ( cur < end )
{
out_arr [ k + + ] = T ( m_cinta [ cur + 1 ] ) ;
cur + = 2 ;
}
break ;
}
case JSON_VTYPE_REAL :
{
while ( cur < end )
{
TsnBitInterprete bit ;
bit . long_value = m_cinta [ cur + 1 ] ;
out_arr [ k + + ] = T ( bit . double_value ) ;
cur + = 2 ;
}
break ;
}
case JSON_VTYPE_BOOLEAN :
{
while ( cur < end )
{
out_arr [ k + + ] = T ( ( m_cinta [ cur ] > > TSN_SBL_BIT_START_ENDTYPE ) & 1 ) ;
cur + + ;
}
break ;
}
case JSON_VTYPE_STRING :
{
while ( cur < end )
{
2026-10-03 22:25:05 -05:00
static string str ;
if ( MakeString ( m_raw , TSN_SBL_CLS_STR_START ( cur ) , TSN_SBL_CLS_STR_LEN ( cur ) , str ) )
out_arr [ k + + ] = T ( str ) ;
//---
2026-09-30 07:39:54 -05:00
cur + + ;
}
break ;
}
default :
break ;
}
}
//+------------------------------------------------------------------+
template < typename T >
bool CJsonParser : : ExistInArray ( int cur , const T val , const uint flags , const int end ) const
{
while ( cur < end )
{
//---
uint ct = uint ( m_cinta [ cur ] & TSN_SBL_BIT_MASK_TYPE ) ;
if ( ( ( 1U < < ct ) & flags ) = = 0 )
{
cur + = GetStepPure ( cur ) ;
continue ;
}
//---
switch ( ct )
{
case JSON_VTYPE_UINTEGER :
{
if ( ( ulong ) m_cinta [ cur + 1 ] = = T ( val ) )
return true ;
break ;
}
case JSON_VTYPE_INTEGER :
{
if ( m_cinta [ cur + 1 ] = = T ( val ) )
return true ;
break ;
}
case JSON_VTYPE_REAL :
{
bit . long_value = m_cinta [ cur + 1 ] ;
if ( bit . double_value = = T ( val ) )
return true ;
break ;
}
case JSON_VTYPE_BOOLEAN :
{
if ( val = = T ( ( m_cinta [ cur ] > > TSN_SBL_BIT_START_ENDTYPE ) & 1 ) )
return true ;
break ;
}
case JSON_VTYPE_STRING :
{
2026-10-03 22:25:05 -05:00
static string str ;
if ( MakeString ( m_raw , TSN_SBL_CLS_STR_START ( cur ) , TSN_SBL_CLS_STR_LEN ( cur ) , str ) & & val = = T ( str ) )
2026-09-30 07:39:54 -05:00
return true ;
break ;
}
case JSON_VTYPE_NULL :
return true ;
default :
return false ;
}
//---
cur + = GetStepPure ( cur ) ;
}
return false ;
}
//+------------------------------------------------------------------+
template < typename T >
bool CJsonParser : : ExistInArrayHomogeneo ( int cur , const T val , const int end ) const
{
switch ( int ( m_cinta [ cur ] & TSN_SBL_BIT_MASK_TYPE ) )
{
case TSN_SBL_BASE_TYPE_UINT :
{
while ( cur < end )
{
if ( val = = T ( ulong ( m_cinta [ cur + 1 ] ) ) )
return true ;
cur + = 2 ;
}
}
case TSN_SBL_BASE_TYPE_INT :
{
while ( cur < end )
{
if ( val = = T ( m_cinta [ cur + 1 ] ) )
return true ;
cur + = 2 ;
}
return false ;
}
case TSN_SBL_BASE_TYPE_FLT :
{
while ( cur < end )
{
TsnBitInterprete bit ;
bit . long_value = m_cinta [ cur + 1 ] ;
if ( val = = T ( bit . double_value ) )
return true ;
cur + = 2 ;
}
return false ;
}
case TSN_SBL_BASE_TYPE_BOL :
{
while ( cur < end )
{
if ( val = = T ( ( m_cinta [ cur ] > > TSN_SBL_BIT_START_ENDTYPE ) & 1 ) )
return true ;
cur + + ;
}
return false ;
}
case TSN_SBL_BASE_TYPE_STR :
{
while ( cur < end )
{
2026-10-03 22:25:05 -05:00
static string str ;
if ( MakeString ( m_raw , TSN_SBL_CLS_STR_START ( cur ) , TSN_SBL_CLS_STR_LEN ( cur ) , str ) & & val = = T ( str ) )
2026-09-30 07:39:54 -05:00
return true ;
2026-10-03 22:25:05 -05:00
cur + + ;
2026-09-30 07:39:54 -05:00
}
break ;
}
default :
return false ;
}
return false ;
}
//---
2026-06-02 21:23:50 -05:00
}
# endif // JSONPARSERBYLEO_SRC_JSONPARSER_MQH