//+------------------------------------------------------------------+ //| JsonBuilder.mqh | //| Copyright 2026, Niquel Mendoza. | //| https://www.mql5.com/ | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, Niquel Mendoza." #property link "https://www.mql5.com/" #property strict #ifndef JSONPARSERBYLEO_SRC_DOM_JSONBUILDER_MQH #define JSONPARSERBYLEO_SRC_DOM_JSONBUILDER_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "BuilderDefs.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ namespace TSN { //+------------------------------------------------------------------+ //| Macros | //+------------------------------------------------------------------+ #define JSONBUILDER_CHECK_PUT_ENCODE_STR(str, needed) \ const int l = StringLen(str); \ const int ex = JSONESCAPE_CR_ENCODE(l) + (needed); \ JSONBUILDER_EXPAND_E(ex) //+------------------------------------------------------------------+ #define JSONBUILDER_CHECK_PUT_ENCODE_STRU(arr, needed) \ if(count==WHOLE_ARRAY) \ count= ArraySize(arr); \ const int ex = JSONESCAPE_CR_ENCODE(count) + (needed); \ JSONBUILDER_EXPAND_E(ex) //+------------------------------------------------------------------+ #define JSONBUILDER_GENERIC_VALS(READ, L) \ JSON_BUILDER_COMMA_F \ m_buf[m_pos++] = '"'; \ CJsonEscape::Encode(v, READ, L, m_buf, m_pos); \ m_buf[m_pos++] = '"'; \ //+------------------------------------------------------------------+ #define JSONBUILDER_GENERIC_VALSTR_WVER \ JSONBUILDER_EXPAND_E(2) \ JSON_BUILDER_COMMA_F \ m_buf[m_pos++] = '"'; \ PutRaw(v); \ JSONBUILDER_EXPAND_E(1) \ m_buf[m_pos++] = '"'; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CJsonBuilder : public CJsonBuilderBase { public: CJsonBuilder(int initial_cap = 1024) : CJsonBuilderBase(initial_cap) {} ~CJsonBuilder() {} //--- Key / Values CJsonBuilder* Key(const string& k); CJsonBuilder* KeyWV(const string& k); // String- Con validacion CJsonBuilder* ValS(const string& v); CJsonBuilder* ValU(const uchar& v[], int read_i = 0, int count = WHOLE_ARRAY); CJsonBuilder* ValSNoRef(const string v); // String- Sin validacion (witohut validation WV) CJsonBuilder* ValSWV(const string& v); CJsonBuilder* ValUWV(const uchar& v[], int count = WHOLE_ARRAY); // buffer fijo sobredimensionado (ej. CStringFixed): solo copia count bytes CJsonBuilder* ValSNoRefWV(const string v); // Valor using CJsonBuilderBase::Val; bool Val(CJsonNode& node); // Valid json CJsonBuilder* ValidJson(const uchar& v[], int count = WHOLE_ARRAY); CJsonBuilder* ValidJson(const string& fragment); CJsonBuilder* ValidJsonNoRef(const string fragment); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CJsonBuilder::Val(CJsonNode& node) { switch(node.GetType()) { case JSON_VTYPE_UINTEGER: { ulong v; if(!node.ToUIntSafe(v)) return false; Val(v); break; } case JSON_VTYPE_INTEGER: { long v; if(!node.ToIntSafe(v)) return false; Val(v); break; } case JSON_VTYPE_REAL: { const double v = node.ToDouble(double("inf")); if(v == double("inf")) return false; Val(v); break; } case JSON_VTYPE_BOOLEAN: { bool v; if(!node.ToBoolSafe(v)) return false; Val(v); break; } case JSON_VTYPE_STRING: { const int start = node.StrStart(); const int len = node.StrLenRaw(); ValU(node.m_ctx.m_raw, start, len); break; } case JSON_VTYPE_NULL: { Null(); break; } default: return false; } return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CJsonBuilder* CJsonBuilder::Key(const string& k) { //--- JSONBUILDER_CHECK_PUT_ENCODE_STR(k, 4) //--- JSON_BUILDER_COMMA_F m_buf[m_pos++] = '"'; CJsonEscape::Encode(k, 0, l, m_buf, m_pos); m_buf[m_pos++] = '"'; m_buf[m_pos++] = ':'; //--- m_stack_first[m_sp] = true; return &this; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CJsonBuilder* CJsonBuilder::ValU(const uchar &v[], int read_i, int count) { JSONBUILDER_CHECK_PUT_ENCODE_STRU(v, 3) JSONBUILDER_GENERIC_VALS(read_i, count) return &this; } //+------------------------------------------------------------------+ CJsonBuilder* CJsonBuilder::ValS(const string& v) { JSONBUILDER_CHECK_PUT_ENCODE_STR(v, 3) JSONBUILDER_GENERIC_VALS(0, l) return &this; } //+------------------------------------------------------------------+ CJsonBuilder* CJsonBuilder::ValSNoRef(const string v) { JSONBUILDER_CHECK_PUT_ENCODE_STR(v, 3) JSONBUILDER_GENERIC_VALS(0, l) return &this; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // WV en key solo acepta ASCCI puro no caracteres de control (no espca) menos emojis (tipico en keys harcodeadas) // Si reuiqer full use la version completa CJsonBuilder* CJsonBuilder::KeyWV(const string &k) { //--- const int l = StringLen(k); const int req = l + 4; JSONBUILDER_EXPAND_E(req) //--- JSON_BUILDER_COMMA_F m_buf[m_pos++] = '"'; //--- for(int i = 0; i < l; i++) m_buf[m_pos++] = (uchar)k[i]; //-- m_buf[m_pos++] = '"'; m_buf[m_pos++] = ':'; //--- m_stack_first[m_sp] = true; return &this; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // WV aqui implcia no escape pero UTF si se soporta (en string en uchar NO) CJsonBuilder* CJsonBuilder::ValSWV(const string& v) { JSONBUILDER_GENERIC_VALSTR_WVER return &this; } //+------------------------------------------------------------------+ CJsonBuilder* CJsonBuilder::ValSNoRefWV(const string v) { JSONBUILDER_GENERIC_VALSTR_WVER return &this; } //+------------------------------------------------------------------+ CJsonBuilder* CJsonBuilder::ValUWV(const uchar &v[], int count) { //--- JSONBUILDER_EXPAND_E(2) JSON_BUILDER_COMMA_F m_buf[m_pos++] = '"'; PutRaw(v, count); JSONBUILDER_EXPAND_E(1) m_buf[m_pos++] = '"'; return &this; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CJsonBuilder* CJsonBuilder::ValidJson(const uchar& v[], int count = WHOLE_ARRAY) { JSON_BUILDER_COMMA PutRaw(v, count); return &this; } //+------------------------------------------------------------------+ CJsonBuilder* CJsonBuilder::ValidJson(const string& fragment) { JSON_BUILDER_COMMA PutRaw(fragment); return &this; } //+------------------------------------------------------------------+ CJsonBuilder* CJsonBuilder::ValidJsonNoRef(const string fragment) { JSON_BUILDER_COMMA PutRaw(fragment); return &this; } //--- //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // Nota deje esto pero tengan cuidado con esto... dado que no hay garantias de uso lo puse mas que todo para evitar tener que instancia un segundo builder // ahora el uso adecuado es digmoas en una funcion usarlo todo de golpe (sin llamar a funciones intermedias o aseguramente que esa funcion intermedia no lo llame) y listo // osea uso y desecho... algo asi... no tatno como "si fuera mio" si requieres cache o algo asi.. lo mejors es tener miembro CJsonBuilder... CJsonBuilder g_json_builder; } // namespace TSN //+------------------------------------------------------------------+ #endif // JSONPARSERBYLEO_SRC_DOM_JSONBUILDER_MQH