2026-08-24 16:40:07 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| 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"
|
2026-08-25 08:02:51 -05:00 | | | #include <TSN/MQLArticles/Utils/StructBytesCre.mqh>
|
2026-08-24 16:40:07 -05:00 | | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | namespace TSN
|
| | | {
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-08-24 21:32:18 -05:00 | | | #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)
|
2026-08-24 16:40:07 -05:00 | | |
|
2026-08-24 21:55:43 -05:00 | | | //--- forward
|
| | | class CRSPIteradorBase;
|
| | |
|
2026-08-25 08:02:51 -05:00 | | | template <typename TNumHashes, typename TBaseHash>
|
| | | class CRSPIteratorHash;
|
| | |
|
2026-09-26 21:47:11 -05:00 | | | //--- trim right
|
| | | #define RSPNODE_CORRECT_R_WSPACES \
|
2026-08-24 22:42:17 -05:00 | | | 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;\
|
| | | }
|
| | |
|
2026-08-25 08:02:51 -05:00 | | | //---
|
| | |
|
2026-08-24 16:40:07 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-08-24 21:32:18 -05:00 | | | struct CRSPNode
|
2026-08-24 16:40:07 -05:00 | | | {
|
| | | CRSPParser* m_ctx;
|
| | | int m_idx;
|
| | |
|
2026-08-24 21:32:18 -05:00 | | | //----
|
2026-08-24 22:33:45 -05:00 | | | CRSPNode(const int _idx, CRSPParser* _ctx) : m_idx(_idx), m_ctx(_ctx) {}
|
2026-08-24 21:32:18 -05:00 | | | CRSPNode() : m_idx(-1), m_ctx(NULL) {}
|
| | |
|
2026-08-24 22:33:45 -05:00 | | |
|
| | | //---
|
| | | __forceinline int RootSize() const { return m_ctx.m_root_values; }
|
| | |
|
2026-08-24 16:40:07 -05:00 | | | //---
|
| | | // Navega en el root
|
2026-08-24 21:32:18 -05:00 | | | CRSPNode operator[](const string& key);
|
| | | CRSPNode At(const int index) const;
|
| | | string AtKey(const int index);
|
| | |
|
| | | //---
|
| | | bool HasKey(const string& key);
|
2026-08-24 16:40:07 -05:00 | | |
|
| | | //---
|
2026-08-24 21:32:18 -05:00 | | | __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); }
|
2026-08-24 16:40:07 -05:00 | | |
|
| | | //--- Value
|
2026-08-24 21:32:18 -05:00 | | | CRSPNode Value() const;
|
| | |
|
2026-08-24 16:40:07 -05:00 | | | //-- to str
|
| | | string ToString(const string def = "") const;
|
| | | int ToStringUArray(uchar& data[]) const;
|
2026-09-26 21:47:11 -05:00 | | | __forceinline int StrLenRaw() const;
|
| | | __forceinline int StrStart() const;
|
2026-08-24 16:40:07 -05:00 | | | __forceinline bool CompareStrWith(const string& str) const;
|
| | |
|
2026-08-24 21:32:18 -05:00 | | | //-- to bytes (asume hex string)
|
2026-08-25 09:19:11 -05:00 | | | int HexToBytes(uchar& buf[]) const;
|
2026-08-24 16:40:07 -05:00 | | |
|
| | | //--- Is
|
2026-08-24 21:32:18 -05:00 | | | __forceinline bool IsValid() const { return RSPDATA_IS_VALID_F; }
|
| | | __forceinline bool IsInvalid() const { return !RSPDATA_IS_VALID_F; }
|
2026-08-24 16:40:07 -05:00 | | |
|
| | | //--- Meta
|
2026-08-24 21:32:18 -05:00 | | | __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; }
|
2026-08-24 16:40:07 -05:00 | | |
|
| | | //---
|
2026-08-25 08:02:51 -05:00 | | | template <typename TNumHashes, typename THashBase>
|
| | | TSN::CRSPIteratorHash<TNumHashes, THashBase> MakeHashIterator(const string& keys[]) const
|
| | | {
|
| | | if(RSPDATA_IS_NOT_VALID)
|
| | | return CRSPIteratorHash<TNumHashes, THashBase>::EMPTY;
|
| | | return CRSPIteratorHash<TNumHashes, THashBase>(keys, m_ctx, m_idx);
|
| | | }
|
2026-08-24 21:32:18 -05:00 | | |
|
2026-08-24 21:55:43 -05:00 | | | //---
|
| | | template <typename THashBase>
|
| | | CRSPIteradorBase* MakeInteligentIterador(const string& keys[]) const;
|
| | |
|
2026-08-24 21:32:18 -05:00 | | | //---
|
| | | static const CRSPNode EMPTY_NODE;
|
2026-08-25 08:02:51 -05:00 | | |
|
| | | //---
|
| | | bool MoveNextPositionsThis(const int posiciones);
|
| | | CRSPNode MoveNextPositions(const int posiciones) const;
|
2026-08-25 09:19:11 -05:00 | | |
|
| | | //---
|
| | | static bool BytesEq(const uchar& a[], const uchar& b[]);
|
2026-08-24 16:40:07 -05:00 | | | };
|
| | |
|
2026-08-24 21:32:18 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | const CRSPNode CRSPNode::EMPTY_NODE;
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | CRSPNode CRSPNode::operator[](const string& key)
|
| | | {
|
| | | //---
|
| | | if(RSPDATA_IS_NOT_VALID)
|
| | | return CRSPNode::EMPTY_NODE;
|
| | | //---
|
2026-08-24 22:33:45 -05:00 | | | int cur = 0;
|
2026-08-24 21:32:18 -05:00 | | | 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;
|
| | | //---
|
2026-08-24 22:33:45 -05:00 | | | int cur = 0;
|
2026-08-24 21:32:18 -05:00 | | | 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
|
| | |
|
| | | //---
|
2026-09-26 21:47:11 -05:00 | | | const int start = TSN_SBL_CNG_STR_START(m_idx);;
|
| | | int slen = TSN_SBL_CNG_STR_LEN(m_idx);
|
2026-08-24 21:32:18 -05:00 | | | //---
|
2026-09-26 21:47:11 -05:00 | | | RSPNODE_CORRECT_R_WSPACES
|
2026-08-24 21:32:18 -05:00 | | | //---
|
| | | 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
|
| | |
|
| | | //---
|
2026-09-26 21:47:11 -05:00 | | | const int start = TSN_SBL_CNG_STR_START(m_idx);;
|
| | | int slen = TSN_SBL_CNG_STR_LEN(m_idx);
|
2026-08-24 21:32:18 -05:00 | | |
|
| | | //---
|
2026-09-26 21:47:11 -05:00 | | | RSPNODE_CORRECT_R_WSPACES
|
2026-08-24 21:32:18 -05:00 | | | //---
|
| | | 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}
|
2026-08-25 09:19:11 -05:00 | | | int CRSPNode::HexToBytes(uchar &buf[]) const
|
2026-08-24 21:32:18 -05:00 | | | {
|
| | | 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
|
| | |
|
| | | //---
|
2026-09-26 21:47:11 -05:00 | | | const int start = TSN_SBL_CNG_STR_START(m_idx);;
|
| | | int slen = TSN_SBL_CNG_STR_LEN(m_idx);
|
2026-08-24 21:32:18 -05:00 | | |
|
| | | //---
|
2026-09-26 21:47:11 -05:00 | | | RSPNODE_CORRECT_R_WSPACES
|
2026-08-24 21:32:18 -05:00 | | |
|
| | | //---
|
2026-09-26 21:47:11 -05:00 | | | return CHexUtils::HexToBytes(m_ctx.m_raw, start, slen, buf);
|
2026-08-24 21:32:18 -05:00 | | | }
|
| | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-09-26 21:47:11 -05:00 | | | __forceinline int CRSPNode::StrLenRaw(void) const
|
2026-08-24 21:32:18 -05:00 | | | {
|
| | | if(RSPDATA_IS_NOT_VALID || (m_ctx.m_cinta[m_idx]&TSN_SBL_BIT_MASK_TYPE) != RSPDATA_TYPE_PLAIN_VALUE)
|
| | | return 0;
|
2026-09-26 21:47:11 -05:00 | | | return TSN_SBL_CNG_STR_LEN(m_idx);
|
2026-08-24 21:32:18 -05:00 | | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
2026-09-26 21:47:11 -05:00 | | | __forceinline int CRSPNode::StrStart(void) const
|
2026-08-24 21:32:18 -05:00 | | | {
|
| | | if(RSPDATA_IS_NOT_VALID || (m_ctx.m_cinta[m_idx]&TSN_SBL_BIT_MASK_TYPE) != RSPDATA_TYPE_PLAIN_VALUE)
|
2026-09-26 21:47:11 -05:00 | | | return 0;
|
| | | return TSN_SBL_CNG_STR_START(m_idx);
|
2026-08-24 21:32:18 -05:00 | | | }
|
| | |
|
2026-08-25 08:02:51 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | 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);
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-08-25 09:19:11 -05:00 | | | 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;
|
| | | }
|
2026-08-24 16:40:07 -05:00 | | |
|
2026-08-24 22:33:45 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-08-24 22:42:17 -05:00 | | | CRSPNode CRSPParser::GetRoot(void)
|
2026-08-24 22:33:45 -05:00 | | | {
|
| | | if(m_cinta_pos == 0)
|
| | | return CRSPNode::EMPTY_NODE;
|
| | | return CRSPNode(0, &this);
|
| | | }
|
2026-08-24 16:40:07 -05:00 | | | }
|
| | | #endif // CRYPTOBYLEO_RSPPARSER_NODE_MQH
|