2026-10-05 17:54:12 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| Main.mqh |
|
| | | //| Copyright 2026, Niquel Mendoza. |
|
| | | //| https://www.mql5.com |
|
| | | //+------------------------------------------------------------------+
|
| | | #property copyright "Copyright 2026, Niquel Mendoza."
|
| | | #property link "https://www.mql5.com"
|
| | | #property strict
|
| | |
|
| | | #ifndef BASESPARSERSLAN_UE_MAIN_MQH
|
| | | #define BASESPARSERSLAN_UE_MAIN_MQH
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | #include <TSN\\Tables\\UE.mqh>
|
| | | #include "Def.mqh"
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | namespace TSN
|
| | | {
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | // Esta clase como tal se encargar de desescapar strings.. con reglas de escape
|
| | | // ya depende del elngauje final...
|
| | | // aparte el backend como tal debera de proporcional una tabla de escapes validos
|
| | | //--- optimizaciones
|
| | | // estuve busncado buen rato un par de horas... un buen algoritmo paara utf8 branchless
|
| | | // etc.. pero no tuve buenos reusltoas el tema es uqe un CLZ banrhacles etc para contar bytes requerido para utf8
|
| | | // en mql5 es mas costoso incluso con miss predict que una verisno de ternarios ifs...
|
| | | // y en parte tiene snrinfgo CLZ + otra talba son mas cosots, acceso a memoeira luego vaiors shifts or etc..
|
| | | // dado qeu eMQL5 no tieen clz nativo, hay que simualres con brujin y patrones de bits..
|
| | | // asi qeu creo que sincmante este algoetim de ifelseif parece ser el indicado para MQL5
|
| | | // no veo uan alternativa mejor para esto.. o que logre superarlo las version con CLZ o branhclees
|
| | | // son en promedio un 40-300% mas lentas, asi que me quedare con la via "simple y legible" en MQL6
|
| | | // no todo es brancless aqui .. se veia venir tmb
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | class CBSFLUnescape
|
| | | {
|
| | | public:
|
| | | CBSFLUnescape(void) {}
|
| | | ~CBSFLUnescape(void) {}
|
| | |
|
| | | //--- Basicos
|
| | | // string \ uarray
|
| | | // decodifica los ecapes a utf16
|
2026-10-06 08:02:39 -05:00 | | | template <typename TBackend>
|
2026-10-05 17:54:12 -05:00 | | | static bool MakeString(const uchar &in[], int i, int len, string& res);
|
2026-10-08 13:38:10 -05:00 | | |
|
| | |
|
2026-10-05 17:54:12 -05:00 | | | // decodifica los escapes a utf8
|
2026-10-06 08:02:39 -05:00 | | | template <typename TBackend, typename TUnicodeOne>
|
2026-10-05 17:54:12 -05:00 | | | static int MakeUArray(const uchar &in[], int i, int len, uchar &res[], int pos = 0);
|
| | |
|
2026-10-08 13:38:10 -05:00 | | |
|
| | | // decodifica los ecapes a un hash compatible con vm
|
| | | template <typename TBackend>
|
| | | static bool MakeHash(const uchar &in[], int& i, int len, ulong& hash);
|
| | |
|
2026-10-05 17:54:12 -05:00 | | | };
|
| | |
|
2026-10-08 13:38:10 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | template <typename TBackend>
|
| | | static bool CBSFLUnescape::MakeHash(const uchar &in[], int& i, int len, ulong &hash)
|
| | | {
|
| | | //---
|
| | | hash = 14695981039346656037ULL;
|
| | | for(;; i++) // nota aqui el " se nos garantiza pero igual en uncidoe hay que vertiicar el len
|
| | | {
|
| | | //---
|
| | | const uchar ch = in[i];
|
| | | if(ch == '\\')
|
| | | {
|
| | | const uchar next = TBackend::s_unescape_table[in[++i]];
|
| | | switch(next)
|
| | | {
|
| | | case TSN_TABLE_UNESCAPE_U32:
|
| | | {
|
| | | //--- U32 si requiere "desescaparlo"
|
| | | if(i + 8 >= len)
|
| | | return false;
|
| | | DOMBASEULTIS_U_U32_MAKESTRING_CODE(code, i)
|
| | | if(code > 0x10FFFF)
|
| | | return false;
|
| | |
|
| | | //---
|
| | | if(code <= 0xffff)
|
| | | {
|
| | | DOMBASEULTIS_U_MKH_ITER(code)
|
| | | }
|
| | | else // surrogates
|
| | | {
|
| | | code -= 0x10000;
|
| | | DOMBASEULTIS_U_MKH_ITER(ushort(0xD800 + (code >> 10)))
|
| | | DOMBASEULTIS_U_MKH_ITER(ushort(0xDC00 + (code & 0x3FF)))
|
| | | }
|
| | | break;
|
| | | }
|
| | | case TSN_TABLE_UNESCAPE_HEX:
|
| | | {
|
| | | if(i + 2 >= len)
|
| | | return false;
|
| | |
|
| | | //---
|
| | | uchar v = g_arr_valid_hex_chars[in[++i]] << 4;
|
| | | v |= g_arr_valid_hex_chars[in[++i]];
|
| | | DOMBASEULTIS_U_MKH_ITER(v)
|
| | | break;
|
| | | }
|
| | | case TSN_TABLE_UNESCAPE_UNICODE:
|
| | | {
|
| | | if(i + 4 >= len)
|
| | | return false;
|
| | |
|
| | | //---
|
| | | DOMBASEULTIS_U_UNICODE_MAKESTRING_CODE(code, i)
|
| | | DOMBASEULTIS_U_MKH_ITER(code)
|
| | | break;
|
| | | }
|
| | | case TSN_TABLE_UNESCAPE_INVALID:
|
| | | return false;
|
| | | default:
|
| | | DOMBASEULTIS_U_MKH_ITER(next)
|
| | | break;
|
| | | }
|
| | | continue;
|
| | | }
|
| | | if(ch == '"')
|
| | | {
|
| | | i++; // lo dejamos luego del "
|
| | | return true;
|
| | | }
|
| | |
|
| | | //--
|
| | | DOMBASEULTIS_U_MKH_ITER(ch)
|
| | | }
|
| | | return true;
|
| | | }
|
| | |
|
2026-10-05 17:54:12 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | // 1. se saume un input valido en utf8 etc...
|
| | | // 2. Ahora lo qeu hace esta funcion es desescapar y aparte los \uXXXX como mql5 es UTF16
|
| | | // los pone tal cual.. ahora los UTF32 (\UXXXXXXXX) auqi si hay logica de surrogate etc..
|
2026-10-06 08:02:39 -05:00 | | | template <typename TBackend>
|
2026-10-05 17:54:12 -05:00 | | | static bool CBSFLUnescape::MakeString(const uchar &in[], int i, int len, string& res)
|
| | | {
|
| | | //---
|
| | | StringInit(res, len, ' ');
|
| | | int pos = 0;
|
| | |
|
| | | //---
|
| | | len += i;
|
| | | for(; i < len; i++)
|
| | | {
|
| | | //---
|
| | | const uchar ch = in[i];
|
| | | if(ch == '\\')
|
| | | {
|
| | | const uchar next = TBackend::s_unescape_table[in[++i]];
|
| | | switch(next)
|
| | | {
|
| | | case TSN_TABLE_UNESCAPE_U32:
|
| | | {
|
| | | //--- U32 si requiere "desescaparlo"
|
| | | if(i + 8 >= len)
|
| | | return false;
|
| | | DOMBASEULTIS_U_U32_MAKESTRING_CODE(code, i)
|
| | | if(code > 0x10FFFF)
|
| | | return false;
|
| | |
|
| | | //---
|
| | | if(code <= 0xffff)
|
| | | {
|
| | | res.SetChar(pos++, (ushort)code);
|
| | | }
|
| | | else // surrogates
|
| | | {
|
| | | code -= 0x10000;
|
| | | res.SetChar(pos++, ushort(0xD800 + (code >> 10))); // high
|
2026-10-05 21:57:35 -05:00 | | | res.SetChar(pos++, ushort(0xDC00 + (code & 0x3FF))); // low
|
2026-10-05 17:54:12 -05:00 | | | }
|
| | | break;
|
| | | }
|
| | | case TSN_TABLE_UNESCAPE_HEX:
|
| | | {
|
| | | if(i + 2 >= len)
|
| | | return false;
|
| | |
|
| | | //---
|
2026-10-05 21:57:35 -05:00 | | | uchar v = g_arr_valid_hex_chars[in[++i]] << 4;
|
2026-10-05 17:54:12 -05:00 | | | v |= g_arr_valid_hex_chars[in[++i]];
|
| | | res.SetChar(pos++, v);
|
| | | break;
|
| | | }
|
| | | case TSN_TABLE_UNESCAPE_UNICODE:
|
| | | {
|
| | | if(i + 4 >= len)
|
| | | return false;
|
| | |
|
| | | //---
|
| | | DOMBASEULTIS_U_UNICODE_MAKESTRING_CODE(code, i)
|
| | | res.SetChar(pos++, code);
|
| | | break;
|
| | | }
|
| | | case TSN_TABLE_UNESCAPE_INVALID:
|
| | | return false;
|
| | | default:
|
| | | res.SetChar(pos++, next);
|
| | | break;
|
| | | }
|
| | | continue;
|
| | | }
|
| | |
|
2026-10-06 08:02:39 -05:00 | | | //--
|
2026-10-05 17:54:12 -05:00 | | | res.SetChar(pos++, ch);
|
| | | }
|
| | |
|
| | | //---
|
| | | res.Truncate(pos);
|
| | | return true;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | // Toma los bytes in y luego para los escapes \u \U \x los pasa utf8
|
| | | template <typename TBackend, typename TUnicodeOne>
|
| | | static int CBSFLUnescape::MakeUArray(const uchar &in[], int i, int len, uchar &res[], int pos = 0)
|
| | | {
|
| | | //---
|
| | | ArrayResize(res, len);
|
| | |
|
| | | //---
|
| | | len += i;
|
| | | for(; i < len; i++)
|
| | | {
|
| | | //---
|
| | | const uchar ch = in[i];
|
| | | if(ch == '\\')
|
| | | {
|
| | | const uchar next = TBackend::s_unescape_table[in[++i]];
|
| | | switch(next)
|
| | | {
|
| | | case TSN_TABLE_UNESCAPE_U32:
|
| | | {
|
| | | if(i + 8 >= len)
|
2026-10-18 17:02:48 -05:00 | | | return -1;
|
2026-10-05 17:54:12 -05:00 | | |
|
| | | //---
|
| | | DOMBASEULTIS_U_U32_MAKESTRING_CODE(code, i)
|
| | | if(code > 0x10FFFF)
|
| | | return false;
|
| | |
|
| | | //--- logica aqui...
|
| | | BSFL_WRITE_ASCCI(code)
|
| | | else
|
| | | if(code < 0x10000)
|
| | | {
|
| | | BSFL_UTF8_WRITE_3(code)
|
| | | }
|
| | | else
|
| | | {
|
| | | BSFL_UTF8_WRITE_4(code)
|
| | | }
|
| | |
|
| | | //---
|
| | | break;
|
| | | }
|
| | | case TSN_TABLE_UNESCAPE_HEX:
|
| | | {
|
| | | if(i + 2 >= len)
|
2026-10-18 17:02:48 -05:00 | | | return -1;
|
2026-10-05 17:54:12 -05:00 | | |
|
| | | //---
|
| | | uchar v = g_arr_valid_hex_chars[in[++i]] << 4;
|
| | | v |= g_arr_valid_hex_chars[in[++i]];
|
| | |
|
| | | //---
|
2026-10-05 21:57:35 -05:00 | | | if(v < 0x80)
|
| | | res[pos++] = (v);
|
| | | else
|
| | | {
|
| | | res[pos++] = (0xC0 | (v >> 6));
|
| | | res[pos++] = (0x80 | (v & 0x3F));
|
| | | }
|
2026-10-05 17:54:12 -05:00 | | | break;
|
| | | }
|
| | | case TSN_TABLE_UNESCAPE_UNICODE:
|
| | | {
|
| | | if(i + 4 >= len)
|
| | | return -1; // error
|
| | |
|
| | | //---
|
| | | DOMBASEULTIS_U_UNICODE_MAKESTRING_CODE(code, i)
|
| | |
|
| | | //---
|
| | | BSFL_WRITE_ASCCI(code)
|
| | |
|
| | | //--- verificamos si el unicode one esta presente (osea si no veriicamos surrogates si no tal cual como yaml)
|
| | | // o json que si hay que verificar...
|
2026-10-05 21:57:35 -05:00 | | | if(sizeof(TUnicodeOne) == sizeof(BSFL_UE_SURROGATES))
|
2026-10-05 17:54:12 -05:00 | | | {
|
| | | uint cp = code;
|
| | | if(code >= 0xD800 && code <= 0xDBFF) // Esta en rango buscamos otro mas.
|
| | | {
|
| | | if(i + 6 < len && in[i + 1] == '\\' && in[i + 2] == 'u')
|
| | | {
|
| | | int j = i + 2;
|
| | | DOMBASEULTIS_U_UNICODE_MAKESTRING_CODE(low, j)
|
| | | if(low >= 0xDC00 && low <= 0xDFFF)
|
| | | {
|
| | | cp = 0x10000 + ((code - 0xD800) << 10) + (low - 0xDC00);
|
| | | i = j;
|
| | |
|
| | | //--- emoji
|
| | | BSFL_UTF8_WRITE_4(cp)
|
| | | continue;
|
| | | }
|
| | | }
|
| | |
|
| | | //---
|
| | | // if(sizeof(TStrict) == JSONUNESCAPE_STRICT)
|
| | | // return -1;
|
| | | code = 0xFFFD; // huerfano, no hay low surrogate despues
|
| | | }
|
| | | else
|
| | | if(code >= 0xDC00 && code <= 0xDFFF)
|
| | | {
|
| | | // if(sizeof(TStrict) == JSONUNESCAPE_STRICT)
|
| | | // return -1;
|
| | | code = 0xFFFD;
|
| | | }
|
| | | }
|
| | | // si no lo hay entonces siremp max 0xffff unico
|
| | |
|
| | | //---
|
| | | BSFL_UTF8_WRITE_3(code)
|
| | | continue;
|
| | | }
|
| | | case TSN_TABLE_UNESCAPE_INVALID:
|
| | | return -1; // error
|
| | | default:
|
| | | res[pos++] = next;
|
| | | continue;
|
| | | }
|
| | | }
|
| | | //---
|
| | | res[pos++] = ch;
|
| | | }
|
| | |
|
| | | //---
|
| | | return ArrayResize(res, pos);
|
| | | }
|
| | | //---
|
| | | }
|
| | | #endif // BASESPARSERSLAN_UE_MAIN_MQH
|
| | | //+------------------------------------------------------------------+
|