| //+------------------------------------------------------------------+
|
| //| JsonDomSerializer.mqh |
|
| //| Copyright 2026, MetaQuotes Ltd. |
|
| //| https://www.mql5.com |
|
| //+------------------------------------------------------------------+
|
| #property copyright "Copyright 2026, Niquel Mendoza."
|
| #property link "https://www.mql5.com"
|
| #property strict
|
|
|
| #ifndef JSONPARSERBYLEO_SRC_DOM_JSONDOMSERIALIZER_MQH
|
| #define JSONPARSERBYLEO_SRC_DOM_JSONDOMSERIALIZER_MQH
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| #include "..\\Ser\\JsonEscape.mqh"
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| namespace TSN
|
| {
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| #define JSDOMBASE_DOMSER_EMPTY (TSN_SBL_BASE_DOM_NULL+1)
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| class CJsonDomSerializer
|
| {
|
| public:
|
| //---
|
| uchar m_buf[];
|
| int m_buf_s;
|
| int m_buf_r;
|
|
|
| private:
|
| //---
|
| uchar m_dbl_reserve;
|
| uchar m_digits;
|
|
|
| //-- stacks
|
| CHashMapFastIterator(string, CDomNodeBase*) m_stack_it_obj[JSONPARSERBYLEO_MAX_STACK];
|
| int m_stack_count[JSONPARSERBYLEO_MAX_STACK];
|
| int m_stack_ix[JSONPARSERBYLEO_MAX_STACK];
|
| int m_stack_k[JSONPARSERBYLEO_MAX_STACK];
|
| int m_stack_it_obj_curr;
|
|
|
| public:
|
| CJsonDomSerializer(void);
|
| ~CJsonDomSerializer(void) {}
|
|
|
| //---
|
| void Digitos(uchar v);
|
| __forceinline uchar Digitos() const { return m_digits; }
|
|
|
| //---
|
| bool Serialize(CDomNodeBase* v);
|
| };
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| CJsonDomSerializer::CJsonDomSerializer()
|
| : m_buf_s(0), m_buf_r(4096), m_dbl_reserve(MQLARTICLES_CONV_MAXDIG_DBL(8)), m_digits(8), m_stack_it_obj_curr(0)
|
| {
|
| ArrayResize(m_buf, m_buf_r, m_buf_r);
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| #define DOMMANAGERCHEKCAP_JSON(N) \
|
| if(m_buf_s + (N) >= m_buf_r) \
|
| { \
|
| m_buf_r = (m_buf_s + (N)) << 1; \
|
| ArrayResize(m_buf, m_buf_r, m_buf_r); \
|
| }
|
|
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| void CJsonDomSerializer::Digitos(uchar v)
|
| {
|
| m_digits = v;
|
| m_dbl_reserve = MQLARTICLES_CONV_MAXDIG_DBL(v);
|
| }
|
|
|
| //+------------------------------------------------------------------+
|
| //| |
|
| //+------------------------------------------------------------------+
|
| bool CJsonDomSerializer::Serialize(CDomNodeBase* v)
|
| {
|
| //---
|
| uchar next = v.m_type;
|
| m_stack_it_obj_curr = -1;
|
| m_buf_s = 0;
|
|
|
| //---
|
| while(true)
|
| {
|
| switch(next)
|
| {
|
| // case 0: nuevas updates esto ya no existe no hay el tipo key este diremctne vive en el hashmap
|
| // break; // Sale noma..
|
| case TSN_SBL_BASE_TYPE_ARR:
|
| {
|
| //---
|
| m_stack_it_obj_curr++;
|
| m_stack_ix[m_stack_it_obj_curr] = v.m_v.ix;
|
| m_stack_count[m_stack_it_obj_curr] = v.Size();
|
| m_stack_k[m_stack_it_obj_curr] = 0;
|
|
|
| //---
|
| DOMMANAGERCHEKCAP_JSON(1)
|
| m_buf[m_buf_s++] = '[';
|
| break;
|
| }
|
| case TSN_SBL_BASE_TYPE_OBJ:
|
| {
|
| //---
|
| m_stack_it_obj_curr++;
|
| m_stack_it_obj[m_stack_it_obj_curr] = v.HashMap().BeginIteration();
|
| m_stack_ix[m_stack_it_obj_curr] = -1; // no usar
|
| m_stack_k[m_stack_it_obj_curr] = 0;
|
|
|
| //---
|
| DOMMANAGERCHEKCAP_JSON(1)
|
| m_buf[m_buf_s++] = '{';
|
| break;
|
| }
|
| case TSN_SBL_BASE_TYPE_UINT:
|
| {
|
| //---
|
| DOMMANAGERCHEKCAP_JSON(MQLARTICLES_CONV_MAXDIG_UL)
|
| STRCONV_VALTOBUFFER_USIGNED(v.m_v.uv, m_buf, m_buf_s)
|
|
|
| //---
|
| break;
|
| }
|
| case TSN_SBL_BASE_TYPE_INT:
|
| {
|
| //---
|
| DOMMANAGERCHEKCAP_JSON(MQLARTICLES_CONV_MAXDIG_L)
|
| STRCONV_VALTOBUFFER_SIGNED(v.m_v.iv, m_buf, m_buf_s, ulong, uvalue)
|
|
|
| //---
|
| break;
|
| }
|
| case TSN_SBL_BASE_TYPE_FLT:
|
| {
|
| //---
|
| DOMMANAGERCHEKCAP_JSON(m_dbl_reserve)
|
|
|
| //---
|
| if(!MathIsValidNumber(v.m_v.dv))
|
| {
|
| m_buf[m_buf_s++] = 'n';
|
| m_buf[m_buf_s++] = 'u';
|
| m_buf[m_buf_s++] = 'l';
|
| m_buf[m_buf_s++] = 'l';
|
| break; // Salimos..
|
| }
|
|
|
| //---
|
| CValueToBuffer::ToValue(v.m_v.dv, m_buf, m_buf_s, m_digits);
|
|
|
| //---
|
| break;
|
| }
|
| case TSN_SBL_BASE_TYPE_BOL:
|
| {
|
| DOMMANAGERCHEKCAP_JSON(7)
|
| if(v.m_v.bv)
|
| {
|
| m_buf[m_buf_s++] = 't';
|
| m_buf[m_buf_s++] = 'r';
|
| m_buf[m_buf_s++] = 'u';
|
| m_buf[m_buf_s++] = 'e';
|
| }
|
| else
|
| {
|
| m_buf[m_buf_s++] = 'f';
|
| m_buf[m_buf_s++] = 'a';
|
| m_buf[m_buf_s++] = 'l';
|
| m_buf[m_buf_s++] = 's';
|
| m_buf[m_buf_s++] = 'e';
|
| }
|
| break;
|
| }
|
| case TSN_SBL_BASE_TYPE_STR:
|
| {
|
| //---
|
| const int i = v.m_v.ix;
|
| const int l = StringLen(v.m_ctx.m_string_stack[i]);
|
| const int r = JSONESCAPE_CR_ENCODE(l) + 2;
|
| DOMMANAGERCHEKCAP_JSON(r)
|
|
|
| //---
|
| m_buf[m_buf_s++] = '"';
|
| CJsonEscape::Encode(v.m_ctx.m_string_stack[i], 0, l, m_buf, m_buf_s);
|
| m_buf[m_buf_s++] = '"';
|
|
|
| //---
|
| break;
|
| }
|
| case TSN_SBL_BASE_DOM_NULL:
|
| {
|
| DOMMANAGERCHEKCAP_JSON(6)
|
| m_buf[m_buf_s++] = 'n';
|
| m_buf[m_buf_s++] = 'u';
|
| m_buf[m_buf_s++] = 'l';
|
| m_buf[m_buf_s++] = 'l';
|
| break;
|
| }
|
| case JSDOMBASE_DOMSER_EMPTY:
|
| break;
|
| default:
|
| return false;
|
| }
|
|
|
| //----
|
| if(m_stack_ix[m_stack_it_obj_curr] == -1)
|
| {
|
| if(m_stack_it_obj[m_stack_it_obj_curr].IsValid())
|
| {
|
| if(m_stack_k[m_stack_it_obj_curr] > 0)
|
| m_buf[m_buf_s++] = ',';
|
|
|
| //--- Key
|
| static string out;
|
| m_stack_it_obj[m_stack_it_obj_curr].Key(out);
|
|
|
| //---
|
| const int l = StringLen(out);
|
| const int r = JSONESCAPE_CR_ENCODE(l) + 3;
|
| DOMMANAGERCHEKCAP_JSON(r)
|
|
|
| //--- Escape
|
| m_buf[m_buf_s++] = '"';
|
| CJsonEscape::Encode(out, 0, l, m_buf, m_buf_s);
|
| m_buf[m_buf_s++] = '"';
|
| m_buf[m_buf_s++] = ':';
|
|
|
| //--- Value
|
| v = m_stack_it_obj[m_stack_it_obj_curr].Val(); // assing..
|
| m_stack_it_obj[m_stack_it_obj_curr].Next();
|
| next = v.m_type;
|
|
|
| //---
|
| m_stack_k[m_stack_it_obj_curr]++;
|
| continue;
|
| }
|
|
|
| //---
|
| // Ya no..
|
| DOMMANAGERCHEKCAP_JSON(2)
|
| m_buf[m_buf_s++] = '}';
|
| }
|
| else
|
| {
|
| if(m_stack_k[m_stack_it_obj_curr] < m_stack_count[m_stack_it_obj_curr])
|
| {
|
| //---
|
| if(m_stack_k[m_stack_it_obj_curr] > 0)
|
| m_buf[m_buf_s++] = ',';
|
|
|
| //--- Avanzamos..
|
| v = v.m_ctx.m_node[m_stack_ix[m_stack_it_obj_curr]].values[m_stack_k[m_stack_it_obj_curr]++]; // assing..
|
| next = v.m_type;
|
| continue;
|
| }
|
|
|
| //---
|
| // Ya no ...
|
| DOMMANAGERCHEKCAP_JSON(2)
|
| m_buf[m_buf_s++] = ']';
|
| }
|
|
|
| //---
|
| m_stack_it_obj_curr--; // Baja
|
| if(m_stack_it_obj_curr < 0)
|
| return true;
|
|
|
| //---
|
| next = JSDOMBASE_DOMSER_EMPTY; // break y vuleve a evaluar denbuvo...
|
| }
|
|
|
| //---
|
| return false;
|
| }
|
| }
|
| //+------------------------------------------------------------------+
|
| #endif // JSONPARSERBYLEO_SRC_DOM_JSONDOMSERIALIZER_MQH
|