//+------------------------------------------------------------------+ //| 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_JSONCORE_JSONPARSER_MQH #define JSONPARSERBYLEO_SRC_JSONCORE_JSONPARSER_MQH //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #include "JsonDefines.mqh" #include "JsonUE.mqh" //--- #ifdef JSONPARSERBYLEO_DLL #include "..\\DLL\\Main.mqh" #endif // JSONPARSERBYLEO_DLL //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ namespace TSN { //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CJsonParser : public CBaseStructuredLan { protected: //--- #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) {} //--- Correct padding // Para data raw se puede usar el json uchar directamtne void CorrectPadding(); #ifdef JSONPARSERBYLEO_DLL void CorrectPaddingSimd(); #endif // JSONPARSERBYLEO_DLL //--- Parseo bool AutoParseByFileExt(const int file_ext_type); 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 = ""); //--- Config void Options(const uint f); //--- Step __forceinline int GetStep(const int idx) const; __forceinline int GetStepPure(const int idx) const; //--- GetRoot CJsonNode GetRoot(); //--- Info void PrintCintaTypes(const int start, const int num) const; //--- Node void NodeHashing(int curr, const int obj_count, const int bend, int& table_pos); bool SerializeToDom(CDomNodeBase* root, CDomNodeManager* manager, int cur, const int end); //--- Strings\Keys // uso en get value o exatcion template __forceinline string GetRawAsStr(int idx) const { return CharArrayToString(m_raw, TSN_SBL_CLS_STR_START(idx, int), TSN_SBL_CLS_STR_LEN(idx, (2 - sizeof(TKey)), int)); } template __forceinline int GetRawAsUArr(int idx, uchar &res[], int pos = 0) const { return ArrayCopy(res, m_raw, pos, TSN_SBL_CLS_STR_START(idx, int), TSN_SBL_CLS_STR_LEN(idx, (2 - sizeof(TKey)), int)); } template __forceinline bool GetStrAsStr(int idx, string &res) const { return JSONPBL_MAKESTRING(m_raw, TSN_SBL_CLS_STR_START(idx, int), TSN_SBL_CLS_STR_LEN(idx, (2 - sizeof(TKey)), int), res); } template __forceinline int GetStrAsUArr(int idx, uchar &res[], int pos = 0) const { return JSONPBL_MAKEUARR(m_raw, TSN_SBL_CLS_STR_START(idx, int), TSN_SBL_CLS_STR_LEN(idx, (2 - sizeof(TKey)), int), res, pos, BSFL_UE_SURROGATES); } //--- Funciones para node (interno de uso interno) 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; __forceinline int NodeAt(int cur, const int index) const; int NodeFindByHashFvn1A64(const ulong kh, int cur, const int end); __forceinline int NodeObjAtSlow(int cur, const int index) const; int NodeKeyToPositionSlow(const ulong kh, int cur, const int end); int NodeGetKeys(int cur, string &keys[], const int end) const; //--- Print error general 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); //--- Tablas generales static const string s_dtype_to_str[JSON_VTYPE_TOTAL]; static string s_str; }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CJsonParser::CJsonParser(void) { m_next = TSN_JSON_TOK_INVALID + 1; // Apunta a un valor invalido // Estro para que en caso se usa parse simd (no de errores "fantasma" dado que m_next no se usa ahi) #ifdef JSONPARSERBYLEO_DLL m_index_r = ArrayResize(m_index, 256, 256); #endif // JSONPARSERBYLEO_DLL } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CJsonParser::Options(const uint f) { m_jit_enabled = (f & BSFL_OPT_F_ENABLE_JIT) != 0 ? TSN_SBL_BIT_JIT_INITIAL_V : TSN_SBL_BIT_JIT_INV_VAL; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #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 // {"a":0} //+------------------------------------------------------------------+ 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); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // ponemos el jit attemp en vlao rinvalido, y table size le hacemos un pop.. #define BASESPARSERSAN_NODEHASHING_FINISH_ERR \ m_cinta[lock] = TSN_SBL_BIT_JIT_INV_VAL; \ m_tables_size--; //--- void 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 //--- 4 siempre dado que menos no se permite.. m_pfh.MaxValSeed(m_max_att++); m_pfh.InitAlg(obj_count, 0.70, 4); //--- 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; const int lock = curr + 1; curr += TSN_SBL_SLOT_OBJ_SIZE; // Ahora en key //--- while(curr < bend) { //--- m_tables[table_pos].pos_arr[pos_c] = curr; // Assing //--- const ulong v = m_cinta[curr]; ulong hash; if(TSN_SBL_KEY_HAS_ISN_HASH(v)) // no tiene hash { int i = int(v >> TSN_SBL_BIT_STR_START); if(!JSONPBL_MAKEHASH(m_raw, i, m_len, hash)) { BASESPARSERSAN_NODEHASHING_FINISH_ERR return; } m_cinta[curr] |= TSN_SBL_KEY_FLAG_HASH; // lo ponemos como valido... m_cinta[curr + TSN_SBL_KEY_OFF_HASH] = hash; // para reproducibildiad } else hash = m_cinta[curr + TSN_SBL_KEY_OFF_HASH]; // en la siguiente posicion esta el hash lo obtenemos tal cual //--- keys_h[pos_c] = hash; posiciones[pos_c] = pos_c; pos_c++; //--- curr += TSN_SBL_KEYSLOT_SIZE; // salta KEY curr += GetStep(curr); // salta VAL } //--- assing de tamaños const int fn = m_pfh.m_final_table_size; m_tables[table_pos].sizes = BSFL_T_PACK(m_pfh.m_buckets_size_last, m_pfh.m_final_table_size_last); //--- resize de arrays iniciales ArrayResize(m_tables[table_pos].pos_index, fn); 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; //---- BASESPARSERSAN_NODEHASHING_FINISH_ERR return; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int CJsonParser::CalcRegType(const string& file_name) { return (int)JPBL_HashExt(file_name); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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 | //+------------------------------------------------------------------+ //--- para aumtenar el numero de elementos. #define TSN_JSON_AUMENT curr_count++; //--- 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) & 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; \ } //--- unrolled find key #define TSN_JSON_FINDKEY_FINAL_U4 \ if(m_raw[m_pos] == '"') \ break; \ m_pos++; \ if(m_raw[m_pos] == '"') \ break; \ m_pos++; \ if(m_raw[m_pos] == '"') \ break; \ m_pos++; \ if(m_raw[m_pos] == '"') \ break; \ m_pos++; //--- unrooled find normal #define JSONPARSERBYLEO_FIND_FINAL_STR_IT \ if((c = m_raw[m_pos]) == '"') \ break; \ m_pos += (c == '\\') + 1; \ if((c = m_raw[m_pos]) == '"') \ break; \ m_pos += (c == '\\') + 1; \ if((c = m_raw[m_pos]) == '"') \ break; \ m_pos += (c == '\\') + 1; \ if((c = m_raw[m_pos]) == '"') \ break; \ m_pos += (c == '\\') + 1; //+------------------------------------------------------------------+ //| Parseo de numeros | //+------------------------------------------------------------------+ //--- make string #define JSONPARSERBYLEO_NUM_MAKE_STRING m_cinta[m_cinta_pos++] = JSON_VTYPE_STRING \ | ulong(m_pos - start) << TSN_SBL_BIT_STR_LEN(TSN_SBL_SLEN_STR) \ | ulong(start) << TSN_SBL_BIT_STR_START; //+------------------------------------------------------------------+ //| Parse con simd | //+------------------------------------------------------------------+ // m_last_err = TSN_JSON_NOT_ERR; quizas no hague falta dado qeu en la DLL siemrpe se stea con noterr o eso #ifdef JSONPARSERBYLEO_DLL __forceinline bool CJsonParser::ParseSimd() { //--- Iniciales m_pos = m_offset; m_tables_size = 0; return JsonParserResolve(m_raw, m_cinta, m_index, m_len, m_jit_enabled, (int&)m_last_err, m_cinta_pos, m_pos ); } #endif // JSONPARSERBYLEO_DLL //+------------------------------------------------------------------+ //| Parse normal | //+------------------------------------------------------------------+ bool CJsonParser::Parse() { //--- m_last_err = TSN_JSON_NOT_ERR; m_pos = m_offset; m_cinta_pos = 0; m_tables_size = 0; //--- uint curr_state = 0; uint curr_count = 0; uint curr_padre = 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 // No easy { uchar __c = m_raw[++m_pos]; while(__c < 33) __c = m_raw[++m_pos]; //--- if(__c == '{') m_next = TSN_JSON_TOK_LLAVE_INI; else if(__c == '[') m_next = TSN_JSON_TOK_COR_INI; else // Single value { m_next = TSN_JSON_TOK_INVALID; } } //--- Bucle while(true) { switch(m_next) { //--- case TSN_JSON_TOK_NUMBER_NEG: { //--- solo 3 varaibles nada mas en general (garantizado) long v = 0; const uint 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 uint digitos = m_pos - start; // digitos que se van acomulando (parte ent + dec) if(STRCONV_DECX_CH_IS_PDEC(ch)) { uint 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.ulong_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: { //--- const uint start = m_pos; // Primer valor const uchar fc = m_raw[start] ^ '0'; ulong v = fc; // Tal cual sin mas.. // Segundo valor uchar ch = m_raw[++m_pos] ^ '0'; //--- switch(0) { default: // scope con psoiblidad de break. { //--- if(ch > 9) // Mayor break; if(!v) // LZ { 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 uint 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) { uint 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.ulong_value; } else { JSONPARSERBYLEO_NUM_MAKE_STRING } } else { m_cinta[m_cinta_pos++] = JSON_VTYPE_UINTEGER; m_cinta[m_cinta_pos++] = v; } //--- TSN_JSON_AUMENT TSN_JSON_NEXT_NO_NEXT_KEY break; } //--- case TSN_JSON_TOK_STRING: { //--- const uint 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; const ulong x_qt = chunk ^ TSNTABLES_SWAR_MASK_COMILLA; ulong has_bs = TSNTABLES_SWAR_HAS(x_bs); ulong has_qt = TSNTABLES_SWAR_HAS(x_qt); //--- if((has_bs | has_qt) == 0) // Fast path { m_pos += 8; continue; } //--- if(has_bs == 0) // Si not iene bs (pero confirmamos que no es 0) (Fast path) { 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 | ulong(m_pos - start) << TSN_SBL_BIT_STR_LEN(TSN_SBL_SLEN_STR) | ulong(start) << TSN_SBL_BIT_STR_START; m_pos++; // Luego del " break; } //--- Slow path has_bs = TSNTABLES_SWAR_HAS_EXACT(x_bs); has_qt = TSNTABLES_SWAR_HAS_EXACT(x_qt); //--- 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 | ulong(m_pos - start) << TSN_SBL_BIT_STR_LEN(TSN_SBL_SLEN_STR) | ulong(start) << TSN_SBL_BIT_STR_START; //--- m_pos++; break; } else { m_pos += 8;// + ((prev & compacted_bs) >> 7U); // 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 uchar c; while(true) // Find unrrolled 20 { JSONPARSERBYLEO_FIND_FINAL_STR_IT JSONPARSERBYLEO_FIND_FINAL_STR_IT JSONPARSERBYLEO_FIND_FINAL_STR_IT JSONPARSERBYLEO_FIND_FINAL_STR_IT JSONPARSERBYLEO_FIND_FINAL_STR_IT } //--- m_cinta[m_cinta_pos++] = JSON_VTYPE_STRING | ulong(m_pos - start) << TSN_SBL_BIT_STR_LEN(TSN_SBL_SLEN_STR) | ulong(start) << TSN_SBL_BIT_STR_START; 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 | 1ULL << TSN_SBL_BIT_START_BOOL); //--- 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(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: { //--- guardar lo uqe tenaismos (numero de elementos) (+1 para contar este nuevo elemento) m_cinta[curr_padre] = curr_count + 1; //--- nuevo, ahora guardamos la direccion de nuesto padre y la nuestar (rempalzao num el por mientas) m_cinta[m_cinta_pos] = JSON_VTYPE_OBJ | ulong(m_cinta_pos) << TSN_SBL_PARSE_START_CINTAPOS | ulong(curr_padre) << TSN_SBL_BIT_START_NUM_C; curr_padre = ++m_cinta_pos; // apunta al inicio + 1 (lo modificamos para count, ahora apunta aqui..) m_cinta_pos++; // salta la posicion 1 //--- reiniciamos los estados curr_state = TSN_JSON_CTX_IN_OBJ; curr_count = 0; //--- uchar _c = m_raw[++m_pos]; while(_c < 33) _c = m_raw[++m_pos]; //--- if(_c == '"') m_next = TSN_JSON_TOK_KEY; else if(_c == '}') m_next = TSN_JSON_TOK_LLAVE_END; else { m_last_err = TSN_JSON_ERR_MALFORDMED_JSON_AFTER_LLAVE_INI; m_next = TSN_JSON_TOK_INVALID; } //--- break; } case TSN_JSON_TOK_COR_INI: { //--- guardar lo uqe tenaismos (numero de elementos) (+1 para contar este nuevo elemento) m_cinta[curr_padre] = curr_count + 1; //--- nuevo, ahora guardamos la direccion de nuesto padre y la nuestar (rempalzao num el por mientas) m_cinta[m_cinta_pos] = JSON_VTYPE_ARR | ulong(m_cinta_pos) << TSN_SBL_PARSE_START_CINTAPOS | ulong(curr_padre) << TSN_SBL_BIT_START_NUM_C; curr_padre = ++m_cinta_pos; // apunta al inicio + 1 (lo modificamos para count, ahora apunta aqui..) m_cinta_pos++; // salta la posicion 1 //--- reiniciamos los estados curr_state = TSN_JSON_CTX_IN_ARR; curr_count = 0; //--- Find //- con el pre salta.. el [ uchar _c = m_raw[++m_pos]; while(_c < 33) _c = m_raw[++m_pos]; //- check 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: { //--- cacheamos el valor de cinta [curr_padre-1] = apunta a los datos m_cinta[curr_padre] = m_jit_enabled; // le damos su valor final const uint idata = --curr_padre; const ulong v = m_cinta[idata]; // ahora si rehacemos el valor con todo ya listo.. (curr padre apunta a la posicion correcta) m_cinta[idata] = JSON_VTYPE_OBJ | ulong(curr_count) << TSN_SBL_BIT_START_NUM_EL | ulong(m_cinta_pos - ((v >> 1) & TSN_SBL_PARSE_MASK_CINTAPOS_S)) << TSN_SBL_BIT_START_NUM_C; curr_padre = uint(v >> TSN_SBL_BIT_START_NUM_C); // ahora obtenemos su padre.. //--- if(curr_padre == idata) // dado que cur_padre apunta a la psocion 2.. [0][1 aqui] entonces con 1... return true; //--- curr_count = (uint)m_cinta[curr_padre]; // le devolvemos.. curr_state = TSN_JSON_MAKE_STATE(m_cinta[curr_padre - 1] & TSN_SBL_PARSE_MASK_OA_T); m_pos++; //--- TSN_JSON_NEXT_NO_NEXT_KEY break; } case TSN_JSON_TOK_COR_END: { //--- cacheamos el valor de cinta [curr_padre-1] = apunta a los datos const uint idata = --curr_padre; const ulong v = m_cinta[idata]; // ahora si rehacemos el valor con todo ya listo.. (curr padre apunta a la posicion correcta) m_cinta[idata] = JSON_VTYPE_ARR | ulong(curr_count) << TSN_SBL_BIT_START_NUM_EL | ulong(m_cinta_pos - ((v >> 1) & TSN_SBL_PARSE_MASK_CINTAPOS_S)) << TSN_SBL_BIT_START_NUM_C; curr_padre = uint(v >> TSN_SBL_BIT_START_NUM_C); // ahora obtenemos su padre.. //--- if(curr_padre == idata) // dado que cur_padre apunta a la psocion 2.. [0][1 aqui] entonces con 1... return true; //--- curr_count = (uint)m_cinta[curr_padre]; // le devolvemos.. curr_state = TSN_JSON_MAKE_STATE(m_cinta[curr_padre - 1] & TSN_SBL_PARSE_MASK_OA_T); m_pos++; //--- TSN_JSON_NEXT_NO_NEXT_KEY break; } case TSN_JSON_TOK_KEY: { const uint start = ++m_pos; //--- 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 | ulong(m_pos - start) << TSN_SBL_BIT_STR_LEN(TSN_SBL_SLEN_KEY) | ulong(start) << TSN_SBL_BIT_STR_START; m_pos++; break; } m_pos++; } #else // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS*/ //--- while(true) { TSN_JSON_FINDKEY_FINAL_U4 TSN_JSON_FINDKEY_FINAL_U4 TSN_JSON_FINDKEY_FINAL_U4 TSN_JSON_FINDKEY_FINAL_U4 } //--- m_cinta[m_cinta_pos++] = JSON_VTYPE_KEY | ulong(m_pos - start) << TSN_SBL_BIT_STR_LEN(TSN_SBL_SLEN_KEY) | ulong(start) << TSN_SBL_BIT_STR_START; m_pos++; #endif // JSONPARSERBYLEO_ENABLE_ESCAPED_COMMILAS_IN_KEYS //--- m_cinta_pos++; // hash ignoramos. //--- Find : while(m_raw[m_pos] != ':') { //--- //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; } } } //+------------------------------------------------------------------+ //| GetStep | //+------------------------------------------------------------------+ __forceinline int CJsonParser::GetStepPure(const int idx) const { switch(int(m_cinta[idx] & TSN_SBL_BIT_MASK_TYPE)) { case JSON_VTYPE_ARR: case JSON_VTYPE_OBJ: 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; case JSON_VTYPE_KEY: return TSN_SBL_KEYSLOT_SIZE; default: return 1; } } //+------------------------------------------------------------------+ __forceinline int CJsonParser::GetStep(const int idx) const { switch(int(m_cinta[idx] & TSN_SBL_BIT_MASK_TYPE)) { case JSON_VTYPE_ARR: case JSON_VTYPE_OBJ: 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; case JSON_VTYPE_KEY: return TSN_SBL_KEYSLOT_SIZE; default: return 1; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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_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_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_UINTEGER: { 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_INTEGER: { if(current_container[sp].m_type == JSON_VTYPE_ARR) current_container[sp].AddItem(new CDomNodeBase(manager, (long)m_cinta[cur + 1])); else prev_value = (long)m_cinta[cur + 1]; break; } case JSON_VTYPE_REAL: { TsnBitInterprete un; un.ulong_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_BOOL) != 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 = TSN_SBL_CLS_STR_START(cur, int); const int slen = TSN_SBL_CLS_STR_LEN(cur, TSN_SBL_SLEN_STR, int); //--- 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(!JSONPBL_MAKESTRING(m_raw, s, slen, manager.m_string_stack[idx])) { m_pos = s; 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(!JSONPBL_MAKESTRING(m_raw, s, slen, manager.m_string_stack[idx])) { m_pos = s; 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; } case JSON_VTYPE_KEY: { const int s = TSN_SBL_CLS_STR_START(cur, int); const int slen = TSN_SBL_CLS_STR_LEN(cur, TSN_SBL_SLEN_KEY, int); if(!JSONPBL_MAKESTRING(m_raw, s, slen, s_str)) { m_pos = s; m_last_err = TSN_JSON_ERR_IN_MATERIALIZE_STRING_PARSE_ERR; return false; } prev_value = current_container[sp][s_str]; 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 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_ARR: { const int count = TSN_SBL_CLS_AO_NUM_EL(p, int); const int num_c = TSN_SBL_CLS_AO_STEP(p, int); text += "count=" + (string)count + " num_c=" + (string)num_c; break; } case JSON_VTYPE_OBJ: { const int count = TSN_SBL_CLS_AO_NUM_EL(p, int); const int num_c = TSN_SBL_CLS_AO_STEP(p, int); const bool jit = TSN_SBL_CLS_OBJ_JIT(p + 1) != 0; const ulong attemps = TSN_SBL_CLS_OBJ_JIT_ATTMP(p + 1); text += "count=" + (string)count + " num_c=" + (string)num_c + " is_jit=" + (string)jit + " jit_attemps=" + (string)attemps; break; } case JSON_VTYPE_UINTEGER: { STRCONV_VALTOBUFFER_ULLSTR_WR(m_cinta[p + 1], s_str, w) text += "val=" + s_str; break; } case JSON_VTYPE_INTEGER: { text += "val=" + (string)m_cinta[p + 1]; break; } case JSON_VTYPE_REAL: { TsnBitInterprete un; un.ulong_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_BOOL) & 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_SLEN_STR)) & TSN_SBL_BIT_STR_MASK_LEN(TSN_SBL_SLEN_STR)); //--- if(JSONPBL_MAKESTRING(m_raw, s, slen, s_str)) text += "start=" + (string)s + " len=" + (string)slen + " val=\"" + s_str + "\""; else text += "start=" + (string)s + " len=" + (string)slen + " val=Invalid"; break; } case JSON_VTYPE_NULL: text += "null"; break; 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_SLEN_KEY)) & TSN_SBL_BIT_STR_MASK_LEN(TSN_SBL_SLEN_KEY)); //--- if(JSONPBL_MAKESTRING(m_raw, s, slen, s_str)) text += "start=" + (string)s + " len=" + (string)slen + " val=\"" + s_str + "\""; else text += "start=" + (string)s + " len=" + (string)slen + " val=Invalid"; break; } //--- default: break; } Print(text); p += GetStepPure(p); } } //+------------------------------------------------------------------+ //| Errores | //+------------------------------------------------------------------+ 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_AFTER_LLAVE_INI: out += "Invalid character find in json, finding valid value ['}' or '\"'] 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_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) // Solo si es tok invalid (si no nada) 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); } //+------------------------------------------------------------------+ //| Tablas finales | //+------------------------------------------------------------------+ string CJsonParser::s_str = ""; // streimp para las funciones internas (que requiran string) const string CJsonParser::s_dtype_to_str[JSON_VTYPE_TOTAL] = { "", "", "", "ulong", "long", "double", "bool", "string", "" }; //--- } #endif // JSONPARSERBYLEO_SRC_JSONCORE_JSONPARSER_MQH //+------------------------------------------------------------------+