diff --git a/src/hashutils.cpp b/src/hashutils.cpp index 4409cce..22b47bc 100644 --- a/src/hashutils.cpp +++ b/src/hashutils.cpp @@ -76,7 +76,7 @@ bool hashutils::Extract(LPCCH type, UINT64 hash, LPCH out, SIZE_T outSize) { return true; } -LPCCH hashutils::ExtractTmp(LPCCH type, UINT64 hash) { +LPCH hashutils::ExtractTmp(LPCCH type, UINT64 hash) { ReadDefaultFile(); Extract(type, hash, g_buffer, 2048); return g_buffer; @@ -108,11 +108,22 @@ UINT32 hashutils::Hash32(LPCCH str) { return 0x8001 * ((9 * hash) ^ ((9 * hash) >> 11)); } -UINT64 hashutils::Hash64(LPCCH str) { - UINT64 hash = 0xcbf29ce484222325LL; +UINT64 hashutils::Hash64(LPCCH str, UINT64 start) { + UINT64 hash = start; for (LPCCH data = str; *data; data++) { - hash = hash ^ tolower(*data); + if (*data >= 'A' && *data <= 'Z') { + // to lower + hash = hash ^ (UINT8)(*data - 'A'); + } + else if (*data == '\\') { + // replace path char + hash = hash ^ '/'; + } + else { + hash = hash ^ *data; + } + hash *= 0x100000001b3; } diff --git a/src/hashutils.hpp b/src/hashutils.hpp index 10e4607..66363ce 100644 --- a/src/hashutils.hpp +++ b/src/hashutils.hpp @@ -2,16 +2,85 @@ #include namespace hashutils { + /* + * Read the default hash file + */ void ReadDefaultFile(); + /* + * Load a hash file + */ void LoadMap(LPCWCH file); + /* + * Add a hash into the map + */ void Add(LPCCH str); + /* + * Extract a hash into a buffer + * @param type Hash type + * @param hash Hashed value + * @param out Out buffer + * @param outSize Out size + * @return if the hash was in the hash map + */ bool Extract(LPCCH type, UINT64 hash, LPCH out, SIZE_T outSize); - LPCCH ExtractTmp(LPCCH type, UINT64 hash); + /* + * Extract a hash into a buffer + * @param type Hash type + * @param hash Hashed value + * @return non thread-safe temporary pointer to a representation of this hash, the result is valid until the next call to ExtractTmp + */ + LPCH ExtractTmp(LPCCH type, UINT64 hash); + /* + * Call ExtractTmp for a script name and apply formatting + * @param hash Script hash + * @return script formatted value, same condition as ExtractTmp + */ + inline LPCH ExtractTmpScript(UINT64 hash) { + LPCH unhash = ExtractTmp("script", hash); + + // replace '/' -> '\' in script + for (LPCH script = unhash; *script; script++) { + if (*script == '/') { + *script = '\\'; + } + } + + return unhash; + } + /* + * Extract a pointer to a hash value + * @param hash Hashed value + * @return String to the value or NULL if the hash isn't in the hash map + */ LPCCH ExtractPtr(UINT64 hash); + /* + * @return the size of the hash map + */ SIZE_T Size(); + /* + * Compute the hash32 on a string (canon id) + * @param str String to compute + * @return hashed value + */ UINT32 Hash32(LPCCH str); - UINT64 Hash64(LPCCH str); + /* + * Compute the hash64 on a string (fnva1), path are unformatted + * @param str String to compute + * @param start Start value, can be a previous hash to concatenate hashes + * @return Hashed value + */ + UINT64 Hash64(LPCCH str, UINT64 start = 0xcbf29ce484222325LL); + /* + * Compute the hash32 on a string (canon id), but allow pattern like "function_123456" + * @param str String to compute + * @return Hashed value + */ UINT32 Hash32Pattern(LPCCH str); + /* + * Compute the hash64 on a string (fnva1), but allow pattern like "hash_123456", path are unformatted + * @param str String to compute + * @return Hashed value + */ UINT64 Hash64Pattern(LPCCH str); } \ No newline at end of file diff --git a/src/tools/gsc.cpp b/src/tools/gsc.cpp index 74d115e..0e41a21 100644 --- a/src/tools/gsc.cpp +++ b/src/tools/gsc.cpp @@ -192,6 +192,7 @@ int GscInfoHandleData(tool::gsc::T8GSCOBJ* data, size_t size, const char* path, std::cerr << "Can't open output file " << asmfnamebuff << "\n"; return -1; } + std::cout << "Decompiling into '" << asmfnamebuff << "'...\n"; if (opt.m_copyright) { asmout << "// " << opt.m_copyright << "\n"; } @@ -267,7 +268,7 @@ int GscInfoHandleData(tool::gsc::T8GSCOBJ* data, size_t size, const char* path, UINT64 *includes = reinterpret_cast(&data->magic[data->include_offset]); for (size_t i = 0; i < data->include_count; i++) { - asmout << "#include " << hashutils::ExtractTmp("script", includes[i]) << ";\n"; + asmout << "#using " << hashutils::ExtractTmpScript(includes[i]) << ";\n"; } if (data->include_count) { asmout << "\n"; @@ -1128,15 +1129,15 @@ void tool::gsc::T8GSCExport::DumpFunctionHeader(std::ostream& asmout, BYTE* gscF if (!specialClassMember) { asmout << "function "; } + if (flags & T8GSCExportFlags::PRIVATE) { + asmout << "private "; + } if (flags & T8GSCExportFlags::AUTOEXEC) { asmout << "autoexec "; } if (flags & T8GSCExportFlags::EVENT) { asmout << "event_handler[" << hashutils::ExtractTmp("event", callback_event) << "] " << std::flush; } - if (flags & T8GSCExportFlags::PRIVATE) { - asmout << "private "; - } if (ctx.m_opt.m_dasm && (classMember || (flags & T8GSCExportFlags::CLASS_DESTRUCTOR))) { asmout << hashutils::ExtractTmp("class", name_space) diff --git a/src/tools/gsc_opcodes.cpp b/src/tools/gsc_opcodes.cpp index b662846..a442989 100644 --- a/src/tools/gsc_opcodes.cpp +++ b/src/tools/gsc_opcodes.cpp @@ -211,7 +211,7 @@ class ASMContextNodeFuncRef : public ASMContextNode { if (m_nsp) { out << hashutils::ExtractTmp("namespace", m_nsp) << std::flush; if (m_script) { - out << "<" << hashutils::ExtractTmp("script", m_script) << ">" << std::flush; + out << "<" << hashutils::ExtractTmpScript(m_script) << ">" << std::flush; } out << "::"; } @@ -2367,6 +2367,28 @@ class OPCodeInfoEnd : public OPCodeInfo { } }; +class OPCodeInfoClearArray : public OPCodeInfo { +public: + OPCodeInfoClearArray(OPCode id, LPCCH name) : OPCodeInfo(id, name) { + } + using OPCodeInfo::OPCodeInfo; + + int Dump(std::ostream& out, UINT16 value, ASMContext& context, tool::gsc::T8GSCOBJContext& objctx) const override { + if (context.m_runDecompiler) { + auto* fieldId = context.GetFieldIdASMCNode(); + auto* key = context.PopASMCNode(); + + ASMContextNode* accessNode = new ASMContextNodeArrayAccess(fieldId, key); + context.PushASMCNode(new ASMContextNodeLeftRightOperator(accessNode, new ASMContextNodeValue("undefined"), " = ", PRIORITY_SET, TYPE_SET)); + + context.CompleteStatement(); + } + out << "\n"; + + return 0; + } +}; + class OPCodeInfoStatement : public OPCodeInfo { LPCCH m_operatorName; public: @@ -3059,7 +3081,7 @@ class OPCodeInfoT8CGetLazyFunction : public OPCodeInfo { base += 16; out << "@" << hashutils::ExtractTmp("namespace", nsp) - << "<" << std::flush << hashutils::ExtractTmp("script", script) + << "<" << std::flush << hashutils::ExtractTmpScript(script) << ">::" << std::flush << hashutils::ExtractTmp("function", function) << std::endl; if (context.m_runDecompiler) { @@ -3279,7 +3301,7 @@ void tool::gsc::opcode::RegisterOpCodes() { RegisterOpCodeHandler(new OPCodeInfoPreScriptCall(OPCODE_PreScriptCall, "PreScriptCall")); RegisterOpCodeHandler(new OPCodeInfoGetConstant(OPCODE_EmptyArray, "EmptyArray", "[]")); - RegisterOpCodeHandler(new OPCodeInfoGetConstantSet(OPCODE_ClearArray, "ClearArray", "[]", true)); + RegisterOpCodeHandler(new OPCodeInfoClearArray(OPCODE_ClearArray, "ClearArray")); RegisterOpCodeHandler(new OPCodeInfoGetConstantRef(OPCODE_GetSelfObject, "GetSelfObject", "self")); // class stuff