//+------------------------------------------------------------------+ //| RSP.mqh | //| Copyright 2026, Niquel Mendoza | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, Niquel Mendoza" #property link "https://www.mql5.com" #property strict #ifndef CRYPTOBYLEO_RSPPARSER_RSP_MQH #define CRYPTOBYLEO_RSPPARSER_RSP_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "Def.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ namespace TSN { //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CRSPParser : public CBaseLanFormat { public: int m_root_values; private: //--- last err ENUM_RSPPARSER_LAST_ERR m_last_err; //--- parseo int m_prev_start_v; // el ultimo valor esta entre [] osea meta bool m_last_meta; // mascara de fin #ifndef RSPDATA_DESACTIVE_SWAR ulong m_last_val_mask; #else uchar m_last_val_char; #endif // RSPDATA_DESACTIVE_SWAR public: CRSPParser(void); ~CRSPParser(void) {} //--- __forceinline void CorrectPadding() { CorrectPadingInternal('\n', 8); } //--- bool AutoParseByFileExt(const int file_ext_type); int AssingFile(const string& file_name, const bool comon_flag); //-- // verifica si una clave esta limpia // En caso no lo este ejeucta la limpiza ahi mismo void VerifyCleanKey(const int cur, const int start, int& len); //--- bool KeysEqual(const string &str, const int curr); bool StrEquals(const string &str, const int curr) const; //--- __forceinline ENUM_RSPPARSER_LAST_ERR LastErr() const { return m_last_err; } //--- bool Parse(); //--- void ErrorInfo(bool with_avanze = false) const; //--- bool SaveCompiled(const string & file_name_out, const bool out_common_flag) const; bool SaveCompiled(const string & file_name_out, const bool out_common_flag, const string & file_name_data, const bool data_common_flag) const; //--- void PrintCintaTypes(const int start, const int num) const; //--- CRSPNode GetRoot(); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CRSPParser::CRSPParser() : #ifndef RSPDATA_DESACTIVE_SWAR m_last_val_mask(TSNTABLES_SWAR_MASK_NEW_LINE) #else // RSPDATA_DESACTIVE_SWAR m_last_val_char('\n') #endif // RSPDATA_DESACTIVE_SWAR { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CRSPParser::AutoParseByFileExt(const int file_ext_type) { switch(file_ext_type) { case TSN_SLF_RAW_FILE: { CorrectPadding(); // Auto return Parse(); } case TSN_SLF_RAW_EMBEBED: { return m_cinta_pos > 0 && m_len > 0; } default: { m_last_err = RSPPARSER_LAST_ERR_INVALID_EXT_FILE; m_pos = 0; return false; } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CRSPParser::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; 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); 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; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CRSPParser::VerifyCleanKey(const int cur, const int start, int& len) { const int k = cur + 1; // kpos+1 if(((m_cinta[k] >> RSPDATA_BITSTART_ISKEY_CLEAN) & RSPDATA_MASK_META_IS) == 0) { int j = (start + len) - 1; while(j >= start && m_raw[j] < 33) { j--; } len = (j - start) + 1; m_cinta[cur] = long(RSPDATA_TYPE_PLAIN_KEY) | long(len) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; m_cinta[k] |= RSPDATA_BITSTART_ISKEY_CLEAN_F; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CRSPParser::KeysEqual(const string &str, const int curr) { //--- const int start = int(m_cinta[curr] >> TSN_SBL_BIT_STR_START); int len = int((m_cinta[curr] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); //--- VerifyCleanKey(curr, start, 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; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // luego de un valor buscar key // el |1 lo hacemos para acitvar el bit 1 cosa uqe aumenta en 1 el valor base del token // En el enum estan definidos de tal forma qeu si le aumentmos 1 para value=key (ahora es key) // y los demas tambien // coment aunenta en uno ahora es comentp // lo que tambien aumenta es cor que pasa a ser corp // e invalid pasa a (fuera) de rango (defualt en NEXTT) // maxima velocidad sin branches #define TSN_RSPPARSER_NEXTV \ while(true) \ { \ if(m_pos >= m_len) \ { \ return true; \ } \ const uchar cfasd = m_raw[m_pos]; \ if(cfasd < 33) \ { \ m_pos++; \ continue; \ } \ m_next = g_tsn_rsp_t_to_tokesn[cfasd]|1; \ break;\ } //--- #define RSPDATA_PARSE_FIND_CHAR_UNROLLED_8(CH) \ if(m_raw[m_pos] == CH)\ break;\ m_pos++;\ if(m_raw[m_pos] == CH)\ break;\ m_pos++;\ if(m_raw[m_pos] == CH)\ break;\ m_pos++;\ if(m_raw[m_pos] == CH)\ break;\ m_pos++;\ if(m_raw[m_pos] == CH)\ break;\ m_pos++;\ if(m_raw[m_pos] == CH)\ break;\ m_pos++;\ if(m_raw[m_pos] == CH)\ break;\ m_pos++;\ if(m_raw[m_pos] == CH)\ break; \ m_pos++; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CRSPParser::Parse(void) { //--- m_pos = m_offset; m_cinta_pos = 0; m_last_meta = false; m_last_err = RSPPARSER_LAST_ERR_NOT; m_root_values = 0; //--- Initial while(true) { const uchar _c = m_raw[m_pos]; if(_c < 33) { m_pos++; continue; } m_next = g_tsn_rsp_t_to_tokesn[_c] | 1; break; } //--- Iter while(true) { switch(m_next) { //--- case RSPDATA_TOK_TYPE_VALUE: { // m_prev_start_v = start del key qeu este ultimo nos definio para este valor #ifndef RSPDATA_DESACTIVE_SWAR while(true) { 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 = chunk ^ m_last_val_mask; const ulong has_x = TSNTABLES_SWAR_HAS(x); if(has_x == 0) { m_pos += 8; //--- if((m_pos + 7) >= m_len) { m_last_err = RSPPARSER_LAST_ERR_SE_BUSCABA_FIN_V; return false; } //--- continue; } //--- // Si hay \n const ulong flag = TSNTABLES_SWAR_64_DEJAR_SOLO_MINUS_SIG_BYTE(has_x); m_pos += TSNTABLES_SWAR_64_GET_BYTE(flag); // Ahora mismo en \n break; } //--- m_last_val_mask = TSNTABLES_SWAR_MASK_NEW_LINE; #else // RSPDATA_DESACTIVE_SWAR while(true) { RSPDATA_PARSE_FIND_CHAR_UNROLLED_8(m_last_val_char) //--- if((m_pos + 7) >= m_len) { m_last_err = RSPPARSER_LAST_ERR_SE_BUSCABA_FIN_V; return false; } } //--- m_last_val_char = '\n'; #endif // RSPDATA_DESACTIVE_SWAR // Ahora mismo en \n //--- m_cinta[m_cinta_pos++] = long(RSPDATA_TYPE_PLAIN_VALUE) | long(m_pos - m_prev_start_v) << TSN_SBL_BIT_STR_LEN | long(m_prev_start_v) << TSN_SBL_BIT_STR_START; //--- m_pos++; // Luiego del \n m_root_values++; //--- TSN_RSPPARSER_NEXTV break; } //--- case RSPDATA_TOK_TYPE_KEY: { // ahora mismo justo en kstart const int start = m_pos++; //--- // Por deqfecto desactivo en priomedio als key no superan los 8 chars ahi // asi que no hay mucho beneficio #ifdef RSPDATA_PARSER_KEY_ACTIVE_SWAR while(true) { //Print(CharArrayToString(m_raw, m_pos, 7)); 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 = chunk ^ TSNTABLES_SWAR_MASK_IGUAL; const ulong has_x = TSNTABLES_SWAR_HAS(x); if(has_x == 0) { m_pos += 8; //--- if((m_pos + 7) >= m_len) { m_last_err = RSPPARSER_LAST_ERR_SE_BUSCABA_EQ; return false; } continue; } //--- // Si hay = const ulong flag = TSNTABLES_SWAR_64_DEJAR_SOLO_MINUS_SIG_BYTE(has_x); m_pos += TSNTABLES_SWAR_64_GET_BYTE(flag); break; } #else // RSPDATA_PARSER_KEY_ACTIVE_SWAR while(true) { RSPDATA_PARSE_FIND_CHAR_UNROLLED_8('=') //--- if((m_pos + 7) >= m_len) { m_last_err = RSPPARSER_LAST_ERR_SE_BUSCABA_EQ; return false; } } #endif // RSPDATA_PARSER_KEY_ACTIVE_SWAR // Ahora mismo justo en = m_cinta[m_cinta_pos++] = long(RSPDATA_TYPE_PLAIN_KEY) | long(m_pos - start) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; // ahora toca meta m_cinta[m_cinta_pos++] = long(RSPDATA_TYPE_META) | long(m_last_meta) << TSN_SBL_BIT_START_ENDTYPE; //--- avanzamos m_pos++; // Ahora toca value m_prev_start_v = m_pos; m_last_meta = false; //--- Ahora buscamos el valor while(true) { const uchar f = m_raw[m_pos]; if(f < 33) { if(f == '\n') { // No habai nada estamos en\n entonces 0 m_cinta[m_cinta_pos++] = long(RSPDATA_TYPE_PLAIN_VALUE) | long(0) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; //--- TSN_RSPPARSER_NEXTV break; } //--- m_pos++; if(m_pos >= m_len) // o en todo caso fin { m_cinta[m_cinta_pos++] = long(RSPDATA_TYPE_PLAIN_VALUE) | long(0) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; return true; } //--- m_prev_start_v++; // nada avanzamos.. continue; } //--- Justo aqui nos detenemos. Vemos que sigue comentario o valor // Valor raw tal cual (sin 1 asi que el value es vlaue ya no se pasa a key) m_next = g_tsn_rsp_t_to_tokesn[f]; break; } //--- break; } //--- [ ] case RSPDATA_TOK_TYPE_COR: case RSPDATA_TOK_TYPE_COR_P: { m_pos++; // luego del cor // m_last_meta = true; // saltar ws while(true) { if(m_raw[m_pos] < 33) continue; break; } // camibamos las mcaras para que en vez de \n sea ] fin de valor #ifndef RSPDATA_DESACTIVE_SWAR m_last_val_mask = TSNTABLES_SWAR_MASK_COR_END; #else m_last_val_char = ']'; #endif // ahora mismo ene l primer char de key m_next = RSPDATA_TOK_TYPE_KEY; break; } //--- case RSPDATA_TOK_TYPE_COMMENT: case RSPDATA_TOK_TYPE_COMMENT_P: { m_pos++; // Siguiente.. //--- #ifndef RSPDATA_DESACTIVE_SWAR while(true) { //Print(CharArrayToString(m_raw, m_pos, 7)); 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 = chunk ^ TSNTABLES_SWAR_MASK_NEW_LINE; const ulong has_x = TSNTABLES_SWAR_HAS(x); if(has_x == 0) { m_pos += 8; //--- Check if((m_pos + 7) >= m_len) { m_last_err = RSPPARSER_LAST_ERR_SE_BUSCABA_FIN_DE_LINEA; return false; } continue; } //--- // Si hay \n const ulong flag = TSNTABLES_SWAR_64_DEJAR_SOLO_MINUS_SIG_BYTE(has_x); m_pos += TSNTABLES_SWAR_64_GET_BYTE(flag); // Ahora mismo en \n+1 \n[aqui] break; } #else // RSPDATA_DESACTIVE_SWAR while(true) { RSPDATA_PARSE_FIND_CHAR_UNROLLED_8('\n') //--- if((m_pos + 7) >= m_len) { m_last_err = RSPPARSER_LAST_ERR_SE_BUSCABA_FIN_DE_LINEA; return false; } } #endif // RSPDATA_DESACTIVE_SWAR //--- m_pos++; // Si o si sigue key TSN_RSPPARSER_NEXTV break; } //--- case RSPDATA_TOK_INVALID: { m_last_err = RSPPARSER_LAST_ERR_INVALID_TOKEN; return false; } //--- default: m_last_err = RSPPARSER_LAST_ERR_INVALID_NEXTT; return false; } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CRSPParser::AssingFile(const string &file_name, const bool comon_flag) { //--- if(FileGetExtension(file_name) == RSPPARSER_TAPECACHE_EXT) // jsontp tape cache { ::ResetLastError(); const int fh = FileOpen(file_name, FILE_BIN | FILE_ANSI | (comon_flag ? FILE_COMMON : 0) | FILE_READ); if(fh == INVALID_HANDLE) { return -1; } // Metadata (cinta\yaml) m_cinta_pos = FileReadInteger(fh); // Nota que cuadno se guarda se hace con el tamaño exacto m_cinta_reserve = m_cinta_pos; // Mismo tamaño const int type = FileReadInteger(fh); // Tipo () //--- if(type == TSN_SLF_RAW_EMBEBED) { m_len = FileReadInteger(fh); m_offset = FileReadInteger(fh); FileReadArray(fh, m_cinta, 0, m_cinta_pos); // Total // Yaml embebido (aqui no hace falta hacer nada ya todo esta hecho.. osea lo de encoding etc..) FileReadArray(fh, m_raw, 0, m_len); } else // Dir { const bool common = bool(FileReadInteger(fh, CHAR_VALUE)); const int file_name_len = FileReadInteger(fh); if(AssingFile(FileReadString(fh, file_name_len), common) == TSN_SLF_EXT_TYPE_CACHE_FILE) { FileClose(fh); return -1; // fallo } FileReadArray(fh, m_cinta, 0, m_cinta_pos); } //--- FileClose(fh); return TSN_SLF_EXT_TYPE_CACHE_FILE; } else // Ninguno de los dos... json normal O jsonasm { const int l = (int)FileLoad(file_name, m_raw, (comon_flag ? FILE_COMMON : 0)); if(l == -1) return -1; //--- m_len = l; //--- NormalizeUft(); //--- return TSN_SLF_EXT_TYPE_FILE; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ //--- Ambos // 4 bytes: m_cinta_pos // 4 bytes: type //--- bool CRSPParser::SaveCompiled(const string & file_name_out, const bool out_common_flag) const { ::ResetLastError(); const int fh = FileOpen(file_name_out, FILE_BIN | (out_common_flag ? FILE_COMMON : 0) | FILE_WRITE | FILE_ANSI); if(fh == INVALID_HANDLE) { return false; } //--- Comun FileWriteInteger(fh, m_cinta_pos); FileWriteInteger(fh, TSN_SLF_RAW_EMBEBED); //--- // 4 bytes: len // 4 bytes: offset // array: cinta // array yaml //--- FileWriteInteger(fh, m_len); FileWriteInteger(fh, m_offset); FileWriteArray(fh, m_cinta, 0, m_cinta_pos); FileWriteArray(fh, m_raw, 0, m_len); //--- FileClose(fh); //--- return true; } //+------------------------------------------------------------------+ bool CRSPParser::SaveCompiled(const string & file_name_out, const bool out_common_flag, const string & file_name_data, const bool data_common_flag) const { //--- ::ResetLastError(); const int fh = FileOpen(file_name_out, FILE_BIN | (out_common_flag ? FILE_COMMON : 0) | FILE_WRITE | FILE_ANSI); if(fh == INVALID_HANDLE) { return false; } //--- Comun FileWriteInteger(fh, m_cinta_pos); FileWriteInteger(fh, TSN_SLF_RAW_FILE); //--- // 1 bytes: comon // 4 bytes: len // string: name_file // array: cinta //--- FileWriteInteger(fh, data_common_flag, CHAR_VALUE); const int len = StringLen(file_name_data); FileWriteInteger(fh, len); FileWriteString(fh, file_name_data, len); FileWriteArray(fh, m_cinta, 0, m_cinta_pos); //--- FileClose(fh); //--- return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CRSPParser::ErrorInfo(bool with_avanze = false) const { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CRSPParser::PrintCintaTypes(const int start, const int num) const { //--- int p = fmax(start, 0); const int end = (num == WHOLE_ARRAY || (p + num) > m_cinta_pos) ? m_cinta_pos : (p + num); //--- while(p < end) { const ENUM_RSPDATA_TYPE tipo = ENUM_RSPDATA_TYPE(m_cinta[p] & TSN_SBL_BIT_MASK_TYPE); string text = "[" + (string)p + "] " + EnumToString(tipo) + " | "; //--- switch(tipo) { case RSPDATA_TYPE_PLAIN_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); //--- text += "start=" + (string)s + " len=" + (string)slen + " key=\"" + CharArrayToString(m_raw, s, slen) + "\""; break; } case RSPDATA_TYPE_PLAIN_VALUE: { 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); //--- text += "start=" + (string)s + " len=" + (string)slen + " val=\"" + CharArrayToString(m_raw, s, slen) + "\""; break; } case RSPDATA_TYPE_META: { static BitInterpreter un; un.long_value = m_cinta[p + 1]; text += StringFormat("is_cor=%s is_val_cleaned=%s is_key_cleaned=%s", (((m_cinta[p] >> TSN_SBL_BIT_START_ENDTYPE) & RSPDATA_MASK_META_IS) != 0 ? "true" : "false"), (((m_cinta[p] >> RSPDATA_BITSTART_ISVAL_CLEAN) & RSPDATA_MASK_META_IS) != 0 ? "true" : "false"), (((m_cinta[p] >> RSPDATA_BITSTART_ISKEY_CLEAN) & RSPDATA_MASK_META_IS) != 0 ? "true" : "false") ); break; } default: break; } Print(text); p++; } } //--- } //+------------------------------------------------------------------+ #endif // CRYPTOBYLEO_RSPPARSER_RSP_MQH