//+------------------------------------------------------------------+ //| Node.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_NODE_MQH #define CRYPTOBYLEO_RSPPARSER_NODE_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "RSP.mqh" #include //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ namespace TSN { //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #define RSPDATA_TRIPLET_KEYVALUEMETA (3) #define RSPDATA_IS_VALID (m_ctx!=NULL) #define RSPDATA_IS_NOT_VALID (m_ctx==NULL) #define RSPDATA_IS_VALID_F (RSPDATA_IS_VALID && m_idx!=-1) #define RSPDATA_IS_VAL_TO_REVISE (((m_ctx.m_cinta[m_idx-1] >> RSPDATA_BITSTART_ISVAL_CLEAN) & RSPDATA_MASK_META_IS) == 0) //--- #define RSPNODE_NH(NH) TSN::MQLARTICLES_STRUCT_BYTES_##NH //--- forward class CRSPIteradorBase; template class CRSPIteratorHash; //--- #define RSPNODE_CORRECT_VAL \ if(RSPDATA_IS_VAL_TO_REVISE)\ {\ int i = (start + slen) - 1;\ while(i >= start && m_ctx.m_raw[i] < 33)\ {\ i--;\ }\ slen = (i - start) + 1;\ m_ctx.m_cinta[m_idx] = long(RSPDATA_TYPE_PLAIN_VALUE)\ | long(slen) << TSN_SBL_BIT_STR_LEN\ | long(start) << TSN_SBL_BIT_STR_START;\ m_ctx.m_cinta[m_idx - 1] |= RSPDATA_BITSTART_ISVAL_CLEAN_F;\ } //--- //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ struct CRSPNode { CRSPParser* m_ctx; int m_idx; //---- CRSPNode(const int _idx, CRSPParser* _ctx) : m_idx(_idx), m_ctx(_ctx) {} CRSPNode() : m_idx(-1), m_ctx(NULL) {} //--- __forceinline int RootSize() const { return m_ctx.m_root_values; } //--- // Navega en el root CRSPNode operator[](const string& key); CRSPNode At(const int index) const; string AtKey(const int index); //--- bool HasKey(const string& key); //--- __forceinline ENUM_RSPDATA_TYPE GetType() const { return ENUM_RSPDATA_TYPE(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE); } __forceinline uint GetFlag() const { return 1 << uint(m_ctx.m_cinta[m_idx] & TSN_SBL_BIT_MASK_TYPE); } //--- Value CRSPNode Value() const; //-- to str string ToString(const string def = "") const; int ToStringUArray(uchar& data[]) const; int StrLenRaw() const; __forceinline bool CompareStrWith(const string& str) const; //-- to bytes (asume hex string) int HexToBytes(uchar& buf[]) const; //--- Is __forceinline bool IsValid() const { return RSPDATA_IS_VALID_F; } __forceinline bool IsInvalid() const { return !RSPDATA_IS_VALID_F; } //--- Meta __forceinline bool MetaIsCor() const { return ((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_ENDTYPE) & RSPDATA_MASK_META_IS) != 0; } __forceinline bool MetaCleanedKey() const { return ((m_ctx.m_cinta[m_idx] >> RSPDATA_BITSTART_ISKEY_CLEAN) & RSPDATA_MASK_META_IS) != 0; } __forceinline bool MetaCleanedValue() const { return ((m_ctx.m_cinta[m_idx] >> RSPDATA_BITSTART_ISVAL_CLEAN) & RSPDATA_MASK_META_IS) != 0; } //--- template TSN::CRSPIteratorHash MakeHashIterator(const string& keys[]) const { if(RSPDATA_IS_NOT_VALID) return CRSPIteratorHash::EMPTY; return CRSPIteratorHash(keys, m_ctx, m_idx); } //--- template CRSPIteradorBase* MakeInteligentIterador(const string& keys[]) const; //--- static const CRSPNode EMPTY_NODE; //--- bool MoveNextPositionsThis(const int posiciones); CRSPNode MoveNextPositions(const int posiciones) const; //--- static bool BytesEq(const uchar& a[], const uchar& b[]); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ const CRSPNode CRSPNode::EMPTY_NODE; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CRSPNode CRSPNode::operator[](const string& key) { //--- if(RSPDATA_IS_NOT_VALID) return CRSPNode::EMPTY_NODE; //--- int cur = 0; while(cur < m_ctx.m_cinta_pos) { if(m_ctx.KeysEqual(key, cur)) // + 1 para estar en META return CRSPNode(cur + 1, m_ctx); cur += RSPDATA_TRIPLET_KEYVALUEMETA; } return CRSPNode::EMPTY_NODE; } //+------------------------------------------------------------------+ bool CRSPNode::HasKey(const string &key) { //--- if(RSPDATA_IS_NOT_VALID) return false; //--- int cur = 0; while(cur < m_ctx.m_cinta_pos) { if(m_ctx.KeysEqual(key, cur)) // + 1 para estar en META return true; cur += RSPDATA_TRIPLET_KEYVALUEMETA; } return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CRSPNode CRSPNode::At(const int index) const { //--- if(RSPDATA_IS_NOT_VALID || index < 0 || index >= m_ctx.m_cinta_pos) return CRSPNode::EMPTY_NODE; //--- devuelve META return CRSPNode((index * RSPDATA_TRIPLET_KEYVALUEMETA) + 1, m_ctx); } //+------------------------------------------------------------------+ string CRSPNode::AtKey(const int index) { //--- if(RSPDATA_IS_NOT_VALID || index < 0 || index >= m_ctx.m_cinta_pos) return ""; //--- devuelve string const int base = (index * RSPDATA_TRIPLET_KEYVALUEMETA); //--- const int start = int(m_ctx.m_cinta[base] >> TSN_SBL_BIT_STR_START); int slen = int((m_ctx.m_cinta[base] >> TSN_SBL_BIT_START_ENDTYPE) & TSN_SBL_BIT_STR_MASK_LEN); //--- m_ctx.VerifyCleanKey(base, start, slen); //--- return CharArrayToString(m_ctx.m_raw, start, slen); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CRSPNode CRSPNode::Value(void) const { //--- if(RSPDATA_IS_NOT_VALID) return CRSPNode::EMPTY_NODE; // si estamos en META +1 = value return CRSPNode(m_idx + 1, m_ctx); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string CRSPNode::ToString(const string def = "") const { if(RSPDATA_IS_NOT_VALID || (m_ctx.m_cinta[m_idx]&TSN_SBL_BIT_MASK_TYPE) != RSPDATA_TYPE_PLAIN_VALUE) return def; // ahora si en value // tenemos que recortar por la parte alta //--- const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_START); int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_ENDTYPE) & TSN_SBL_BIT_STR_MASK_LEN); //--- RSPNODE_CORRECT_VAL //--- return CharArrayToString(m_ctx.m_raw, start, slen); } //+------------------------------------------------------------------+ int CRSPNode::ToStringUArray(uchar &data[]) const { if(RSPDATA_IS_NOT_VALID || (m_ctx.m_cinta[m_idx]&TSN_SBL_BIT_MASK_TYPE) != RSPDATA_TYPE_PLAIN_VALUE) return 0; // ahora si en value // tenemos que recortar por la parte alta //--- const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_START); int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_ENDTYPE) & TSN_SBL_BIT_STR_MASK_LEN); //--- RSPNODE_CORRECT_VAL //--- return ArrayCopy(data, m_ctx.m_raw, 0, start, slen); } //+------------------------------------------------------------------+ // interpretna un mensaje multiplo de 2 len como una cadena de bytes LE // Si no hay caracters NO HEX se intemapn como FF (invalidos) nota eso // osea que // "kkkk" da buf[] = {0xff, 0xff} int CRSPNode::HexToBytes(uchar &buf[]) const { if(RSPDATA_IS_NOT_VALID || (m_ctx.m_cinta[m_idx]&TSN_SBL_BIT_MASK_TYPE) != RSPDATA_TYPE_PLAIN_VALUE) return 0; // ahora si en value // tenemos que recortar por la parte alta //--- const int start = int(m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_STR_START); int slen = int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_ENDTYPE) & TSN_SBL_BIT_STR_MASK_LEN); //--- RSPNODE_CORRECT_VAL //--- const int sob = slen & 1; // % 2 (vemos si hay sobrante o si es multiplo de dos exacto) int exact_len = slen - sob; ArrayResize(buf, (slen >> 1) + (sob << 1)); int w = 0; //--- exact_len += start; // para que peuda empzar bien.. int i = start; //--- for(i; i < exact_len; i += 2) buf[w++] = g_arr_valid_hex_chars[m_ctx.m_raw[i]] | g_arr_valid_hex_chars[m_ctx.m_raw[i + 1]] << 4; if(sob) // solo rellenmaso alto (la parte alta la inteprntamos como 0) buf[w++] = m_ctx.m_raw[i]; //--- return w; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CRSPNode::StrLenRaw(void) const { if(RSPDATA_IS_NOT_VALID || (m_ctx.m_cinta[m_idx]&TSN_SBL_BIT_MASK_TYPE) != RSPDATA_TYPE_PLAIN_VALUE) return 0; return int((m_ctx.m_cinta[m_idx] >> TSN_SBL_BIT_START_ENDTYPE) & TSN_SBL_BIT_STR_MASK_LEN); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CRSPNode::CompareStrWith(const string &str) const { if(RSPDATA_IS_NOT_VALID || (m_ctx.m_cinta[m_idx]&TSN_SBL_BIT_MASK_TYPE) != RSPDATA_TYPE_PLAIN_VALUE) return false; return m_ctx.StrEquals(str, m_idx); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CRSPNode::MoveNextPositionsThis(const int posiciones) { if(RSPDATA_IS_NOT_VALID) return false; const int next_pos = m_idx + posiciones; if(next_pos >= m_ctx.m_cinta_pos) return false; m_idx = next_pos; return true; } //+------------------------------------------------------------------+ CRSPNode CRSPNode::MoveNextPositions(const int posiciones) const { if(RSPDATA_IS_NOT_VALID) return CRSPNode::EMPTY_NODE; const int next_pos = m_idx + posiciones; if(next_pos >= m_ctx.m_cinta_pos) return CRSPNode::EMPTY_NODE; return CRSPNode(next_pos, m_ctx); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ static bool CRSPNode::BytesEq(const uchar &a[], const uchar &b[]) { const int ta = ArraySize(a); if(ta != ArraySize(b)) return false; for(int i = 0; i < ta; i++) { if(a[i] != b[i]) return false; } return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CRSPNode CRSPParser::GetRoot(void) { if(m_cinta_pos == 0) return CRSPNode::EMPTY_NODE; return CRSPNode(0, &this); } } #endif // CRYPTOBYLEO_RSPPARSER_NODE_MQH