//+------------------------------------------------------------------+ //| JsonParser.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_JSONPARSER_MQH #define JSONPARSERBYLEO_SRC_JSONPARSER_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "JsonDefines.mqh" #include //--- #ifdef JSONPARSERBYLEO_DLL #include "DLL\\Main.mqh" #endif // JSONPARSERBYLEO_DLL //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ namespace TSN { //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ //#define JSONPARSERBYLEO_DESACTIVE_SWAR //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CJsonParser : public CBaseStructuredLan { protected: //--- uint m_stak_num[JSONPARSERBYLEO_MAX_STACK]; int m_stak_pos[JSONPARSERBYLEO_MAX_STACK]; ushort m_stak_state[JSONPARSERBYLEO_MAX_STACK]; int m_stak_curr; ushort m_stak_curr_state; //--- #ifdef JSONPARSERBYLEO_DLL int m_index[]; int m_index_r; #endif // JSONPARSERBYLEO_DLL //--- ENUM_TSN_JSON_LAST_ERR m_last_err; //--- int CalcRegType(const string& file_name) override final; public: CJsonParser(void); ~CJsonParser(void) {} //--- Parse + Correct padding // Para data raw se puede usar el json uchar directamtne bool AutoParseByFileExt(const int file_ext_type); void CorrectPadding(); #ifdef JSONPARSERBYLEO_DLL void CorrectPaddingSimd(); #endif // JSONPARSERBYLEO_DLL //--- bool Parse(); #ifdef JSONPARSERBYLEO_DLL __forceinline bool ParseSimd(); #endif // JSONPARSERBYLEO_DLL //--- Errores __forceinline ENUM_TSN_JSON_LAST_ERR LastErr() const { return m_last_err; } void CatchErr(); void ErrorInfo(const string header = ""); //--- Step __forceinline int GetStep(const int idx) const; __forceinline int GetStepPure(const int idx) const; //--- Info void PrintCintaTypes(const int start, const int num) const; //--- Comparacion // keys bool KeysEqual(const ulong key_hash_fnv1a64, const int curr) const; bool KeysEqual(const string& str, const int curr) const; // strings bool StrEquals(const string &str, const int curr) const; //--- Clean node string CleanNode(int i, const int end) const; int CleanNode(int i, const int end, uchar &out[], int k, bool ajustar_arr) const; //--- Extra (node-use) bool NodeHashing(int curr, const int obj_count, const int bend, int& table_pos); bool SerializeToDom(CDomNodeBase* root, CDomNodeManager* manager, int cur, const int end); //--- Array template void ToArray(int cur, T& out_arr[], const int end) const; template bool ExistInArray(int cur, const T val, const uint flags, const int end) const; template bool ExistInArrayHomogeneo(int cur, const T val, const int end) const; //--- Make // uso en get value o exatcion static bool MakeString(const uchar &in[], int i, int len, string& res); static int MakeUArray(const uchar &in[], int i, int len, uchar &res[], int pos = 0); static bool MakeKeyHashFNV1A64(const uchar &in[], int& i, int len, ulong& hash); static bool EscapePointer(const string &in, int& p, int len, ulong& hash); //--- static void PrintError(const string& header, const uchar& buf[], const int len, int col, int line, ENUM_TSN_JSON_LAST_ERR err, string& salida, bool print = true); //--- CJsonNode GetRoot(); //--- Tablas generales static const string s_dtype_to_str[JSON_VTYPE_TOTAL]; static const char s_slots_size_arrobj; }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CJsonParser::CJsonParser(void) { m_next = TSN_JSON_TOK_INVALID; #ifdef JSONPARSERBYLEO_DLL m_index_r = ArrayResize(m_index, 256, 256); #endif // JSONPARSERBYLEO_DLL } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ const string CJsonParser::s_dtype_to_str[JSON_VTYPE_TOTAL] = { "", "", "", "ulong", "long", "double", "bool", "string", "" }; const char CJsonParser::s_slots_size_arrobj = 2; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #ifdef JSONPARSERBYLEO_DLL void CJsonParser::CorrectPaddingSimd() { //--- const int new_len = m_len + 64; ArrayResize(m_raw, new_len); //--- int i = m_len; m_raw[i++] = ' '; m_raw[i++] = '^'; // para cor ini para que falle bien.. // esto es para el caso de " no cerrado o { asi tal cual.. entonces ahi // porzariamos a econnotrar un "" el cual ya lo manejaria y seria invalido m_raw[i++] = '"'; m_raw[i++] = ' '; m_raw[i++] = '"'; // esto es para el key... los dos primeors eran para que no de fuera de rango en index.. // en caso tengos un { asi tal cual... ecnontrar una key... pero luego le sigue : pero ahora pondmores // , asi que == ':' fallaria retornando false, lo neceismtos dado que , se procesa como estrucuutra en la dll m_raw[i++] = ','; //--- for(; i < new_len; i++) m_raw[i] = ' '; // vacio //--- Reservamos if(m_len > m_cinta_reserve) { m_cinta_reserve = m_len; ArrayResize(m_cinta, m_len); } //--- if(m_len > m_index_r) { m_index_r = m_len; ArrayResize(m_index, m_index_r); } } #endif // JSONPARSERBYLEO_DLL //+------------------------------------------------------------------+ void CJsonParser::CorrectPadding() { //--- //const int new_len = ; ArrayResize(m_raw, m_len + 11); //--- Rellenamos // esto es por el escapado. caso borde donde el json su ultimo char sea \ y avanze ++ // entonces con esto apaleamos eso.. m_raw[m_len] = ' '; // este caracter es invalido por lo que en casos donde haya [ (sin mas asi tal cual) // como no tenemos chekeos de rango entonces se tompara con este daond un error de malformacion m_raw[m_len + 1] = '^'; m_raw[m_len + 2] = '"'; // justo luego 8 caracteres m_raw[m_len + 3] = '\n'; // en una key invalida cargara a paritr de aqui 7 caracterres mas.. m_raw[m_len + 4] = '"'; // esto para poder encontrar el cierre de key... aparte en asm // un token " asi suelto no es valido asi que daria error en caso haya un ; asi no mas.. sin \n (lo enocnr) // igual por el padding pero luego avnazar a " pero este como tal no es token valido // invalidos para que sigmoas si un valor esta fuera de rango como un string o algo asi // falle aqui.... m_raw[m_len + 5] = '^'; // m_raw[m_len + 6] = '^'; m_raw[m_len + 7] = '^'; m_raw[m_len + 8] = '^'; m_raw[m_len + 9] = '^'; m_raw[m_len + 10] = '^'; //--- Reservamos if(m_len > m_cinta_reserve) { m_cinta_reserve = m_len; ArrayResize(m_cinta, m_len); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CJsonParser::NodeHashing(int curr, const int obj_count, const int bend, int& table_pos) { //--- inicial BASESPARSERSLAN_START_NODE_HASH(table_pos, curr) //--- m_tables[table_pos].table_size = obj_count; // Numero de objetos //--- m_pfh.MaxValSeed(m_max_att++); m_pfh.InitAlg(obj_count, 0.70, TSN_NODEBASEREAD_MIN_JIT_VALUES_TO_HASH_MIN); //--- ArrayResize(m_tables[table_pos].pos_arr, obj_count); //--- Obtnemos las posiciones de incio ulong keys_h[]; int posiciones[]; ArrayResize(keys_h, obj_count); ArrayResize(posiciones, obj_count); int pos_c = 0; curr += 2; // Ahora en key //--- while(curr < bend) { const long v = m_cinta[curr]; if(int(v & TSN_SBL_BIT_MASK_TYPE) != JSON_VTYPE_KEY) { curr += GetStep(curr); continue; } //--- m_tables[table_pos].pos_arr[pos_c] = curr; // Assing //--- ulong key_hash = FNV_OFFSET_BASIS; int i = int(v >> TSN_SBL_BIT_STR_START); // len const int len = i + int((v >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); // len //--- Hash 64 while(i < len) { key_hash ^= m_raw[i]; key_hash *= FNV_PRIME; i++; } // PrintFormat("Hash para %s = %I64u", CharArrayToString(m_raw, int(m_cinta[curr] >> TSN_SBL_BIT_STR_START), // int((m_cinta[curr] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN)), key_hash); //--- keys_h[pos_c] = key_hash; posiciones[pos_c] = pos_c; pos_c++; //--- curr++; // salta KEY curr += GetStep(curr); // salta VAL } // Cacheado const int fn = m_pfh.m_final_table_size; //--- Last m_tables[table_pos].final_table_l = m_pfh.m_final_table_size_last; m_tables[table_pos].bucket_l = m_pfh.m_buckets_size_last; // Iniciamos.. ArrayResize(m_tables[table_pos].pos_index, fn); //ArrayInitialize(m_tables[table_pos].pos_index, -1); no hace falta el que nos indica valides es key hash si key hash es invalido o no machte no llega aqui //--- ArrayResize(m_tables[table_pos].key_hash, fn); ArrayInitialize(m_tables[table_pos].key_hash, 0ULL); //--- if(m_pfh.RunWValue(keys_h, posiciones, m_tables[table_pos].seeds, m_tables[table_pos].pos_index, m_tables[table_pos].key_hash)) return true; //---- m_tables_size--; // pop return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CJsonParser::CalcRegType(const string& file_name) { return (int)JPBL_HashExt(file_name); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CJsonParser::KeysEqual(const string &str, const int curr) const { //--- const int start = int(m_cinta[curr] >> TSN_SBL_BIT_STR_START); const int len = int((m_cinta[curr] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); const int l = StringLen(str); //--- if(l != len) return false; //--- for(int i = 0; i < l; i++) if(str[i] != m_raw[start + i]) return false; //--- return true; } //+------------------------------------------------------------------+ bool CJsonParser::KeysEqual(const ulong key_hash_fnv1a64, const int curr) const { const int start = int(m_cinta[curr] >> TSN_SBL_BIT_STR_START); const int len = int((m_cinta[curr] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); ulong hash = FNV_OFFSET_BASIS; for(int i = start; i < (start + len); i++) { hash ^= m_raw[i]; hash *= FNV_PRIME; } return hash == key_hash_fnv1a64; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CJsonParser::StrEquals(const string &str, const int curr) const { //--- // m_cinta[m_cinta_pos++] = long(m_pos - 1) | long(start) << TSN_JSON_BIT_STR_START_END; const int start = int(m_cinta[curr] >> TSN_SBL_BIT_STR_START); const int len = int((m_cinta[curr] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); //PrintFormat("Exact = '%s', other = '%s'", CharArrayToString(m_raw, start, len), str); const int l = StringLen(str); //--- if(l != len) return false; for(int i = 0; i < l; i++) { if(str[i] != m_raw[start + i]) return false; } return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string CJsonParser::CleanNode(int i, const int end) const { //--- string str; int k = 0; StringInit(str, (end - i) + 1, ' '); // "\"\"" //--- bool in = false; for(i; i <= end; i++) { const uchar c = m_raw[i]; //--- if(in) { str.SetChar(k++, c); if(c == '\\') { str.SetChar(k++, m_raw[++i]); continue; } in = (c != '"'); } else { if(c < 33) continue; str.SetChar(k++, c); in = (c == '"'); } } //-- StringSetLength(str, k); return str; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CJsonParser::CleanNode(int i, const int end, uchar &out[], int k, bool ajustar_arr) const { //--- const int needed = (end - i) + 1; const int rsize = ArraySize(out); const int e = needed + k; if(rsize <= e) { ArrayResize(out, rsize + e); } //--- bool in = false; for(i; i <= end; i++) { const uchar c = m_raw[i]; //--- if(in) { out[k++] = c; if(c == '\\') { out[k++] = m_raw[++i]; continue; } in = (c != '"'); } else { if(c < 33) continue; out[k++] = c; in = (c == '"'); } } //-- if(ajustar_arr) // Ajustamos exacto ArrayResize(out, k); //-- return k - (e - needed); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CJsonParser::AutoParseByFileExt(const int file_ext_type) { switch(file_ext_type) { case TSN_SLF_RAW_FILE: { CorrectPadding(); // Auto return Parse(); } case TSN_SLF_RAW_EMBEBED: { return m_cinta_pos > 0 && m_len > 0; } default: { m_last_err = TSN_JSON_ERR_INVALID_EXT_FILE; m_pos = 0; return false; } } } //+------------------------------------------------------------------+ //| Macros de avanze | //+------------------------------------------------------------------+ //--- #define TSN_JSON_AUMENT m_stak_num[m_stak_curr]++; //--- Se usa solo al incio de un llave ini validos " y } #define TSN_JSON_NEXT_LLAVE_INI \ while(true) \ { \ const uchar _c = m_raw[m_pos]; \ if(_c == '"') \ { \ m_next=TSN_JSON_TOK_KEY; \ break; \ } \ if(_c== '}') \ { \ m_next=TSN_JSON_TOK_LLAVE_END; \ break; \ } \ m_pos++; \ } //--- Generico // Luego de un valor siempre , o su fin // 1 en la tabl to token es INVALID (dara error..de malformed..) // Este se usa luego de un valor.. la idea es que luego de un valor "" numero t\f\n ] } // tiene que haber o un }] o en todo caso , de continuacino solo eso... #define TSN_JSON_NEXT_NO_NEXT_KEY \ uchar _c = m_raw[m_pos]; \ while(_c < 33) { _c = m_raw[++m_pos]; } \ m_next = g_table_json_tokens[_c]; \ if(((1 << m_next) & m_stak_curr_state) == 0) \ { \ m_last_err= TSN_JSON_ERR_MALFORDMED_JSON_AFTER_VAL; \ return false; \ } //--- Luego de una coma en array // Luego de una , y KEY siempre siempre valor #define TSN_JSON_NEXT_VALUE_COMM_KEY \ uchar _c; \ while((_c=m_raw[++m_pos])<33) {} \ m_next = g_table_json_tokens[_c]; \ if(((1 << m_next) & TSN_JSON_F_ALL_I_VAL) == 0) \ { \ m_last_err= TSN_JSON_ERR_MALFORDMED_JSON_FIND_VAL; \ return false; \ } //+------------------------------------------------------------------+ //| Parseo de numeros | //+------------------------------------------------------------------+ //--- make string #define JSONPARSERBYLEO_NUM_MAKE_STRING m_cinta[m_cinta_pos++] = JSON_VTYPE_STRING \ | long(m_pos - start) << TSN_SBL_BIT_STR_LEN \ | long(start) << TSN_SBL_BIT_STR_START; //+------------------------------------------------------------------+ //| Parse con simd | //+------------------------------------------------------------------+ #ifdef JSONPARSERBYLEO_DLL __forceinline bool CJsonParser::ParseSimd() { //--- Iniciales m_last_err = TSN_JSON_NOT_ERR; m_tables_size = 0; return JsonParserResolve(m_raw, m_cinta, m_index, m_len, m_offset, (int&)m_last_err, m_cinta_pos, m_pos ); } #endif // JSONPARSERBYLEO_DLL //+------------------------------------------------------------------+ //| Parse normal | //+------------------------------------------------------------------+ bool CJsonParser::Parse() { //--- m_stak_curr = -1; m_last_err = TSN_JSON_NOT_ERR; m_pos = m_offset; m_cinta_pos = 0; m_tables_size = 0; //--- Inicial const uchar _f_c = m_raw[m_pos]; if(_f_c == '{') { m_next = TSN_JSON_TOK_LLAVE_INI; } else if(_f_c == '[') { m_next = TSN_JSON_TOK_COR_INI; } else { m_pos++; while(true) { const uchar _f__c = m_raw[m_pos]; if(_f__c < 33) { m_pos++; continue; } //--- if(_f__c == '{') { m_next = TSN_JSON_TOK_LLAVE_INI; } else if(_f__c == '[') { m_next = TSN_JSON_TOK_COR_INI; } else { m_next = TSN_JSON_TOK_INVALID; } break; } } //--- Bucle while(true) { switch(m_next) { //--- case TSN_JSON_TOK_NUMBER_NEG: { //--- solo 3 varaibles nada mas en general (garantizado) long v = 0; const int start = m_pos; uchar ch = m_raw[++m_pos] ^ '0'; //--- switch(0) { default: // scope con psoiblidad de break. { //--- primera iteracion sin cheking DOMBASEUTIL_PARSE_NUM_U1(v) //--- Interesante: sigue siendo cero pero me pide mas digitios ?¿ if(!v) { m_last_err = TSN_JSON_ERR_LEADING_ZEROS; m_next = TSN_JSON_TOK_INVALID; continue; } //--- 19 iteraciones maximo DOMBASEUTIL_PARSE_NUM_UNROLLED_17(v) STRCONV_TOV_ALG(v, ch) if((ch = m_raw[++m_pos] ^ '0') > 9) { if(v > 0) break; } else // aun es valido asi que seguimos saltando el numero completo (parte entera) (pero ya sabmeos que es invalido) { DOMBASEUTIL_NUM_SKIP_NUMBER } //--- revismoos si es dec, si lo es saltamos la parte dec if(STRCONV_DECX_CH_IS_DEC(ch)) break; //--- pasamos a str y ya no caemos abajo de aqui: JSONPARSERBYLEO_NUM_MAKE_STRING TSN_JSON_AUMENT TSN_JSON_NEXT_NO_NEXT_KEY continue; // esto aplica a nivel de while } } //--- vemos si decimal if(STRCONV_DECX_CH_IS_DEC(ch)) { long exponente = 0; // exponente int digitos = m_pos - start; // digitos que se van acomulando (parte ent + dec) if(STRCONV_DECX_CH_IS_PDEC(ch)) { int ds = ++m_pos; // inicio if((ch = m_raw[m_pos] ^ '0') > 9) { m_last_err = TSN_JSON_ERR_EXPECTED_NUMBER_AFECTER_DECIMALP; return false; } while(true) { //DOMBASEUTIL_NUM_PROCCES_FIRST_DEC(v, ch, m_pos, ds, digitos) DOMBASEUTIL_PARSE_NUM_UNROLLED_18(v) DOMBASEUTIL_NUM_SKIP_NUMBER break; } //--- ds = (m_pos - ds); // numero de digitos de la parte decimal digitos += ds; exponente -= ds; } if(STRCONV_DECX_CH_IS_E(ch)) // { bool exp_positivo = true; ch = m_raw[++m_pos] ^ '0'; if(ch > 9) { if(STRCONV_DECX_CH_IS_MINUS(ch)) exp_positivo = false; if((ch = m_raw[++m_pos] ^ '0') > 9) { m_last_err = TSN_JSON_ERR_EXPECTED_NUMBER_AFECTER_EXP; return false; // sale } } int expo = 0; while(true) // siguimos acomulando en v { DOMBASEUTIL_PARSE_NUM_U1(expo) if(expo == 0) // leading zeros.. ahora mismo aun hay digitos pero el primero es 0.. { DOMBASEUTIL_PARSE_SKIP_LZ } // pos apunta al curr no cero ch ya tiene su valor en caso sea 00000x (no numero) sale.. DOMBASEUTIL_PARSE_NUM_UNROLLED_8(expo) STRCONV_TOV_ALG(expo, ch) if((ch = m_raw[++m_pos] ^ '0') > 9) // 10cimo digito { if(expo > 0) // es valido break; // no ov } else // sigue saltamos todo lo que hya { DOMBASEUTIL_NUM_SKIP_NUMBER } expo = INT_MAX; break; } exponente += exp_positivo ? expo : -expo; } //--- 1 dado que start incluye el - if(STRCONV_DOUBLE_SAFE_DBL_P(digitos, exponente, 1)) { TsnBitInterprete bit; bit.double_value = -STRCONV_TO_DOUBLE_ALG(exponente, v); m_cinta[m_cinta_pos++] = JSON_VTYPE_REAL; m_cinta[m_cinta_pos++] = bit.long_value; } else // make_string: numero grande o que ya no se peude representar con precision (a string) { JSONPARSERBYLEO_NUM_MAKE_STRING } } else { m_cinta[m_cinta_pos++] = JSON_VTYPE_INTEGER; m_cinta[m_cinta_pos++] = -v; } //--- TSN_JSON_AUMENT TSN_JSON_NEXT_NO_NEXT_KEY break; } //--- case TSN_JSON_TOK_NUMBER: { //--- ulong v = 0; const int start = m_pos; uchar ch = m_raw[start] ^ '0'; const uchar fc = ch; //--- switch(0) { default: // scope con psoiblidad de break. { //--- DOMBASEUTIL_PARSE_NUM_U1(v) if(!v) { m_last_err = TSN_JSON_ERR_LEADING_ZEROS; m_next = TSN_JSON_TOK_INVALID; continue; } //--- 19 iteraciones maximo DOMBASEUTIL_PARSE_NUM_UNROLLED_18(v) STRCONV_TOV_ALG(v, ch) if((ch = m_raw[++m_pos] ^ '0') > 9) { if(fc == 1 && v > LONG_MAX) break; } else // aun es valido asi que seguimos saltando el numero completo (parte entera) (pero ya sabmeos que es invalido) { DOMBASEUTIL_NUM_SKIP_NUMBER } //--- revismoos si es dec, si es asi lo mandamos para la funcion dec aqui solo big integer if(STRCONV_DECX_CH_IS_DEC(ch)) break; //--- pasamos a str y ya no caemos abajo de aqui: JSONPARSERBYLEO_NUM_MAKE_STRING TSN_JSON_AUMENT TSN_JSON_NEXT_NO_NEXT_KEY continue; // esto aplica a nivel de while } } //--- vemos si decimal if(STRCONV_DECX_CH_IS_DEC(ch)) // v por lo tanto llega bien aqui como entero unsigned valido { long exponente = 0; // exponente int digitos = m_pos - start; // digitos que se van acomulando (parte ent + dec) if(STRCONV_DECX_CH_IS_PDEC(ch)) // punto decimal (tomar precuacion aqui si v puede dar overflow y voltear no hay chekeo) { int ds = ++m_pos; if((ch = m_raw[m_pos] ^ '0') > 9) { m_last_err = TSN_JSON_ERR_EXPECTED_NUMBER_AFECTER_DECIMALP; return false; } while(true) { //DOMBASEUTIL_NUM_PROCCES_FIRST_DEC(v, ch, m_pos, ds, digitos) DOMBASEUTIL_PARSE_NUM_UNROLLED_18(v) DOMBASEUTIL_NUM_SKIP_NUMBER break; } //--- ds = (m_pos - ds); // numero de digitos de la parte decimal digitos += ds; exponente -= ds; } if(STRCONV_DECX_CH_IS_E(ch)) // { bool exp_positivo = true; ch = m_raw[++m_pos] ^ '0'; if(ch > 9) { if(STRCONV_DECX_CH_IS_MINUS(ch)) exp_positivo = false; if((ch = m_raw[++m_pos] ^ '0') > 9) { m_last_err = TSN_JSON_ERR_EXPECTED_NUMBER_AFECTER_EXP; return false; // sale } } int expo = 0; while(true) { DOMBASEUTIL_PARSE_NUM_U1(expo) if(expo == 0) // leading zeros.. ahora mismo aun hay digitos pero el primero es 0.. { DOMBASEUTIL_PARSE_SKIP_LZ } // pos apunta al curr no cero ch ya tiene su valor en caso sea 00000x (no numero) sale.. DOMBASEUTIL_PARSE_NUM_UNROLLED_8(expo) STRCONV_TOV_ALG(expo, ch) if((ch = m_raw[++m_pos] ^ '0') > 9) // 10cimo digito { if(expo > 0) // es valido break; // no ov } else // sigue saltamos todo lo que hya { DOMBASEUTIL_NUM_SKIP_NUMBER } expo = INT_MAX; break; } exponente += exp_positivo ? expo : -expo; } //--- if(STRCONV_DOUBLE_SAFE_DBL(digitos, exponente)) { TsnBitInterprete bit; bit.double_value = STRCONV_TO_DOUBLE_ALG(exponente, v); m_cinta[m_cinta_pos++] = JSON_VTYPE_REAL; m_cinta[m_cinta_pos++] = bit.long_value; } else { JSONPARSERBYLEO_NUM_MAKE_STRING } } else { m_cinta[m_cinta_pos++] = JSON_VTYPE_UINTEGER; m_cinta[m_cinta_pos++] = (long)v; } //--- TSN_JSON_AUMENT TSN_JSON_NEXT_NO_NEXT_KEY break; } //--- case TSN_JSON_TOK_STRING: { //--- const int start = ++m_pos; //--- #ifndef JSONPARSERBYLEO_DESACTIVE_SWAR //--- Pase inicial 8 en 8 while(true) { // PrintFormat("Analizando: '%s'", CharArrayToString(m_raw, m_pos, 8)); const ulong chunk = (ulong)m_raw[m_pos] | (ulong)m_raw[m_pos + 1] << 8 | (ulong)m_raw[m_pos + 2] << 16 | (ulong)m_raw[m_pos + 3] << 24 | (ulong)m_raw[m_pos + 4] << 32 | (ulong)m_raw[m_pos + 5] << 40 | (ulong)m_raw[m_pos + 6] << 48 | (ulong)m_raw[m_pos + 7] << 56; //--- const ulong x_bs = chunk ^ TSNTABLES_SWAR_MASK_BACK_SLASH; ulong has_bs = TSNTABLES_SWAR_HAS(x_bs); const ulong x_qt = chunk ^ TSNTABLES_SWAR_MASK_COMILLA; const ulong has_qt = TSNTABLES_SWAR_HAS(x_qt); //--- if((has_bs | has_qt) == 0) // Caso comun. .. ninguno de los dos.. continuamos.. { m_pos += 8; continue; } //--- if(has_bs == 0) // Si not iene bs (pero confirmamos que no es 0) // Entonces no tirne bs pero si qt salimos de una.. { const ulong flag_real = TSNTABLES_BIT_DEJAR_SOLO_MINUS_SIG_BYTE(has_qt); //--- m_pos += TSNTABLES_CTZ_64_GET_BYTE(flag_real); m_cinta[m_cinta_pos++] = JSON_VTYPE_STRING | long(m_pos - start) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; m_pos++; // Luego del " break; } //--- Hay bs si o si pero tambien puede haber " const uchar compacted_bs = TSNTABLES_COMPACT_UL(has_bs); const uchar prev = (((compacted_bs << 1) | TSNTABLES_MASK_IMPARES) - compacted_bs) ^ TSNTABLES_MASK_IMPARES; const uchar escaped = prev ^ compacted_bs; //--- const uchar compacted_qt = TSNTABLES_COMPACT_UL(has_qt); const uchar qt_final = compacted_qt & ~escaped; //Print("nada"); //--- if(qt_final) // Hay un qt real de cierre { //--- // Avanzamos y cerramos.. m_pos += g_tsntables_table_ctz_i8[qt_final]; m_cinta[m_cinta_pos++] = JSON_VTYPE_STRING | long(m_pos - start) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; //--- m_pos++; break; } else { m_pos += 8; // Print(CharToString(m_raw[m_pos])); // escape if(((prev & compacted_bs) >> 7U) != 0) // Overflow el ultimo char es \ y el siguiente escapa { //Print("siuu"); m_pos++; // Uno mas.. luego del currend } } } #else // JSONPARSERBYLEO_DESACTIVE_SWAR //--- Char por char while(true) { const uchar c = m_raw[m_pos]; if(c == '\\') { m_pos += 2; continue; } if(c == '"') { // STRING 1 slot: [tipo(4)|len(28low)|start(32high)] m_cinta[m_cinta_pos++] = JSON_VTYPE_STRING | long(m_pos - start) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; m_pos++; break; } m_pos++; } #endif // JSONPARSERBYLEO_DESACTIVE_SWAR //--- TSN_JSON_AUMENT TSN_JSON_NEXT_NO_NEXT_KEY //--- break; } case TSN_JSON_TOK_BOOL_TRUE: { const uint k = (uint)m_raw[++m_pos] | (uint)m_raw[++m_pos] << 8 | (uint)m_raw[++m_pos] << 16; if(k != TSNJSON_VAL_TRUE) return false; //--- m_pos++; m_cinta[m_cinta_pos++] = (JSON_VTYPE_BOOLEAN | 1LL << 4); //--- TSN_JSON_AUMENT TSN_JSON_NEXT_NO_NEXT_KEY break; } case TSN_JSON_TOK_BOOL_FALSE: { //const uint k = (uint)m_raw[++m_pos] | (uint)m_raw[++m_pos] << 8 | (uint)m_raw[++m_pos] << 16 | (uint)m_raw[++m_pos] << 24; if(m_raw[++m_pos] != 'a' || m_raw[++m_pos] != 'l' || m_raw[++m_pos] != 's' || m_raw[++m_pos] != 'e') return false; //--- m_pos++; m_cinta[m_cinta_pos++] = JSON_VTYPE_BOOLEAN; //--- TSN_JSON_AUMENT TSN_JSON_NEXT_NO_NEXT_KEY break; } case TSN_JSON_TOK_NULL: { const uint k = (uint)m_raw[++m_pos] | (uint)m_raw[++m_pos] << 8 | (uint)m_raw[++m_pos] << 16; if(k != TSNJSON_VAL_NULL) return false; //--- m_pos++; m_cinta[m_cinta_pos++] = JSON_VTYPE_NULL; //--- TSN_JSON_AUMENT TSN_JSON_NEXT_NO_NEXT_KEY break; } case TSN_JSON_TOK_COMMA: { //--- if(m_stak_curr_state == TSN_JSON_CTX_IN_OBJ) { while(m_raw[++m_pos] != '"') {} m_next = TSN_JSON_TOK_KEY; } else { TSN_JSON_NEXT_VALUE_COMM_KEY } break; } case TSN_JSON_TOK_LLAVE_INI: { //TSN_JSON_RESERVAR(1) m_cinta[m_cinta_pos] = JSON_VTYPE_OBJ; //--- m_stak_curr++; m_stak_curr_state = TSN_JSON_CTX_IN_OBJ; m_stak_state[m_stak_curr] = TSN_JSON_CTX_IN_OBJ; m_stak_num[m_stak_curr] = 0; m_stak_pos[m_stak_curr] = m_cinta_pos++; //--- m_cinta[m_cinta_pos++] = m_pos++; //--- TSN_JSON_NEXT_LLAVE_INI //--- break; } case TSN_JSON_TOK_COR_INI: { m_cinta[m_cinta_pos] = JSON_VTYPE_ARR; //--- m_stak_curr++; m_stak_curr_state = TSN_JSON_CTX_IN_ARR; m_stak_state[m_stak_curr] = TSN_JSON_CTX_IN_ARR; m_stak_num[m_stak_curr] = 0; m_stak_pos[m_stak_curr] = m_cinta_pos++; //--- m_cinta[m_cinta_pos++] = m_pos++; //--- uchar _c = m_raw[m_pos]; while(_c < 33) _c = m_raw[++m_pos]; //--- m_next = g_table_json_tokens[_c]; if(((1 << m_next) & TSN_JSON_F_VAL_COR) == 0) { m_last_err = TSN_JSON_ERR_MALFORDMED_JSON_AFTER_COR_INI; return false; } //--- break; } case TSN_JSON_TOK_LLAVE_END: case TSN_JSON_TOK_COR_END: { //--- const int lp = m_stak_pos[m_stak_curr]; m_cinta[lp] |= long(m_stak_num[m_stak_curr]) << TSN_SBL_BIT_START_NUM_EL | long(m_cinta_pos - lp) << TSN_SBL_BIT_START_NUM_C; m_cinta[lp + 1] |= long(m_pos) << TSN_JSON_BIT_END_T; //--- if(--m_stak_curr < 0) return true; //--- m_stak_curr_state = m_stak_state[m_stak_curr]; //--- m_pos++; //--- TSN_JSON_AUMENT TSN_JSON_NEXT_NO_NEXT_KEY //--- break; } case TSN_JSON_TOK_KEY: { const int start = ++m_pos; //--- #ifdef JSONPARSERBYLEO_ACTIVE_SWAR_KEYS //--- Pase inicial 8 en 8 while(true) { // "asdasdasd".........." // PrintFormat("Analizando: '%s'", CharArrayToString(m_raw, m_pos, 8)); const ulong chunk = (ulong)m_raw[m_pos] | (ulong)m_raw[m_pos + 1] << 8 | (ulong)m_raw[m_pos + 2] << 16 | (ulong)m_raw[m_pos + 3] << 24 | (ulong)m_raw[m_pos + 4] << 32 | (ulong)m_raw[m_pos + 5] << 40 | (ulong)m_raw[m_pos + 6] << 48 | (ulong)m_raw[m_pos + 7] << 56; //--- #ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS const ulong x_bs = chunk ^ TSNTABLES_SWAR_MASK_BACK_SLASH; ulong has_bs = TSNTABLES_SWAR_HAS(x_bs); #endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS const ulong x_qt = chunk ^ TSNTABLES_SWAR_MASK_COMILLA; const ulong has_qt = TSNTABLES_SWAR_HAS(x_qt); //--- #ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS if((has_bs | has_qt) == 0) // Caso comun. .. ninguno de los dos.. continuamos.. { m_pos += 8; continue; } #else // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS if(has_qt == 0) // Caso comun. .. ninguno de los dos.. continuamos.. { m_pos += 8; continue; } #endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS //--- #ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS if(has_bs == 0) // Si not iene bs (pero confirmamos que no es 0) // Entonces no tirne bs pero si qt salimos de una.. { #endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS const ulong flag_real = TSNTABLES_BIT_DEJAR_SOLO_MINUS_SIG_BYTE(has_qt); //--- m_pos += TSNTABLES_CTZ_64_GET_BYTE(flag_real); m_cinta[m_cinta_pos++] = JSON_VTYPE_KEY | long(m_pos - start) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; m_pos++; // Luego del " break; #ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS } //--- const uchar compacted_bs = TSNTABLES_COMPACT_UL(has_bs); const uchar prev = (((compacted_bs << 1) | TSNTABLES_MASK_IMPARES) - compacted_bs) ^ TSNTABLES_MASK_IMPARES; const uchar escaped = prev ^ compacted_bs; //--- const uchar compacted_qt = TSNTABLES_COMPACT_UL(has_qt); const uchar qt_final = compacted_qt & ~escaped; //--- if(qt_final) // Hay un qt real de cierre { //--- // Avanzamos y cerramos.. m_pos += g_tsntables_table_ctz_i8[qt_final]; m_cinta[m_cinta_pos++] = JSON_VTYPE_STRING | long(m_pos - start) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; m_pos++; // Luego del " break; } else { m_pos += 8; // Print(CharToString(m_raw[m_pos])); if(((prev & compacted_bs) >> 7U) != 0) // Overflow el ultimo char es \ y el siguiente escapa { //Print("siuu"); m_pos++; // Uno mas.. luego del currend } } #endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS } #else // JSONPARSERBYLEO_ACTIVE_SWAR_KEYS //--- Char por char #ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS while(true) { const uchar c = m_raw[m_pos]; if(c == '\\') { m_pos += 2; continue; } if(c == '"') { //--- m_cinta[m_cinta_pos++] = JSON_VTYPE_KEY | long(m_pos - start) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; m_pos++; break; } m_pos++; } #else // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS*/ //--- while(m_raw[m_pos] != '"') m_pos++; //--- m_cinta[m_cinta_pos++] = JSON_VTYPE_KEY | long(m_pos - start) << TSN_SBL_BIT_STR_LEN | long(start) << TSN_SBL_BIT_STR_START; m_pos++; #endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS #endif // JSONPARSERBYLEO_ACTIVE_SWAR_KEYS //--- Find : while(true) { //--- if(m_raw[m_pos] == ':') break; //--- m_pos++; if(m_pos >= m_len) { m_last_err = TSN_JSON_ERR_MALFODERD_KEY_EXPECTED_DOS_PUNTOS; return false; } } //--- Buscamos valor TSN_JSON_NEXT_VALUE_COMM_KEY //--- break; } default: return false; } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ __forceinline int CJsonParser::GetStepPure(const int idx) const { switch(int(m_cinta[idx] & TSN_SBL_BIT_MASK_TYPE)) { case JSON_VTYPE_KEY: return 1; case JSON_VTYPE_OBJ: case JSON_VTYPE_ARR: case JSON_VTYPE_UINTEGER: case JSON_VTYPE_INTEGER: case JSON_VTYPE_REAL: return 2; case JSON_VTYPE_BOOLEAN: case JSON_VTYPE_STRING: case JSON_VTYPE_NULL: return 1; default: return 1; } } //+------------------------------------------------------------------+ //| GetStep: posiciones que ocupa el nodo idx en la cinta | //+------------------------------------------------------------------+ __forceinline int CJsonParser::GetStep(const int idx) const { switch(int(m_cinta[idx] & TSN_SBL_BIT_MASK_TYPE)) { case JSON_VTYPE_KEY: return 1; case JSON_VTYPE_OBJ: case JSON_VTYPE_ARR: return int(m_cinta[idx] >> TSN_SBL_BIT_START_NUM_C); case JSON_VTYPE_UINTEGER: case JSON_VTYPE_INTEGER: case JSON_VTYPE_REAL: return 2; case JSON_VTYPE_BOOLEAN: case JSON_VTYPE_STRING: case JSON_VTYPE_NULL: return 1; default: return 1; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CJsonNode CJsonParser::GetRoot() { if(m_cinta_pos == 0) return CJsonNode::EMPTY_NODE; return CJsonNode(&this, 0, GetStep(0)); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CJsonParser::SerializeToDom(CDomNodeBase *root, CDomNodeManager* manager, int cur, const int end) { //--- Temp m_last_err = TSN_JSON_NOT_ERR; CDomNodeBase* prev_value; // valolr qeu devuelve key CDomNodeBase* current_container[JSONPARSERBYLEO_MAX_STACK]; // contenedor int current_ends[JSONPARSERBYLEO_MAX_STACK]; int sp = 0; //--- Inicial const int c = int((m_cinta[cur] >> TSN_SBL_BIT_START_NUM_EL) & TSN_SBL_BIT_MASK_NUM_EL); if((m_cinta[cur]&TSN_SBL_BIT_MASK_TYPE) == JSON_VTYPE_OBJ) root.NewObj(c); else root.NewArr(c); //--- current_container[0] = root; current_ends[sp] = end; //--- cur += 2; //--- It while(true) { //--- Check while(cur >= current_ends[sp]) { sp--; // Nivel menos //Print("sp luego: ", sp); if(sp < 0) return true; } //--- const ENUM_JSON_VTYPE tipo = ENUM_JSON_VTYPE(m_cinta[cur] & TSN_SBL_BIT_MASK_TYPE); //Print(EnumToString(tipo), " | ", cur, " | " , sp); //--- switch(tipo) { case JSON_VTYPE_KEY: { const int s = int(m_cinta[cur] >> TSN_SBL_BIT_STR_START); const int slen = int((m_cinta[cur] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); #ifdef JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS const string str = Unescape(s, s + slen - 1); #else const string str = CharArrayToString(m_raw, s, slen); #endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS prev_value = current_container[sp][str]; break; } case JSON_VTYPE_OBJ: { const int count = (int((m_cinta[cur] >> TSN_SBL_BIT_START_NUM_EL) & TSN_SBL_BIT_MASK_NUM_EL)) << 1; if(current_container[sp].m_type == JSON_VTYPE_ARR) // [{}] { const int lock = sp++; current_container[sp] = new CDomNodeBase(manager); current_container[sp].NewObj(count); current_container[lock].AddItem(current_container[sp]); } else // {key:{}} { sp++; prev_value.NewObj(count); current_container[sp] = prev_value; } current_ends[sp] = cur + int(m_cinta[cur] >> TSN_SBL_BIT_START_NUM_C); break; } case JSON_VTYPE_ARR: { const int count = int((m_cinta[cur] >> TSN_SBL_BIT_START_NUM_EL) & TSN_SBL_BIT_MASK_NUM_EL); if(current_container[sp].m_type == JSON_VTYPE_ARR) { const int lock = sp++; current_container[sp] = new CDomNodeBase(manager); current_container[sp].NewArr(count); current_container[lock].AddItem(current_container[sp]); } else // {key:[]} { sp++; prev_value.NewArr(count); current_container[sp] = prev_value; } current_ends[sp] = cur + int(m_cinta[cur] >> TSN_SBL_BIT_START_NUM_C); break; } case JSON_VTYPE_UINTEGER: { if(current_container[sp].m_type == JSON_VTYPE_ARR) current_container[sp].AddItem(new CDomNodeBase(manager, ulong(m_cinta[cur + 1]))); else prev_value = (ulong)m_cinta[cur + 1]; break; } case JSON_VTYPE_INTEGER: { if(current_container[sp].m_type == JSON_VTYPE_ARR) current_container[sp].AddItem(new CDomNodeBase(manager, m_cinta[cur + 1])); else prev_value = m_cinta[cur + 1]; break; } case JSON_VTYPE_REAL: { TsnBitInterprete un; un.long_value = m_cinta[cur + 1]; //--- if(current_container[sp].m_type == JSON_VTYPE_ARR) current_container[sp].AddItem(new CDomNodeBase(manager, un.double_value)); else prev_value = un.double_value; break; } case JSON_VTYPE_BOOLEAN: { const bool v = ((m_cinta[cur] >> TSN_SBL_BIT_START_ENDTYPE) & 1) != 0; //--- if(current_container[sp].m_type == JSON_VTYPE_ARR) current_container[sp].AddItem(new CDomNodeBase(manager, v)); else prev_value = v; break; } case JSON_VTYPE_STRING: { const int s = int(m_cinta[cur] >> TSN_SBL_BIT_STR_START); const int slen = int((m_cinta[cur] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); //--- if(current_container[sp].m_type == JSON_VTYPE_ARR) { CDomNodeBase* ptr = new CDomNodeBase(TSN_SBL_BASE_TYPE_STR, manager); current_container[sp].AddItem(ptr); // lo agregamos const int idx = ptr.m_v.ix; if(!MakeString(m_raw, s, slen, manager.m_string_stack[idx])) { m_last_err = TSN_JSON_ERR_IN_MATERIALIZE_STRING_PARSE_ERR; return false; } } else { prev_value.Type(TSN_SBL_BASE_TYPE_STR); // lo hacemos string const int idx = prev_value.m_v.ix; if(!MakeString(m_raw, s, slen, manager.m_string_stack[idx])) { m_last_err = TSN_JSON_ERR_IN_MATERIALIZE_STRING_PARSE_ERR; return false; } } break; } case JSON_VTYPE_NULL: { //--- if(current_container[sp].m_type == JSON_VTYPE_ARR) current_container[sp].AddItem(new CDomNodeBase(manager)); else prev_value.m_type = JSON_VTYPE_NULL; break; } default: break; } //--- cur += GetStepPure(cur); } //--- return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CJsonParser::PrintCintaTypes(const int start, const int num) const { //--- int p = fmax(start, 0); const int end = (num == WHOLE_ARRAY || (p + num) > m_cinta_pos) ? m_cinta_pos : (p + num); //--- string str; string text; StringReserve(text, 256); // algo razonable. //--- while(p < end) { const ENUM_JSON_VTYPE tipo = ENUM_JSON_VTYPE(m_cinta[p] & TSN_SBL_BIT_MASK_TYPE); text = "[" + (string)p + "] " + EnumToString(tipo) + " | "; //--- switch(tipo) { case JSON_VTYPE_KEY: { const int s = int(m_cinta[p] >> TSN_SBL_BIT_STR_START); const int slen = int((m_cinta[p] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); //--- if(MakeString(m_raw, s, slen, str)) text += "start=" + (string)s + " len=" + (string)slen + " val=\"" + str + "\""; else text += "start=" + (string)s + " len=" + (string)slen + " val=Invalid"; break; } case JSON_VTYPE_OBJ: case JSON_VTYPE_ARR: { const int count = int((m_cinta[p] >> TSN_SBL_BIT_START_NUM_EL) & TSN_SBL_BIT_MASK_NUM_EL); const int num_c = int(m_cinta[p] >> TSN_SBL_BIT_START_NUM_C); const int raw_s = int(m_cinta[p + 1] & TSN_JSON_BIT_RAW_MASK_S); const int raw_e = int(m_cinta[p + 1] >> TSN_JSON_BIT_END_T); text += "count=" + (string)count + " num_c=" + (string)num_c + " raw_start=" + (string)raw_s + " raw_end=" + (string)raw_e; break; } case JSON_VTYPE_UINTEGER: { text += "val=" + CValueToBuffer::ULLToStr(ulong(m_cinta[p + 1])); break; } case JSON_VTYPE_INTEGER: { text += "val=" + (string)m_cinta[p + 1]; break; } case JSON_VTYPE_REAL: { TsnBitInterprete un; un.long_value = m_cinta[p + 1]; text += "val=" + (string)un.double_value; break; } case JSON_VTYPE_BOOLEAN: text += "val=" + (string)(bool)((m_cinta[p] >> TSN_SBL_BIT_START_ENDTYPE) & 1); break; case JSON_VTYPE_STRING: { const int s = int(m_cinta[p] >> TSN_SBL_BIT_STR_START); const int slen = int((m_cinta[p] >> TSN_SBL_BIT_STR_LEN) & TSN_SBL_BIT_STR_MASK_LEN); //--- if(MakeString(m_raw, s, slen, str)) text += "start=" + (string)s + " len=" + (string)slen + " val=\"" + str + "\""; else text += "start=" + (string)s + " len=" + (string)slen + " val=Invalid"; break; } case JSON_VTYPE_NULL: text += "null"; break; //--- default: break; } Print(text); p += GetStepPure(p); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ static void CJsonParser::PrintError(const string& header, const uchar& buf[], const int len, int col, int line, ENUM_TSN_JSON_LAST_ERR err, string& salida, bool print = true) { //--- string out = ""; out.Reserve(256); //--- if(header.Length()) out += "[" + header + "]\n"; //--- out += StringFormat("JSON error at line %d, col %d:\n", line, col); //--- switch(err) { case TSN_JSON_ERR_INVALID_EXT_FILE: out += "Invalid file extension por JsonParserByLeo"; break; case TSN_JSON_ERR_INVALID_CHAR: out += "Invalid character found in json"; break; case TSN_JSON_ERR_MALFORDMED_JSON_AFTER_VAL: out += "Invalid character find in json, finding comma or context close (], })"; break; case TSN_JSON_ERR_MALFORDMED_JSON_AFTER_COR_INI: out += "Invalid character find in json, finding valid value after '['"; break; case TSN_JSON_ERR_MALFORDMED_JSON_FIND_VAL: out += "Invalid character find in json, finding valid value"; break; case TSN_JSON_ERR_MALFODERD_KEY_EXPECTED_DOS_PUNTOS: out += "Invalid JSON key, One of two errors: \"Expected a ':' after a JSON key\" or \"Malformed JSON while searching for characters.\""; break; case TSN_JSON_ERR_MALFOMED_LEN_SUPERADO: out += "Len has superated, but json are not closed, malformed json"; break; case TSN_JSON_ERR_JSON_NOT_FINISH: out += "Json read has finish but not closed in ] or }, malformed json"; break; case TSN_JSON_ERR_LEADING_ZEROS: out += "A number in JSON notation cannot have leading zeros."; break; case TSN_JSON_ERR_EXPECTED_NUMBER_AFECTER_EXP: out += "A number was expected after the 'E' exponent; an invalid character was found."; break; case TSN_JSON_ERR_EXPECTED_NUMBER_AFECTER_DECIMALP: out += "A numeric value was expected after the decimal point."; break; case TSN_JSON_ERR_MALFORMED_TRUE: out += "Malformed 'true' in json"; break; case TSN_JSON_ERR_MALFORMED_FALSE: out += "Malformed 'false' in json"; break; case TSN_JSON_ERR_MALFORMED_NULL: out += "Malformed 'null' in json"; break; case TSN_JSON_ERR_IN_MATERIALIZE_STRING_PARSE_ERR: out += "Error materializing string; possible causes include an invalid escape character or a malformed \\u sequence."; break; case TSN_JSON_ERR_OVERFLOW_IN_STACK: out += "Overflow for maxium stack"; break; case TSN_JSON_ERR_NOT_STRUCUTURAL_CHARS_FOUND: out += "Not structural character found in this json ({ | } | [ | ] | : | ,)"; break; case TSN_JSON_ERR_INVALID_STATE_IN_PARSE_DOUBLE_E: out += "Invalid state for Json Sax Parsing, in parse double value"; break; //--- default: out += "Unknow error"; break; } //--- CParserErrFormat::Format(len, buf, line, col, out, salida); //--- if(print) Print(salida); } //+------------------------------------------------------------------+ // Solo a que tener cuidado con true\false\null // aparte tok invalid tambien dado que este ultimo retorna false void CJsonParser::CatchErr() { //--- if(m_pos >= m_len) m_pos = m_len - 1; //--- if(m_last_err != TSN_JSON_NOT_ERR) return; // ya tiene valor no hace falta //--- switch(m_next) { case TSN_JSON_TOK_BOOL_TRUE: m_last_err = TSN_JSON_ERR_MALFORMED_TRUE; break; case TSN_JSON_TOK_BOOL_FALSE: m_last_err = TSN_JSON_ERR_MALFORMED_FALSE; break; case TSN_JSON_TOK_NULL: m_last_err = TSN_JSON_ERR_MALFORMED_NULL; break; default: { if(m_next == TSN_JSON_TOK_INVALID) m_last_err = TSN_JSON_ERR_INVALID_CHAR; break; } } } //+------------------------------------------------------------------+ void CJsonParser::ErrorInfo(const string header = "") { //--- CatchErr(); //--- if(m_last_err == TSN_JSON_NOT_ERR) return; //--- int col, line; GetLastErrorLocation(col, line); //--- string out = ""; PrintError(header, m_raw, m_len, col, line, m_last_err, out); } //+------------------------------------------------------------------+ //| Arrays helpers para evitar la resolcuino de ctx en todo mommento | //+------------------------------------------------------------------+ template void CJsonParser::ToArray(int cur, T& out_arr[], const int end) const { //--- int k = 0; switch(int(m_cinta[cur] & TSN_SBL_BIT_MASK_TYPE)) { case JSON_VTYPE_UINTEGER: { while(cur < end) { out_arr[k++] = T(ulong(m_cinta[cur + 1])); cur += 2; } break; } case JSON_VTYPE_INTEGER: { while(cur < end) { out_arr[k++] = T(m_cinta[cur + 1]); cur += 2; } break; } case JSON_VTYPE_REAL: { while(cur < end) { TsnBitInterprete bit; bit.long_value = m_cinta[cur + 1]; out_arr[k++] = T(bit.double_value); cur += 2; } break; } case JSON_VTYPE_BOOLEAN: { while(cur < end) { out_arr[k++] = T((m_cinta[cur] >> TSN_SBL_BIT_START_ENDTYPE) & 1); cur++; } break; } case JSON_VTYPE_STRING: { while(cur < end) { static string str; if(MakeString(m_raw, TSN_SBL_CLS_STR_START(cur), TSN_SBL_CLS_STR_LEN(cur), str)) out_arr[k++] = T(str); //--- cur++; } break; } default: break; } } //+------------------------------------------------------------------+ template bool CJsonParser::ExistInArray(int cur, const T val, const uint flags, const int end) const { while(cur < end) { //--- uint ct = uint(m_cinta[cur] & TSN_SBL_BIT_MASK_TYPE); if(((1U << ct) & flags) == 0) { cur += GetStepPure(cur); continue; } //--- switch(ct) { case JSON_VTYPE_UINTEGER: { if((ulong)m_cinta[cur + 1] == T(val)) return true; break; } case JSON_VTYPE_INTEGER: { if(m_cinta[cur + 1] == T(val)) return true; break; } case JSON_VTYPE_REAL: { bit.long_value = m_cinta[cur + 1]; if(bit.double_value == T(val)) return true; break; } case JSON_VTYPE_BOOLEAN: { if(val == T((m_cinta[cur] >> TSN_SBL_BIT_START_ENDTYPE) & 1)) return true; break; } case JSON_VTYPE_STRING: { static string str; if(MakeString(m_raw, TSN_SBL_CLS_STR_START(cur), TSN_SBL_CLS_STR_LEN(cur), str) && val == T(str)) return true; break; } case JSON_VTYPE_NULL: return true; default: return false; } //--- cur += GetStepPure(cur); } return false; } //+------------------------------------------------------------------+ template bool CJsonParser::ExistInArrayHomogeneo(int cur, const T val, const int end) const { switch(int(m_cinta[cur] & TSN_SBL_BIT_MASK_TYPE)) { case TSN_SBL_BASE_TYPE_UINT: { while(cur < end) { if(val == T(ulong(m_cinta[cur + 1]))) return true; cur += 2; } } case TSN_SBL_BASE_TYPE_INT: { while(cur < end) { if(val == T(m_cinta[cur + 1])) return true; cur += 2; } return false; } case TSN_SBL_BASE_TYPE_FLT: { while(cur < end) { TsnBitInterprete bit; bit.long_value = m_cinta[cur + 1]; if(val == T(bit.double_value)) return true; cur += 2; } return false; } case TSN_SBL_BASE_TYPE_BOL: { while(cur < end) { if(val == T((m_cinta[cur] >> TSN_SBL_BIT_START_ENDTYPE) & 1)) return true; cur++; } return false; } case TSN_SBL_BASE_TYPE_STR: { while(cur < end) { static string str; if(MakeString(m_raw, TSN_SBL_CLS_STR_START(cur), TSN_SBL_CLS_STR_LEN(cur), str) && val == T(str)) return true; cur++; } break; } default: return false; } return false; } //--- } #endif // JSONPARSERBYLEO_SRC_JSONPARSER_MQH