2026-06-02 21:23:50 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| JsonNode.mqh |
|
|
|
|
|
//| Copyright 2026, Niquel Mendoza. |
|
|
|
|
|
//| https://www.mql5.com/ |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#property copyright "Copyright 2026, Niquel Mendoza."
|
|
|
|
|
#property link "https://www.mql5.com/"
|
|
|
|
|
#property strict
|
|
|
|
|
|
2026-06-02 22:52:39 -05:00
|
|
|
#ifndef JSONPARSERBYLEO_SRC_JSONNODE_MQH
|
|
|
|
|
#define JSONPARSERBYLEO_SRC_JSONNODE_MQH
|
|
|
|
|
|
2026-06-02 21:23:50 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#include "JsonParser.mqh"
|
2026-06-03 14:16:03 -05:00
|
|
|
#include "JsonBuilder.mqh"
|
2026-06-02 21:23:50 -05:00
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
namespace TSN
|
|
|
|
|
{
|
2026-06-02 22:52:39 -05:00
|
|
|
|
|
|
|
|
// Layout cinta:
|
|
|
|
|
// KEY 2 pos [tipo(8)|hash(32high)] [end(32low)|start(32high)]
|
|
|
|
|
// STRING 2 pos [tipo(8)] [end(32low)|start(32high)]
|
|
|
|
|
// INTEGER 2 pos [tipo(8)] [valor_long]
|
|
|
|
|
// REAL 2 pos [tipo(8)] [valor_long (bits double)]
|
|
|
|
|
// BOOLEAN 1 pos [tipo(8)|val(v)<<8]
|
|
|
|
|
// NULL 1 pos [tipo(8)]
|
2026-06-03 12:20:23 -05:00
|
|
|
// ARR 2 pos [tipo(8)|count(24)|end_abs(32high)] [start(32low)|end(32high)] // To string
|
|
|
|
|
// OBJ 2 pos [tipo(8)|count(24)|end_abs(32high)] [start(32low)|end(32high)] // To string
|
2026-06-02 22:52:39 -05:00
|
|
|
|
2026-06-02 21:23:50 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-06-02 22:52:39 -05:00
|
|
|
#define JSON_NODE_IS_NOT_VALID (m_ctx == NULL || m_idx == -1 || m_end == -1)
|
|
|
|
|
|
|
|
|
|
struct CJsonIteratorArray;
|
|
|
|
|
struct CJsonIteratorObj;
|
2026-06-02 21:23:50 -05:00
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
struct CJsonNode
|
|
|
|
|
{
|
2026-06-02 22:52:39 -05:00
|
|
|
public:
|
2026-06-02 21:23:50 -05:00
|
|
|
CJsonParser* m_ctx;
|
|
|
|
|
int m_idx;
|
|
|
|
|
int m_end;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
CJsonNode()
|
|
|
|
|
: m_ctx(NULL), m_idx(-1), m_end(-1) {}
|
|
|
|
|
//---
|
|
|
|
|
CJsonNode(CJsonParser* _ctx, const int _idx, const int _end)
|
|
|
|
|
: m_ctx(_ctx), m_idx(_idx), m_end(_end) {}
|
|
|
|
|
|
2026-06-02 22:52:39 -05:00
|
|
|
//--- Acceso
|
|
|
|
|
CJsonNode operator[](const string& key) const;
|
|
|
|
|
CJsonNode At(const int index) const;
|
|
|
|
|
CJsonNode AtHomegeneo(const int index) const;
|
|
|
|
|
|
|
|
|
|
//--- Key de objeto por indice
|
|
|
|
|
string AtObjKey(const int index) const;
|
|
|
|
|
string AtObjKeyHomogeneo(const int index) const;
|
|
|
|
|
|
2026-06-03 18:53:05 -05:00
|
|
|
//---
|
|
|
|
|
__forceinline bool HasKey(const string& key) const { return this[key].IsValid(); }
|
|
|
|
|
|
2026-06-02 22:52:39 -05:00
|
|
|
//--- To
|
|
|
|
|
string ToString(const string def = "") const;
|
2026-06-03 16:57:42 -05:00
|
|
|
int ToStringUArray(uchar& data[]) const;
|
2026-06-02 22:52:39 -05:00
|
|
|
long ToInt(const long def) const;
|
|
|
|
|
bool ToIntSafe(long& val) const;
|
|
|
|
|
double ToDouble(const double def) const;
|
|
|
|
|
bool ToDoubleSafe(double& val) const;
|
|
|
|
|
__forceinline bool ToBool(const bool def) const;
|
|
|
|
|
bool ToBoolSafe(bool& val) const;
|
|
|
|
|
|
2026-06-03 12:20:23 -05:00
|
|
|
//---
|
2026-06-03 16:57:42 -05:00
|
|
|
string ComplexToString() const;
|
|
|
|
|
int ComplexToData(uchar& data[]) const;
|
2026-06-03 12:20:23 -05:00
|
|
|
|
2026-06-02 22:52:39 -05:00
|
|
|
//--- Set (mutacion in-place, solo mismo tipo)
|
|
|
|
|
bool SetInt(const long val);
|
|
|
|
|
bool SetDbl(const double val);
|
|
|
|
|
bool SetBool(const bool val);
|
2026-06-02 21:23:50 -05:00
|
|
|
|
2026-06-02 22:52:39 -05:00
|
|
|
//--- Tipo
|
|
|
|
|
__forceinline ENUM_JSON_VTYPE GetType() const { return ENUM_JSON_VTYPE(m_ctx.m_cinta[m_idx] & 0xFF); }
|
2026-06-02 21:23:50 -05:00
|
|
|
|
2026-06-02 22:52:39 -05:00
|
|
|
//--- Is
|
|
|
|
|
__forceinline bool IsValid() const;
|
|
|
|
|
__forceinline bool IsNull() const;
|
|
|
|
|
__forceinline bool IsArray() const;
|
|
|
|
|
__forceinline bool IsObject() const;
|
|
|
|
|
|
|
|
|
|
//--- Size (arr u obj)
|
|
|
|
|
int Size() const;
|
|
|
|
|
|
|
|
|
|
//--- Iteradores
|
|
|
|
|
CJsonIteratorArray BeginArr() const;
|
|
|
|
|
CJsonIteratorObj BeginObj() const;
|
|
|
|
|
|
|
|
|
|
//--- Navegacion raw
|
|
|
|
|
bool MoveToNextToken(const bool solo_en_el_bloque_actual = true);
|
|
|
|
|
CJsonNode MoveNextPositions(const int posiciones, const bool solo_en_el_bloque_actual = true);
|
|
|
|
|
bool MoveNextPositionsThis(const int posiciones, const bool solo_en_el_bloque_actual = true);
|
2026-06-02 21:23:50 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const CJsonNode EMPTY_JSON_NODE;
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-06-03 07:50:45 -05:00
|
|
|
//| |
|
2026-06-02 21:23:50 -05:00
|
|
|
//+------------------------------------------------------------------+
|
2026-06-03 16:57:42 -05:00
|
|
|
string CJsonNode::ComplexToString(void) const
|
2026-06-03 12:20:23 -05:00
|
|
|
{
|
|
|
|
|
const int t = int(m_ctx.m_cinta[m_idx] & 0xFF);
|
2026-06-03 15:48:09 -05:00
|
|
|
if(t != JSON_VTYPE_OBJ && t != JSON_VTYPE_ARR)
|
2026-06-03 12:20:23 -05:00
|
|
|
return "";
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const int start = int(m_ctx.m_cinta[m_idx + 1] & 0xFFFFFFFF);
|
|
|
|
|
const int end = int(m_ctx.m_cinta[m_idx + 1] >> TSN_JSON_BIT_END_T);
|
|
|
|
|
return CharArrayToString(m_ctx.m_json, start, (end - start) + 1);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-03 16:57:42 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
int CJsonNode::ComplexToData(uchar &data[]) const
|
|
|
|
|
{
|
|
|
|
|
const int t = int(m_ctx.m_cinta[m_idx] & 0xFF);
|
|
|
|
|
if(t != JSON_VTYPE_OBJ && t != JSON_VTYPE_ARR)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const int start = int(m_ctx.m_cinta[m_idx + 1] & 0xFFFFFFFF);
|
|
|
|
|
const int end = int(m_ctx.m_cinta[m_idx + 1] >> TSN_JSON_BIT_END_T);
|
|
|
|
|
return ArrayCopy(data, m_ctx.m_json, start, 0, (end - start) + 1);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-03 12:20:23 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-06-02 21:23:50 -05:00
|
|
|
CJsonNode CJsonNode::operator[](const string& key) const
|
|
|
|
|
{
|
2026-06-02 22:52:39 -05:00
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return EMPTY_JSON_NODE;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(int(m_ctx.m_cinta[m_idx] & 0xFF) != JSON_VTYPE_OBJ)
|
|
|
|
|
return EMPTY_JSON_NODE;
|
|
|
|
|
|
|
|
|
|
//--- Hash FNV-1a de la key buscada
|
|
|
|
|
const int len = StringLen(key);
|
|
|
|
|
uint hash = 2166136261;
|
|
|
|
|
for(int k = 0; k < len; k++)
|
|
|
|
|
{
|
|
|
|
|
hash ^= (uint)key[k];
|
|
|
|
|
hash *= 16777619;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--- Iterar pares KEY+VAL
|
2026-06-03 15:48:09 -05:00
|
|
|
int cur = m_idx + 2;
|
2026-06-02 22:52:39 -05:00
|
|
|
while(cur < m_end)
|
|
|
|
|
{
|
|
|
|
|
if(int(m_ctx.m_cinta[cur] & 0xFF) != JSON_VTYPE_KEY)
|
|
|
|
|
{
|
|
|
|
|
cur += m_ctx.GetStep(cur);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if(uint(m_ctx.m_cinta[cur] >> TSN_JSON_BIT_STR_START_HASH) == hash)
|
|
|
|
|
{
|
|
|
|
|
const int val_pos = cur + 2;
|
|
|
|
|
return CJsonNode(m_ctx, val_pos, val_pos + m_ctx.GetStep(val_pos));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cur += 2; // salta KEY
|
|
|
|
|
cur += m_ctx.GetStep(cur); // salta VAL
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return EMPTY_JSON_NODE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| At — acceso por indice en ARR |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
CJsonNode CJsonNode::At(const int index) const
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return EMPTY_JSON_NODE;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(int(m_ctx.m_cinta[m_idx] & 0xFF) != JSON_VTYPE_ARR)
|
|
|
|
|
return EMPTY_JSON_NODE;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const int count = int((m_ctx.m_cinta[m_idx] >> TSN_JSON_BIT_START_ENDTYPE) & 0xFFFFFF);
|
|
|
|
|
if(index < 0 || index >= count)
|
|
|
|
|
return EMPTY_JSON_NODE;
|
|
|
|
|
|
|
|
|
|
//---
|
2026-06-03 15:48:09 -05:00
|
|
|
int cur = m_idx + 2;
|
2026-06-02 22:52:39 -05:00
|
|
|
for(int k = 0; k < index; k++)
|
|
|
|
|
cur += m_ctx.GetStep(cur);
|
|
|
|
|
|
|
|
|
|
return CJsonNode(m_ctx, cur, cur + m_ctx.GetStep(cur));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| AtHomegeneo — acceso por indice en ARR con step fijo |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
CJsonNode CJsonNode::AtHomegeneo(const int index) const
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return EMPTY_JSON_NODE;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(int(m_ctx.m_cinta[m_idx] & 0xFF) != JSON_VTYPE_ARR)
|
|
|
|
|
return EMPTY_JSON_NODE;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const int count = int((m_ctx.m_cinta[m_idx] >> TSN_JSON_BIT_START_ENDTYPE) & 0xFFFFFF);
|
|
|
|
|
if(index < 0 || index >= count)
|
|
|
|
|
return EMPTY_JSON_NODE;
|
|
|
|
|
|
|
|
|
|
//---
|
2026-06-03 15:48:09 -05:00
|
|
|
const int first = m_idx + 2;
|
|
|
|
|
const int step = m_ctx.GetStep(first);
|
|
|
|
|
const int cur = first + index * step;
|
2026-06-02 22:52:39 -05:00
|
|
|
return CJsonNode(m_ctx, cur, cur + step);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| AtObjKey — key string del par en posicion index dentro de OBJ |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
string CJsonNode::AtObjKey(const int index) const
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(int(m_ctx.m_cinta[m_idx] & 0xFF) != JSON_VTYPE_OBJ)
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const int count = int((m_ctx.m_cinta[m_idx] >> TSN_JSON_BIT_START_ENDTYPE) & 0xFFFFFF);
|
|
|
|
|
if(index < 0 || index >= count)
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
|
|
//---
|
2026-06-03 15:48:09 -05:00
|
|
|
int cur = m_idx + 2;
|
2026-06-02 22:52:39 -05:00
|
|
|
for(int k = 0; k < index; k++)
|
|
|
|
|
{
|
|
|
|
|
cur += 2; // salta KEY
|
|
|
|
|
cur += m_ctx.GetStep(cur); // salta VAL
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
// cur apunta al long[0] de KEY, avanzamos al long[1] (start/end)
|
|
|
|
|
const int start = int(m_ctx.m_cinta[cur + 1] >> TSN_JSON_BIT_STR_START_END);
|
|
|
|
|
const int end = int(m_ctx.m_cinta[cur + 1] & 0xFFFFFFFF);
|
|
|
|
|
return CharArrayToString(m_ctx.m_json, start, (end - start) + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| AtObjKeyHomogeneo — igual pero asume step fijo del VAL |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
string CJsonNode::AtObjKeyHomogeneo(const int index) const
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(int(m_ctx.m_cinta[m_idx] & 0xFF) != JSON_VTYPE_OBJ)
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const int count = int((m_ctx.m_cinta[m_idx] >> TSN_JSON_BIT_START_ENDTYPE) & 0xFFFFFF);
|
|
|
|
|
if(index < 0 || index >= count)
|
|
|
|
|
return "";
|
|
|
|
|
|
|
|
|
|
//--- step fijo = 2(KEY) + step(primer VAL)
|
2026-06-03 15:48:09 -05:00
|
|
|
// [OBJ][OPBJ][KEY][KEY][VAL]
|
2026-06-03 16:57:42 -05:00
|
|
|
// 10 11 12 13 14
|
|
|
|
|
const int first_val = m_idx + 4;
|
2026-06-02 22:52:39 -05:00
|
|
|
const int val_step = m_ctx.GetStep(first_val);
|
|
|
|
|
const int pair_step = 2 + val_step;
|
2026-06-03 15:48:09 -05:00
|
|
|
const int key_pos = (m_idx + 2) + index * pair_step;
|
2026-06-02 22:52:39 -05:00
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const int start = int(m_ctx.m_cinta[key_pos + 1] >> TSN_JSON_BIT_STR_START_END);
|
|
|
|
|
const int end = int(m_ctx.m_cinta[key_pos + 1] & 0xFFFFFFFF);
|
|
|
|
|
return CharArrayToString(m_ctx.m_json, start, (end - start) + 1);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-03 16:57:42 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
int CJsonNode::ToStringUArray(uchar &data[]) const
|
|
|
|
|
{
|
|
|
|
|
const int start = int(m_ctx.m_cinta[m_idx + 1] >> TSN_JSON_BIT_STR_START_END);
|
|
|
|
|
const int end = int(m_ctx.m_cinta[m_idx + 1] & 0xFFFFFFFF);
|
|
|
|
|
return m_ctx.Unescape(start, end, data);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-02 22:52:39 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| ToString |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
string CJsonNode::ToString(const string def = "") const
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
switch(int(m_ctx.m_cinta[m_idx] & 0xFF))
|
|
|
|
|
{
|
|
|
|
|
case JSON_VTYPE_INTEGER:
|
|
|
|
|
return string(m_ctx.m_cinta[m_idx + 1]);
|
|
|
|
|
case JSON_VTYPE_REAL:
|
|
|
|
|
{
|
|
|
|
|
static BitInterpreter un;
|
|
|
|
|
un.long_value = m_ctx.m_cinta[m_idx + 1];
|
|
|
|
|
return string(un.double_value);
|
|
|
|
|
}
|
|
|
|
|
case JSON_VTYPE_BOOLEAN:
|
|
|
|
|
return ((m_ctx.m_cinta[m_idx] >> TSN_JSON_BIT_START_ENDTYPE) & 1) != 0 ? "true" : "false";
|
|
|
|
|
case JSON_VTYPE_STRING:
|
|
|
|
|
{
|
|
|
|
|
const int start = int(m_ctx.m_cinta[m_idx + 1] >> TSN_JSON_BIT_STR_START_END);
|
|
|
|
|
const int end = int(m_ctx.m_cinta[m_idx + 1] & 0xFFFFFFFF);
|
|
|
|
|
return m_ctx.Unescape(start, end);
|
|
|
|
|
}
|
|
|
|
|
case JSON_VTYPE_NULL:
|
|
|
|
|
return def;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| ToInt |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
long CJsonNode::ToInt(const long def) const
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
switch(int(m_ctx.m_cinta[m_idx] & 0xFF))
|
|
|
|
|
{
|
|
|
|
|
case JSON_VTYPE_INTEGER:
|
|
|
|
|
return m_ctx.m_cinta[m_idx + 1];
|
|
|
|
|
case JSON_VTYPE_REAL:
|
|
|
|
|
{
|
|
|
|
|
static BitInterpreter un;
|
|
|
|
|
un.long_value = m_ctx.m_cinta[m_idx + 1];
|
|
|
|
|
return long(un.double_value);
|
|
|
|
|
}
|
|
|
|
|
case JSON_VTYPE_BOOLEAN:
|
|
|
|
|
return long((m_ctx.m_cinta[m_idx] >> TSN_JSON_BIT_START_ENDTYPE) & 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CJsonNode::ToIntSafe(long& val) const
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
switch(int(m_ctx.m_cinta[m_idx] & 0xFF))
|
|
|
|
|
{
|
|
|
|
|
case JSON_VTYPE_INTEGER:
|
|
|
|
|
val = m_ctx.m_cinta[m_idx + 1];
|
|
|
|
|
return true;
|
|
|
|
|
case JSON_VTYPE_REAL:
|
|
|
|
|
{
|
|
|
|
|
static BitInterpreter un;
|
|
|
|
|
un.long_value = m_ctx.m_cinta[m_idx + 1];
|
|
|
|
|
val = long(un.double_value);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case JSON_VTYPE_BOOLEAN:
|
|
|
|
|
val = long((m_ctx.m_cinta[m_idx] >> TSN_JSON_BIT_START_ENDTYPE) & 1);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| ToDouble |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
double CJsonNode::ToDouble(const double def) const
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
switch(int(m_ctx.m_cinta[m_idx] & 0xFF))
|
|
|
|
|
{
|
|
|
|
|
case JSON_VTYPE_INTEGER:
|
|
|
|
|
return double(m_ctx.m_cinta[m_idx + 1]);
|
|
|
|
|
case JSON_VTYPE_REAL:
|
|
|
|
|
{
|
|
|
|
|
static BitInterpreter un;
|
|
|
|
|
un.long_value = m_ctx.m_cinta[m_idx + 1];
|
|
|
|
|
return un.double_value;
|
|
|
|
|
}
|
|
|
|
|
case JSON_VTYPE_BOOLEAN:
|
|
|
|
|
return double((m_ctx.m_cinta[m_idx] >> TSN_JSON_BIT_START_ENDTYPE) & 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CJsonNode::ToDoubleSafe(double& val) const
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
switch(int(m_ctx.m_cinta[m_idx] & 0xFF))
|
|
|
|
|
{
|
|
|
|
|
case JSON_VTYPE_INTEGER:
|
|
|
|
|
val = double(m_ctx.m_cinta[m_idx + 1]);
|
|
|
|
|
return true;
|
|
|
|
|
case JSON_VTYPE_REAL:
|
|
|
|
|
{
|
|
|
|
|
static BitInterpreter un;
|
|
|
|
|
un.long_value = m_ctx.m_cinta[m_idx + 1];
|
|
|
|
|
val = un.double_value;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case JSON_VTYPE_BOOLEAN:
|
|
|
|
|
val = double((m_ctx.m_cinta[m_idx] >> TSN_JSON_BIT_START_ENDTYPE) & 1);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| ToBool |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
__forceinline bool CJsonNode::ToBool(const bool def) const
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
switch(int(m_ctx.m_cinta[m_idx] & 0xFF))
|
|
|
|
|
{
|
|
|
|
|
case JSON_VTYPE_INTEGER:
|
|
|
|
|
return m_ctx.m_cinta[m_idx + 1] != 0;
|
|
|
|
|
case JSON_VTYPE_REAL:
|
|
|
|
|
{
|
|
|
|
|
static BitInterpreter un;
|
|
|
|
|
un.long_value = m_ctx.m_cinta[m_idx + 1];
|
|
|
|
|
return un.double_value != 0.0;
|
|
|
|
|
}
|
|
|
|
|
case JSON_VTYPE_BOOLEAN:
|
|
|
|
|
return ((m_ctx.m_cinta[m_idx] >> TSN_JSON_BIT_START_ENDTYPE) & 1) != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return def;
|
2026-06-02 21:23:50 -05:00
|
|
|
}
|
|
|
|
|
|
2026-06-02 22:52:39 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CJsonNode::ToBoolSafe(bool& val) const
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
switch(int(m_ctx.m_cinta[m_idx] & 0xFF))
|
|
|
|
|
{
|
|
|
|
|
case JSON_VTYPE_INTEGER:
|
|
|
|
|
val = m_ctx.m_cinta[m_idx + 1] != 0;
|
|
|
|
|
return true;
|
|
|
|
|
case JSON_VTYPE_REAL:
|
|
|
|
|
{
|
|
|
|
|
static BitInterpreter un;
|
|
|
|
|
un.long_value = m_ctx.m_cinta[m_idx + 1];
|
|
|
|
|
val = un.double_value != 0.0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case JSON_VTYPE_BOOLEAN:
|
|
|
|
|
val = ((m_ctx.m_cinta[m_idx] >> TSN_JSON_BIT_START_ENDTYPE) & 1) != 0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2026-06-02 21:23:50 -05:00
|
|
|
|
2026-06-02 22:52:39 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| SetInt |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CJsonNode::SetInt(const long val)
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if(int(m_ctx.m_cinta[m_idx] & 0xFF) != JSON_VTYPE_INTEGER)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
m_ctx.m_cinta[m_idx + 1] = val;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| SetDbl |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CJsonNode::SetDbl(const double val)
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if(int(m_ctx.m_cinta[m_idx] & 0xFF) != JSON_VTYPE_REAL)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
static BitInterpreter un;
|
|
|
|
|
un.double_value = val;
|
|
|
|
|
m_ctx.m_cinta[m_idx + 1] = un.long_value;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| SetBool |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CJsonNode::SetBool(const bool val)
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(int(m_ctx.m_cinta[m_idx] & 0xFF) != JSON_VTYPE_BOOLEAN)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_ctx.m_cinta[m_idx] = JSON_VTYPE_BOOLEAN | long(val) << TSN_JSON_BIT_START_ENDTYPE;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Size |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
int CJsonNode::Size() const
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const int tipo = int(m_ctx.m_cinta[m_idx] & 0xFF);
|
|
|
|
|
if(tipo != JSON_VTYPE_ARR && tipo != JSON_VTYPE_OBJ)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
return int((m_ctx.m_cinta[m_idx] >> TSN_JSON_BIT_START_ENDTYPE) & 0xFFFFFF);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Is |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
__forceinline bool CJsonNode::IsValid() const { return !JSON_NODE_IS_NOT_VALID; }
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
__forceinline bool CJsonNode::IsNull() const
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return true;
|
|
|
|
|
return int(m_ctx.m_cinta[m_idx] & 0xFF) == JSON_VTYPE_NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
__forceinline bool CJsonNode::IsArray() const
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return false;
|
|
|
|
|
return int(m_ctx.m_cinta[m_idx] & 0xFF) == JSON_VTYPE_ARR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
__forceinline bool CJsonNode::IsObject() const
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return false;
|
|
|
|
|
return int(m_ctx.m_cinta[m_idx] & 0xFF) == JSON_VTYPE_OBJ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Navegacion raw |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CJsonNode::MoveToNextToken(const bool solo_en_el_bloque_actual = true)
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const int next_pos = m_idx + m_ctx.GetStep(m_idx);
|
|
|
|
|
const int final_pos = next_pos + m_ctx.GetStep(next_pos);
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(next_pos >= (solo_en_el_bloque_actual ? m_end : m_ctx.m_cinta_pos))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_idx = next_pos;
|
|
|
|
|
m_end = final_pos;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
CJsonNode CJsonNode::MoveNextPositions(const int posiciones, const bool solo_en_el_bloque_actual = true)
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return EMPTY_JSON_NODE;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const int next_pos = m_idx + posiciones;
|
|
|
|
|
const int final_pos = solo_en_el_bloque_actual ? m_end : next_pos + m_ctx.GetStep(next_pos);
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(next_pos >= (solo_en_el_bloque_actual ? m_end : m_ctx.m_cinta_pos))
|
|
|
|
|
return EMPTY_JSON_NODE;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
return CJsonNode(m_ctx, next_pos, final_pos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CJsonNode::MoveNextPositionsThis(const int posiciones, const bool solo_en_el_bloque_actual = true)
|
|
|
|
|
{
|
|
|
|
|
if(JSON_NODE_IS_NOT_VALID)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
const int next_pos = m_idx + posiciones;
|
|
|
|
|
const int final_pos = solo_en_el_bloque_actual ? m_end : next_pos + m_ctx.GetStep(next_pos);
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
if(next_pos >= (solo_en_el_bloque_actual ? m_end : m_ctx.m_cinta_pos))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
m_idx = next_pos;
|
|
|
|
|
m_end = final_pos;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Iterador de arrays |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
struct CJsonIteratorArray
|
|
|
|
|
{
|
|
|
|
|
CJsonParser* m_ctx;
|
|
|
|
|
int m_cur;
|
|
|
|
|
const int m_end;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
CJsonIteratorArray(CJsonParser* ctx, const int cur, const int end)
|
|
|
|
|
: m_ctx(ctx), m_cur(cur), m_end(end) {}
|
|
|
|
|
//---
|
|
|
|
|
CJsonIteratorArray()
|
|
|
|
|
: m_ctx(NULL), m_cur(0), m_end(0) {}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
__forceinline bool IsValid() { return m_cur < m_end; }
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
void Next()
|
|
|
|
|
{
|
|
|
|
|
if(m_cur >= m_end)
|
|
|
|
|
return;
|
|
|
|
|
m_cur += m_ctx.GetStep(m_cur);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
CJsonNode Val()
|
|
|
|
|
{
|
|
|
|
|
if(m_cur >= m_end)
|
|
|
|
|
return EMPTY_JSON_NODE;
|
|
|
|
|
const int fin = m_cur + m_ctx.GetStep(m_cur);
|
|
|
|
|
return CJsonNode(m_ctx, m_cur, fin);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const CJsonIteratorArray EMPTY_JSON_ITERATOR_ARR;
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Iterador de objetos |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
struct CJsonIteratorObj
|
|
|
|
|
{
|
|
|
|
|
CJsonParser* m_ctx;
|
|
|
|
|
int m_cur;
|
|
|
|
|
const int m_end;
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
CJsonIteratorObj(CJsonParser* ctx, const int cur, const int end)
|
|
|
|
|
: m_ctx(ctx), m_cur(cur), m_end(end) {}
|
|
|
|
|
//---
|
|
|
|
|
CJsonIteratorObj()
|
|
|
|
|
: m_ctx(NULL), m_cur(0), m_end(0) {}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
__forceinline bool IsValid() { return m_cur < m_end; }
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
void Next()
|
|
|
|
|
{
|
|
|
|
|
if(m_cur >= m_end)
|
|
|
|
|
return;
|
|
|
|
|
m_cur += 2; // salta KEY (2 pos)
|
|
|
|
|
m_cur += m_ctx.GetStep(m_cur); // salta VAL
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
string Key()
|
|
|
|
|
{
|
|
|
|
|
if(m_cur >= m_end)
|
|
|
|
|
return "";
|
|
|
|
|
const int s = int(m_ctx.m_cinta[m_cur + 1] >> TSN_JSON_BIT_STR_START_END);
|
|
|
|
|
const int e = int(m_ctx.m_cinta[m_cur + 1] & 0xFFFFFFFF);
|
|
|
|
|
return CharArrayToString(m_ctx.m_json, s, (e - s) + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
CJsonNode Val()
|
|
|
|
|
{
|
|
|
|
|
if(m_cur >= m_end)
|
|
|
|
|
return EMPTY_JSON_NODE;
|
|
|
|
|
const int pos = m_cur + 2;
|
|
|
|
|
const int fin = pos + m_ctx.GetStep(pos);
|
|
|
|
|
return CJsonNode(m_ctx, pos, fin);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const CJsonIteratorObj EMPTY_JSON_ITERATOR_OBJ;
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| BeginArr / BeginObj |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
CJsonIteratorArray CJsonNode::BeginArr() const
|
|
|
|
|
{
|
|
|
|
|
if(int(m_ctx.m_cinta[m_idx] & 0xFF) != JSON_VTYPE_ARR)
|
|
|
|
|
return EMPTY_JSON_ITERATOR_ARR;
|
2026-06-03 15:48:09 -05:00
|
|
|
return CJsonIteratorArray(m_ctx, m_idx + 2, m_end);
|
2026-06-02 22:52:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
CJsonIteratorObj CJsonNode::BeginObj() const
|
|
|
|
|
{
|
|
|
|
|
if(int(m_ctx.m_cinta[m_idx] & 0xFF) != JSON_VTYPE_OBJ)
|
|
|
|
|
return EMPTY_JSON_ITERATOR_OBJ;
|
2026-06-03 15:48:09 -05:00
|
|
|
return CJsonIteratorObj(m_ctx, m_idx + 2, m_end);
|
2026-06-02 22:52:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
2026-06-02 21:23:50 -05:00
|
|
|
}
|
2026-06-02 22:52:39 -05:00
|
|
|
|
2026-06-02 21:23:50 -05:00
|
|
|
//+------------------------------------------------------------------+
|
2026-06-02 22:52:39 -05:00
|
|
|
#endif // JSONPARSERBYLEO_SRC_JSONNODE_MQH
|