diff --git a/config/GM8E01_00/symbols.txt b/config/GM8E01_00/symbols.txt index 446b4bc2..8e38ec9b 100644 --- a/config/GM8E01_00/symbols.txt +++ b/config/GM8E01_00/symbols.txt @@ -41,7 +41,7 @@ __dt__15CMemoryInStreamFv = .text:0x800047AC; // type:function size:0x60 scope:g fn_8000480C = .text:0x8000480C; // type:function size:0x4 EnsureWorldPaksReady__5CMainFv = .text:0x80004810; // type:function size:0x6C scope:global EnsureWorldPakReady__5CMainFUi = .text:0x8000487C; // type:function size:0x170 scope:global -fn_800049EC = .text:0x800049EC; // type:function size:0xB0 +__dt__Q24rstl138vector,Q24rstl17rmemory_allocator>,10SObjectTag>,Q24rstl17rmemory_allocator>Fv = .text:0x800049EC; // type:function size:0xB0 scope:global __dt__Q24rstl66basic_string,Q24rstl17rmemory_allocator>Fv = .text:0x80004A9C; // type:function size:0x50 scope:global AddWorldPaks__5CMainFv = .text:0x80004AEC; // type:function size:0x170 scope:global __pl__4rstlFRCQ24rstl66basic_string,Q24rstl17rmemory_allocator>RCQ24rstl66basic_string,Q24rstl17rmemory_allocator> = .text:0x80004C5C; // type:function size:0x5C scope:global @@ -1554,7 +1554,7 @@ ClearTokenList__9CGameAreaFv = .text:0x80062EF0; // type:function size:0xA8 scop __dt__9CGameAreaFv = .text:0x80062F98; // type:function size:0x274 scope:global fn_8006320C = .text:0x8006320C; // type:function size:0x58 __ct__9CGameAreaFR12CInputStreami = .text:0x80063264; // type:function size:0x498 scope:global -clear__Q24rstl37vectorFv = .text:0x800636FC; // type:function size:0xF4 scope:global +__as__Q24rstl37vectorFRCQ24rstl37vector = .text:0x800636FC; // type:function size:0xF4 scope:global __ct__Q29CGameArea16CPostConstructedFv = .text:0x800637F0; // type:function size:0x1F4 scope:global GetPostConstructedSize__9CGameAreaCFv = .text:0x800639E4; // type:function size:0x80 scope:global GetPreConstructedSize__9CGameAreaCFv = .text:0x80063A64; // type:function size:0x38 scope:global @@ -14340,7 +14340,7 @@ fn_8033AFD4 = .text:0x8033AFD4; // type:function size:0x64 fn_8033B038 = .text:0x8033B038; // type:function size:0x304 GetTagListForFile__10CResLoaderCFRCQ24rstl66basic_string,Q24rstl17rmemory_allocator> = .text:0x8033B33C; // type:function size:0xE0 scope:global fn_8033B41C = .text:0x8033B41C; // type:function size:0x140 -AddPakFileAsync__10CResLoaderFRCQ24rstl66basic_string,Q24rstl17rmemory_allocator>b = .text:0x8033B55C; // type:function size:0x154 scope:global +AddPakFileAsync__10CResLoaderFRCQ24rstl66basic_string,Q24rstl17rmemory_allocator>bb = .text:0x8033B55C; // type:function size:0x154 scope:global LoadNewResourcePartSync__10CResLoaderFRC10SObjectTagiiPc = .text:0x8033B6B0; // type:function size:0xE8 scope:global LoadMemResourceSync__10CResLoaderFRC10SObjectTagPPcPi = .text:0x8033B798; // type:function size:0xB8 scope:global LoadResourceFromMemorySync__10CResLoaderFRC10SObjectTagPCv = .text:0x8033B850; // type:function size:0x118 scope:global @@ -14680,7 +14680,7 @@ StartRead__19SMemoryCardFileInfoFv = .text:0x8034D8F0; // type:function size:0xF fn_8034D9E8 = .text:0x8034D9E8; // type:function size:0xEC GetStatus__13CCardFileInfoFP8CARDStat = .text:0x8034DAD4; // type:function size:0x140 scope:global PumpCardTransfer__Q214CMemoryCardSys13CCardFileInfoFv = .text:0x8034DC14; // type:function size:0x140 scope:global -fn_8034DD54 = .text:0x8034DD54; // type:function size:0xF0 +__as__Q24rstl37vectorFRCQ24rstl37vector = .text:0x8034DD54; // type:function size:0xF0 WriteFile__Q214CMemoryCardSys13CCardFileInfoFv = .text:0x8034DE44; // type:function size:0x70 scope:global CheckCard__14CMemoryCardSysFQ214CMemoryCardSys15EMemoryCardPort = .text:0x8034DEB4; // type:function size:0x24 scope:global Rename__14CMemoryCardSysFQ214CMemoryCardSys15EMemoryCardPortRCQ24rstl66basic_string,Q24rstl17rmemory_allocator>RCQ24rstl66basic_string,Q24rstl17rmemory_allocator> = .text:0x8034DED8; // type:function size:0x2C scope:global @@ -15192,7 +15192,7 @@ __dt__Q24rstl38single_ptr<24CSpawnSystemKeyframeData>Fv = .text:0x80367014; // t __ct__15CGenDescriptionFv = .text:0x8036706C; // type:function size:0x1C8 scope:global element_from_desc__FP15CGenDescriptioni = .text:0x80367234; // type:function size:0x8 scope:local EnsureWorldPakReady__8CPakFileFv = .text:0x8036723C; // type:function size:0x1F0 scope:global -fn_8036742C = .text:0x8036742C; // type:function size:0xF8 +sub_8036742c__8CPakFileFv = .text:0x8036742C; // type:function size:0xF8 scope:global fn_80367524 = .text:0x80367524; // type:function size:0x104 GetDepList__8CPakFileCFv = .text:0x80367628; // type:function size:0x1C scope:global GetResIdByName__8CPakFileCFPCc = .text:0x80367644; // type:function size:0xAC scope:global @@ -15207,16 +15207,16 @@ fn_80368184 = .text:0x80368184; // type:function size:0xC0 Warmup__8CPakFileFv = .text:0x80368244; // type:function size:0x10C scope:global AsyncIdle__8CPakFileFv = .text:0x80368350; // type:function size:0xAC scope:global __dt__8CPakFileFv = .text:0x803683FC; // type:function size:0x194 scope:global -__ct__8CPakFileFRCQ24rstl66basic_string,Q24rstl17rmemory_allocator>b = .text:0x80368590; // type:function size:0xD8 scope:global +__ct__8CPakFileFRCQ24rstl66basic_string,Q24rstl17rmemory_allocator>bb = .text:0x80368590; // type:function size:0xD8 scope:global IsCompressed__Q28CPakFile8SResInfoCFv = .text:0x80368668; // type:function size:0x18 scope:global GetSize__Q28CPakFile8SResInfoCFv = .text:0x80368680; // type:function size:0x20 scope:global GetOffset__Q28CPakFile8SResInfoCFv = .text:0x803686A0; // type:function size:0x1C scope:global GetType__Q28CPakFile8SResInfoCFv = .text:0x803686BC; // type:function size:0x28 scope:global -__ct__Q28CPakFile8SResInfoFUiUiUiUi = .text:0x803686E4; // type:function size:0xA8 scope:global -fn_8036878C = .text:0x8036878C; // type:function size:0x1EC +__ct__Q28CPakFile8SResInfoFUiUiUiUiUi = .text:0x803686E4; // type:function size:0xA8 scope:global +sort,Q24rstl17rmemory_allocator>,Q24rstl26less>__4rstlFQ24rstl130pointer_iterator,Q24rstl17rmemory_allocator>Q24rstl130pointer_iterator,Q24rstl17rmemory_allocator>Q24rstl26less = .text:0x8036878C; // type:function size:0x1EC scope:global fn_80368978 = .text:0x80368978; // type:function size:0xC0 -fn_80368A38 = .text:0x80368A38; // type:function size:0xC0 -fn_80368AF8 = .text:0x80368AF8; // type:function size:0x104 +lower_bound,Q24rstl17rmemory_allocator>,Q28CPakFile8SResInfo,Q24rstl26less>__4rstlFQ24rstl136const_pointer_iterator,Q24rstl17rmemory_allocator>Q24rstl136const_pointer_iterator,Q24rstl17rmemory_allocator>RCQ28CPakFile8SResInfoQ24rstl26less = .text:0x80368A38; // type:function size:0xC0 scope:global +reserve__Q24rstl55vectorFi = .text:0x80368AF8; // type:function size:0x104 scope:global fn_80368BFC = .text:0x80368BFC; // type:function size:0x2C fn_80368C28 = .text:0x80368C28; // type:function size:0x2C fn_80368C54 = .text:0x80368C54; // type:function size:0x14 @@ -15225,8 +15225,8 @@ fn_80368C7C = .text:0x80368C7C; // type:function size:0x44 fn_80368CC0 = .text:0x80368CC0; // type:function size:0x44 fn_80368D04 = .text:0x80368D04; // type:function size:0x28 fn_80368D2C = .text:0x80368D2C; // type:function size:0x28 -fn_80368D54 = .text:0x80368D54; // type:function size:0xBC -fn_80368E10 = .text:0x80368E10; // type:function size:0x94 +__sort3>__4rstlFRQ28CPakFile8SResInfoRQ28CPakFile8SResInfoRQ28CPakFile8SResInfoQ24rstl26less = .text:0x80368D54; // type:function size:0xBC scope:global +__insertion_sort,Q24rstl17rmemory_allocator>,Q24rstl26less>__4rstlFQ24rstl130pointer_iterator,Q24rstl17rmemory_allocator>Q24rstl130pointer_iterator,Q24rstl17rmemory_allocator>Q24rstl26less = .text:0x80368E10; // type:function size:0x94 scope:global Clear__17CPoseAsTransformsFv = .text:0x80368EA4; // type:function size:0x20 scope:global ContainsDataFor__17CPoseAsTransformsCFRC6CSegId = .text:0x80368EC4; // type:function size:0x4C scope:global AccumulateScaledTransform__17CPoseAsTransformsCFRC6CSegIdR9CMatrix3ff = .text:0x80368F10; // type:function size:0x48 scope:global @@ -17882,7 +17882,7 @@ lbl_803D8400 = .rodata:0x803D8400; // type:object size:0x8 @stringBase0 = .rodata:0x803D8408; // type:object size:0x7 scope:local data:string_table @stringBase0 = .rodata:0x803D8410; // type:object size:0x8 scope:local data:string_table skGenOffsets = .rodata:0x803D8418; // type:object size:0xC8 scope:local data:4byte -lbl_803D84E0 = .rodata:0x803D84E0; // type:object size:0x58 +@stringBase0 = .rodata:0x803D84E0; // type:object size:0x53 scope:local data:string_table lbl_803D8538 = .rodata:0x803D8538; // type:object size:0x7 data:string lbl_803D8540 = .rodata:0x803D8540; // type:object size:0x7 data:string kStopAll__16CRumbleGenerator = .rodata:0x803D8548; // type:object size:0x10 scope:global @@ -21547,7 +21547,7 @@ mForegroundEnable__19CStreamAudioManager = .sdata:0x805A8A41; // type:object siz lbl_805A8A48 = .sdata:0x805A8A48; // type:object size:0x4 data:4byte lbl_805A8A4C = .sdata:0x805A8A4C; // type:object size:0x1 lbl_805A8A4D = .sdata:0x805A8A4D; // type:object size:0x3 -lbl_805A8A50 = .sdata:0x805A8A50; // type:object size:0x4 data:4byte +kMinReserveBytes = .sdata:0x805A8A50; // type:object size:0x4 scope:local data:4byte lbl_805A8A54 = .sdata:0x805A8A54; // type:object size:0x4 data:4byte lbl_805A8A58 = .sdata:0x805A8A58; // type:object size:0x1 data:byte lbl_805A8A59 = .sdata:0x805A8A59; // type:object size:0x1 data:byte diff --git a/include/Kyoto/CDvdFile.hpp b/include/Kyoto/CDvdFile.hpp index f9b5db89..002d82c1 100644 --- a/include/Kyoto/CDvdFile.hpp +++ b/include/Kyoto/CDvdFile.hpp @@ -36,6 +36,8 @@ class CDvdFile { void CalcFileOffset(int offset, ESeekOrigin origin); void UpdateFilePos(int pos); const int GetFileSize() const { return x14_size; } + const rstl::string& GetFilename() const { return x18_filename; } + bool IsARAMFile() const { return x8_; } static bool FileExists(const char*); static void DVDARAMXferCallback(long, DVDFileInfo*); diff --git a/include/Kyoto/CFactoryMgr.hpp b/include/Kyoto/CFactoryMgr.hpp index 923b184c..7f80a3f9 100644 --- a/include/Kyoto/CFactoryMgr.hpp +++ b/include/Kyoto/CFactoryMgr.hpp @@ -5,10 +5,11 @@ class CFactoryMgr { public: + static uint FourCCToTypeIdx(uint fcc); + static uint TypeIdxToFourCC(uint idx); + private: uchar pad[0x38]; }; - - #endif // _CFACTORYMGR diff --git a/include/Kyoto/CPakFile.hpp b/include/Kyoto/CPakFile.hpp index 3a1918c2..d1a965fe 100644 --- a/include/Kyoto/CPakFile.hpp +++ b/include/Kyoto/CPakFile.hpp @@ -3,31 +3,82 @@ #include "types.h" +#include "Kyoto/CDvdFile.hpp" +#include "Kyoto/SObjectTag.hpp" + #include "rstl/auto_ptr.hpp" +#include "rstl/pair.hpp" #include "rstl/string.hpp" - -#include "Kyoto/CDvdFile.hpp" -#include "Kyoto/CResLoader.hpp" -#include "Kyoto/IObjectStore.hpp" +#include "rstl/vector.hpp" +#include "rstl/aligned_allocator.hpp" class CDvdRequest; +class CMemoryInStream; -class CPakFile : CDvdFile { +class CPakFile : public CDvdFile { public: +#pragma pack(push, 2) + struct SResInfo { + CAssetId x0_id; + uchar x4_typeFlags; // bit7=compressed, bits0-6=typeIdx + uchar x5_offsetLo; + uchar x6_offsetMid; + uchar x7_mixed; // bits0-6=offset high, bit7=size bit0 + uchar x8_sizeLo; + uchar x9_sizeHi; + + SResInfo(const SResInfo& other) : x0_id(other.x0_id) { + *reinterpret_cast< uint* >(&x4_typeFlags) = *reinterpret_cast< const uint* >(&other.x4_typeFlags); + *reinterpret_cast< ushort* >(&x8_sizeLo) = *reinterpret_cast< const ushort* >(&other.x8_sizeLo); + } + SResInfo& operator=(const SResInfo& other) { + x0_id = other.x0_id; + *reinterpret_cast< uint* >(&x4_typeFlags) = *reinterpret_cast< const uint* >(&other.x4_typeFlags); + *reinterpret_cast< ushort* >(&x8_sizeLo) = *reinterpret_cast< const ushort* >(&other.x8_sizeLo); + return *this; + } + SResInfo(uint id, uint fourCC, uint offset, uint size, uint flags); + + uint GetType() const; + uint GetOffset() const; + uint GetSize() const; + bool IsCompressed() const; + + CAssetId GetId() const { return x0_id; } + bool operator<(const SResInfo& other) const { return x0_id < other.x0_id; } + }; +#pragma pack(pop) + + CPakFile(const rstl::string& filename, bool buildDepList, bool worldPak); + ~CPakFile(); + + void AsyncIdle(); bool IsWorldPak() const { return x28_26_worldPak; } + bool IsCompletelyLoaded() const { return x2c_asyncLoadPhase == 3; } void EnsureWorldPakReady(); void sub_8036742c(); rstl::vector< rstl::pair< rstl::string, SObjectTag > >& NameList() { return x54_nameList; } + const rstl::vector< CAssetId >* GetDepList() const; + const SObjectTag* GetResIdByName(const char* name) const; + const SResInfo* GetResInfo(uint id) const; + const SResInfo* GetResInfoForLoadDirectionless(uint id) const; + const SResInfo* GetResInfoForLoadPreferForward(uint id) const; + uint GetFakeStaticSize() const; private: + void Warmup(); + void InitialHeaderLoad(); + void DataLoad(); + void LoadResourceTable(CMemoryInStream& in); + bool x28_24_buildDepList : 1; bool x28_25_aramFile : 1; bool x28_26_worldPak : 1; bool x28_27_stashedInARAM : 1; int x2c_asyncLoadPhase; // EAsyncPhase rstl::auto_ptr< CDvdRequest > x30_dvdReq; - rstl::vector< uchar > x38_headerData; + rstl::vector< uchar, rstl::aligned_allocator > x38_headerData; uint x48_resTableOffset; uint x4c_resTableCount; int x50_aramBase; @@ -36,5 +87,6 @@ class CPakFile : CDvdFile { rstl::vector< SResInfo > x74_resList; mutable int x84_currentSeek; }; +CHECK_SIZEOF(CPakFile, 0x88) #endif // _CPAKFILE diff --git a/include/Kyoto/CResLoader.hpp b/include/Kyoto/CResLoader.hpp index 36a836bd..34a31fd4 100644 --- a/include/Kyoto/CResLoader.hpp +++ b/include/Kyoto/CResLoader.hpp @@ -1,6 +1,7 @@ #ifndef _CRESLOADER #define _CRESLOADER +#include "Kyoto/CPakFile.hpp" #include "Kyoto/SObjectTag.hpp" #include "types.h" @@ -9,17 +10,8 @@ #include "Kyoto/IObjectStore.hpp" -class CPakFile; class CDvdRequest; -struct SResInfo { - CAssetId x0_id; - bool x4_compressed : 1; - int x4_typeIdx; // CFactoryMgr::ETypeTable - uint x5_offsetDiv32 : 27; - uint x7_sizeDiv32 : 27; -}; - class CResLoader { public: int GetPakCount() const; @@ -42,7 +34,7 @@ class CResLoader { rstl::list< unkptr > x30_pakLoadingList; unkptr x48_curPak; CAssetId x4c_cachedResId; - SResInfo* x50_cachedResInfo; + const CPakFile::SResInfo* x50_cachedResInfo; bool x54_forwardSeek; }; diff --git a/include/rstl/aligned_allocator.hpp b/include/rstl/aligned_allocator.hpp new file mode 100644 index 00000000..27453e36 --- /dev/null +++ b/include/rstl/aligned_allocator.hpp @@ -0,0 +1,30 @@ +#ifndef _RSTL_ALIGNED_ALLOCATOR +#define _RSTL_ALIGNED_ALLOCATOR + +#include "types.h" + +#include "Kyoto/Alloc/CMemory.hpp" + +namespace rstl { +struct aligned_allocator { + aligned_allocator() {} + aligned_allocator(const aligned_allocator&) {} + + template < typename T > + static void allocate(T*& out, int count) { + int size = count * sizeof(T); + if (size == 0) { + out = nullptr; + } else { + out = static_cast< T* >(CMemory::Alloc(size, IAllocator::kHI_RoundUpLen)); + } + } + + template < typename T > + static void deallocate(T* ptr) { + CMemory::Free(ptr); + } +}; +} // namespace rstl + +#endif // _RSTL_ALIGNED_ALLOCATOR diff --git a/include/rstl/pointer_iterator.hpp b/include/rstl/pointer_iterator.hpp index 07ad7330..7b07cbeb 100644 --- a/include/rstl/pointer_iterator.hpp +++ b/include/rstl/pointer_iterator.hpp @@ -55,13 +55,6 @@ class const_pointer_iterator { bool operator<=(const const_pointer_iterator& other) { return current <= other.current; } bool operator>=(const const_pointer_iterator& other) { return current >= other.current; } - // friend const_pointer_iterator operator+(const const_pointer_iterator& x, int v) { - // return const_pointer_iterator(x.current + v); - // } - // friend const_pointer_iterator operator-(const const_pointer_iterator& x, int v) { - // return const_pointer_iterator(x.current - v); - // } - protected: T* current; }; diff --git a/src/Kyoto/CPakFile.cpp b/src/Kyoto/CPakFile.cpp new file mode 100644 index 00000000..11856970 --- /dev/null +++ b/src/Kyoto/CPakFile.cpp @@ -0,0 +1,320 @@ +#pragma inline_max_size(200) + +#include "Kyoto/CPakFile.hpp" + +#include "Kyoto/Alloc/CMemory.hpp" +#include "Kyoto/CARAMManager.hpp" +#include "Kyoto/CFactoryMgr.hpp" +#include "Kyoto/Streams/CMemoryInStream.hpp" +#include "rstl/StringExtras.hpp" +#include "rstl/algorithm.hpp" +#include "rstl/math.hpp" + +#include + +extern "C" int abs(int); + +static inline int round_up_32(int val) { return (val + 31) & ~31; } + +static int kMinReserveBytes = 64; + +// EnsureWorldPakReady +void CPakFile::EnsureWorldPakReady() { + if (x28_26_worldPak && x28_27_stashedInARAM) { + int reserveBytes = + round_up_32(x4c_resTableCount * (int)sizeof(SResInfo)) + (int)sizeof(SResInfo) - 1; + x74_resList.reserve( + (uint)rstl::max_val(reserveBytes, kMinReserveBytes) / (uint)sizeof(SResInfo)); + + for (int i = 0; i < (int)x4c_resTableCount; ++i) { + x74_resList.push_back(SResInfo(i, 'TXTR', 0, 0, 0)); + } + + uint dmaSize = round_up_32(x4c_resTableCount * sizeof(SResInfo)); + CARAMManager::WaitForDMACompletion(CARAMManager::DMAToMRAM( + reinterpret_cast< void* >(x50_aramBase), x74_resList.data(), dmaSize, + CARAMManager::kDMAPrio_One)); + + if (x28_24_buildDepList) { + x64_depList.reserve(x4c_resTableCount); + for (int i = 0; i < (int)x4c_resTableCount; ++i) { + x64_depList.push_back(x74_resList[i].GetId()); + } + } + + x28_27_stashedInARAM = false; + } +} + +// fn_8036742C +void CPakFile::sub_8036742c() { + if (x28_26_worldPak) { + x28_27_stashedInARAM = true; + x64_depList = rstl::vector< CAssetId >(); + x74_resList = rstl::vector< SResInfo >(); + } +} + +// fn_80367524 + +// GetDepList +const rstl::vector< CAssetId >* CPakFile::GetDepList() const { + if (x64_depList.size() != 0) + return &x64_depList; + return nullptr; +} + +// GetResIdByName +const SObjectTag* CPakFile::GetResIdByName(const char* name) const { + if (!x28_27_stashedInARAM) { + for (AUTO(it, x54_nameList.begin()); it != x54_nameList.end(); ++it) { + int cmp = CStringExtras::CompareCaseInsensitive(it->first, rstl::string_l(name)); + if (cmp == 0) { + return &it->second; + } + } + } + return nullptr; +} + +// GetResInfoForLoadPreferForward +const CPakFile::SResInfo* CPakFile::GetResInfoForLoadPreferForward(uint id) const { + if (x28_27_stashedInARAM) + return nullptr; + SResInfo key(id, 'TXTR', 0, 0, 0); + rstl::vector< SResInfo >::const_iterator it = + rstl::lower_bound(x74_resList.begin(), x74_resList.end(), key, rstl::less< SResInfo >()); + if (it == x74_resList.end() || it->GetId() != id) + return nullptr; + const SResInfo* bestInfo = &*it; + int bestDelta = x84_currentSeek - static_cast< int >(bestInfo->GetOffset()); + ++it; + while (it != x74_resList.end()) { + if (it->GetId() != id) + break; + int thisDelta = x84_currentSeek - static_cast< int >(it->GetOffset()); + if ((bestDelta < 0 && (thisDelta > 0 || thisDelta > bestDelta)) || + (bestDelta >= 0 && thisDelta > 0 && thisDelta < bestDelta)) { + bestInfo = &*it; + bestDelta = thisDelta; + } + ++it; + } + x84_currentSeek = bestInfo->GetOffset() + bestInfo->GetSize(); + return bestInfo; +} + +// GetResInfoForLoadDirectionless +const CPakFile::SResInfo* CPakFile::GetResInfoForLoadDirectionless(uint id) const { + if (x28_27_stashedInARAM) + return nullptr; + SResInfo key(id, 'TXTR', 0, 0, 0); + rstl::vector< SResInfo >::const_iterator it = + rstl::lower_bound(x74_resList.begin(), x74_resList.end(), key, rstl::less< SResInfo >()); + if (it == x74_resList.end() || it->GetId() != id) { + return nullptr; + } + const SResInfo* bestInfo = &*it; + int bestDelta = abs(static_cast< int >(bestInfo->GetOffset() - x84_currentSeek)); + ++it; + while (it != x74_resList.end()) { + if (it->GetId() != id) + break; + int thisDelta = abs(static_cast< int >(it->GetOffset() - x84_currentSeek)); + if (thisDelta < bestDelta) { + bestInfo = &*it; + bestDelta = thisDelta; + } + ++it; + } + x84_currentSeek = bestInfo->GetOffset() + bestInfo->GetSize(); + return bestInfo; +} + +// GetResInfo +const CPakFile::SResInfo* CPakFile::GetResInfo(uint id) const { + if (!IsCompletelyLoaded()) + return nullptr; + if (x28_27_stashedInARAM) + return nullptr; + SResInfo key(id, 'TXTR', 0, 0, 0); + rstl::vector< SResInfo >::const_iterator it = + rstl::lower_bound(x74_resList.begin(), x74_resList.end(), key, rstl::less< SResInfo >()); + if (it == x74_resList.end() || it->GetId() != id) { + return nullptr; + } + return &*it; +} + +// GetFakeStaticSize +uint CPakFile::GetFakeStaticSize() const { + return x64_depList.size() * sizeof(uint) + x74_resList.size() * sizeof(SResInfo); +} + +// LoadResourceTable +void CPakFile::LoadResourceTable(CMemoryInStream& in) { + int reserveBytes = round_up_32(x4c_resTableCount * (int)sizeof(SResInfo)) + (int)sizeof(SResInfo) - 1; + x74_resList.reserve((uint)rstl::max_val(reserveBytes, kMinReserveBytes) / (uint)sizeof(SResInfo)); + + if (x28_24_buildDepList) { + x64_depList.reserve(x4c_resTableCount); + } + + for (int i = 0; i < (int)x4c_resTableCount; ++i) { + uint flags = in.Get< uint >(); + uint fourCC = in.Get< uint >(); + uint id = in.Get< uint >(); + uint size = in.Get< uint >(); + uint offset = in.Get< uint >(); + x74_resList.push_back(SResInfo(id, fourCC, offset, size, flags)); + if (x28_24_buildDepList) { + x64_depList.push_back(id); + } + } + + rstl::sort(x74_resList.begin(), x74_resList.end(), rstl::less< SResInfo >()); +} + +// DataLoad +void CPakFile::DataLoad() { + x30_dvdReq = rstl::auto_ptr< CDvdRequest >(); + CMemoryInStream in(&x38_headerData[x48_resTableOffset], + x38_headerData.size() - x48_resTableOffset); + LoadResourceTable(in); + x2c_asyncLoadPhase = 3; + if (x28_26_worldPak) { + uint size = round_up_32(x4c_resTableCount * sizeof(SResInfo)); + x50_aramBase = reinterpret_cast< int >(CARAMManager::Alloc(size)); + uint handle = CARAMManager::DMAToARAM( + x74_resList.data(), reinterpret_cast< void* >(x50_aramBase), size, + CARAMManager::kDMAPrio_One); + CARAMManager::WaitForDMACompletion(handle); + } + x38_headerData = rstl::vector< uchar, rstl::aligned_allocator >(); + CMemory::OffsetFakeStatics(GetFakeStaticSize()); +} + +// InitialHeaderLoad +void CPakFile::InitialHeaderLoad() { + CMemoryInStream in(&x38_headerData[0], x38_headerData.size()); + x30_dvdReq = rstl::auto_ptr< CDvdRequest >(); + + int version = in.ReadInt32(); + if (version != 0x00030005) { + char buf[248]; + sprintf(buf, "%s: Incompatible pak file version -- Current version is %x, you're using %x", + GetFilename().data(), 0x00030005, version); + return; + } + + in.ReadInt32(); + int nameCount = in.ReadInt32(); + x54_nameList.reserve(nameCount); + + for (int i = 0; i < nameCount; ++i) { + int type = in.ReadInt32(); + int id = in.ReadInt32(); + rstl::string name = CStringExtras::ReadString(in); + x54_nameList.push_back(rstl::pair< rstl::string, SObjectTag >(name, SObjectTag(type, id))); + } + + x4c_resTableCount = in.ReadInt32(); + x48_resTableOffset = in.GetReadPosition(); + x2c_asyncLoadPhase = 2; + + int origSize = x38_headerData.size(); + uint resDataSize = x4c_resTableCount * 20; + int newSize = (resDataSize + x48_resTableOffset + 31) & ~31; + if (newSize > origSize) { + x38_headerData.resize(newSize); + x30_dvdReq = rstl::auto_ptr< CDvdRequest >( + AsyncSeekRead(&x38_headerData[0] + origSize, x38_headerData.size() - origSize, + kSO_Set, origSize)); + } else { + DataLoad(); + } +} + +// fn_80368184 + +// Warmup +void CPakFile::Warmup() { + int length = rstl::min_val< int >(Length(), 8192); + x38_headerData.resize(length); + x30_dvdReq = rstl::auto_ptr< CDvdRequest >(SyncRead(&x38_headerData[0], length)); + x2c_asyncLoadPhase = 1; +} + +// AsyncIdle +void CPakFile::AsyncIdle() { + if (x2c_asyncLoadPhase == 3) + return; + if (!IsARAMFileLoaded()) + return; + if (!x30_dvdReq.null() && !x30_dvdReq->IsComplete()) + return; + switch (x2c_asyncLoadPhase) { + case 0: + Warmup(); + break; + case 1: + InitialHeaderLoad(); + break; + case 2: + DataLoad(); + break; + default: + break; + } +} + +// Destructor +CPakFile::~CPakFile() { + while (x2c_asyncLoadPhase != 3) { + AsyncIdle(); + } + + CMemory::OffsetFakeStatics(-static_cast< int >(GetFakeStaticSize())); + CARAMManager::Free(reinterpret_cast< const void* >(x50_aramBase)); +} + +// Constructor +CPakFile::CPakFile(const rstl::string& filename, bool buildDepList, bool worldPak) +: CDvdFile(filename.data()) +, x28_24_buildDepList(buildDepList) +, x28_25_aramFile(IsARAMFile()) +, x28_26_worldPak(worldPak) +, x28_27_stashedInARAM(false) +, x2c_asyncLoadPhase(0) +, x48_resTableOffset(0) +, x4c_resTableCount(0) +, x50_aramBase(reinterpret_cast< int >(CARAMManager::GetInvalidAlloc())) +, x84_currentSeek(-1) {} + +// SResInfo getters +uint CPakFile::SResInfo::GetType() const { + return CFactoryMgr::TypeIdxToFourCC(x4_typeFlags & 0x7f); +} + +uint CPakFile::SResInfo::GetOffset() const { + return ((x5_offsetLo | (x6_offsetMid << 8) | (x7_mixed << 16)) & 0x7FFFFF) << 5; +} + +uint CPakFile::SResInfo::GetSize() const { + return ((x7_mixed >> 7) | (x8_sizeLo << 1) | (x9_sizeHi << 9)) << 5; +} + +bool CPakFile::SResInfo::IsCompressed() const { + return (x4_typeFlags & ~0x7F) != 0; +} + +// SResInfo constructor +CPakFile::SResInfo::SResInfo(uint id, uint fourCC, uint offset, uint size, uint flags) : x0_id(id) { + uint typeIdx = CFactoryMgr::FourCCToTypeIdx(fourCC); + x4_typeFlags = static_cast< uchar >(typeIdx | (flags != 0 ? 0x80 : 0)); + x5_offsetLo = static_cast< uchar >(offset >> 5); + x6_offsetMid = static_cast< uchar >(offset >> 13); + x7_mixed = static_cast< uchar >((offset >> 21) | ((size << 2) & 0x80)); + x8_sizeLo = static_cast< uchar >(size >> 6); + x9_sizeHi = static_cast< uchar >(size >> 14); +}