From 57f17a3aad73694fc1b7d7877e393ed454bfe829 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 25 Nov 2022 00:11:17 +0100 Subject: [PATCH] Use engine's FileSystem API for decompressing and patching RPak files --- r5dev/rtech/rtech_utils.h | 4 +- r5dev/vstdlib/callback.cpp | 136 ++++++++++++++++++++++++------------- 2 files changed, 89 insertions(+), 51 deletions(-) diff --git a/r5dev/rtech/rtech_utils.h b/r5dev/rtech/rtech_utils.h index 2e8010e7..7e2061c9 100644 --- a/r5dev/rtech/rtech_utils.h +++ b/r5dev/rtech/rtech_utils.h @@ -148,8 +148,8 @@ struct RPakHeader_t uint32_t m_nMagic; // 'RPak' uint16_t m_nVersion; // R2 = '7' R5 = '8' uint8_t m_nFlags[0x2]; // - uint8_t m_nHash0[0x8]; // - uint8_t m_nHash1[0x8]; // + uint64_t m_nFileTime; // + uint64_t m_nHash; // uint64_t m_nSizeDisk; // Compressed size uint64_t m_nEmbeddedStarpakOffset; // uint8_t unk0[0x8]; // diff --git a/r5dev/vstdlib/callback.cpp b/r5dev/vstdlib/callback.cpp index 10aa25b4..4b6deaa9 100644 --- a/r5dev/vstdlib/callback.cpp +++ b/r5dev/vstdlib/callback.cpp @@ -55,7 +55,6 @@ #ifndef DEDICATED #include "game/client/viewrender.h" #endif // !DEDICATED -#include "public/utility/binstream.h" /* @@ -419,103 +418,142 @@ void RTech_Decompress_f(const CCommand& args) return; } - static const string modDir = "paks\\Win32\\"; - static const string baseDir = "paks\\Win64\\"; + static const string svModDir = "paks\\Win32\\"; + static const string svBaseDir = "paks\\Win64\\"; - const string pakNameOut = modDir + args.Arg(1); - const string pakNameIn = baseDir + args.Arg(1); - - CreateDirectories(pakNameOut); + const string svPakNameOut = svModDir + args.Arg(1); + const string svPakNameIn = svBaseDir + args.Arg(1); DevMsg(eDLL_T::RTECH, "______________________________________________________________\n"); DevMsg(eDLL_T::RTECH, "-+ RTech decompress ------------------------------------------\n"); - if (!FileExists(pakNameIn)) + if (!FileSystem()->FileExists(svPakNameIn.c_str(), "GAME")) { - Error(eDLL_T::RTECH, NO_ERROR, "%s - pak file '%s' does not exist!\n", __FUNCTION__, pakNameIn.c_str()); + Error(eDLL_T::RTECH, NO_ERROR, "%s - pak file '%s' does not exist!\n", __FUNCTION__, svPakNameIn.c_str()); return; } - DevMsg(eDLL_T::RTECH, " |-+ Processing: '%s'\n", pakNameIn.c_str()); - CIOStream reader(pakNameIn, CIOStream::Mode_t::READ); + DevMsg(eDLL_T::RTECH, " |-+ Processing: '%s'\n", svPakNameIn.c_str()); + FileHandle_t hPakFile = FileSystem()->Open(svPakNameIn.c_str(), "rb", "GAME"); - RPakHeader_t rheader = reader.Read<RPakHeader_t>(); - uint16_t flags = (rheader.m_nFlags[0] << 8) | rheader.m_nFlags[1]; + if (!hPakFile) + { + Error(eDLL_T::RTECH, NO_ERROR, "%s - Unable to open '%s' (insufficient rights?)\n", __FUNCTION__, svPakNameIn.c_str()); + return; + } + + uint32_t nPakLen = FileSystem()->Size(hPakFile); + uint8_t* pPakBuf = MemAllocSingleton()->Alloc<uint8_t>(nPakLen); + + FileSystem()->Read(pPakBuf, nPakLen, hPakFile); + FileSystem()->Close(hPakFile); + + RPakHeader_t* pHeader = reinterpret_cast<RPakHeader_t*>(pPakBuf); + + uint32_t nLen = FileSystem()->Size(hPakFile); + uint16_t flags = (pHeader->m_nFlags[0] << 8) | pHeader->m_nFlags[1]; DevMsg(eDLL_T::RTECH, " | |-+ Header ------------------------------------------------\n"); - DevMsg(eDLL_T::RTECH, " | |-- Magic : '%08X'\n", rheader.m_nMagic); - DevMsg(eDLL_T::RTECH, " | |-- Version : '%hu'\n", rheader.m_nVersion); + DevMsg(eDLL_T::RTECH, " | |-- Magic : '%08X'\n", pHeader->m_nMagic); + DevMsg(eDLL_T::RTECH, " | |-- Version : '%hu'\n", pHeader->m_nVersion); DevMsg(eDLL_T::RTECH, " | |-- Flags : '%04hX'\n", flags); - DevMsg(eDLL_T::RTECH, " | |-- Hash : '%llu%llu'\n", rheader.m_nHash0, rheader.m_nHash1); - DevMsg(eDLL_T::RTECH, " | |-- Entries : '%u'\n", rheader.m_nAssetEntryCount); + DevMsg(eDLL_T::RTECH, " | |-- Hash : '%llu%llu'\n", pHeader->m_nFileTime, pHeader->m_nHash); + DevMsg(eDLL_T::RTECH, " | |-- Entries : '%u'\n", pHeader->m_nAssetEntryCount); DevMsg(eDLL_T::RTECH, " | |-+ Compression -----------------------------------------\n"); - DevMsg(eDLL_T::RTECH, " | |-- Size disk: '%llu'\n", rheader.m_nSizeDisk); - DevMsg(eDLL_T::RTECH, " | |-- Size decp: '%llu'\n", rheader.m_nSizeMemory); + DevMsg(eDLL_T::RTECH, " | |-- Size disk: '%llu'\n", pHeader->m_nSizeDisk); + DevMsg(eDLL_T::RTECH, " | |-- Size decp: '%llu'\n", pHeader->m_nSizeMemory); - if (rheader.m_nMagic != RPAKHEADER) + if (pHeader->m_nMagic != RPAKHEADER) { - Error(eDLL_T::RTECH, NO_ERROR, "%s - pak file '%s' has invalid magic!\n", __FUNCTION__, pakNameIn.c_str()); + Error(eDLL_T::RTECH, NO_ERROR, "%s - pak file '%s' has invalid magic!\n", __FUNCTION__, svPakNameIn.c_str()); + MemAllocSingleton()->Free(pPakBuf); + return; } - if ((rheader.m_nFlags[1] & 1) != 1) + if ((pHeader->m_nFlags[1] & 1) != 1) { - Error(eDLL_T::RTECH, NO_ERROR, "%s - pak file '%s' already decompressed!\n", __FUNCTION__, pakNameIn.c_str()); + Error(eDLL_T::RTECH, NO_ERROR, "%s - pak file '%s' already decompressed!\n", __FUNCTION__, svPakNameIn.c_str()); + MemAllocSingleton()->Free(pPakBuf); + return; } - if (rheader.m_nSizeDisk != reader.GetSize()) + if (pHeader->m_nSizeDisk != nPakLen) { - Error(eDLL_T::RTECH, NO_ERROR, "%s - pak file '%s' decompressed size '%zu' doesn't match expected size '%llu'!\n", __FUNCTION__, pakNameIn.c_str(), reader.GetSize(), rheader.m_nSizeMemory); + Error(eDLL_T::RTECH, NO_ERROR, "%s - pak file '%s' decompressed size '%llu' doesn't match expected size '%llu'!\n", __FUNCTION__, svPakNameIn.c_str(), nPakLen, pHeader->m_nSizeMemory); + MemAllocSingleton()->Free(pPakBuf); + return; } - RPakDecompState_t state; - uint64_t decompSize = g_pRTech->DecompressPakFileInit(&state, const_cast<uint8_t*>(reader.GetData()), reader.GetSize(), NULL, sizeof(RPakHeader_t)); + RPakDecompState_t decompState; + uint64_t nDecompSize = g_pRTech->DecompressPakFileInit(&decompState, pPakBuf, nPakLen, NULL, sizeof(RPakHeader_t)); - if (decompSize == rheader.m_nSizeDisk) + if (nDecompSize == pHeader->m_nSizeDisk) { - Error(eDLL_T::RTECH, NO_ERROR, "%s - calculated size: '%llu' expected: '%llu'!\n", __FUNCTION__, decompSize, rheader.m_nSizeMemory); + Error(eDLL_T::RTECH, NO_ERROR, "%s - calculated size: '%llu' expected: '%llu'!\n", __FUNCTION__, nDecompSize, pHeader->m_nSizeMemory); + MemAllocSingleton()->Free(pPakBuf); + return; } else { - DevMsg(eDLL_T::RTECH, " | |-- Size calc: '%llu'\n", decompSize); + DevMsg(eDLL_T::RTECH, " | |-- Size calc: '%llu'\n", nDecompSize); } - DevMsg(eDLL_T::RTECH, " | |-- Ratio : '%.02f'\n", (rheader.m_nSizeDisk * 100.f) / rheader.m_nSizeMemory); - vector<uint8_t> pakBuf(rheader.m_nSizeMemory, 0); + DevMsg(eDLL_T::RTECH, " | |-- Ratio : '%.02f'\n", (pHeader->m_nSizeDisk * 100.f) / pHeader->m_nSizeMemory); + uint8_t* pDecompBuf = MemAllocSingleton()->Alloc<uint8_t>(pHeader->m_nSizeMemory); - state.m_nOutMask = UINT64_MAX; - state.m_nOut = uint64_t(pakBuf.data()); + decompState.m_nOutMask = UINT64_MAX; + decompState.m_nOut = uint64_t(pDecompBuf); - uint8_t decompResult = g_pRTech->DecompressPakFile(&state, reader.GetSize(), pakBuf.size()); - if (decompResult != 1) + uint8_t nDecompResult = g_pRTech->DecompressPakFile(&decompState, nPakLen, pHeader->m_nSizeMemory); + if (nDecompResult != 1) { - Error(eDLL_T::RTECH, NO_ERROR, "%s - decompression failed for '%s' return value: '%hu'!\n", __FUNCTION__, pakNameIn.c_str(), decompResult); + Error(eDLL_T::RTECH, NO_ERROR, "%s - decompression failed for '%s' return value: '%hu'!\n", __FUNCTION__, svPakNameIn.c_str(), nDecompResult); + MemAllocSingleton()->Free(pPakBuf); + MemAllocSingleton()->Free(pDecompBuf); + return; } - rheader.m_nFlags[1] = 0x0; // Set compressed flag to false for the decompressed pak file. - rheader.m_nSizeDisk = rheader.m_nSizeMemory; // Equal compressed size with decompressed. + pHeader->m_nFlags[1] = 0x0; // Set compressed flag to false for the decompressed pak file. + pHeader->m_nSizeDisk = pHeader->m_nSizeMemory; // Equal compressed size with decompressed. - CIOStream writer(pakNameOut, CIOStream::Mode_t::WRITE); + FileSystem()->CreateDirHierarchy(svModDir.c_str(), "GAME"); + FileHandle_t hDecompFile = FileSystem()->Open(svPakNameOut.c_str(), "wb", "GAME"); - if (rheader.m_nPatchIndex > 0) // Check if its an patch rpak. + if (!hDecompFile) + { + Error(eDLL_T::RTECH, NO_ERROR, "%s - Unable to write to '%s' (read-only?)\n", __FUNCTION__, svPakNameOut.c_str()); + + MemAllocSingleton()->Free(pPakBuf); + MemAllocSingleton()->Free(pDecompBuf); + + return; + } + + if (pHeader->m_nPatchIndex > 0) // Check if its an patch rpak. { // Loop through all the structs and patch their compress size. - for (uint32_t i = 1, patchOffset = (sizeof(RPakHeader_t) + sizeof(uint64_t)); - i <= rheader.m_nPatchIndex; i++, patchOffset += sizeof(RPakPatchCompressedHeader_t)) + for (uint32_t i = 1, nPatchOffset = (sizeof(RPakHeader_t) + sizeof(uint64_t)); + i <= pHeader->m_nPatchIndex; i++, nPatchOffset += sizeof(RPakPatchCompressedHeader_t)) { - RPakPatchCompressedHeader_t* patchHeader = (RPakPatchCompressedHeader_t*)((uintptr_t)pakBuf.data() + patchOffset); - patchHeader->m_nSizeDisk = patchHeader->m_nSizeMemory; // Fix size for decompress. + RPakPatchCompressedHeader_t* pPatchHeader = (RPakPatchCompressedHeader_t*)((uintptr_t)pPakBuf + nPatchOffset); + pPatchHeader->m_nSizeDisk = pPatchHeader->m_nSizeMemory; // Fix size for decompress. } } - memcpy_s(pakBuf.data(), state.m_nDecompSize, &rheader, sizeof(RPakHeader_t)); // Overwrite first 0x80 bytes which are NULL with the header data. - writer.Write(pakBuf.data(), state.m_nDecompSize); + memcpy_s(pDecompBuf, sizeof(RPakHeader_t), pPakBuf, sizeof(RPakHeader_t));// Overwrite first 0x80 bytes which are NULL with the header data. + FileSystem()->Write(pDecompBuf, decompState.m_nDecompSize, hDecompFile); - DevMsg(eDLL_T::RTECH, " | |-- Checksum : '%08X'\n", crc32::update(NULL, pakBuf.data(), state.m_nDecompSize)); - DevMsg(eDLL_T::RTECH, " |-+ Decompressed pak file to: '%s'\n", pakNameOut.c_str()); + DevMsg(eDLL_T::RTECH, " | |-- Checksum : '%08X'\n", crc32::update(NULL, pDecompBuf, decompState.m_nDecompSize)); + DevMsg(eDLL_T::RTECH, " |-+ Decompressed pak file to: '%s'\n", svPakNameOut.c_str()); DevMsg(eDLL_T::RTECH, "--------------------------------------------------------------\n"); + + MemAllocSingleton()->Free(pPakBuf); + MemAllocSingleton()->Free(pDecompBuf); + + FileSystem()->Close(hDecompFile); } /*