mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Use engine's FileSystem API for decompressing and patching RPak files
This commit is contained in:
parent
1e76624c9b
commit
57f17a3aad
@ -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]; //
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user