From 138e822d859fd9ff9d79e1ce16823992ad43aec4 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 9 Jun 2019 21:14:42 +0200 Subject: Dep/CascLib: Update to ladislav-zezula/CascLib@03a3bcaed285ab0d8ff0845a65ffe7d1fa653960 --- dep/CascLib/src/CascCommon.h | 1 + dep/CascLib/src/CascDecrypt.cpp | 3 + dep/CascLib/src/CascLib.h | 44 + dep/CascLib/src/CascOpenFile.cpp | 5 +- dep/CascLib/src/CascReadFile.cpp | 10 + dep/CascLib/src/CascRootFile_MNDX.cpp | 2981 +++++++++++++++++++++++++++++++++ dep/CascLib/src/CascRootFile_Mndx.cpp | 2981 --------------------------------- dep/CascLib/src/common/Common.cpp | 29 - dep/CascLib/src/common/Common.h | 9 - dep/CascLib/src/common/Csv.h | 2 +- 10 files changed, 3043 insertions(+), 3022 deletions(-) create mode 100644 dep/CascLib/src/CascRootFile_MNDX.cpp delete mode 100644 dep/CascLib/src/CascRootFile_Mndx.cpp (limited to 'dep/CascLib/src') diff --git a/dep/CascLib/src/CascCommon.h b/dep/CascLib/src/CascCommon.h index 3ce527061c2..f32be935352 100644 --- a/dep/CascLib/src/CascCommon.h +++ b/dep/CascLib/src/CascCommon.h @@ -342,6 +342,7 @@ struct TCascFile DWORD bVerifyIntegrity:1; // If true, then the data are validated more strictly when read DWORD bDownloadFileIf:1; // If true, then the data will be downloaded from the online storage if missing DWORD bLocalFileStream:1; // If true, then the file stream is a local file + DWORD bOvercomeEncrypted:1; // If true, then CascReadFile will fill the part that is encrypted (and key was not found) with zeros LPBYTE pbFileCache; // Pointer to file cache DWORD cbFileCache; // Size of the file cache diff --git a/dep/CascLib/src/CascDecrypt.cpp b/dep/CascLib/src/CascDecrypt.cpp index 043d8effa66..42bf3084801 100644 --- a/dep/CascLib/src/CascDecrypt.cpp +++ b/dep/CascLib/src/CascDecrypt.cpp @@ -480,6 +480,9 @@ int CascDirectCopy(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, D return ERROR_SUCCESS; } +//----------------------------------------------------------------------------- +// Public functions + bool WINAPI CascAddEncryptionKey(HANDLE hStorage, ULONGLONG KeyName, LPBYTE Key) { PCASC_ENCRYPTION_KEY pEncKey; diff --git a/dep/CascLib/src/CascLib.h b/dep/CascLib/src/CascLib.h index 9695ad7429a..52451ac8f20 100644 --- a/dep/CascLib/src/CascLib.h +++ b/dep/CascLib/src/CascLib.h @@ -26,6 +26,49 @@ extern "C" { #endif +//----------------------------------------------------------------------------- +// Use the apropriate library +// +// The library type is encoded in the library name as the following +// CascLibXYZ.lib +// +// X - D for Debug version, R for Release version +// Y - A for ANSI version, U for Unicode version +// Z - S for static-linked CRT library, D for multithreaded DLL CRT library +// +#if defined(_MSC_VER) && !defined(__CASCLIB_SELF__) && !defined(CASCLIB_NO_AUTO_LINK_LIBRARY) + + #ifdef _DEBUG // DEBUG VERSIONS + #ifndef _UNICODE + #ifdef _DLL + #pragma comment(lib, "CascLibDAD.lib") // Debug Ansi CRT-DLL version + #else + #pragma comment(lib, "CascLibDAS.lib") // Debug Ansi CRT-LIB version + #endif + #else + #ifdef _DLL + #pragma comment(lib, "CascLibDUD.lib") // Debug Unicode CRT-DLL version + #else + #pragma comment(lib, "CascLibDUS.lib") // Debug Unicode CRT-LIB version + #endif + #endif + #else // RELEASE VERSIONS + #ifndef _UNICODE + #ifdef _DLL + #pragma comment(lib, "CascLibRAD.lib") // Release Ansi CRT-DLL version + #else + #pragma comment(lib, "CascLibRAS.lib") // Release Ansi CRT-LIB version + #endif + #else + #ifdef _DLL + #pragma comment(lib, "CascLibRUD.lib") // Release Unicode CRT-DLL version + #else + #pragma comment(lib, "CascLibRUS.lib") // Release Unicode CRT-LIB version + #endif + #endif + #endif + +#endif //----------------------------------------------------------------------------- // Defines @@ -40,6 +83,7 @@ extern "C" { #define CASC_OPEN_TYPE_MASK 0x0000000F // The mask which gets open type from the dwFlags #define CASC_OPEN_FLAGS_MASK 0xFFFFFFF0 // The mask which gets open type from the dwFlags #define CASC_STRICT_DATA_CHECK 0x00000010 // Verify all data read from a file +#define CASC_OVERCOME_ENCRYPTED 0x00000020 // When CascReadFile encounters a block encrypted with a key that is missing, the block is filled with zeros and returned as success #define CASC_LOCALE_ALL 0xFFFFFFFF #define CASC_LOCALE_NONE 0x00000000 diff --git a/dep/CascLib/src/CascOpenFile.cpp b/dep/CascLib/src/CascOpenFile.cpp index 741ab1e1005..45d10bc18f1 100644 --- a/dep/CascLib/src/CascOpenFile.cpp +++ b/dep/CascLib/src/CascOpenFile.cpp @@ -36,8 +36,9 @@ bool OpenFileByCKeyEntry(TCascStorage * hs, PCASC_CKEY_ENTRY pCKeyEntry, DWORD d // Create the file handle structure if((hf = new TCascFile(hs, pCKeyEntry)) != NULL) { - hf->bVerifyIntegrity = (dwOpenFlags & CASC_STRICT_DATA_CHECK) ? true : false; - hf->bDownloadFileIf = (hs->dwFeatures & CASC_FEATURE_ONLINE) ? true : false; + hf->bVerifyIntegrity = (dwOpenFlags & CASC_STRICT_DATA_CHECK) ? true : false; + hf->bDownloadFileIf = (hs->dwFeatures & CASC_FEATURE_ONLINE) ? true : false; + hf->bOvercomeEncrypted = (dwOpenFlags & CASC_OVERCOME_ENCRYPTED) ? true : false; nError = ERROR_SUCCESS; } else diff --git a/dep/CascLib/src/CascReadFile.cpp b/dep/CascLib/src/CascReadFile.cpp index 2720d6d5adb..2f444d0d80f 100644 --- a/dep/CascLib/src/CascReadFile.cpp +++ b/dep/CascLib/src/CascReadFile.cpp @@ -791,6 +791,16 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW pbEncodedFrame, pFrame->EncodedSize, (DWORD)(pFrame - hf->pFrames)); + + // Some people find it handy to extract data from partially encrypted file, + // even at the cost producing files that are corrupt. + // We overcome missing decryption key by zeroing the encrypted portions + if(nError == ERROR_FILE_ENCRYPTED && hf->bOvercomeEncrypted) + { + memset(pbDecodedFrame, 0, pFrame->ContentSize); + nError = ERROR_SUCCESS; + } + if (nError == ERROR_SUCCESS) { // Mark the frame as loaded diff --git a/dep/CascLib/src/CascRootFile_MNDX.cpp b/dep/CascLib/src/CascRootFile_MNDX.cpp new file mode 100644 index 00000000000..9dca8d30eb4 --- /dev/null +++ b/dep/CascLib/src/CascRootFile_MNDX.cpp @@ -0,0 +1,2981 @@ +/*****************************************************************************/ +/* CascRootFile_MNDX.cpp Copyright (c) Ladislav Zezula 2014 */ +/*---------------------------------------------------------------------------*/ +/* Common functions for CascLib */ +/* Note: "HOTS" refers to Play.exe, v2.5.0.29049 (Heroes of the Storm Alpha) */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 18.05.14 1.00 Lad The first version of CascRootFile_MNDX.cpp */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "CascLib.h" +#include "CascCommon.h" + +//----------------------------------------------------------------------------- +// Local defines + +#define MNDX_MAR_SIGNATURE 0x0052414d // 'MAR\0' +#define MAR_PACKAGE_NAMES 0 // MAR with package names only +#define MAR_STRIPPED_NAMES 1 // MAR with names where packages were stripped +#define MAR_FULL_NAMES 2 // MAR with full file names +#define MAR_COUNT 3 // Maximum of 3 MAR files are supported + +#define MNDX_SEARCH_INITIALIZING 0 +#define MNDX_SEARCH_SEARCHING 2 +#define MNDX_SEARCH_FINISHED 4 + +#define MNDX_MAX_ENTRIES(type) (0xFFFFFFFF / sizeof(type)) + +#define MNDX_INVALID_SIZE_T ((size_t)(-1)) + +#define MNDX_LAST_CKEY_ENTRY 0x80000000 + +//----------------------------------------------------------------------------- +// Local structures + +typedef union _SETBITS +{ + struct + { + DWORD Lower08 : 8; // Number of set bits in the lower 1 byte + DWORD Lower16 : 8; // Number of set bits in the lower 2 bytes + DWORD Lower24 : 8; // Number of set bits in the lower 3 bytes + DWORD Lower32 : 8; // Number of set bits in the 32-bit integer + } u; + + DWORD SetBitsAll; // The total set bits mask + +} SETBITS, *PSETBITS; + +typedef struct _HASH_ENTRY +{ + DWORD NodeIndex; // Index of the path node + DWORD NextIndex; // ID of the first subnode in the hash table + + union + { + DWORD FragmentOffset; // Offset of the path fragment in the TPathFragmentTable + DWORD ChildTableIndex; // Starting search index for the child database (if child database is present) + char SingleChar; // If the upper 24 bits of the FragmentOffset is 0xFFFFFFFF, this single character + }; + // Otherwise --> Offset to the name fragment table +} HASH_ENTRY, *PHASH_ENTRY; + +typedef struct _FILE_MNDX_HEADER +{ + DWORD Signature; // 'MNDX' + DWORD HeaderVersion; // Must be <= 2 + DWORD FormatVersion; + +} FILE_MNDX_HEADER, *PFILE_MNDX_HEADER; + +typedef struct _MNDX_PACKAGE +{ + char * szFileName; // Pointer to file name + size_t nLength; // Length of the file name + size_t nIndex; // Package index + +} MNDX_PACKAGE, *PMNDX_PACKAGE; + +// Root file entry for CASC storages with MNDX root file (Heroes of the Storm) +// Corresponds to the in-file structure +typedef struct _MNDX_CKEY_ENTRY +{ + DWORD Flags; // High 8 bits: Flags, low 24 bits: package index + BYTE CKey[MD5_HASH_SIZE]; // Content key for the file + DWORD ContentSize; // Uncompressed file size, in bytes + +} MNDX_CKEY_ENTRY, *PMNDX_CKEY_ENTRY; + +typedef struct _FILE_MAR_INFO +{ + DWORD MarIndex; + DWORD MarDataSize; + DWORD MarDataSizeHi; + DWORD MarDataOffset; + DWORD MarDataOffsetHi; +} FILE_MAR_INFO, *PFILE_MAR_INFO; + +//----------------------------------------------------------------------------- +// Local variables + +unsigned char table_1BA1818[0x800] = +{ + 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x07, 0x07, 0x07, 0x01, 0x07, 0x02, 0x02, 0x01, 0x07, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, + 0x07, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, + 0x07, 0x05, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, + 0x05, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, + 0x07, 0x06, 0x06, 0x01, 0x06, 0x02, 0x02, 0x01, 0x06, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, + 0x06, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, + 0x06, 0x05, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, + 0x05, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, + 0x07, 0x07, 0x07, 0x01, 0x07, 0x02, 0x02, 0x01, 0x07, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, + 0x07, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, + 0x07, 0x05, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, + 0x05, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, + 0x07, 0x06, 0x06, 0x01, 0x06, 0x02, 0x02, 0x01, 0x06, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, + 0x06, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, + 0x06, 0x05, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, + 0x05, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x02, 0x07, 0x07, 0x07, 0x03, 0x07, 0x03, 0x03, 0x02, + 0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x02, 0x07, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02, + 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x02, 0x07, 0x05, 0x05, 0x03, 0x05, 0x03, 0x03, 0x02, + 0x07, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02, + 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x02, 0x07, 0x06, 0x06, 0x03, 0x06, 0x03, 0x03, 0x02, + 0x07, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x02, 0x06, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02, + 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x02, 0x06, 0x05, 0x05, 0x03, 0x05, 0x03, 0x03, 0x02, + 0x06, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x02, 0x07, 0x07, 0x07, 0x03, 0x07, 0x03, 0x03, 0x02, + 0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x02, 0x07, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02, + 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x02, 0x07, 0x05, 0x05, 0x03, 0x05, 0x03, 0x03, 0x02, + 0x07, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02, + 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x02, 0x07, 0x06, 0x06, 0x03, 0x06, 0x03, 0x03, 0x02, + 0x07, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x02, 0x06, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02, + 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x02, 0x06, 0x05, 0x05, 0x03, 0x05, 0x03, 0x03, 0x02, + 0x06, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04, 0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x03, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x03, + 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04, 0x07, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x03, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x03, + 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x04, 0x07, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x03, + 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x03, + 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x04, 0x06, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x03, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04, 0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x03, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x03, + 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04, 0x07, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x03, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x03, + 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x04, 0x07, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x03, + 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x03, + 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x04, 0x06, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x03, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x04, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, + 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x04, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x04, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, + 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x04, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 +}; + +//----------------------------------------------------------------------------- +// Local functions - Number of set bits in an integer + +// HOTS: inlined +static SETBITS GetNumberOfSetBits(DWORD Value32) +{ + SETBITS SetBits; + + Value32 = ((Value32 >> 1) & 0x55555555) + (Value32 & 0x55555555); + Value32 = ((Value32 >> 2) & 0x33333333) + (Value32 & 0x33333333); + Value32 = ((Value32 >> 4) & 0x0F0F0F0F) + (Value32 & 0x0F0F0F0F); + SetBits.SetBitsAll = Value32 * 0x01010101; + + return SetBits; +} + +static DWORD GetNumberOfSetBits32(DWORD Value32) +{ + return GetNumberOfSetBits(Value32).u.Lower32; +} + +static LPBYTE CaptureData(LPBYTE pbRootPtr, LPBYTE pbRootEnd, void * pvBuffer, size_t cbLength) +{ + // Check whether there is enough data in the buffer + if((pbRootPtr + cbLength) > pbRootEnd) + return NULL; + + // Copy the data + memcpy(pvBuffer, pbRootPtr, cbLength); + return pbRootPtr + cbLength; +} + +//----------------------------------------------------------------------------- +// The TPathStop structure + +struct TPathStop +{ + TPathStop() + { + LoBitsIndex = 0; + field_4 = 0; + Count = 0; + HiBitsIndex_PathFragment = CASC_INVALID_INDEX; + field_10 = 0xFFFFFFFF; + } + + TPathStop(DWORD arg_0, DWORD arg_4, DWORD arg_8) + { + LoBitsIndex = arg_0; + field_4 = arg_4; + Count = arg_8; + HiBitsIndex_PathFragment = CASC_INVALID_INDEX; + field_10 = 0xFFFFFFFF; + } + + DWORD LoBitsIndex; + DWORD field_4; + DWORD Count; + DWORD HiBitsIndex_PathFragment; + DWORD field_10; +}; + +//----------------------------------------------------------------------------- +// Basic array implementations + +class TByteStream +{ + public: + + // HOTS: 01959990 + TByteStream() + { + pbByteData = NULL; + pvMappedFile = NULL; + cbByteData = 0; + field_C = 0; + hFile = 0; + hMap = 0; + } + + // HOTS: 19599F0 + template + int GetBytes(size_t length, T ** Pointer) + { + // Is there enough bytes in the array? + if(length > cbByteData) + return ERROR_BAD_FORMAT; + + // Give the buffer to the caller + Pointer[0] = (T *)(pbByteData); + + // Move pointers + pbByteData += length; + cbByteData -= length; + return ERROR_SUCCESS; + } + + int CopyBytes(void * value, size_t length) + { + // Is there enough bytes in the array? + if(length > cbByteData) + return ERROR_BAD_FORMAT; + + // Give the buffer to the caller + memcpy(value, pbByteData, length); + + // Move pointers + pbByteData += length; + cbByteData -= length; + return ERROR_SUCCESS; + } + + // HOTS: 1959A60 + int SkipBytes(size_t cbByteCount) + { + LPBYTE Pointer; + + return GetBytes(cbByteCount, &Pointer); + } + + // HOTS: 1959AF0 + int SetByteBuffer(LPBYTE pbNewByteData, size_t cbNewByteData) + { + if(pbNewByteData != NULL || cbNewByteData == 0) + { + pbByteData = pbNewByteData; + cbByteData = cbNewByteData; + return ERROR_SUCCESS; + } + + return ERROR_INVALID_PARAMETER; + } + + // HOTS: 1957160 + template + int GetValue(T & Value) + { + T * Pointer; + int nError; + + nError = GetBytes(sizeof(T), (LPBYTE *)(&Pointer)); + if(nError != ERROR_SUCCESS) + return nError; + + Value = Pointer[0]; + return ERROR_SUCCESS; + } + + // Retrieves the item count in the array + template + int GetArrayItemCount(DWORD & ArraySize, DWORD & ItemCount) + { + ULONGLONG ByteCount; + int nError; + + // The first 8 bytes is the byte size of the array + nError = GetValue(ByteCount); + if(nError != ERROR_SUCCESS) + return nError; + + // Extract the number of bytes + if(ByteCount > 0xFFFFFFFF || (ByteCount % sizeof(T)) != 0) + return ERROR_BAD_FORMAT; + + // Give the result to the caller + ItemCount = (DWORD)(ByteCount / sizeof(T)); + ArraySize = (DWORD)(ByteCount); + return ERROR_SUCCESS; + } + + // HOTS: 1957190: + // HOTS: 19571E0: + // HOTS: 1957230: + // HOTS: 1957280: + template + int GetArray(T ** Pointer, size_t ItemCount) + { + int nError = ERROR_SUCCESS; + + // Verify parameters + if(Pointer == NULL && ItemCount != 0) + return ERROR_INVALID_PARAMETER; + if(ItemCount > MNDX_MAX_ENTRIES(T)) + return ERROR_NOT_ENOUGH_MEMORY; + + // Allocate bytes for the array + if (Pointer != NULL) + { + Pointer[0] = CASC_ALLOC(T, ItemCount); + if (Pointer[0] == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Get the pointer to the array + nError = CopyBytes(Pointer[0], sizeof(T) * ItemCount); + } + + return nError; + } + + LPBYTE pbByteData; + void * pvMappedFile; + size_t cbByteData; + DWORD field_C; + HANDLE hFile; + HANDLE hMap; +}; + +//----------------------------------------------------------------------------- +// TGenericArray interface/implementation + +template +class TGenericArray +{ + public: + + TGenericArray() + { + ItemArray = NULL; + ItemCount = 0; + MaxItemCount = 0; + bIsValidArray = false; + } + + ~TGenericArray() + { + CASC_FREE(ItemArray); + } + + T & operator[] (size_t index) + { + assert(index < ItemCount); + return ItemArray[index]; + } + + // HOTS: 1957090 (SetDwordsValid) + // HOTS: 19570B0 (SetBaseValsValid) + // HOTS: 19570D0 (? SetBitsValid ?) + // HOTS: 19570F0 (SetPathFragmentsValid) + int SetArrayValid() + { + if(bIsValidArray != 0) + return ERROR_ALREADY_EXISTS; + + bIsValidArray = true; + return ERROR_SUCCESS; + } + + // HOTS: 19575A0 (char) + // HOTS: 1957600 (TPathStop) + void SetMaxItems(DWORD NewMaxItemCount) + { + T * OldArray = ItemArray; + T * NewArray; + + // Allocate new data buffer + NewArray = CASC_ALLOC(T, NewMaxItemCount); + if(NewArray != NULL) + { + // Copy the old items to the buffer + for(size_t i = 0; i < ItemCount; i++) + { + NewArray[i] = ItemArray[i]; + } + } + + ItemArray = NewArray; + MaxItemCount = NewMaxItemCount; + CASC_FREE(OldArray); + } + + // HOTS: 19575A0 (char) + // HOTS: 1957600 (TPathStop) + void SetMaxItemsIf(DWORD NewMaxItemCount) + { + if(NewMaxItemCount > MaxItemCount) + { + if(MaxItemCount > (NewMaxItemCount / 2)) + { + if(MaxItemCount <= (MNDX_MAX_ENTRIES(T) / 2)) + NewMaxItemCount = MaxItemCount + MaxItemCount; + else + NewMaxItemCount = MNDX_MAX_ENTRIES(T); + } + + SetMaxItems(NewMaxItemCount); + } + } + + // HOTS: inline + // HOTS: 1958330 + void Insert(T NewItem) + { + // Make sure we have enough capacity for the new item + SetMaxItemsIf(ItemCount + 1); + + // Put the character to the slot that has been reserved + ItemArray[ItemCount++] = NewItem; + } + + // HOTS: 19583A0 + void GrowArray(DWORD NewItemCount) + { + DWORD OldMaxItemCount = MaxItemCount; + + // Make sure we have enough capacity for new items + SetMaxItemsIf(NewItemCount); + + // Initialize the newly inserted items + for(DWORD i = OldMaxItemCount; i < NewItemCount; i++) + { + ItemArray[i] = T(); + } + + ItemCount = NewItemCount; + } + + // HOTS: 1957440 + // HOTS: 19574E0 + // HOTS: 1957690 + // HOTS: 1957700 + // HOTS: 195A220 + // HOTS: 1958580 + int LoadFromStream(TByteStream & InStream) + { + DWORD NumberOfBytes; + int nError; + + // Get and verify the number of items + nError = InStream.GetArrayItemCount(NumberOfBytes, ItemCount); + if(nError != ERROR_SUCCESS) + return nError; + + // Get the pointer to the array + nError = InStream.GetArray(&ItemArray, ItemCount); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07); + if(nError != ERROR_SUCCESS) + return nError; + + return SetArrayValid(); + } + + T * ItemArray; + DWORD ItemCount; // Number of items in the array + DWORD MaxItemCount; // Capacity of the array + bool bIsValidArray; +}; + +class TBitEntryArray : public TGenericArray +{ + public: + + TBitEntryArray() : TGenericArray() + { + BitsPerEntry = 0; + EntryBitMask = 0; + TotalEntries = 0; + } + + ~TBitEntryArray() + {} + + DWORD GetItem(DWORD EntryIndex) + { + DWORD dwItemIndex = (EntryIndex * BitsPerEntry) >> 0x05; + DWORD dwStartBit = (EntryIndex * BitsPerEntry) & 0x1F; + DWORD dwEndBit = dwStartBit + BitsPerEntry; + DWORD dwResult; + + // If the end bit index is greater than 32, + // we also need to load from the next 32-bit item + if(dwEndBit > 0x20) + { + dwResult = (ItemArray[dwItemIndex + 1] << (0x20 - dwStartBit)) | (ItemArray[dwItemIndex] >> dwStartBit); + } + else + { + dwResult = ItemArray[dwItemIndex] >> dwStartBit; + } + + // Now we also need to mask the result by the bit mask + return dwResult & EntryBitMask; + } + + int LoadBitsFromStream(TByteStream & InStream) + { + ULONGLONG Value64 = 0; + int nError; + + nError = LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.GetValue(BitsPerEntry); + if(nError != ERROR_SUCCESS) + return nError; + if(BitsPerEntry > 0x20) + return ERROR_BAD_FORMAT; + + nError = InStream.GetValue(EntryBitMask); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.GetValue(Value64); + if(nError != ERROR_SUCCESS) + return nError; + if(Value64 > 0xFFFFFFFF) + return ERROR_BAD_FORMAT; + TotalEntries = (DWORD)Value64; + + assert((BitsPerEntry * TotalEntries) / 32 <= ItemCount); + return ERROR_SUCCESS; + } + + DWORD BitsPerEntry; + DWORD EntryBitMask; + DWORD TotalEntries; +}; + +//----------------------------------------------------------------------------- +// TSparseArray functions + +#define INDEX_TO_GROUP(val) (val >> 9) +#define GROUP_TO_INDEX(grp) (grp << 9) + +// For each 0x200-th bit, this contains information about amount of "1" bits +typedef struct _BASEVALS +{ + DWORD BaseValue200; // Item value of every 0x200-th item + + DWORD AddValue40 : 7; // For each 0x40 items (above the base200), + DWORD AddValue80 : 8; // we have extra shortcut to the item value + DWORD AddValueC0 : 8; // that is to be added to BaseValue200 + DWORD AddValue100 : 9; + DWORD AddValue140 : 9; + DWORD AddValue180 : 9; + DWORD AddValue1C0 : 9; + + DWORD __xalignment : 5; // Filling +} BASEVALS, *PBASEVALS; + +class TSparseArray +{ + public: + + TSparseArray() + { + TotalItemCount = 0; + ValidItemCount = 0; + } + + // HOTS: 1958630 + int LoadFromStream(TByteStream & InStream) + { + DWORD total_count = 0; + DWORD valid_count = 0; + int nError; + + nError = ItemBits.LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.GetValue(total_count); + if(nError != ERROR_SUCCESS) + return nError; + nError = InStream.GetValue(valid_count); + if(nError != ERROR_SUCCESS) + return nError; + if(valid_count > total_count) + return ERROR_FILE_CORRUPT; + + TotalItemCount = total_count; + ValidItemCount = valid_count; + + nError = BaseVals.LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + nError = IndexToItem0.LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + nError = IndexToItem1.LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + return ERROR_SUCCESS; + } + + // Returns true if the array is empty + bool IsEmpty() + { + return (TotalItemCount == 0); + } + + // Returns true if the item at n-th position is present + bool IsItemPresent(size_t index) + { + // (index >> 0x05) gives the DWORD, (1 << (ItemIndex & 0x1F)) gives the bit + return (ItemBits[index >> 0x05] & (1 << (index & 0x1F))) ? true : false; + } + + // Retrieves the value of the n-th item in the sparse array. + // Note that for items that are not present, the value is equal + // to the nearest lower present value + DWORD GetItemValueAt(size_t index) + { + BASEVALS & SetBitsCount = BaseVals[index >> 0x09]; + DWORD IntValue; + DWORD BitMask; + + // + // Since we don't want to count bits for the entire array, + // there are item value shortcuts every 0x200 items, + // and then every 0x40 items above the 0x200 base + // + + // 1) We have base value for every 0x200-th item + IntValue = SetBitsCount.BaseValue200; + + // 2) Add the base value for each 0x40-th item above the 0x200 base + switch(((index >> 0x06) & 0x07) - 1) + { + case 0: // Add the 1st value (7 bits) + IntValue += SetBitsCount.AddValue40; + break; + + case 1: // Add the 2nd value (8 bits) + IntValue += SetBitsCount.AddValue80; + break; + + case 2: // Add the 3rd value (8 bits) + IntValue += SetBitsCount.AddValueC0; + break; + + case 3: // Add the 4th value (9 bits) + IntValue += SetBitsCount.AddValue100; + break; + + case 4: // Add the 5th value (9 bits) + IntValue += SetBitsCount.AddValue140; + break; + + case 5: // Add the 6th value (9 bits) + IntValue += SetBitsCount.AddValue180; + break; + + case 6: // Add the 7th value (9 bits) + IntValue += SetBitsCount.AddValue1C0; + break; + } + + // 3) Count the bits of the higher DWORD, if the index 0x20 - 0x30 above the 0x200 base + if(index & 0x20) + IntValue += GetNumberOfSetBits32(ItemBits[(index >> 0x05) - 1]); + + // 4) Count the bits in the current DWORD (masked by bit index mask) + BitMask = (1 << (index & 0x1F)) - 1; + return IntValue + GetNumberOfSetBits32(ItemBits[index >> 0x05] & BitMask); + } + + DWORD FindGroup_Items0(DWORD index) + { + // Setup the group range to search + DWORD minGroup = (IndexToItem0[INDEX_TO_GROUP(index) + 0]) >> 9; + DWORD maxGroup = (IndexToItem0[INDEX_TO_GROUP(index) + 1] + 0x1FF) >> 9; + + // Search the groups and find the BASEVALS structure + // For spans less than 10 groups, use sequential search, otherwise binary search. + if ((maxGroup - minGroup) < 10) + { + // HOTS: 1959CF7 + while (index >= GROUP_TO_INDEX(minGroup) - BaseVals[minGroup + 1].BaseValue200 + 0x200) + { + // HOTS: 1959D14 + minGroup++; + } + } + else + { + // HOTS: 1959D2E + while ((minGroup + 1) < maxGroup) + { + // HOTS: 1959D38 + DWORD middleValue = (maxGroup + minGroup) >> 1; + + if (index < (maxGroup << 0x09) - BaseVals[maxGroup].BaseValue200) + { + // HOTS: 01959D4B + maxGroup = middleValue; + } + else + { + // HOTS: 1959D50 + minGroup = middleValue; + } + } + } + + return minGroup; + } + + DWORD FindGroup_Items1(DWORD index) + { + DWORD groupIndex = (index >> 0x09); + DWORD startValue = IndexToItem1[groupIndex] >> 9; + DWORD nextValue = (IndexToItem1[groupIndex + 1] + 0x1FF) >> 9; + + // Find the BASEVALS structure which the start index belongs to + // For less than 10 values, use sequential search. Otherwise, use binary search + if ((nextValue - startValue) < 10) + { + // HOTS: 01959F94 + while (index >= BaseVals[startValue + 1].BaseValue200) + { + // HOTS: 1959FA3 + startValue++; + } + } + else + { + // Binary search (HOTS: 1959FAD) + if ((startValue + 1) < nextValue) + { + // HOTS: 1959FB4 + DWORD middleValue = (nextValue + startValue) >> 1; + + if (index < BaseVals[middleValue].BaseValue200) + { + // HOTS: 1959FC4 + nextValue = middleValue; + } + else + { + // HOTS: 1959FC8 + startValue = middleValue; + } + } + } + + return startValue; + } + + // Returns the value of Item0[index] (HOTS: 1959CB0) + DWORD GetItem0(DWORD index) + { + SETBITS zeroBits; + DWORD groupIndex; + DWORD dwordIndex; + DWORD itemIndex; + DWORD bitGroup; + DWORD edx = index; + +#ifdef _DEBUG + //if (TotalItemCount > 0x200) + //{ + // FILE * fp = fopen("e:\\Ladik\\Appdir\\CascLib\\doc\\mndx-sparse-array.txt", "wt"); + // Dump(fp); + // fclose(fp); + //} +#endif + + // If the index is at begin of the group, we just return the start value + if ((index & 0x1FF) == 0) + return IndexToItem0[INDEX_TO_GROUP(index)]; + + // Find the group where the index belongs to + groupIndex = FindGroup_Items0(index); + + // HOTS: 1959D5F + edx += BaseVals[groupIndex].BaseValue200 - (groupIndex << 0x09); + dwordIndex = (groupIndex << 4); + + if (edx < 0x100 - BaseVals[groupIndex].AddValue100) + { + // HOTS: 1959D8C + if (edx < 0x80 - BaseVals[groupIndex].AddValue80) + { + // HOTS: 01959DA2 + if (edx >= 0x40 - BaseVals[groupIndex].AddValue40) + { + // HOTS: 01959DB7 + dwordIndex += 2; + edx = edx + BaseVals[groupIndex].AddValue40 - 0x40; + } + } + else + { + // HOTS: 1959DC0 + if (edx < 0xC0 - BaseVals[groupIndex].AddValueC0) + { + // HOTS: 1959DD3 + dwordIndex += 4; + edx = edx + BaseVals[groupIndex].AddValue80 - 0x80; + } + else + { + // HOTS: 1959DD3 + dwordIndex += 6; + edx = edx + BaseVals[groupIndex].AddValueC0 - 0xC0; + } + } + } + else + { + // HOTS: 1959DE8 + if (edx < 0x180 - BaseVals[groupIndex].AddValue180) + { + // HOTS: 01959E00 + if (edx < 0x140 - BaseVals[groupIndex].AddValue140) + { + // HOTS: 1959E11 + dwordIndex += 8; + edx = edx + BaseVals[groupIndex].AddValue100 - 0x100; + } + else + { + // HOTS: 1959E1D + dwordIndex += 10; + edx = edx + BaseVals[groupIndex].AddValue140 - 0x140; + } + } + else + { + // HOTS: 1959E29 + if (edx < 0x1C0 - BaseVals[groupIndex].AddValue1C0) + { + // HOTS: 1959E3D + dwordIndex += 12; + edx = edx + BaseVals[groupIndex].AddValue180 - 0x180; + } + else + { + // HOTS: 1959E49 + dwordIndex += 14; + edx = edx + BaseVals[groupIndex].AddValue1C0 - 0x1C0; + } + } + } + + // HOTS: 1959E53: + // Calculate the number of bits set in the value of "bitGroup" + bitGroup = ~ItemBits[dwordIndex]; + zeroBits = GetNumberOfSetBits(bitGroup); + + if (edx >= zeroBits.u.Lower32) + { + // HOTS: 1959ea4 + bitGroup = ~ItemBits[++dwordIndex]; + edx = edx - zeroBits.u.Lower32; + zeroBits = GetNumberOfSetBits(bitGroup); + } + + // Re-calculate the item index + itemIndex = (dwordIndex << 0x05); + + // HOTS: 1959eea + if (edx < zeroBits.u.Lower16) + { + // HOTS: 1959EFC + if (edx >= zeroBits.u.Lower08) + { + // HOTS: 1959F05 + bitGroup >>= 0x08; + itemIndex += 0x08; + edx -= zeroBits.u.Lower08; + } + } + else + { + // HOTS: 1959F0D + if (edx < zeroBits.u.Lower24) + { + // HOTS: 1959F19 + bitGroup >>= 0x10; + itemIndex += 0x10; + edx -= zeroBits.u.Lower16; + } + else + { + // HOTS: 1959F23 + bitGroup >>= 0x18; + itemIndex += 0x18; + edx -= zeroBits.u.Lower24; + } + } + + // HOTS: 1959f2b + edx = edx << 0x08; + bitGroup = bitGroup & 0xFF; + + // BUGBUG: Possible buffer overflow here. Happens when dwItemIndex >= 0x9C. + // The same happens in Heroes of the Storm (build 29049), so I am not sure + // if this is a bug or a case that never happens + assert((bitGroup + edx) < sizeof(table_1BA1818)); + return table_1BA1818[bitGroup + edx] + itemIndex; + } + + DWORD GetItem1(DWORD index) + { + SETBITS setBits; + DWORD distFromBase; + DWORD groupIndex; + DWORD dwordIndex; + DWORD itemIndex; + DWORD bitGroup; + + // If the index is at begin of the group, we just return the start value + if ((index & 0x1FF) == 0) + return IndexToItem1[INDEX_TO_GROUP(index)]; + + // Find the group where the index belongs to + groupIndex = FindGroup_Items1(index); + + // Calculate the base200 dword index (HOTS: 1959FD4) + distFromBase = index - BaseVals[groupIndex].BaseValue200; + dwordIndex = groupIndex << 0x04; + + // Calculate the dword index including the sub-checkpoint + if (distFromBase < BaseVals[groupIndex].AddValue100) + { + // HOTS: 1959FF1 + if (distFromBase < BaseVals[groupIndex].AddValue80) + { + // HOTS: 0195A000 + if (distFromBase >= BaseVals[groupIndex].AddValue40) + { + // HOTS: 195A007 + distFromBase = distFromBase - BaseVals[groupIndex].AddValue40; + dwordIndex += 2; + } + } + else + { + // HOTS: 195A00E + if (distFromBase < BaseVals[groupIndex].AddValueC0) + { + // HOTS: 195A01A + distFromBase = distFromBase - BaseVals[groupIndex].AddValue80; + dwordIndex += 4; + } + else + { + // HOTS: 195A01F + distFromBase = distFromBase - BaseVals[groupIndex].AddValueC0; + dwordIndex += 6; + } + } + } + else + { + // HOTS: 195A026 + if (distFromBase < BaseVals[groupIndex].AddValue180) + { + // HOTS: 195A037 + if (distFromBase < BaseVals[groupIndex].AddValue140) + { + // HOTS: 195A041 + distFromBase = distFromBase - BaseVals[groupIndex].AddValue100; + dwordIndex += 8; + } + else + { + // HOTS: 195A048 + distFromBase = distFromBase - BaseVals[groupIndex].AddValue140; + dwordIndex += 10; + } + } + else + { + // HOTS: 195A04D + if (distFromBase < BaseVals[groupIndex].AddValue1C0) + { + // HOTS: 195A05A + distFromBase = distFromBase - BaseVals[groupIndex].AddValue180; + dwordIndex += 12; + } + else + { + // HOTS: 195A061 + distFromBase = distFromBase - BaseVals[groupIndex].AddValue1C0; + dwordIndex += 14; + } + } + } + + // HOTS: 195A066 + bitGroup = ItemBits[dwordIndex]; + setBits = GetNumberOfSetBits(bitGroup); + + // Get total number of set bits in the bit group + if (distFromBase >= setBits.u.Lower32) + { + // HOTS: 195A0B2 + bitGroup = ItemBits[++dwordIndex]; + distFromBase = distFromBase - setBits.u.Lower32; + setBits = GetNumberOfSetBits(bitGroup); + } + + // Calculate the item index + itemIndex = (dwordIndex << 0x05); + + // Get the number of set bits in the lower word (HOTS: 195A0F6) + if (distFromBase < setBits.u.Lower16) + { + // HOTS: 195A111 + if (distFromBase >= setBits.u.Lower08) + { + // HOTS: 195A111 + itemIndex = itemIndex + 0x08; + bitGroup = bitGroup >> 0x08; + distFromBase = distFromBase - setBits.u.Lower08; + } + } + else + { + // HOTS: 195A119 + if (distFromBase < setBits.u.Lower24) + { + // HOTS: 195A125 + bitGroup = bitGroup >> 0x10; + itemIndex = itemIndex + 0x10; + distFromBase = distFromBase - setBits.u.Lower16; + } + else + { + // HOTS: 195A12F + bitGroup = bitGroup >> 0x18; + itemIndex = itemIndex + 0x18; + distFromBase = distFromBase - setBits.u.Lower24; + } + } + + bitGroup = bitGroup & 0xFF; + distFromBase = distFromBase << 0x08; + + // BUGBUG: Potential buffer overflow + // Happens in Heroes of the Storm when index == 0x5B + assert((bitGroup + distFromBase) < sizeof(table_1BA1818)); + return table_1BA1818[bitGroup + distFromBase] + itemIndex; + } + +#ifdef _DEBUG + void Dump(FILE * fp) + { + size_t * ArrayNormal; + size_t * ArrayInvert; + size_t IndexNormal = 0; + size_t IndexInvert = 0; + + // Output numbers of set bits for every 0x200-th item + fprintf(fp, "Number of set bits for every 0x200-th index\n" + "========================================================\n" + " Index Base200h +40 +80 +C0 +100 +140 +180 +1C0\n" + "--------------------------------------------------------\n"); + for (size_t i = 0; i < BaseVals.ItemCount; i++) + { + fprintf(fp, "[%08zX]: %08x %04x %04x %04x %04x %04x %04x %04x\n", GROUP_TO_INDEX(i), BaseVals[i].BaseValue200, + BaseVals[i].AddValue40, + BaseVals[i].AddValue80, + BaseVals[i].AddValueC0, + BaseVals[i].AddValue100, + BaseVals[i].AddValue140, + BaseVals[i].AddValue180, + BaseVals[i].AddValue1C0); + } + fprintf(fp, "\n"); + + // Output values of Item1 and Item0 for every 0x200-th index + fprintf(fp, "Item0 and Item1 for every 0x200-th index\n" + "========================================\n" + " Index Item0 Item1\n" + "-----------------------------\n"); + for (size_t i = 0; i < IndexToItem0.ItemCount; i++) + { + fprintf(fp, "[%08zX]: %08x %08x\n", GROUP_TO_INDEX(i), IndexToItem0[i], IndexToItem1[i]); + } + fprintf(fp, "\n"); + + + // Output values of Item1 and Item0 for every index + ArrayNormal = new size_t[TotalItemCount]; + ArrayInvert = new size_t[TotalItemCount]; + if (ArrayNormal && ArrayInvert) + { + // Invalidate both arrays + memset(ArrayNormal, 0xFF, TotalItemCount * sizeof(size_t)); + memset(ArrayInvert, 0xFF, TotalItemCount * sizeof(size_t)); + + // Load the both arrays + for (size_t i = 0; i < TotalItemCount; i++) + { + if (IsItemPresent(i)) + ArrayNormal[IndexNormal++] = i; + else + ArrayInvert[IndexInvert++] = i; + } + + // Output both arrays + fprintf(fp, "Item0 and Item1 for every index\n" + "========================================\n" + " Index Item0 Item1\n" + "-----------------------------\n"); + for (size_t i = 0; i < TotalItemCount; i++) + { + char NormalValue[0x20]; + char InvertValue[0x20]; + + if (ArrayNormal[i] == MNDX_INVALID_SIZE_T && ArrayInvert[i] == MNDX_INVALID_SIZE_T) + break; + fprintf(fp, "[%08zX]: %8s %8s\n", i, DumpValue(InvertValue, _countof(InvertValue), ArrayInvert[i]), DumpValue(NormalValue, _countof(NormalValue), ArrayNormal[i])); + } + fprintf(fp, "\n"); + } + + // Free both arrays + delete[] ArrayNormal; + delete[] ArrayInvert; + + // Output array of all values + fprintf(fp, "Item List: Index -> Value\n==========================\n"); + for (size_t i = 0; i < TotalItemCount; i++) + { + if (IsItemPresent(i)) + { + fprintf(fp, "[%08zX]: %08x\n", i, GetItemValueAt(i)); + } + else + { + fprintf(fp, "[%08zX]: NOT PRESENT\n", i); + } + } + fprintf(fp, "\n"); + } + + char * DumpValue(char * szBuffer, size_t cchBuffer, size_t value) + { + CascStrPrintf(szBuffer, cchBuffer, (value != MNDX_INVALID_SIZE_T) ? "%08zX" : " - ", value); + return szBuffer; + } +#endif + + TGenericArray ItemBits; // A bit array for each item. 1 if the item is present. + size_t TotalItemCount; // Total number of items in the array + size_t ValidItemCount; // Number of present items in the array + TGenericArray BaseVals; // For each 0x200-th item, this contains the number of set bits up to that 0x200-th item + TGenericArray IndexToItem0; // Mapping of index to invert item. An "invert" item is an item whose bit in "ItemBits" is zero. + TGenericArray IndexToItem1; // Mapping of index to normal item. An "normal" item is an item whose bit in "ItemBits" is set. +}; + +//----------------------------------------------------------------------------- +// TStruct40 functions + +class TStruct40 +{ + public: + + TStruct40() + { + NodeIndex = 0; + ItemCount = 0; + PathLength = 0; + SearchPhase = MNDX_SEARCH_INITIALIZING; + } + + // HOTS: 19586B0 + void BeginSearch() + { + // HOTS: 19586BD + PathBuffer.ItemCount = 0; + PathBuffer.SetMaxItemsIf(0x40); + + // HOTS: 19586E1 + // Set the new item count + PathStops.GrowArray(0); + PathStops.SetMaxItemsIf(4); + + PathLength = 0; + NodeIndex = 0; + ItemCount = 0; + SearchPhase = MNDX_SEARCH_SEARCHING; + } + + DWORD CalcHashValue(const char * szPath) + { + return (BYTE)(szPath[PathLength]) ^ (NodeIndex << 0x05) ^ NodeIndex; + } + + TGenericArray PathStops; // Array of path checkpoints + TGenericArray PathBuffer; // Buffer for building a file name + DWORD NodeIndex; // ID of a path node being searched; starting with 0 + DWORD PathLength; // Length of the path in the PathBuffer + DWORD ItemCount; + DWORD SearchPhase; // 0 = initializing, 2 = searching, 4 = finished +}; + +//----------------------------------------------------------------------------- +// Local functions - TMndxSearch + +class TMndxSearch +{ + public: + + // HOTS: 01956EE0 + TMndxSearch() + { + szSearchMask = NULL; + cchSearchMask = 0; + szFoundPath = NULL; + cchFoundPath = 0; + nIndex = 0; + } + + // HOTS: 01956F00 + ~TMndxSearch() + {} + + // HOTS: 01956E70 + int SetSearchMask( + const char * szNewSearchMask, + size_t cchNewSearchMask) + { + if(szSearchMask == NULL && cchSearchMask != 0) + return ERROR_INVALID_PARAMETER; + + Struct40.SearchPhase = MNDX_SEARCH_INITIALIZING; + + szSearchMask = szNewSearchMask; + cchSearchMask = cchNewSearchMask; + return ERROR_SUCCESS; + } + + TStruct40 Struct40; + const char * szSearchMask; // Search mask without wildcards + size_t cchSearchMask; // Length of the search mask + const char * szFoundPath; // Found path name + size_t cchFoundPath; // Length of the found path name + DWORD nIndex; // Index of the file name +}; + +//----------------------------------------------------------------------------- +// TPathFragmentTable class. This class implements table of the path fragments. +// These path fragments can either by terminated by zeros (ASCIIZ) +// or can be marked by the external "PathMarks" structure + +class TPathFragmentTable +{ + public: + + // HOTS: 0195A290 + TPathFragmentTable() + {} + + // HOTS: inlined + ~TPathFragmentTable() + {} + + // HOTS: 195A180 + bool ComparePathFragment(TMndxSearch * pSearch, size_t nFragmentOffset) + { + TStruct40 * pStruct40 = &pSearch->Struct40; + + // Do we have path fragment separators in an external structure? + if(PathMarks.IsEmpty()) + { + // Keep searching as long as the name matches with the fragment + while(PathFragments[nFragmentOffset] == pSearch->szSearchMask[pStruct40->PathLength]) + { + // Move to the next character + pStruct40->PathLength++; + nFragmentOffset++; + + // Is it the end of the fragment or end of the path? + if(PathFragments[nFragmentOffset] == 0) + return true; + if(pStruct40->PathLength >= pSearch->cchSearchMask) + return false; + } + + return false; + } + else + { + // Keep searching as long as the name matches with the fragment + while(PathFragments[nFragmentOffset] == pSearch->szSearchMask[pStruct40->PathLength]) + { + // Move to the next character + pStruct40->PathLength++; + + // Is it the end of the path fragment? + if(PathMarks.IsItemPresent(nFragmentOffset++)) + return true; + if(nFragmentOffset >= pSearch->cchSearchMask) + return false; + } + + return false; + } + } + + // HOTS: 195A3F0 + void CopyPathFragment(TMndxSearch * pSearch, size_t nFragmentOffset) + { + TStruct40 * pStruct40 = &pSearch->Struct40; + + // Do we have path fragment separators in an external structure? + if (PathMarks.IsEmpty()) + { + // HOTS: 195A40C + while (PathFragments[nFragmentOffset] != 0) + { + // Insert the character to the path being built + pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset++]); + } + } + else + { + // HOTS: 195A4B3 + while(!PathMarks.IsItemPresent(nFragmentOffset)) + { + // Insert the character to the path being built + pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset++]); + } + } + } + + // HOTS: 195A570 + bool CompareAndCopyPathFragment(TMndxSearch * pSearch, size_t nFragmentOffset) + { + TStruct40 * pStruct40 = &pSearch->Struct40; + + // Do we have path fragment separators in an external structure? + if(PathMarks.IsEmpty()) + { + // Keep copying as long as we don't reach the end of the search mask + while(pStruct40->PathLength < pSearch->cchSearchMask) + { + // HOTS: 195A5A0 + if(PathFragments[nFragmentOffset] != pSearch->szSearchMask[pStruct40->PathLength]) + return false; + + // HOTS: 195A5B7 + pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset++]); + pStruct40->PathLength++; + + // If we found the end of the fragment, return success + if(PathFragments[nFragmentOffset] == 0) + return true; + } + + // HOTS: 195A660 + // Now we need to copy the rest of the fragment + while(PathFragments[nFragmentOffset] != 0) + { + pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset]); + nFragmentOffset++; + } + } + else + { + // Keep copying as long as we don't reach the end of the search mask + while(nFragmentOffset < pSearch->cchSearchMask) + { + if(PathFragments[nFragmentOffset] != pSearch->szSearchMask[pStruct40->PathLength]) + return false; + + pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset]); + pStruct40->PathLength++; + + // If we found the end of the fragment, return success + if(PathMarks.IsItemPresent(nFragmentOffset++)) + return true; + } + + // Now we need to copy the rest of the fragment + while(!PathMarks.IsItemPresent(nFragmentOffset)) + { + // HOTS: 195A7A6 + pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset++]); + } + } + + return true; + } + + // HOTS: 0195A820 + int LoadFromStream(TByteStream & InStream) + { + int nError; + + nError = PathFragments.LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + return PathMarks.LoadFromStream(InStream); + } + + TGenericArray PathFragments; + TSparseArray PathMarks; +}; + +//----------------------------------------------------------------------------- +// TStruct10 functions + +class TStruct10 +{ + public: + + TStruct10() + { + field_0 = 0x03; + field_4 = 0x200; + field_8 = 0x1000; + field_C = 0x20000; + } + + // HOTS: 1956FD0 + int sub_1956FD0(DWORD dwBitMask) + { + switch(dwBitMask & 0xF80) + { + case 0x00: + field_4 = 0x200; + return ERROR_SUCCESS; + + case 0x80: + field_4 = 0x80; + return ERROR_SUCCESS; + + case 0x100: + field_4 = 0x100; + return ERROR_SUCCESS; + + case 0x200: + field_4 = 0x200; + return ERROR_SUCCESS; + + case 0x400: + field_4 = 0x400; + return ERROR_SUCCESS; + + case 0x800: + field_4 = 0x800; + return ERROR_SUCCESS; + } + + return ERROR_INVALID_PARAMETER; + } + + // HOTS: 1957050 + int sub_1957050(DWORD dwBitMask) + { + switch(dwBitMask & 0xF0000) + { + case 0x00: + field_C = 0x20000; + return ERROR_SUCCESS; + + case 0x10000: + field_C = 0x10000; + return ERROR_SUCCESS; + + case 0x20000: + field_C = 0x20000; + return ERROR_SUCCESS; + } + + return ERROR_INVALID_PARAMETER; + } + + // HOTS: 19572E0 + int sub_19572E0(DWORD dwBitMask) + { + DWORD dwSubMask; + int nError; + + if(dwBitMask & 0xFFF00000) + return ERROR_INVALID_PARAMETER; + + dwSubMask = dwBitMask & 0x7F; + if(dwSubMask) + field_0 = dwSubMask; + + nError = sub_1956FD0(dwBitMask); + if(nError != ERROR_SUCCESS) + return nError; + + dwSubMask = dwBitMask & 0xF000; + if(dwSubMask == 0 || dwSubMask == 0x1000) + { + field_8 = 0x1000; + return sub_1957050(dwBitMask); + } + + if(dwSubMask == 0x2000) + { + field_8 = 0x2000; + return sub_1957050(dwBitMask); + } + + return ERROR_INVALID_PARAMETER; + } + + // HOTS: 1957800 + int sub_1957800(DWORD dwBitMask) + { + return sub_19572E0(dwBitMask); + } + + DWORD field_0; + DWORD field_4; + DWORD field_8; + DWORD field_C; +}; + +//----------------------------------------------------------------------------- +// TFileNameDatabase interface/implementation + +class TFileNameDatabase +{ + public: + + // HOTS: 01958730 + TFileNameDatabase() + { + HashTableMask = 0; + field_214 = 0; + pChildDB = NULL; + } + + ~TFileNameDatabase() + { + delete pChildDB; + } + + // Returns nonzero if the name fragment match is a single-char match + bool IsPathFragmentSingleChar(HASH_ENTRY * pHashEntry) + { + return ((pHashEntry->FragmentOffset & 0xFFFFFF00) == 0xFFFFFF00); + } + + // Returns true if the given collision path fragment is a string (aka more than 1 char) + bool IsPathFragmentString(size_t index) + { + return CollisionHiBitsIndexes.IsItemPresent(index); + } + + // HOTS: 1957350, inlined + DWORD GetPathFragmentOffset1(DWORD index_lobits) + { + DWORD index_hibits = CollisionHiBitsIndexes.GetItemValueAt(index_lobits); + + return (HiBitsTable.GetItem(index_hibits) << 0x08) | LoBitsTable[index_lobits]; + } + + // Retrieves fragment_offset/subtable_index of the path fragment, with check for starting value + DWORD GetPathFragmentOffset2(DWORD & index_hibits, DWORD index_lobits) + { + // If the hi-bits index is invalid, we need to get its starting value + if (index_hibits == CASC_INVALID_INDEX) + { +/* + printf("\n"); + for (DWORD i = 0; i < CollisionHiBitsIndexes.TotalItemCount; i++) + { + if (CollisionHiBitsIndexes.IsItemPresent(i)) + printf("[%02X] = %02X\n", i, CollisionHiBitsIndexes.GetIntValueAt(i)); + else + printf("[%02X] = NOT_PRESENT\n", i); + } +*/ + index_hibits = CollisionHiBitsIndexes.GetItemValueAt(index_lobits); + } + else + { + index_hibits++; + } + + // Now we use both NodeIndex and HiBits index for retrieving the path fragment index + return (HiBitsTable.GetItem(index_hibits) << 0x08) | LoBitsTable[index_lobits]; + } + + // HOTS: 1956DA0 + int Load(LPBYTE pbMarData, size_t cbMarData) + { + TByteStream ByteStream; + DWORD dwSignature; + int nError; + + if(pbMarData == NULL && cbMarData != 0) + return ERROR_INVALID_PARAMETER; + + nError = ByteStream.SetByteBuffer(pbMarData, cbMarData); + if(nError == ERROR_SUCCESS) + { + // Get pointer to MAR signature + nError = ByteStream.GetValue(dwSignature); + if(nError != ERROR_SUCCESS) + return nError; + + // Verify the signature + if(dwSignature != MNDX_MAR_SIGNATURE) + return ERROR_BAD_FORMAT; + + // HOTS: 1956E11 + nError = LoadFromStream(ByteStream); + } + + return nError; + } + + // HOTS: 19584B0 + int SetChildDatabase(TFileNameDatabase * pNewDB) + { + if(pNewDB != NULL && pChildDB == pNewDB) + return ERROR_INVALID_PARAMETER; + + if(pChildDB != NULL) + delete pChildDB; + pChildDB = pNewDB; + return ERROR_SUCCESS; + } + + // HOTS: 1957970 + bool ComparePathFragment(TMndxSearch * pSearch) + { + TStruct40 * pStruct40 = &pSearch->Struct40; + PHASH_ENTRY pHashEntry; + DWORD ColTableIndex; + DWORD HiBitsIndex; + DWORD NodeIndex; + + // Calculate the item hash from the current char and fragment ID + NodeIndex = pStruct40->CalcHashValue(pSearch->szSearchMask) & HashTableMask; + pHashEntry = &HashTable[NodeIndex]; + + // Does the hash value ID match? + if(pHashEntry->NodeIndex == pStruct40->NodeIndex) + { + // Check if there is single character match + if (!IsPathFragmentSingleChar(pHashEntry)) + { + // Check if there is a name fragment match + if (pChildDB != NULL) + { + if (!pChildDB->ComparePathFragmentByIndex(pSearch, pHashEntry->ChildTableIndex)) + return false; + } + else + { + if (!PathFragmentTable.ComparePathFragment(pSearch, pHashEntry->FragmentOffset)) + return false; + } + } + else + { + pStruct40->PathLength++; + } + + pStruct40->NodeIndex = pHashEntry->NextIndex; + return true; + } + + // + // Conflict: Multiple node IDs give the same table index + // + + // HOTS: 1957A0E + ColTableIndex = CollisionTable.GetItem0(pStruct40->NodeIndex) + 1; + pStruct40->NodeIndex = (ColTableIndex - pStruct40->NodeIndex - 1); + HiBitsIndex = CASC_INVALID_INDEX; + + // HOTS: 1957A41: + while(CollisionTable.IsItemPresent(ColTableIndex)) + { + // HOTS: 1957A41 + // Check if the low 8 bits if the fragment offset contain a single character + // or an offset to a name fragment + if(IsPathFragmentString(pStruct40->NodeIndex)) + { + DWORD FragmentOffset = GetPathFragmentOffset2(HiBitsIndex, pStruct40->NodeIndex); + DWORD SavePathLength = pStruct40->PathLength; // HOTS: 1957A83 + + // Do we have a child database? + if(pChildDB != NULL) + { + // HOTS: 1957AEC + if(pChildDB->ComparePathFragmentByIndex(pSearch, FragmentOffset)) + return true; + } + else + { + // HOTS: 1957AF7 + if(PathFragmentTable.ComparePathFragment(pSearch, FragmentOffset)) + return true; + } + + // HOTS: 1957B0E + // If there was partial match with the fragment, end the search + if(pStruct40->PathLength != SavePathLength) + return false; + } + else + { + // HOTS: 1957B1C + if(LoBitsTable[pStruct40->NodeIndex] == pSearch->szSearchMask[pStruct40->PathLength]) + { + pStruct40->PathLength++; + return true; + } + } + + // HOTS: 1957B32 + pStruct40->NodeIndex++; + ColTableIndex++; + } + + return false; + } + + // HOTS: 1957B80 + bool ComparePathFragmentByIndex(TMndxSearch * pSearch, DWORD TableIndex) + { + TStruct40 * pStruct40 = &pSearch->Struct40; + PHASH_ENTRY pHashEntry; + DWORD eax; + + // HOTS: 1957B95 + for (;;) + { + // Get the hasn table item + pHashEntry = &HashTable[TableIndex & HashTableMask]; + + // + if (TableIndex == pHashEntry->NextIndex) + { + // HOTS: 01957BB4 + if (!IsPathFragmentSingleChar(pHashEntry)) + { + // HOTS: 1957BC7 + if (pChildDB != NULL) + { + // HOTS: 1957BD3 + if (!pChildDB->ComparePathFragmentByIndex(pSearch, pHashEntry->ChildTableIndex)) + return false; + } + else + { + // HOTS: 1957BE0 + if (!PathFragmentTable.ComparePathFragment(pSearch, pHashEntry->FragmentOffset)) + return false; + } + } + else + { + // HOTS: 1957BEE + if (pSearch->szSearchMask[pStruct40->PathLength] != pHashEntry->SingleChar) + return false; + pStruct40->PathLength++; + } + + // HOTS: 1957C05 + TableIndex = pHashEntry->NodeIndex; + if (TableIndex == 0) + return true; + + if (pStruct40->PathLength >= pSearch->cchSearchMask) + return false; + } + else + { + // HOTS: 1957C30 + if (IsPathFragmentString(TableIndex)) + { + DWORD FragmentOffset = GetPathFragmentOffset1(TableIndex); + + // HOTS: 1957C4C + if (pChildDB != NULL) + { + // HOTS: 1957C58 + if (!pChildDB->ComparePathFragmentByIndex(pSearch, FragmentOffset)) + return false; + } + else + { + // HOTS: 1957350 + if (!PathFragmentTable.ComparePathFragment(pSearch, FragmentOffset)) + return false; + } + } + else + { + // HOTS: 1957C8E + if (LoBitsTable[TableIndex] != pSearch->szSearchMask[pStruct40->PathLength]) + return false; + + pStruct40->PathLength++; + } + + // HOTS: 1957CB2 + if (TableIndex <= field_214) + return true; + + if (pStruct40->PathLength >= pSearch->cchSearchMask) + return false; + + eax = CollisionTable.GetItem1(TableIndex); + TableIndex = (eax - TableIndex - 1); + } + } + } + + // HOTS: 1958D70 + void CopyPathFragmentByIndex(TMndxSearch * pSearch, DWORD TableIndex) + { + TStruct40 * pStruct40 = &pSearch->Struct40; + PHASH_ENTRY pHashEntry; + + // HOTS: 1958D84 + for (;;) + { + pHashEntry = &HashTable[TableIndex & HashTableMask]; + if (TableIndex == pHashEntry->NextIndex) + { + // HOTS: 1958DA6 + if (!IsPathFragmentSingleChar(pHashEntry)) + { + // HOTS: 1958DBA + if (pChildDB != NULL) + { + pChildDB->CopyPathFragmentByIndex(pSearch, pHashEntry->ChildTableIndex); + } + else + { + PathFragmentTable.CopyPathFragment(pSearch, pHashEntry->FragmentOffset); + } + } + else + { + // HOTS: 1958DE7 + // Insert the low 8 bits to the path being built + pStruct40->PathBuffer.Insert(pHashEntry->SingleChar); + } + + // HOTS: 1958E71 + TableIndex = pHashEntry->NodeIndex; + if (TableIndex == 0) + return; + } + else + { + // HOTS: 1958E8E + if (IsPathFragmentString(TableIndex)) + { + DWORD FragmentOffset = GetPathFragmentOffset1(TableIndex); + + // HOTS: 1958EAF + if (pChildDB != NULL) + { + pChildDB->CopyPathFragmentByIndex(pSearch, FragmentOffset); + } + else + { + PathFragmentTable.CopyPathFragment(pSearch, FragmentOffset); + } + } + else + { + // HOTS: 1958F50 + // Insert one character to the path being built + pStruct40->PathBuffer.Insert(LoBitsTable[TableIndex]); + } + + // HOTS: 1958FDE + if (TableIndex <= field_214) + return; + + TableIndex = 0xFFFFFFFF - TableIndex + CollisionTable.GetItem1(TableIndex); + } + } + } + + // HOTS: 1958B00 + bool CompareAndCopyPathFragment(TMndxSearch * pSearch) + { + TStruct40 * pStruct40 = &pSearch->Struct40; + PHASH_ENTRY pHashEntry; + DWORD HiBitsIndex; + DWORD ColTableIndex; + DWORD TableIndex; +/* + FILE * fp = fopen("E:\\PathFragmentTable.txt", "wt"); + if (fp != NULL) + { + for (DWORD i = 0; i < HashTable.ItemCount; i++) + { + FragOffs = HashTable[i].FragOffs; + fprintf(fp, "%02x ('%c') %08X %08X %08X", i, (0x20 <= i && i < 0x80) ? i : 0x20, HashTable[i].ItemIndex, HashTable[i].NextIndex, FragOffs); + + if(FragOffs != 0x00800000) + { + if((FragOffs & 0xFFFFFF00) == 0xFFFFFF00) + fprintf(fp, " '%c'", (char)(FragOffs & 0xFF)); + else + fprintf(fp, " %s", &PathFragmentTable.PathFragments[FragOffs]); + } + fprintf(fp, "\n"); + } + + fclose(fp); + } +*/ + // Calculate the item hash from the current char and fragment ID + TableIndex = pStruct40->CalcHashValue(pSearch->szSearchMask) & HashTableMask; + pHashEntry = &HashTable[TableIndex]; + + // Does the hash value ID match? + if(pStruct40->NodeIndex == pHashEntry->NodeIndex) + { + // If the higher 24 bits are set, then the fragment is just one letter, + // contained directly in the table. + if(!IsPathFragmentSingleChar(pHashEntry)) + { + // HOTS: 1958B59 + if (pChildDB != NULL) + { + if (!pChildDB->CompareAndCopyPathFragmentByIndex(pSearch, pHashEntry->ChildTableIndex)) + return false; + } + else + { + if (!PathFragmentTable.CompareAndCopyPathFragment(pSearch, pHashEntry->FragmentOffset)) + return false; + } + } + else + { + // HOTS: 1958B88 + pStruct40->PathBuffer.Insert(pHashEntry->SingleChar); + pStruct40->PathLength++; + } + + // HOTS: 1958BCA + pStruct40->NodeIndex = pHashEntry->NextIndex; + return true; + } + + // HOTS: 1958BE5 + ColTableIndex = CollisionTable.GetItem0(pStruct40->NodeIndex) + 1; + pStruct40->NodeIndex = (ColTableIndex - pStruct40->NodeIndex - 1); + HiBitsIndex = CASC_INVALID_INDEX; + + // Keep searching while we have a valid collision table entry + while(CollisionTable.IsItemPresent(ColTableIndex)) + { + // If we have high bits in the the bit at NodeIndex is set, it means that there is fragment offset + // If not, the byte in LoBitsTable is the character + if(IsPathFragmentString(pStruct40->NodeIndex)) + { + DWORD FragmentOffset = GetPathFragmentOffset2(HiBitsIndex, pStruct40->NodeIndex); + DWORD SavePathLength = pStruct40->PathLength; // HOTS: 1958C62 + + // Do we have a child database? + if(pChildDB != NULL) + { + // HOTS: 1958CCB + if(pChildDB->CompareAndCopyPathFragmentByIndex(pSearch, FragmentOffset)) + return true; + } + else + { + // HOTS: 1958CD6 + if(PathFragmentTable.CompareAndCopyPathFragment(pSearch, FragmentOffset)) + return true; + } + + // HOTS: 1958CED + if(SavePathLength != pStruct40->PathLength) + return false; + } + else + { + // HOTS: 1958CFB + if(LoBitsTable[pStruct40->NodeIndex] == pSearch->szSearchMask[pStruct40->PathLength]) + { + // HOTS: 1958D11 + pStruct40->PathBuffer.Insert(LoBitsTable[pStruct40->NodeIndex]); + pStruct40->PathLength++; + return true; + } + } + + // HOTS: 1958D11 + pStruct40->NodeIndex++; + ColTableIndex++; + } + + return false; + } + + // HOTS: 1959010 + bool CompareAndCopyPathFragmentByIndex(TMndxSearch * pSearch, DWORD TableIndex) + { + TStruct40 * pStruct40 = &pSearch->Struct40; + PHASH_ENTRY pHashEntry; + + // HOTS: 1959024 + for(;;) + { + pHashEntry = &HashTable[TableIndex & HashTableMask]; + if(TableIndex == pHashEntry->NextIndex) + { + // HOTS: 1959047 + if(!IsPathFragmentSingleChar(pHashEntry)) + { + // HOTS: 195905A + if(pChildDB != NULL) + { + if(!pChildDB->CompareAndCopyPathFragmentByIndex(pSearch, pHashEntry->ChildTableIndex)) + return false; + } + else + { + if(!PathFragmentTable.CompareAndCopyPathFragment(pSearch, pHashEntry->FragmentOffset)) + return false; + } + } + else + { + // HOTS: 1959092 + if(pHashEntry->SingleChar != pSearch->szSearchMask[pStruct40->PathLength]) + return false; + + // Insert the low 8 bits to the path being built + pStruct40->PathBuffer.Insert(pHashEntry->SingleChar); + pStruct40->PathLength++; + } + + // HOTS: 195912E + TableIndex = pHashEntry->NodeIndex; + if(TableIndex == 0) + return true; + } + else + { + // HOTS: 1959147 + if(IsPathFragmentString(TableIndex)) + { + // HOTS: 195917C + DWORD FragmentOffset = GetPathFragmentOffset1(TableIndex); + + if(pChildDB != NULL) + { + if(!pChildDB->CompareAndCopyPathFragmentByIndex(pSearch, FragmentOffset)) + return false; + } + else + { + if(!PathFragmentTable.CompareAndCopyPathFragment(pSearch, FragmentOffset)) + return false; + } + } + else + { + // HOTS: 195920E + if(LoBitsTable[TableIndex] != pSearch->szSearchMask[pStruct40->PathLength]) + return false; + + // Insert one character to the path being built + pStruct40->PathBuffer.Insert(LoBitsTable[TableIndex]); + pStruct40->PathLength++; + } + + // HOTS: 19592B6 + if(TableIndex <= field_214) + return true; + + TableIndex = 0xFFFFFFFF - TableIndex + CollisionTable.GetItem1(TableIndex); + } + + // HOTS: 19592D5 + if(pStruct40->PathLength >= pSearch->cchSearchMask) + break; + } + + CopyPathFragmentByIndex(pSearch, TableIndex); + return true; + } + + // HOTS: 1959460 + bool DoSearch(TMndxSearch * pSearch) + { + TStruct40 * pStruct40 = &pSearch->Struct40; + TPathStop * pPathStop; + DWORD edi; + + // Perform action based on the search phase + switch (pStruct40->SearchPhase) + { + case MNDX_SEARCH_INITIALIZING: + { + // HOTS: 1959489 + pStruct40->BeginSearch(); + + // If the caller passed a part of the search path, we need to find that one + while (pStruct40->PathLength < pSearch->cchSearchMask) + { + if (!CompareAndCopyPathFragment(pSearch)) + { + pStruct40->SearchPhase = MNDX_SEARCH_FINISHED; + return false; + } + } + + // HOTS: 19594b0 + TPathStop PathStop(pStruct40->NodeIndex, 0, pStruct40->PathBuffer.ItemCount); + pStruct40->PathStops.Insert(PathStop); + pStruct40->ItemCount = 1; + + if (FileNameIndexes.IsItemPresent(pStruct40->NodeIndex)) + { + pSearch->szFoundPath = &pStruct40->PathBuffer[0]; + pSearch->cchFoundPath = pStruct40->PathBuffer.ItemCount; + pSearch->nIndex = FileNameIndexes.GetItemValueAt(pStruct40->NodeIndex); + return true; + } + } + // No break here, go straight to the MNDX_SEARCH_SEARCHING + + case MNDX_SEARCH_SEARCHING: + { + // HOTS: 1959522 + for (;;) + { + // HOTS: 1959530 + if (pStruct40->ItemCount == pStruct40->PathStops.ItemCount) + { + TPathStop * pLastStop; + DWORD ColTableIndex; + + pLastStop = &pStruct40->PathStops[pStruct40->PathStops.ItemCount - 1]; + + ColTableIndex = CollisionTable.GetItem0(pLastStop->LoBitsIndex) + 1; + + // Insert a new structure + TPathStop PathStop(ColTableIndex - pLastStop->LoBitsIndex - 1, ColTableIndex, 0); + pStruct40->PathStops.Insert(PathStop); + } + + // HOTS: 19595BD + pPathStop = &pStruct40->PathStops[pStruct40->ItemCount]; + + // HOTS: 19595CC + if (CollisionTable.IsItemPresent(pPathStop->field_4++)) + { + // HOTS: 19595F2 + pStruct40->ItemCount++; + + if (IsPathFragmentString(pPathStop->LoBitsIndex)) + { + DWORD FragmentOffset = GetPathFragmentOffset2(pPathStop->HiBitsIndex_PathFragment, pPathStop->LoBitsIndex); + + // HOTS: 1959630 + if (pChildDB != NULL) + { + // HOTS: 1959649 + pChildDB->CopyPathFragmentByIndex(pSearch, FragmentOffset); + } + else + { + // HOTS: 1959654 + PathFragmentTable.CopyPathFragment(pSearch, FragmentOffset); + } + } + else + { + // HOTS: 1959665 + // Insert one character to the path being built + pStruct40->PathBuffer.Insert(LoBitsTable[pPathStop->LoBitsIndex]); + } + + // HOTS: 19596AE + pPathStop->Count = pStruct40->PathBuffer.ItemCount; + + // HOTS: 19596b6 + if (FileNameIndexes.IsItemPresent(pPathStop->LoBitsIndex)) + { + // HOTS: 19596D1 + if (pPathStop->field_10 == 0xFFFFFFFF) + { + // HOTS: 19596D9 + pPathStop->field_10 = FileNameIndexes.GetItemValueAt(pPathStop->LoBitsIndex); + } + else + { + pPathStop->field_10++; + } + + // HOTS: 1959755 + pSearch->szFoundPath = &pStruct40->PathBuffer[0]; + pSearch->cchFoundPath = pStruct40->PathBuffer.ItemCount; + pSearch->nIndex = pPathStop->field_10; + return true; + } + } + else + { + // HOTS: 19596E9 + if (pStruct40->ItemCount == 1) + { + pStruct40->SearchPhase = MNDX_SEARCH_FINISHED; + return false; + } + + // HOTS: 19596F5 + pStruct40->PathStops[pStruct40->ItemCount - 1].LoBitsIndex++; + edi = pStruct40->PathStops[pStruct40->ItemCount - 2].Count; + pStruct40->PathBuffer.SetMaxItemsIf(edi); + + // HOTS: 1959749 + pStruct40->PathBuffer.ItemCount = edi; + pStruct40->ItemCount--; + } + } + } + + case MNDX_SEARCH_FINISHED: + break; + } + + return false; + } + + // HOTS: 1957EF0 + bool FindFileInDatabase(TMndxSearch * pSearch) + { + TStruct40 * pStruct40 = &pSearch->Struct40; + + pStruct40->NodeIndex = 0; + pStruct40->PathLength = 0; + pStruct40->SearchPhase = MNDX_SEARCH_INITIALIZING; + + if(pSearch->cchSearchMask > 0) + { + while(pStruct40->PathLength < pSearch->cchSearchMask) + { + // HOTS: 01957F12 + if(!ComparePathFragment(pSearch)) + return false; + } + } + + // HOTS: 1957F26 + if(!FileNameIndexes.IsItemPresent(pStruct40->NodeIndex)) + return false; + + pSearch->szFoundPath = pSearch->szSearchMask; + pSearch->cchFoundPath = pSearch->cchSearchMask; + pSearch->nIndex = FileNameIndexes.GetItemValueAt(pStruct40->NodeIndex); + return true; + } + + // HOTS: 1959790 + int LoadFromStream(TByteStream & InStream) + { + DWORD dwBitMask; + int nError; + + nError = CollisionTable.LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + nError = FileNameIndexes.LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + nError = CollisionHiBitsIndexes.LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + // HOTS: 019597CD + nError = LoBitsTable.LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + nError = HiBitsTable.LoadBitsFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + // HOTS: 019597F5 + nError = PathFragmentTable.LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + // HOTS: 0195980A + if(CollisionHiBitsIndexes.ValidItemCount != 0 && PathFragmentTable.PathFragments.ItemCount == 0) + { + TFileNameDatabase * pNewDB; + + pNewDB = new TFileNameDatabase; + if (pNewDB == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + nError = SetChildDatabase(pNewDB); + if(nError != ERROR_SUCCESS) + return nError; + + nError = pChildDB->LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + } + + // HOTS: 0195986B + nError = HashTable.LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + HashTableMask = HashTable.ItemCount - 1; + + nError = InStream.GetValue(field_214); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.GetValue(dwBitMask); + if(nError != ERROR_SUCCESS) + return nError; + + return Struct10.sub_1957800(dwBitMask); + } + + TSparseArray CollisionTable; // Table of valid collisions, indexed by NodeIndex + TSparseArray FileNameIndexes; // Array of file name indexes + TSparseArray CollisionHiBitsIndexes; // Table of indexes of high bits (above 8 bits) for collisions + + // This pair of arrays serves for fast conversion from node index to FragmentOffset / FragmentChar + TGenericArray LoBitsTable; // Array of lower 8 bits of name fragment offset + TBitEntryArray HiBitsTable; // Array of upper x bits of name fragment offset + + TPathFragmentTable PathFragmentTable; + TFileNameDatabase * pChildDB; + + TGenericArray HashTable; // Hash table for searching name fragments + + DWORD HashTableMask; // Mask to get hash table index from hash value + DWORD field_214; + TStruct10 Struct10; +}; + +//----------------------------------------------------------------------------- +// Local functions - MAR file + +class TMndxMarFile +{ + public: + + TMndxMarFile() + { + pDatabase = NULL; + pbMarData = NULL; + cbMarData = 0; + } + + ~TMndxMarFile() + { + if(pDatabase != NULL) + delete pDatabase; + CASC_FREE(pbMarData); + } + + // HOTS: 00E94180 + int LoadRootData(FILE_MAR_INFO & MarInfo, LPBYTE pbRootFile, LPBYTE pbRootEnd) + { + // Allocate the MAR data + pbMarData = CASC_ALLOC(BYTE, MarInfo.MarDataSize); + cbMarData = MarInfo.MarDataSize; + if(pbMarData == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Capture the MAR data + if(!CaptureData(pbRootFile + MarInfo.MarDataOffset, pbRootEnd, pbMarData, cbMarData)) + return ERROR_FILE_CORRUPT; + + // Create the file name database + pDatabase = new TFileNameDatabase(); + if(pDatabase == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + return pDatabase->Load(pbMarData, cbMarData); + } + + // HOTS: 1956C60 + int SearchFile(TMndxSearch * pSearch) + { + int nError = ERROR_SUCCESS; + + if(pDatabase == NULL) + return ERROR_INVALID_PARAMETER; + + if(!pDatabase->FindFileInDatabase(pSearch)) + nError = ERROR_FILE_NOT_FOUND; + + return nError; + } + + // HOTS: 1956CE0 + int DoSearch(TMndxSearch * pSearch, bool * pbFindResult) + { + int nError = ERROR_SUCCESS; + + if(pDatabase == NULL) + return ERROR_INVALID_PARAMETER; + + *pbFindResult = pDatabase->DoSearch(pSearch); + return nError; + } + + // HOTS: 1956D20 + int GetFileNameCount(size_t * PtrFileNameCount) + { + if(pDatabase == NULL) + return ERROR_INVALID_PARAMETER; + + PtrFileNameCount[0] = pDatabase->FileNameIndexes.ValidItemCount; + return ERROR_SUCCESS; + } + +// protected: + TFileNameDatabase * pDatabase; + LPBYTE pbMarData; + size_t cbMarData; +}; + +//----------------------------------------------------------------------------- +// Implementation of root file functions + +typedef struct _FILE_MNDX_INFO +{ + BYTE RootFileName[MD5_HASH_SIZE]; // Name (aka MD5) of the root file + DWORD HeaderVersion; // Must be <= 2 + DWORD FormatVersion; + DWORD field_1C; + DWORD field_20; + DWORD MarInfoOffset; // Offset of the first MAR entry info + DWORD MarInfoCount; // Number of the MAR info entries + DWORD MarInfoSize; // Size of the MAR info entry + DWORD CKeyEntriesOffset; // Offset of the CKey entries, relative to begin of the root file + DWORD CKeyEntriesCount; // Number of CKeys (files) in the root file + DWORD FileNameCount; // Number of unique file names. More files with the same name in the different packages can exist + DWORD CKeyEntrySize; // Size of one CKey root entry + TMndxMarFile * MarFiles[MAR_COUNT]; // File name list for the packages + +} FILE_MNDX_INFO, *PFILE_MNDX_INFO; + +struct TMndxHandler +{ + public: + + // + // Constructor and destructor + // + + TMndxHandler() + { + memset(this, 0, sizeof(TMndxHandler)); + } + + ~TMndxHandler() + { + PMNDX_PACKAGE pPackage; + size_t i; + + for(i = 0; i < MAR_COUNT; i++) + delete MndxInfo.MarFiles[i]; + CASC_FREE(FileNameIndexToCKeyIndex); + pCKeyEntries = NULL; + + for(i = 0; i < Packages.ItemCount(); i++) + { + pPackage = (PMNDX_PACKAGE)Packages.ItemAt(i); + CASC_FREE(pPackage->szFileName); + } + Packages.Free(); + } + + // + // Helper functions + // + + static LPBYTE CaptureRootHeader(FILE_MNDX_HEADER & MndxHeader, LPBYTE pbRootPtr, LPBYTE pbRootEnd) + { + // Capture the root header + pbRootPtr = CaptureData(pbRootPtr, pbRootEnd, &MndxHeader, sizeof(FILE_MNDX_HEADER)); + if (pbRootPtr == NULL) + return NULL; + + // Check signature and version + if (MndxHeader.Signature != CASC_MNDX_ROOT_SIGNATURE || MndxHeader.FormatVersion > 2 || MndxHeader.FormatVersion < 1) + return NULL; + + // Passed + return pbRootPtr + sizeof(FILE_MNDX_HEADER); + } + + int LoadPackageNames() + { + TMndxMarFile * pMarFile = MndxInfo.MarFiles[MAR_PACKAGE_NAMES]; + TMndxSearch Search; + PMNDX_PACKAGE pPackage; + size_t nPackageCount = 0x40; + bool bFindResult = false; + int nError; + + // Prepare the file name search in the top level directory + Search.SetSearchMask("", 0); + + // Allocate initial name list structure + pMarFile->GetFileNameCount(&nPackageCount); + nError = Packages.Create(nPackageCount); + if(nError != ERROR_SUCCESS) + return nError; + + // Reset the package array + Packages.Reset(); + + // Keep searching as long as we find something + while(pMarFile->DoSearch(&Search, &bFindResult) == ERROR_SUCCESS && bFindResult) + { + // Insert new package to the array + assert(Search.nIndex < nPackageCount); + pPackage = (PMNDX_PACKAGE)Packages.InsertAt(Search.nIndex); + if (pPackage != NULL) + { + // The package mut not be initialized yet + assert(pPackage->szFileName == NULL); + + // Allocate space for the file name + pPackage->szFileName = CASC_ALLOC(char, Search.cchFoundPath + 1); + if (pPackage->szFileName == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill the package structure + memcpy(pPackage->szFileName, Search.szFoundPath, Search.cchFoundPath); + pPackage->szFileName[Search.cchFoundPath] = 0; + pPackage->nLength = Search.cchFoundPath; + pPackage->nIndex = Search.nIndex; + } + } + + // Give the packages to the caller + return ERROR_SUCCESS; + } + + int Load(const FILE_MNDX_HEADER & MndxHeader, LPBYTE pbRootFile, LPBYTE pbRootEnd) + { + TMndxMarFile * pMarFile; + FILE_MAR_INFO MarInfo; + size_t nFilePointer = 0; + DWORD i; + int nError = ERROR_SUCCESS; + + // Copy the header into the MNDX info + MndxInfo.HeaderVersion = MndxHeader.HeaderVersion; + MndxInfo.FormatVersion = MndxHeader.FormatVersion; + nFilePointer += sizeof(FILE_MNDX_HEADER); + + // Header version 2 has 2 extra fields that we need to load + if(MndxInfo.HeaderVersion == 2) + { + if(!CaptureData(pbRootFile + nFilePointer, pbRootEnd, &MndxInfo.field_1C, sizeof(DWORD) + sizeof(DWORD))) + return ERROR_FILE_CORRUPT; + nFilePointer += sizeof(DWORD) + sizeof(DWORD); + } + + // Load the rest of the file header + if(!CaptureData(pbRootFile + nFilePointer, pbRootEnd, &MndxInfo.MarInfoOffset, 0x1C)) + return ERROR_FILE_CORRUPT; + + // Verify the structure + if(MndxInfo.MarInfoCount > MAR_COUNT || MndxInfo.MarInfoSize != sizeof(FILE_MAR_INFO)) + return ERROR_FILE_CORRUPT; + + // Load all MAR infos + for(i = 0; i < MndxInfo.MarInfoCount; i++) + { + // Capture the n-th MAR info + nFilePointer = MndxInfo.MarInfoOffset + (MndxInfo.MarInfoSize * i); + if(!CaptureData(pbRootFile + nFilePointer, pbRootEnd, &MarInfo, sizeof(FILE_MAR_INFO))) + return ERROR_FILE_CORRUPT; + + // Allocate MAR_FILE structure + pMarFile = new TMndxMarFile(); + if(pMarFile == NULL) + { + nError = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // Create the database from the MAR data + nError = pMarFile->LoadRootData(MarInfo, pbRootFile, pbRootEnd); + if(nError != ERROR_SUCCESS) + break; + + // Assign the MAR file to the MNDX info structure + MndxInfo.MarFiles[i] = pMarFile; + } + + // All three MAR files must be loaded + // HOTS: 00E9503B + if(nError == ERROR_SUCCESS) + { + if(MndxInfo.MarFiles[MAR_PACKAGE_NAMES] == NULL || MndxInfo.MarFiles[MAR_STRIPPED_NAMES] == NULL || MndxInfo.MarFiles[MAR_FULL_NAMES] == NULL) + nError = ERROR_BAD_FORMAT; + if(MndxInfo.CKeyEntrySize != sizeof(MNDX_CKEY_ENTRY)) + nError = ERROR_BAD_FORMAT; + } + + // Load the array of Ckey entries. All present files are in the array, + // the same names (differentiated by package ID) are groupped together + if(nError == ERROR_SUCCESS) + { + size_t CKeyEntriesSize; + size_t FileNameCount = 0; + + pMarFile = MndxInfo.MarFiles[MAR_STRIPPED_NAMES]; + nError = ERROR_FILE_CORRUPT; + + // Capture the array of CKey entries + if(pMarFile->GetFileNameCount(&FileNameCount) == ERROR_SUCCESS && FileNameCount == MndxInfo.FileNameCount) + { + CKeyEntriesSize = MndxInfo.CKeyEntriesCount * MndxInfo.CKeyEntrySize; + if ((pbRootFile + MndxInfo.CKeyEntriesOffset + CKeyEntriesSize) <= pbRootEnd) + { + pCKeyEntries = (PMNDX_CKEY_ENTRY)(pbRootFile + MndxInfo.CKeyEntriesOffset); + nError = ERROR_SUCCESS; + } + } + } + + // Pick the CKey entries that are the first with a given name + if(nError == ERROR_SUCCESS) + { + assert(MndxInfo.FileNameCount <= MndxInfo.CKeyEntriesCount); + FileNameIndexToCKeyIndex = CASC_ALLOC(PMNDX_CKEY_ENTRY, MndxInfo.FileNameCount + 1); + if(FileNameIndexToCKeyIndex != NULL) + { + PMNDX_CKEY_ENTRY pRootEntry = pCKeyEntries; + DWORD nFileNameIndex = 0; + + // The first entry is always beginning of a file name group + FileNameIndexToCKeyIndex[nFileNameIndex++] = pRootEntry; + + // Get the remaining file name groups + for(i = 0; i < MndxInfo.CKeyEntriesCount; i++, pRootEntry++) + { + if (nFileNameIndex > MndxInfo.FileNameCount) + break; + + if (pRootEntry->Flags & MNDX_LAST_CKEY_ENTRY) + { + FileNameIndexToCKeyIndex[nFileNameIndex++] = pRootEntry + 1; + } + } + + // Verify the final number of file names + if ((nFileNameIndex - 1) != MndxInfo.FileNameCount) + nError = ERROR_BAD_FORMAT; + } + else + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Load the package names from the 0-th MAR file + if(nError == ERROR_SUCCESS) + { + nError = LoadPackageNames(); + } + + return nError; + } + + int LoadFileNames(TCascStorage * hs, CASC_FILE_TREE & FileTree) + { + PCASC_CKEY_ENTRY pCKeyEntry; + PMNDX_CKEY_ENTRY pRootEntry; + PMNDX_CKEY_ENTRY pRootEnd = pCKeyEntries + MndxInfo.CKeyEntriesCount; + PMNDX_PACKAGE pPackage; + TMndxMarFile * pMarFile = MndxInfo.MarFiles[MAR_STRIPPED_NAMES]; + TMndxSearch Search; + char szFileName[MAX_PATH]; + bool bFindResult = false; + int nError; + + // Setup the search mask + Search.SetSearchMask("", 0); + + // Keep searching ad long as we found something + while ((nError = pMarFile->DoSearch(&Search, &bFindResult)) == ERROR_SUCCESS && bFindResult) + { + // Sanity check + assert(Search.cchFoundPath < MAX_PATH); + + // The found file name index must fall into range of file names + if (Search.nIndex < MndxInfo.FileNameCount) + { + // Retrieve the first-in-group CKey entry of that name + pRootEntry = FileNameIndexToCKeyIndex[Search.nIndex]; + + // Now take all files of that name, prepend their package name and insert to file tree + while(pRootEntry < pRootEnd) + { + // Find the appropriate CKey entry in the central storage + pCKeyEntry = FindCKeyEntry_CKey(hs, pRootEntry->CKey); + if (pCKeyEntry != NULL) + { + size_t nPackageIndex = pRootEntry->Flags & 0x00FFFFFF; + + // Retrieve the package for this entry + pPackage = (PMNDX_PACKAGE)Packages.ItemAt(nPackageIndex); + if (pPackage != NULL) + { + // Sanity check + assert(pPackage->nIndex == nPackageIndex); + + // Merge the package name and file name + MakeFileName(szFileName, _countof(szFileName), pPackage, &Search); + + // Insert the entry to the file tree + FileTree.InsertByName(pCKeyEntry, szFileName); + } + } + + // Is this the last-in-group entry? + if (pRootEntry->Flags & MNDX_LAST_CKEY_ENTRY) + break; + pRootEntry++; + } + } + } + + return nError; + } + + // + // Helper functions + // + + void MakeFileName(char * szBuffer, size_t cchBuffer, PMNDX_PACKAGE pPackage, TMndxSearch * pSearch) + { + char * szBufferEnd = szBuffer + cchBuffer - 1; + + // Buffer length check + assert((pPackage->nLength + 1 + pSearch->cchFoundPath + 1) < cchBuffer); + + // Copy the package name + if ((szBuffer + pPackage->nLength) < szBufferEnd) + { + memcpy(szBuffer, pPackage->szFileName, pPackage->nLength); + szBuffer += pPackage->nLength; + } + + // Append slash + if ((szBuffer + 1) < szBufferEnd) + *szBuffer++ = '/'; + + // Append file name + if ((szBuffer + pSearch->cchFoundPath) < szBufferEnd) + { + memcpy(szBuffer, pSearch->szFoundPath, pSearch->cchFoundPath); + szBuffer += pSearch->cchFoundPath; + } + + szBuffer[0] = 0; + } + + protected: + + FILE_MNDX_INFO MndxInfo; + + PMNDX_CKEY_ENTRY * FileNameIndexToCKeyIndex; + PMNDX_CKEY_ENTRY pCKeyEntries; + CASC_ARRAY Packages; // Linear list of present packages +}; + +//----------------------------------------------------------------------------- +// Handler definition for MNDX root file + +struct TRootHandler_MNDX : public TFileTreeRoot +{ + public: + + TRootHandler_MNDX() : TFileTreeRoot(0) + { + // MNDX supports file names and CKeys + dwFeatures |= CASC_FEATURE_FILE_NAMES | CASC_FEATURE_ROOT_CKEY; + } + + int Load(TCascStorage * hs, const FILE_MNDX_HEADER & MndxHeader, LPBYTE pbRootFile, LPBYTE pbRootEnd) + { + TMndxHandler Handler; + int nError; + + // Load and parse the entire MNDX structure + nError = Handler.Load(MndxHeader, pbRootFile, pbRootEnd); + if (nError == ERROR_SUCCESS) + { + // Search all file names and insert them into the file tree + nError = Handler.LoadFileNames(hs, FileTree); + } + + return nError; + } +}; + +//----------------------------------------------------------------------------- +// Public functions - MNDX info + +int RootHandler_CreateMNDX(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile) +{ + TRootHandler_MNDX * pRootHandler = NULL; + FILE_MNDX_HEADER MndxHeader; + LPBYTE pbRootEnd = pbRootFile + cbRootFile; + int nError = ERROR_BAD_FORMAT; + + // Verify the header of the ROOT file + if(TMndxHandler::CaptureRootHeader(MndxHeader, pbRootFile, pbRootEnd) != NULL) + { + // Allocate the root handler object + pRootHandler = new TRootHandler_MNDX(); + if(pRootHandler != NULL) + { + // Load the root directory. If load failed, we free the object + nError = pRootHandler->Load(hs, MndxHeader, pbRootFile, pbRootEnd); + if(nError != ERROR_SUCCESS) + { + delete pRootHandler; + pRootHandler = NULL; + } + } + } + + // Assign the root directory (or NULL) and return error + hs->pRootHandler = pRootHandler; + return nError; +} diff --git a/dep/CascLib/src/CascRootFile_Mndx.cpp b/dep/CascLib/src/CascRootFile_Mndx.cpp deleted file mode 100644 index 9dca8d30eb4..00000000000 --- a/dep/CascLib/src/CascRootFile_Mndx.cpp +++ /dev/null @@ -1,2981 +0,0 @@ -/*****************************************************************************/ -/* CascRootFile_MNDX.cpp Copyright (c) Ladislav Zezula 2014 */ -/*---------------------------------------------------------------------------*/ -/* Common functions for CascLib */ -/* Note: "HOTS" refers to Play.exe, v2.5.0.29049 (Heroes of the Storm Alpha) */ -/*---------------------------------------------------------------------------*/ -/* Date Ver Who Comment */ -/* -------- ---- --- ------- */ -/* 18.05.14 1.00 Lad The first version of CascRootFile_MNDX.cpp */ -/*****************************************************************************/ - -#define __CASCLIB_SELF__ -#include "CascLib.h" -#include "CascCommon.h" - -//----------------------------------------------------------------------------- -// Local defines - -#define MNDX_MAR_SIGNATURE 0x0052414d // 'MAR\0' -#define MAR_PACKAGE_NAMES 0 // MAR with package names only -#define MAR_STRIPPED_NAMES 1 // MAR with names where packages were stripped -#define MAR_FULL_NAMES 2 // MAR with full file names -#define MAR_COUNT 3 // Maximum of 3 MAR files are supported - -#define MNDX_SEARCH_INITIALIZING 0 -#define MNDX_SEARCH_SEARCHING 2 -#define MNDX_SEARCH_FINISHED 4 - -#define MNDX_MAX_ENTRIES(type) (0xFFFFFFFF / sizeof(type)) - -#define MNDX_INVALID_SIZE_T ((size_t)(-1)) - -#define MNDX_LAST_CKEY_ENTRY 0x80000000 - -//----------------------------------------------------------------------------- -// Local structures - -typedef union _SETBITS -{ - struct - { - DWORD Lower08 : 8; // Number of set bits in the lower 1 byte - DWORD Lower16 : 8; // Number of set bits in the lower 2 bytes - DWORD Lower24 : 8; // Number of set bits in the lower 3 bytes - DWORD Lower32 : 8; // Number of set bits in the 32-bit integer - } u; - - DWORD SetBitsAll; // The total set bits mask - -} SETBITS, *PSETBITS; - -typedef struct _HASH_ENTRY -{ - DWORD NodeIndex; // Index of the path node - DWORD NextIndex; // ID of the first subnode in the hash table - - union - { - DWORD FragmentOffset; // Offset of the path fragment in the TPathFragmentTable - DWORD ChildTableIndex; // Starting search index for the child database (if child database is present) - char SingleChar; // If the upper 24 bits of the FragmentOffset is 0xFFFFFFFF, this single character - }; - // Otherwise --> Offset to the name fragment table -} HASH_ENTRY, *PHASH_ENTRY; - -typedef struct _FILE_MNDX_HEADER -{ - DWORD Signature; // 'MNDX' - DWORD HeaderVersion; // Must be <= 2 - DWORD FormatVersion; - -} FILE_MNDX_HEADER, *PFILE_MNDX_HEADER; - -typedef struct _MNDX_PACKAGE -{ - char * szFileName; // Pointer to file name - size_t nLength; // Length of the file name - size_t nIndex; // Package index - -} MNDX_PACKAGE, *PMNDX_PACKAGE; - -// Root file entry for CASC storages with MNDX root file (Heroes of the Storm) -// Corresponds to the in-file structure -typedef struct _MNDX_CKEY_ENTRY -{ - DWORD Flags; // High 8 bits: Flags, low 24 bits: package index - BYTE CKey[MD5_HASH_SIZE]; // Content key for the file - DWORD ContentSize; // Uncompressed file size, in bytes - -} MNDX_CKEY_ENTRY, *PMNDX_CKEY_ENTRY; - -typedef struct _FILE_MAR_INFO -{ - DWORD MarIndex; - DWORD MarDataSize; - DWORD MarDataSizeHi; - DWORD MarDataOffset; - DWORD MarDataOffsetHi; -} FILE_MAR_INFO, *PFILE_MAR_INFO; - -//----------------------------------------------------------------------------- -// Local variables - -unsigned char table_1BA1818[0x800] = -{ - 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x05, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x07, 0x07, 0x07, 0x01, 0x07, 0x02, 0x02, 0x01, 0x07, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, - 0x07, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, - 0x07, 0x05, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, - 0x05, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, - 0x07, 0x06, 0x06, 0x01, 0x06, 0x02, 0x02, 0x01, 0x06, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, - 0x06, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, - 0x06, 0x05, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, - 0x05, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, - 0x07, 0x07, 0x07, 0x01, 0x07, 0x02, 0x02, 0x01, 0x07, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, - 0x07, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, - 0x07, 0x05, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, - 0x05, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, - 0x07, 0x06, 0x06, 0x01, 0x06, 0x02, 0x02, 0x01, 0x06, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, - 0x06, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, - 0x06, 0x05, 0x05, 0x01, 0x05, 0x02, 0x02, 0x01, 0x05, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, - 0x05, 0x04, 0x04, 0x01, 0x04, 0x02, 0x02, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x02, 0x07, 0x07, 0x07, 0x03, 0x07, 0x03, 0x03, 0x02, - 0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x02, 0x07, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02, - 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x02, 0x07, 0x05, 0x05, 0x03, 0x05, 0x03, 0x03, 0x02, - 0x07, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02, - 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x02, 0x07, 0x06, 0x06, 0x03, 0x06, 0x03, 0x03, 0x02, - 0x07, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x02, 0x06, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02, - 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x02, 0x06, 0x05, 0x05, 0x03, 0x05, 0x03, 0x03, 0x02, - 0x06, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x02, 0x07, 0x07, 0x07, 0x03, 0x07, 0x03, 0x03, 0x02, - 0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x02, 0x07, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02, - 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x02, 0x07, 0x05, 0x05, 0x03, 0x05, 0x03, 0x03, 0x02, - 0x07, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02, - 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x02, 0x07, 0x06, 0x06, 0x03, 0x06, 0x03, 0x03, 0x02, - 0x07, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x02, 0x06, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02, - 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x02, 0x06, 0x05, 0x05, 0x03, 0x05, 0x03, 0x03, 0x02, - 0x06, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x02, 0x05, 0x04, 0x04, 0x03, 0x04, 0x03, 0x03, 0x02, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04, 0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x03, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x03, - 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04, 0x07, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x03, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x03, - 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x04, 0x07, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x03, - 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x03, - 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x04, 0x06, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x03, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04, 0x07, 0x07, 0x07, 0x04, 0x07, 0x04, 0x04, 0x03, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x03, - 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04, 0x07, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x03, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x03, - 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x04, 0x07, 0x06, 0x06, 0x04, 0x06, 0x04, 0x04, 0x03, - 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x03, - 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x04, 0x06, 0x05, 0x05, 0x04, 0x05, 0x04, 0x04, 0x03, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x04, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, - 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x04, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x07, 0x05, 0x05, 0x04, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x04, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, - 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x06, 0x06, 0x05, 0x06, 0x05, 0x05, 0x04, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x06, 0x07, 0x06, 0x06, 0x05, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 -}; - -//----------------------------------------------------------------------------- -// Local functions - Number of set bits in an integer - -// HOTS: inlined -static SETBITS GetNumberOfSetBits(DWORD Value32) -{ - SETBITS SetBits; - - Value32 = ((Value32 >> 1) & 0x55555555) + (Value32 & 0x55555555); - Value32 = ((Value32 >> 2) & 0x33333333) + (Value32 & 0x33333333); - Value32 = ((Value32 >> 4) & 0x0F0F0F0F) + (Value32 & 0x0F0F0F0F); - SetBits.SetBitsAll = Value32 * 0x01010101; - - return SetBits; -} - -static DWORD GetNumberOfSetBits32(DWORD Value32) -{ - return GetNumberOfSetBits(Value32).u.Lower32; -} - -static LPBYTE CaptureData(LPBYTE pbRootPtr, LPBYTE pbRootEnd, void * pvBuffer, size_t cbLength) -{ - // Check whether there is enough data in the buffer - if((pbRootPtr + cbLength) > pbRootEnd) - return NULL; - - // Copy the data - memcpy(pvBuffer, pbRootPtr, cbLength); - return pbRootPtr + cbLength; -} - -//----------------------------------------------------------------------------- -// The TPathStop structure - -struct TPathStop -{ - TPathStop() - { - LoBitsIndex = 0; - field_4 = 0; - Count = 0; - HiBitsIndex_PathFragment = CASC_INVALID_INDEX; - field_10 = 0xFFFFFFFF; - } - - TPathStop(DWORD arg_0, DWORD arg_4, DWORD arg_8) - { - LoBitsIndex = arg_0; - field_4 = arg_4; - Count = arg_8; - HiBitsIndex_PathFragment = CASC_INVALID_INDEX; - field_10 = 0xFFFFFFFF; - } - - DWORD LoBitsIndex; - DWORD field_4; - DWORD Count; - DWORD HiBitsIndex_PathFragment; - DWORD field_10; -}; - -//----------------------------------------------------------------------------- -// Basic array implementations - -class TByteStream -{ - public: - - // HOTS: 01959990 - TByteStream() - { - pbByteData = NULL; - pvMappedFile = NULL; - cbByteData = 0; - field_C = 0; - hFile = 0; - hMap = 0; - } - - // HOTS: 19599F0 - template - int GetBytes(size_t length, T ** Pointer) - { - // Is there enough bytes in the array? - if(length > cbByteData) - return ERROR_BAD_FORMAT; - - // Give the buffer to the caller - Pointer[0] = (T *)(pbByteData); - - // Move pointers - pbByteData += length; - cbByteData -= length; - return ERROR_SUCCESS; - } - - int CopyBytes(void * value, size_t length) - { - // Is there enough bytes in the array? - if(length > cbByteData) - return ERROR_BAD_FORMAT; - - // Give the buffer to the caller - memcpy(value, pbByteData, length); - - // Move pointers - pbByteData += length; - cbByteData -= length; - return ERROR_SUCCESS; - } - - // HOTS: 1959A60 - int SkipBytes(size_t cbByteCount) - { - LPBYTE Pointer; - - return GetBytes(cbByteCount, &Pointer); - } - - // HOTS: 1959AF0 - int SetByteBuffer(LPBYTE pbNewByteData, size_t cbNewByteData) - { - if(pbNewByteData != NULL || cbNewByteData == 0) - { - pbByteData = pbNewByteData; - cbByteData = cbNewByteData; - return ERROR_SUCCESS; - } - - return ERROR_INVALID_PARAMETER; - } - - // HOTS: 1957160 - template - int GetValue(T & Value) - { - T * Pointer; - int nError; - - nError = GetBytes(sizeof(T), (LPBYTE *)(&Pointer)); - if(nError != ERROR_SUCCESS) - return nError; - - Value = Pointer[0]; - return ERROR_SUCCESS; - } - - // Retrieves the item count in the array - template - int GetArrayItemCount(DWORD & ArraySize, DWORD & ItemCount) - { - ULONGLONG ByteCount; - int nError; - - // The first 8 bytes is the byte size of the array - nError = GetValue(ByteCount); - if(nError != ERROR_SUCCESS) - return nError; - - // Extract the number of bytes - if(ByteCount > 0xFFFFFFFF || (ByteCount % sizeof(T)) != 0) - return ERROR_BAD_FORMAT; - - // Give the result to the caller - ItemCount = (DWORD)(ByteCount / sizeof(T)); - ArraySize = (DWORD)(ByteCount); - return ERROR_SUCCESS; - } - - // HOTS: 1957190: - // HOTS: 19571E0: - // HOTS: 1957230: - // HOTS: 1957280: - template - int GetArray(T ** Pointer, size_t ItemCount) - { - int nError = ERROR_SUCCESS; - - // Verify parameters - if(Pointer == NULL && ItemCount != 0) - return ERROR_INVALID_PARAMETER; - if(ItemCount > MNDX_MAX_ENTRIES(T)) - return ERROR_NOT_ENOUGH_MEMORY; - - // Allocate bytes for the array - if (Pointer != NULL) - { - Pointer[0] = CASC_ALLOC(T, ItemCount); - if (Pointer[0] == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - // Get the pointer to the array - nError = CopyBytes(Pointer[0], sizeof(T) * ItemCount); - } - - return nError; - } - - LPBYTE pbByteData; - void * pvMappedFile; - size_t cbByteData; - DWORD field_C; - HANDLE hFile; - HANDLE hMap; -}; - -//----------------------------------------------------------------------------- -// TGenericArray interface/implementation - -template -class TGenericArray -{ - public: - - TGenericArray() - { - ItemArray = NULL; - ItemCount = 0; - MaxItemCount = 0; - bIsValidArray = false; - } - - ~TGenericArray() - { - CASC_FREE(ItemArray); - } - - T & operator[] (size_t index) - { - assert(index < ItemCount); - return ItemArray[index]; - } - - // HOTS: 1957090 (SetDwordsValid) - // HOTS: 19570B0 (SetBaseValsValid) - // HOTS: 19570D0 (? SetBitsValid ?) - // HOTS: 19570F0 (SetPathFragmentsValid) - int SetArrayValid() - { - if(bIsValidArray != 0) - return ERROR_ALREADY_EXISTS; - - bIsValidArray = true; - return ERROR_SUCCESS; - } - - // HOTS: 19575A0 (char) - // HOTS: 1957600 (TPathStop) - void SetMaxItems(DWORD NewMaxItemCount) - { - T * OldArray = ItemArray; - T * NewArray; - - // Allocate new data buffer - NewArray = CASC_ALLOC(T, NewMaxItemCount); - if(NewArray != NULL) - { - // Copy the old items to the buffer - for(size_t i = 0; i < ItemCount; i++) - { - NewArray[i] = ItemArray[i]; - } - } - - ItemArray = NewArray; - MaxItemCount = NewMaxItemCount; - CASC_FREE(OldArray); - } - - // HOTS: 19575A0 (char) - // HOTS: 1957600 (TPathStop) - void SetMaxItemsIf(DWORD NewMaxItemCount) - { - if(NewMaxItemCount > MaxItemCount) - { - if(MaxItemCount > (NewMaxItemCount / 2)) - { - if(MaxItemCount <= (MNDX_MAX_ENTRIES(T) / 2)) - NewMaxItemCount = MaxItemCount + MaxItemCount; - else - NewMaxItemCount = MNDX_MAX_ENTRIES(T); - } - - SetMaxItems(NewMaxItemCount); - } - } - - // HOTS: inline - // HOTS: 1958330 - void Insert(T NewItem) - { - // Make sure we have enough capacity for the new item - SetMaxItemsIf(ItemCount + 1); - - // Put the character to the slot that has been reserved - ItemArray[ItemCount++] = NewItem; - } - - // HOTS: 19583A0 - void GrowArray(DWORD NewItemCount) - { - DWORD OldMaxItemCount = MaxItemCount; - - // Make sure we have enough capacity for new items - SetMaxItemsIf(NewItemCount); - - // Initialize the newly inserted items - for(DWORD i = OldMaxItemCount; i < NewItemCount; i++) - { - ItemArray[i] = T(); - } - - ItemCount = NewItemCount; - } - - // HOTS: 1957440 - // HOTS: 19574E0 - // HOTS: 1957690 - // HOTS: 1957700 - // HOTS: 195A220 - // HOTS: 1958580 - int LoadFromStream(TByteStream & InStream) - { - DWORD NumberOfBytes; - int nError; - - // Get and verify the number of items - nError = InStream.GetArrayItemCount(NumberOfBytes, ItemCount); - if(nError != ERROR_SUCCESS) - return nError; - - // Get the pointer to the array - nError = InStream.GetArray(&ItemArray, ItemCount); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07); - if(nError != ERROR_SUCCESS) - return nError; - - return SetArrayValid(); - } - - T * ItemArray; - DWORD ItemCount; // Number of items in the array - DWORD MaxItemCount; // Capacity of the array - bool bIsValidArray; -}; - -class TBitEntryArray : public TGenericArray -{ - public: - - TBitEntryArray() : TGenericArray() - { - BitsPerEntry = 0; - EntryBitMask = 0; - TotalEntries = 0; - } - - ~TBitEntryArray() - {} - - DWORD GetItem(DWORD EntryIndex) - { - DWORD dwItemIndex = (EntryIndex * BitsPerEntry) >> 0x05; - DWORD dwStartBit = (EntryIndex * BitsPerEntry) & 0x1F; - DWORD dwEndBit = dwStartBit + BitsPerEntry; - DWORD dwResult; - - // If the end bit index is greater than 32, - // we also need to load from the next 32-bit item - if(dwEndBit > 0x20) - { - dwResult = (ItemArray[dwItemIndex + 1] << (0x20 - dwStartBit)) | (ItemArray[dwItemIndex] >> dwStartBit); - } - else - { - dwResult = ItemArray[dwItemIndex] >> dwStartBit; - } - - // Now we also need to mask the result by the bit mask - return dwResult & EntryBitMask; - } - - int LoadBitsFromStream(TByteStream & InStream) - { - ULONGLONG Value64 = 0; - int nError; - - nError = LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.GetValue(BitsPerEntry); - if(nError != ERROR_SUCCESS) - return nError; - if(BitsPerEntry > 0x20) - return ERROR_BAD_FORMAT; - - nError = InStream.GetValue(EntryBitMask); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.GetValue(Value64); - if(nError != ERROR_SUCCESS) - return nError; - if(Value64 > 0xFFFFFFFF) - return ERROR_BAD_FORMAT; - TotalEntries = (DWORD)Value64; - - assert((BitsPerEntry * TotalEntries) / 32 <= ItemCount); - return ERROR_SUCCESS; - } - - DWORD BitsPerEntry; - DWORD EntryBitMask; - DWORD TotalEntries; -}; - -//----------------------------------------------------------------------------- -// TSparseArray functions - -#define INDEX_TO_GROUP(val) (val >> 9) -#define GROUP_TO_INDEX(grp) (grp << 9) - -// For each 0x200-th bit, this contains information about amount of "1" bits -typedef struct _BASEVALS -{ - DWORD BaseValue200; // Item value of every 0x200-th item - - DWORD AddValue40 : 7; // For each 0x40 items (above the base200), - DWORD AddValue80 : 8; // we have extra shortcut to the item value - DWORD AddValueC0 : 8; // that is to be added to BaseValue200 - DWORD AddValue100 : 9; - DWORD AddValue140 : 9; - DWORD AddValue180 : 9; - DWORD AddValue1C0 : 9; - - DWORD __xalignment : 5; // Filling -} BASEVALS, *PBASEVALS; - -class TSparseArray -{ - public: - - TSparseArray() - { - TotalItemCount = 0; - ValidItemCount = 0; - } - - // HOTS: 1958630 - int LoadFromStream(TByteStream & InStream) - { - DWORD total_count = 0; - DWORD valid_count = 0; - int nError; - - nError = ItemBits.LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.GetValue(total_count); - if(nError != ERROR_SUCCESS) - return nError; - nError = InStream.GetValue(valid_count); - if(nError != ERROR_SUCCESS) - return nError; - if(valid_count > total_count) - return ERROR_FILE_CORRUPT; - - TotalItemCount = total_count; - ValidItemCount = valid_count; - - nError = BaseVals.LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - nError = IndexToItem0.LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - nError = IndexToItem1.LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - return ERROR_SUCCESS; - } - - // Returns true if the array is empty - bool IsEmpty() - { - return (TotalItemCount == 0); - } - - // Returns true if the item at n-th position is present - bool IsItemPresent(size_t index) - { - // (index >> 0x05) gives the DWORD, (1 << (ItemIndex & 0x1F)) gives the bit - return (ItemBits[index >> 0x05] & (1 << (index & 0x1F))) ? true : false; - } - - // Retrieves the value of the n-th item in the sparse array. - // Note that for items that are not present, the value is equal - // to the nearest lower present value - DWORD GetItemValueAt(size_t index) - { - BASEVALS & SetBitsCount = BaseVals[index >> 0x09]; - DWORD IntValue; - DWORD BitMask; - - // - // Since we don't want to count bits for the entire array, - // there are item value shortcuts every 0x200 items, - // and then every 0x40 items above the 0x200 base - // - - // 1) We have base value for every 0x200-th item - IntValue = SetBitsCount.BaseValue200; - - // 2) Add the base value for each 0x40-th item above the 0x200 base - switch(((index >> 0x06) & 0x07) - 1) - { - case 0: // Add the 1st value (7 bits) - IntValue += SetBitsCount.AddValue40; - break; - - case 1: // Add the 2nd value (8 bits) - IntValue += SetBitsCount.AddValue80; - break; - - case 2: // Add the 3rd value (8 bits) - IntValue += SetBitsCount.AddValueC0; - break; - - case 3: // Add the 4th value (9 bits) - IntValue += SetBitsCount.AddValue100; - break; - - case 4: // Add the 5th value (9 bits) - IntValue += SetBitsCount.AddValue140; - break; - - case 5: // Add the 6th value (9 bits) - IntValue += SetBitsCount.AddValue180; - break; - - case 6: // Add the 7th value (9 bits) - IntValue += SetBitsCount.AddValue1C0; - break; - } - - // 3) Count the bits of the higher DWORD, if the index 0x20 - 0x30 above the 0x200 base - if(index & 0x20) - IntValue += GetNumberOfSetBits32(ItemBits[(index >> 0x05) - 1]); - - // 4) Count the bits in the current DWORD (masked by bit index mask) - BitMask = (1 << (index & 0x1F)) - 1; - return IntValue + GetNumberOfSetBits32(ItemBits[index >> 0x05] & BitMask); - } - - DWORD FindGroup_Items0(DWORD index) - { - // Setup the group range to search - DWORD minGroup = (IndexToItem0[INDEX_TO_GROUP(index) + 0]) >> 9; - DWORD maxGroup = (IndexToItem0[INDEX_TO_GROUP(index) + 1] + 0x1FF) >> 9; - - // Search the groups and find the BASEVALS structure - // For spans less than 10 groups, use sequential search, otherwise binary search. - if ((maxGroup - minGroup) < 10) - { - // HOTS: 1959CF7 - while (index >= GROUP_TO_INDEX(minGroup) - BaseVals[minGroup + 1].BaseValue200 + 0x200) - { - // HOTS: 1959D14 - minGroup++; - } - } - else - { - // HOTS: 1959D2E - while ((minGroup + 1) < maxGroup) - { - // HOTS: 1959D38 - DWORD middleValue = (maxGroup + minGroup) >> 1; - - if (index < (maxGroup << 0x09) - BaseVals[maxGroup].BaseValue200) - { - // HOTS: 01959D4B - maxGroup = middleValue; - } - else - { - // HOTS: 1959D50 - minGroup = middleValue; - } - } - } - - return minGroup; - } - - DWORD FindGroup_Items1(DWORD index) - { - DWORD groupIndex = (index >> 0x09); - DWORD startValue = IndexToItem1[groupIndex] >> 9; - DWORD nextValue = (IndexToItem1[groupIndex + 1] + 0x1FF) >> 9; - - // Find the BASEVALS structure which the start index belongs to - // For less than 10 values, use sequential search. Otherwise, use binary search - if ((nextValue - startValue) < 10) - { - // HOTS: 01959F94 - while (index >= BaseVals[startValue + 1].BaseValue200) - { - // HOTS: 1959FA3 - startValue++; - } - } - else - { - // Binary search (HOTS: 1959FAD) - if ((startValue + 1) < nextValue) - { - // HOTS: 1959FB4 - DWORD middleValue = (nextValue + startValue) >> 1; - - if (index < BaseVals[middleValue].BaseValue200) - { - // HOTS: 1959FC4 - nextValue = middleValue; - } - else - { - // HOTS: 1959FC8 - startValue = middleValue; - } - } - } - - return startValue; - } - - // Returns the value of Item0[index] (HOTS: 1959CB0) - DWORD GetItem0(DWORD index) - { - SETBITS zeroBits; - DWORD groupIndex; - DWORD dwordIndex; - DWORD itemIndex; - DWORD bitGroup; - DWORD edx = index; - -#ifdef _DEBUG - //if (TotalItemCount > 0x200) - //{ - // FILE * fp = fopen("e:\\Ladik\\Appdir\\CascLib\\doc\\mndx-sparse-array.txt", "wt"); - // Dump(fp); - // fclose(fp); - //} -#endif - - // If the index is at begin of the group, we just return the start value - if ((index & 0x1FF) == 0) - return IndexToItem0[INDEX_TO_GROUP(index)]; - - // Find the group where the index belongs to - groupIndex = FindGroup_Items0(index); - - // HOTS: 1959D5F - edx += BaseVals[groupIndex].BaseValue200 - (groupIndex << 0x09); - dwordIndex = (groupIndex << 4); - - if (edx < 0x100 - BaseVals[groupIndex].AddValue100) - { - // HOTS: 1959D8C - if (edx < 0x80 - BaseVals[groupIndex].AddValue80) - { - // HOTS: 01959DA2 - if (edx >= 0x40 - BaseVals[groupIndex].AddValue40) - { - // HOTS: 01959DB7 - dwordIndex += 2; - edx = edx + BaseVals[groupIndex].AddValue40 - 0x40; - } - } - else - { - // HOTS: 1959DC0 - if (edx < 0xC0 - BaseVals[groupIndex].AddValueC0) - { - // HOTS: 1959DD3 - dwordIndex += 4; - edx = edx + BaseVals[groupIndex].AddValue80 - 0x80; - } - else - { - // HOTS: 1959DD3 - dwordIndex += 6; - edx = edx + BaseVals[groupIndex].AddValueC0 - 0xC0; - } - } - } - else - { - // HOTS: 1959DE8 - if (edx < 0x180 - BaseVals[groupIndex].AddValue180) - { - // HOTS: 01959E00 - if (edx < 0x140 - BaseVals[groupIndex].AddValue140) - { - // HOTS: 1959E11 - dwordIndex += 8; - edx = edx + BaseVals[groupIndex].AddValue100 - 0x100; - } - else - { - // HOTS: 1959E1D - dwordIndex += 10; - edx = edx + BaseVals[groupIndex].AddValue140 - 0x140; - } - } - else - { - // HOTS: 1959E29 - if (edx < 0x1C0 - BaseVals[groupIndex].AddValue1C0) - { - // HOTS: 1959E3D - dwordIndex += 12; - edx = edx + BaseVals[groupIndex].AddValue180 - 0x180; - } - else - { - // HOTS: 1959E49 - dwordIndex += 14; - edx = edx + BaseVals[groupIndex].AddValue1C0 - 0x1C0; - } - } - } - - // HOTS: 1959E53: - // Calculate the number of bits set in the value of "bitGroup" - bitGroup = ~ItemBits[dwordIndex]; - zeroBits = GetNumberOfSetBits(bitGroup); - - if (edx >= zeroBits.u.Lower32) - { - // HOTS: 1959ea4 - bitGroup = ~ItemBits[++dwordIndex]; - edx = edx - zeroBits.u.Lower32; - zeroBits = GetNumberOfSetBits(bitGroup); - } - - // Re-calculate the item index - itemIndex = (dwordIndex << 0x05); - - // HOTS: 1959eea - if (edx < zeroBits.u.Lower16) - { - // HOTS: 1959EFC - if (edx >= zeroBits.u.Lower08) - { - // HOTS: 1959F05 - bitGroup >>= 0x08; - itemIndex += 0x08; - edx -= zeroBits.u.Lower08; - } - } - else - { - // HOTS: 1959F0D - if (edx < zeroBits.u.Lower24) - { - // HOTS: 1959F19 - bitGroup >>= 0x10; - itemIndex += 0x10; - edx -= zeroBits.u.Lower16; - } - else - { - // HOTS: 1959F23 - bitGroup >>= 0x18; - itemIndex += 0x18; - edx -= zeroBits.u.Lower24; - } - } - - // HOTS: 1959f2b - edx = edx << 0x08; - bitGroup = bitGroup & 0xFF; - - // BUGBUG: Possible buffer overflow here. Happens when dwItemIndex >= 0x9C. - // The same happens in Heroes of the Storm (build 29049), so I am not sure - // if this is a bug or a case that never happens - assert((bitGroup + edx) < sizeof(table_1BA1818)); - return table_1BA1818[bitGroup + edx] + itemIndex; - } - - DWORD GetItem1(DWORD index) - { - SETBITS setBits; - DWORD distFromBase; - DWORD groupIndex; - DWORD dwordIndex; - DWORD itemIndex; - DWORD bitGroup; - - // If the index is at begin of the group, we just return the start value - if ((index & 0x1FF) == 0) - return IndexToItem1[INDEX_TO_GROUP(index)]; - - // Find the group where the index belongs to - groupIndex = FindGroup_Items1(index); - - // Calculate the base200 dword index (HOTS: 1959FD4) - distFromBase = index - BaseVals[groupIndex].BaseValue200; - dwordIndex = groupIndex << 0x04; - - // Calculate the dword index including the sub-checkpoint - if (distFromBase < BaseVals[groupIndex].AddValue100) - { - // HOTS: 1959FF1 - if (distFromBase < BaseVals[groupIndex].AddValue80) - { - // HOTS: 0195A000 - if (distFromBase >= BaseVals[groupIndex].AddValue40) - { - // HOTS: 195A007 - distFromBase = distFromBase - BaseVals[groupIndex].AddValue40; - dwordIndex += 2; - } - } - else - { - // HOTS: 195A00E - if (distFromBase < BaseVals[groupIndex].AddValueC0) - { - // HOTS: 195A01A - distFromBase = distFromBase - BaseVals[groupIndex].AddValue80; - dwordIndex += 4; - } - else - { - // HOTS: 195A01F - distFromBase = distFromBase - BaseVals[groupIndex].AddValueC0; - dwordIndex += 6; - } - } - } - else - { - // HOTS: 195A026 - if (distFromBase < BaseVals[groupIndex].AddValue180) - { - // HOTS: 195A037 - if (distFromBase < BaseVals[groupIndex].AddValue140) - { - // HOTS: 195A041 - distFromBase = distFromBase - BaseVals[groupIndex].AddValue100; - dwordIndex += 8; - } - else - { - // HOTS: 195A048 - distFromBase = distFromBase - BaseVals[groupIndex].AddValue140; - dwordIndex += 10; - } - } - else - { - // HOTS: 195A04D - if (distFromBase < BaseVals[groupIndex].AddValue1C0) - { - // HOTS: 195A05A - distFromBase = distFromBase - BaseVals[groupIndex].AddValue180; - dwordIndex += 12; - } - else - { - // HOTS: 195A061 - distFromBase = distFromBase - BaseVals[groupIndex].AddValue1C0; - dwordIndex += 14; - } - } - } - - // HOTS: 195A066 - bitGroup = ItemBits[dwordIndex]; - setBits = GetNumberOfSetBits(bitGroup); - - // Get total number of set bits in the bit group - if (distFromBase >= setBits.u.Lower32) - { - // HOTS: 195A0B2 - bitGroup = ItemBits[++dwordIndex]; - distFromBase = distFromBase - setBits.u.Lower32; - setBits = GetNumberOfSetBits(bitGroup); - } - - // Calculate the item index - itemIndex = (dwordIndex << 0x05); - - // Get the number of set bits in the lower word (HOTS: 195A0F6) - if (distFromBase < setBits.u.Lower16) - { - // HOTS: 195A111 - if (distFromBase >= setBits.u.Lower08) - { - // HOTS: 195A111 - itemIndex = itemIndex + 0x08; - bitGroup = bitGroup >> 0x08; - distFromBase = distFromBase - setBits.u.Lower08; - } - } - else - { - // HOTS: 195A119 - if (distFromBase < setBits.u.Lower24) - { - // HOTS: 195A125 - bitGroup = bitGroup >> 0x10; - itemIndex = itemIndex + 0x10; - distFromBase = distFromBase - setBits.u.Lower16; - } - else - { - // HOTS: 195A12F - bitGroup = bitGroup >> 0x18; - itemIndex = itemIndex + 0x18; - distFromBase = distFromBase - setBits.u.Lower24; - } - } - - bitGroup = bitGroup & 0xFF; - distFromBase = distFromBase << 0x08; - - // BUGBUG: Potential buffer overflow - // Happens in Heroes of the Storm when index == 0x5B - assert((bitGroup + distFromBase) < sizeof(table_1BA1818)); - return table_1BA1818[bitGroup + distFromBase] + itemIndex; - } - -#ifdef _DEBUG - void Dump(FILE * fp) - { - size_t * ArrayNormal; - size_t * ArrayInvert; - size_t IndexNormal = 0; - size_t IndexInvert = 0; - - // Output numbers of set bits for every 0x200-th item - fprintf(fp, "Number of set bits for every 0x200-th index\n" - "========================================================\n" - " Index Base200h +40 +80 +C0 +100 +140 +180 +1C0\n" - "--------------------------------------------------------\n"); - for (size_t i = 0; i < BaseVals.ItemCount; i++) - { - fprintf(fp, "[%08zX]: %08x %04x %04x %04x %04x %04x %04x %04x\n", GROUP_TO_INDEX(i), BaseVals[i].BaseValue200, - BaseVals[i].AddValue40, - BaseVals[i].AddValue80, - BaseVals[i].AddValueC0, - BaseVals[i].AddValue100, - BaseVals[i].AddValue140, - BaseVals[i].AddValue180, - BaseVals[i].AddValue1C0); - } - fprintf(fp, "\n"); - - // Output values of Item1 and Item0 for every 0x200-th index - fprintf(fp, "Item0 and Item1 for every 0x200-th index\n" - "========================================\n" - " Index Item0 Item1\n" - "-----------------------------\n"); - for (size_t i = 0; i < IndexToItem0.ItemCount; i++) - { - fprintf(fp, "[%08zX]: %08x %08x\n", GROUP_TO_INDEX(i), IndexToItem0[i], IndexToItem1[i]); - } - fprintf(fp, "\n"); - - - // Output values of Item1 and Item0 for every index - ArrayNormal = new size_t[TotalItemCount]; - ArrayInvert = new size_t[TotalItemCount]; - if (ArrayNormal && ArrayInvert) - { - // Invalidate both arrays - memset(ArrayNormal, 0xFF, TotalItemCount * sizeof(size_t)); - memset(ArrayInvert, 0xFF, TotalItemCount * sizeof(size_t)); - - // Load the both arrays - for (size_t i = 0; i < TotalItemCount; i++) - { - if (IsItemPresent(i)) - ArrayNormal[IndexNormal++] = i; - else - ArrayInvert[IndexInvert++] = i; - } - - // Output both arrays - fprintf(fp, "Item0 and Item1 for every index\n" - "========================================\n" - " Index Item0 Item1\n" - "-----------------------------\n"); - for (size_t i = 0; i < TotalItemCount; i++) - { - char NormalValue[0x20]; - char InvertValue[0x20]; - - if (ArrayNormal[i] == MNDX_INVALID_SIZE_T && ArrayInvert[i] == MNDX_INVALID_SIZE_T) - break; - fprintf(fp, "[%08zX]: %8s %8s\n", i, DumpValue(InvertValue, _countof(InvertValue), ArrayInvert[i]), DumpValue(NormalValue, _countof(NormalValue), ArrayNormal[i])); - } - fprintf(fp, "\n"); - } - - // Free both arrays - delete[] ArrayNormal; - delete[] ArrayInvert; - - // Output array of all values - fprintf(fp, "Item List: Index -> Value\n==========================\n"); - for (size_t i = 0; i < TotalItemCount; i++) - { - if (IsItemPresent(i)) - { - fprintf(fp, "[%08zX]: %08x\n", i, GetItemValueAt(i)); - } - else - { - fprintf(fp, "[%08zX]: NOT PRESENT\n", i); - } - } - fprintf(fp, "\n"); - } - - char * DumpValue(char * szBuffer, size_t cchBuffer, size_t value) - { - CascStrPrintf(szBuffer, cchBuffer, (value != MNDX_INVALID_SIZE_T) ? "%08zX" : " - ", value); - return szBuffer; - } -#endif - - TGenericArray ItemBits; // A bit array for each item. 1 if the item is present. - size_t TotalItemCount; // Total number of items in the array - size_t ValidItemCount; // Number of present items in the array - TGenericArray BaseVals; // For each 0x200-th item, this contains the number of set bits up to that 0x200-th item - TGenericArray IndexToItem0; // Mapping of index to invert item. An "invert" item is an item whose bit in "ItemBits" is zero. - TGenericArray IndexToItem1; // Mapping of index to normal item. An "normal" item is an item whose bit in "ItemBits" is set. -}; - -//----------------------------------------------------------------------------- -// TStruct40 functions - -class TStruct40 -{ - public: - - TStruct40() - { - NodeIndex = 0; - ItemCount = 0; - PathLength = 0; - SearchPhase = MNDX_SEARCH_INITIALIZING; - } - - // HOTS: 19586B0 - void BeginSearch() - { - // HOTS: 19586BD - PathBuffer.ItemCount = 0; - PathBuffer.SetMaxItemsIf(0x40); - - // HOTS: 19586E1 - // Set the new item count - PathStops.GrowArray(0); - PathStops.SetMaxItemsIf(4); - - PathLength = 0; - NodeIndex = 0; - ItemCount = 0; - SearchPhase = MNDX_SEARCH_SEARCHING; - } - - DWORD CalcHashValue(const char * szPath) - { - return (BYTE)(szPath[PathLength]) ^ (NodeIndex << 0x05) ^ NodeIndex; - } - - TGenericArray PathStops; // Array of path checkpoints - TGenericArray PathBuffer; // Buffer for building a file name - DWORD NodeIndex; // ID of a path node being searched; starting with 0 - DWORD PathLength; // Length of the path in the PathBuffer - DWORD ItemCount; - DWORD SearchPhase; // 0 = initializing, 2 = searching, 4 = finished -}; - -//----------------------------------------------------------------------------- -// Local functions - TMndxSearch - -class TMndxSearch -{ - public: - - // HOTS: 01956EE0 - TMndxSearch() - { - szSearchMask = NULL; - cchSearchMask = 0; - szFoundPath = NULL; - cchFoundPath = 0; - nIndex = 0; - } - - // HOTS: 01956F00 - ~TMndxSearch() - {} - - // HOTS: 01956E70 - int SetSearchMask( - const char * szNewSearchMask, - size_t cchNewSearchMask) - { - if(szSearchMask == NULL && cchSearchMask != 0) - return ERROR_INVALID_PARAMETER; - - Struct40.SearchPhase = MNDX_SEARCH_INITIALIZING; - - szSearchMask = szNewSearchMask; - cchSearchMask = cchNewSearchMask; - return ERROR_SUCCESS; - } - - TStruct40 Struct40; - const char * szSearchMask; // Search mask without wildcards - size_t cchSearchMask; // Length of the search mask - const char * szFoundPath; // Found path name - size_t cchFoundPath; // Length of the found path name - DWORD nIndex; // Index of the file name -}; - -//----------------------------------------------------------------------------- -// TPathFragmentTable class. This class implements table of the path fragments. -// These path fragments can either by terminated by zeros (ASCIIZ) -// or can be marked by the external "PathMarks" structure - -class TPathFragmentTable -{ - public: - - // HOTS: 0195A290 - TPathFragmentTable() - {} - - // HOTS: inlined - ~TPathFragmentTable() - {} - - // HOTS: 195A180 - bool ComparePathFragment(TMndxSearch * pSearch, size_t nFragmentOffset) - { - TStruct40 * pStruct40 = &pSearch->Struct40; - - // Do we have path fragment separators in an external structure? - if(PathMarks.IsEmpty()) - { - // Keep searching as long as the name matches with the fragment - while(PathFragments[nFragmentOffset] == pSearch->szSearchMask[pStruct40->PathLength]) - { - // Move to the next character - pStruct40->PathLength++; - nFragmentOffset++; - - // Is it the end of the fragment or end of the path? - if(PathFragments[nFragmentOffset] == 0) - return true; - if(pStruct40->PathLength >= pSearch->cchSearchMask) - return false; - } - - return false; - } - else - { - // Keep searching as long as the name matches with the fragment - while(PathFragments[nFragmentOffset] == pSearch->szSearchMask[pStruct40->PathLength]) - { - // Move to the next character - pStruct40->PathLength++; - - // Is it the end of the path fragment? - if(PathMarks.IsItemPresent(nFragmentOffset++)) - return true; - if(nFragmentOffset >= pSearch->cchSearchMask) - return false; - } - - return false; - } - } - - // HOTS: 195A3F0 - void CopyPathFragment(TMndxSearch * pSearch, size_t nFragmentOffset) - { - TStruct40 * pStruct40 = &pSearch->Struct40; - - // Do we have path fragment separators in an external structure? - if (PathMarks.IsEmpty()) - { - // HOTS: 195A40C - while (PathFragments[nFragmentOffset] != 0) - { - // Insert the character to the path being built - pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset++]); - } - } - else - { - // HOTS: 195A4B3 - while(!PathMarks.IsItemPresent(nFragmentOffset)) - { - // Insert the character to the path being built - pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset++]); - } - } - } - - // HOTS: 195A570 - bool CompareAndCopyPathFragment(TMndxSearch * pSearch, size_t nFragmentOffset) - { - TStruct40 * pStruct40 = &pSearch->Struct40; - - // Do we have path fragment separators in an external structure? - if(PathMarks.IsEmpty()) - { - // Keep copying as long as we don't reach the end of the search mask - while(pStruct40->PathLength < pSearch->cchSearchMask) - { - // HOTS: 195A5A0 - if(PathFragments[nFragmentOffset] != pSearch->szSearchMask[pStruct40->PathLength]) - return false; - - // HOTS: 195A5B7 - pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset++]); - pStruct40->PathLength++; - - // If we found the end of the fragment, return success - if(PathFragments[nFragmentOffset] == 0) - return true; - } - - // HOTS: 195A660 - // Now we need to copy the rest of the fragment - while(PathFragments[nFragmentOffset] != 0) - { - pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset]); - nFragmentOffset++; - } - } - else - { - // Keep copying as long as we don't reach the end of the search mask - while(nFragmentOffset < pSearch->cchSearchMask) - { - if(PathFragments[nFragmentOffset] != pSearch->szSearchMask[pStruct40->PathLength]) - return false; - - pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset]); - pStruct40->PathLength++; - - // If we found the end of the fragment, return success - if(PathMarks.IsItemPresent(nFragmentOffset++)) - return true; - } - - // Now we need to copy the rest of the fragment - while(!PathMarks.IsItemPresent(nFragmentOffset)) - { - // HOTS: 195A7A6 - pStruct40->PathBuffer.Insert(PathFragments[nFragmentOffset++]); - } - } - - return true; - } - - // HOTS: 0195A820 - int LoadFromStream(TByteStream & InStream) - { - int nError; - - nError = PathFragments.LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - return PathMarks.LoadFromStream(InStream); - } - - TGenericArray PathFragments; - TSparseArray PathMarks; -}; - -//----------------------------------------------------------------------------- -// TStruct10 functions - -class TStruct10 -{ - public: - - TStruct10() - { - field_0 = 0x03; - field_4 = 0x200; - field_8 = 0x1000; - field_C = 0x20000; - } - - // HOTS: 1956FD0 - int sub_1956FD0(DWORD dwBitMask) - { - switch(dwBitMask & 0xF80) - { - case 0x00: - field_4 = 0x200; - return ERROR_SUCCESS; - - case 0x80: - field_4 = 0x80; - return ERROR_SUCCESS; - - case 0x100: - field_4 = 0x100; - return ERROR_SUCCESS; - - case 0x200: - field_4 = 0x200; - return ERROR_SUCCESS; - - case 0x400: - field_4 = 0x400; - return ERROR_SUCCESS; - - case 0x800: - field_4 = 0x800; - return ERROR_SUCCESS; - } - - return ERROR_INVALID_PARAMETER; - } - - // HOTS: 1957050 - int sub_1957050(DWORD dwBitMask) - { - switch(dwBitMask & 0xF0000) - { - case 0x00: - field_C = 0x20000; - return ERROR_SUCCESS; - - case 0x10000: - field_C = 0x10000; - return ERROR_SUCCESS; - - case 0x20000: - field_C = 0x20000; - return ERROR_SUCCESS; - } - - return ERROR_INVALID_PARAMETER; - } - - // HOTS: 19572E0 - int sub_19572E0(DWORD dwBitMask) - { - DWORD dwSubMask; - int nError; - - if(dwBitMask & 0xFFF00000) - return ERROR_INVALID_PARAMETER; - - dwSubMask = dwBitMask & 0x7F; - if(dwSubMask) - field_0 = dwSubMask; - - nError = sub_1956FD0(dwBitMask); - if(nError != ERROR_SUCCESS) - return nError; - - dwSubMask = dwBitMask & 0xF000; - if(dwSubMask == 0 || dwSubMask == 0x1000) - { - field_8 = 0x1000; - return sub_1957050(dwBitMask); - } - - if(dwSubMask == 0x2000) - { - field_8 = 0x2000; - return sub_1957050(dwBitMask); - } - - return ERROR_INVALID_PARAMETER; - } - - // HOTS: 1957800 - int sub_1957800(DWORD dwBitMask) - { - return sub_19572E0(dwBitMask); - } - - DWORD field_0; - DWORD field_4; - DWORD field_8; - DWORD field_C; -}; - -//----------------------------------------------------------------------------- -// TFileNameDatabase interface/implementation - -class TFileNameDatabase -{ - public: - - // HOTS: 01958730 - TFileNameDatabase() - { - HashTableMask = 0; - field_214 = 0; - pChildDB = NULL; - } - - ~TFileNameDatabase() - { - delete pChildDB; - } - - // Returns nonzero if the name fragment match is a single-char match - bool IsPathFragmentSingleChar(HASH_ENTRY * pHashEntry) - { - return ((pHashEntry->FragmentOffset & 0xFFFFFF00) == 0xFFFFFF00); - } - - // Returns true if the given collision path fragment is a string (aka more than 1 char) - bool IsPathFragmentString(size_t index) - { - return CollisionHiBitsIndexes.IsItemPresent(index); - } - - // HOTS: 1957350, inlined - DWORD GetPathFragmentOffset1(DWORD index_lobits) - { - DWORD index_hibits = CollisionHiBitsIndexes.GetItemValueAt(index_lobits); - - return (HiBitsTable.GetItem(index_hibits) << 0x08) | LoBitsTable[index_lobits]; - } - - // Retrieves fragment_offset/subtable_index of the path fragment, with check for starting value - DWORD GetPathFragmentOffset2(DWORD & index_hibits, DWORD index_lobits) - { - // If the hi-bits index is invalid, we need to get its starting value - if (index_hibits == CASC_INVALID_INDEX) - { -/* - printf("\n"); - for (DWORD i = 0; i < CollisionHiBitsIndexes.TotalItemCount; i++) - { - if (CollisionHiBitsIndexes.IsItemPresent(i)) - printf("[%02X] = %02X\n", i, CollisionHiBitsIndexes.GetIntValueAt(i)); - else - printf("[%02X] = NOT_PRESENT\n", i); - } -*/ - index_hibits = CollisionHiBitsIndexes.GetItemValueAt(index_lobits); - } - else - { - index_hibits++; - } - - // Now we use both NodeIndex and HiBits index for retrieving the path fragment index - return (HiBitsTable.GetItem(index_hibits) << 0x08) | LoBitsTable[index_lobits]; - } - - // HOTS: 1956DA0 - int Load(LPBYTE pbMarData, size_t cbMarData) - { - TByteStream ByteStream; - DWORD dwSignature; - int nError; - - if(pbMarData == NULL && cbMarData != 0) - return ERROR_INVALID_PARAMETER; - - nError = ByteStream.SetByteBuffer(pbMarData, cbMarData); - if(nError == ERROR_SUCCESS) - { - // Get pointer to MAR signature - nError = ByteStream.GetValue(dwSignature); - if(nError != ERROR_SUCCESS) - return nError; - - // Verify the signature - if(dwSignature != MNDX_MAR_SIGNATURE) - return ERROR_BAD_FORMAT; - - // HOTS: 1956E11 - nError = LoadFromStream(ByteStream); - } - - return nError; - } - - // HOTS: 19584B0 - int SetChildDatabase(TFileNameDatabase * pNewDB) - { - if(pNewDB != NULL && pChildDB == pNewDB) - return ERROR_INVALID_PARAMETER; - - if(pChildDB != NULL) - delete pChildDB; - pChildDB = pNewDB; - return ERROR_SUCCESS; - } - - // HOTS: 1957970 - bool ComparePathFragment(TMndxSearch * pSearch) - { - TStruct40 * pStruct40 = &pSearch->Struct40; - PHASH_ENTRY pHashEntry; - DWORD ColTableIndex; - DWORD HiBitsIndex; - DWORD NodeIndex; - - // Calculate the item hash from the current char and fragment ID - NodeIndex = pStruct40->CalcHashValue(pSearch->szSearchMask) & HashTableMask; - pHashEntry = &HashTable[NodeIndex]; - - // Does the hash value ID match? - if(pHashEntry->NodeIndex == pStruct40->NodeIndex) - { - // Check if there is single character match - if (!IsPathFragmentSingleChar(pHashEntry)) - { - // Check if there is a name fragment match - if (pChildDB != NULL) - { - if (!pChildDB->ComparePathFragmentByIndex(pSearch, pHashEntry->ChildTableIndex)) - return false; - } - else - { - if (!PathFragmentTable.ComparePathFragment(pSearch, pHashEntry->FragmentOffset)) - return false; - } - } - else - { - pStruct40->PathLength++; - } - - pStruct40->NodeIndex = pHashEntry->NextIndex; - return true; - } - - // - // Conflict: Multiple node IDs give the same table index - // - - // HOTS: 1957A0E - ColTableIndex = CollisionTable.GetItem0(pStruct40->NodeIndex) + 1; - pStruct40->NodeIndex = (ColTableIndex - pStruct40->NodeIndex - 1); - HiBitsIndex = CASC_INVALID_INDEX; - - // HOTS: 1957A41: - while(CollisionTable.IsItemPresent(ColTableIndex)) - { - // HOTS: 1957A41 - // Check if the low 8 bits if the fragment offset contain a single character - // or an offset to a name fragment - if(IsPathFragmentString(pStruct40->NodeIndex)) - { - DWORD FragmentOffset = GetPathFragmentOffset2(HiBitsIndex, pStruct40->NodeIndex); - DWORD SavePathLength = pStruct40->PathLength; // HOTS: 1957A83 - - // Do we have a child database? - if(pChildDB != NULL) - { - // HOTS: 1957AEC - if(pChildDB->ComparePathFragmentByIndex(pSearch, FragmentOffset)) - return true; - } - else - { - // HOTS: 1957AF7 - if(PathFragmentTable.ComparePathFragment(pSearch, FragmentOffset)) - return true; - } - - // HOTS: 1957B0E - // If there was partial match with the fragment, end the search - if(pStruct40->PathLength != SavePathLength) - return false; - } - else - { - // HOTS: 1957B1C - if(LoBitsTable[pStruct40->NodeIndex] == pSearch->szSearchMask[pStruct40->PathLength]) - { - pStruct40->PathLength++; - return true; - } - } - - // HOTS: 1957B32 - pStruct40->NodeIndex++; - ColTableIndex++; - } - - return false; - } - - // HOTS: 1957B80 - bool ComparePathFragmentByIndex(TMndxSearch * pSearch, DWORD TableIndex) - { - TStruct40 * pStruct40 = &pSearch->Struct40; - PHASH_ENTRY pHashEntry; - DWORD eax; - - // HOTS: 1957B95 - for (;;) - { - // Get the hasn table item - pHashEntry = &HashTable[TableIndex & HashTableMask]; - - // - if (TableIndex == pHashEntry->NextIndex) - { - // HOTS: 01957BB4 - if (!IsPathFragmentSingleChar(pHashEntry)) - { - // HOTS: 1957BC7 - if (pChildDB != NULL) - { - // HOTS: 1957BD3 - if (!pChildDB->ComparePathFragmentByIndex(pSearch, pHashEntry->ChildTableIndex)) - return false; - } - else - { - // HOTS: 1957BE0 - if (!PathFragmentTable.ComparePathFragment(pSearch, pHashEntry->FragmentOffset)) - return false; - } - } - else - { - // HOTS: 1957BEE - if (pSearch->szSearchMask[pStruct40->PathLength] != pHashEntry->SingleChar) - return false; - pStruct40->PathLength++; - } - - // HOTS: 1957C05 - TableIndex = pHashEntry->NodeIndex; - if (TableIndex == 0) - return true; - - if (pStruct40->PathLength >= pSearch->cchSearchMask) - return false; - } - else - { - // HOTS: 1957C30 - if (IsPathFragmentString(TableIndex)) - { - DWORD FragmentOffset = GetPathFragmentOffset1(TableIndex); - - // HOTS: 1957C4C - if (pChildDB != NULL) - { - // HOTS: 1957C58 - if (!pChildDB->ComparePathFragmentByIndex(pSearch, FragmentOffset)) - return false; - } - else - { - // HOTS: 1957350 - if (!PathFragmentTable.ComparePathFragment(pSearch, FragmentOffset)) - return false; - } - } - else - { - // HOTS: 1957C8E - if (LoBitsTable[TableIndex] != pSearch->szSearchMask[pStruct40->PathLength]) - return false; - - pStruct40->PathLength++; - } - - // HOTS: 1957CB2 - if (TableIndex <= field_214) - return true; - - if (pStruct40->PathLength >= pSearch->cchSearchMask) - return false; - - eax = CollisionTable.GetItem1(TableIndex); - TableIndex = (eax - TableIndex - 1); - } - } - } - - // HOTS: 1958D70 - void CopyPathFragmentByIndex(TMndxSearch * pSearch, DWORD TableIndex) - { - TStruct40 * pStruct40 = &pSearch->Struct40; - PHASH_ENTRY pHashEntry; - - // HOTS: 1958D84 - for (;;) - { - pHashEntry = &HashTable[TableIndex & HashTableMask]; - if (TableIndex == pHashEntry->NextIndex) - { - // HOTS: 1958DA6 - if (!IsPathFragmentSingleChar(pHashEntry)) - { - // HOTS: 1958DBA - if (pChildDB != NULL) - { - pChildDB->CopyPathFragmentByIndex(pSearch, pHashEntry->ChildTableIndex); - } - else - { - PathFragmentTable.CopyPathFragment(pSearch, pHashEntry->FragmentOffset); - } - } - else - { - // HOTS: 1958DE7 - // Insert the low 8 bits to the path being built - pStruct40->PathBuffer.Insert(pHashEntry->SingleChar); - } - - // HOTS: 1958E71 - TableIndex = pHashEntry->NodeIndex; - if (TableIndex == 0) - return; - } - else - { - // HOTS: 1958E8E - if (IsPathFragmentString(TableIndex)) - { - DWORD FragmentOffset = GetPathFragmentOffset1(TableIndex); - - // HOTS: 1958EAF - if (pChildDB != NULL) - { - pChildDB->CopyPathFragmentByIndex(pSearch, FragmentOffset); - } - else - { - PathFragmentTable.CopyPathFragment(pSearch, FragmentOffset); - } - } - else - { - // HOTS: 1958F50 - // Insert one character to the path being built - pStruct40->PathBuffer.Insert(LoBitsTable[TableIndex]); - } - - // HOTS: 1958FDE - if (TableIndex <= field_214) - return; - - TableIndex = 0xFFFFFFFF - TableIndex + CollisionTable.GetItem1(TableIndex); - } - } - } - - // HOTS: 1958B00 - bool CompareAndCopyPathFragment(TMndxSearch * pSearch) - { - TStruct40 * pStruct40 = &pSearch->Struct40; - PHASH_ENTRY pHashEntry; - DWORD HiBitsIndex; - DWORD ColTableIndex; - DWORD TableIndex; -/* - FILE * fp = fopen("E:\\PathFragmentTable.txt", "wt"); - if (fp != NULL) - { - for (DWORD i = 0; i < HashTable.ItemCount; i++) - { - FragOffs = HashTable[i].FragOffs; - fprintf(fp, "%02x ('%c') %08X %08X %08X", i, (0x20 <= i && i < 0x80) ? i : 0x20, HashTable[i].ItemIndex, HashTable[i].NextIndex, FragOffs); - - if(FragOffs != 0x00800000) - { - if((FragOffs & 0xFFFFFF00) == 0xFFFFFF00) - fprintf(fp, " '%c'", (char)(FragOffs & 0xFF)); - else - fprintf(fp, " %s", &PathFragmentTable.PathFragments[FragOffs]); - } - fprintf(fp, "\n"); - } - - fclose(fp); - } -*/ - // Calculate the item hash from the current char and fragment ID - TableIndex = pStruct40->CalcHashValue(pSearch->szSearchMask) & HashTableMask; - pHashEntry = &HashTable[TableIndex]; - - // Does the hash value ID match? - if(pStruct40->NodeIndex == pHashEntry->NodeIndex) - { - // If the higher 24 bits are set, then the fragment is just one letter, - // contained directly in the table. - if(!IsPathFragmentSingleChar(pHashEntry)) - { - // HOTS: 1958B59 - if (pChildDB != NULL) - { - if (!pChildDB->CompareAndCopyPathFragmentByIndex(pSearch, pHashEntry->ChildTableIndex)) - return false; - } - else - { - if (!PathFragmentTable.CompareAndCopyPathFragment(pSearch, pHashEntry->FragmentOffset)) - return false; - } - } - else - { - // HOTS: 1958B88 - pStruct40->PathBuffer.Insert(pHashEntry->SingleChar); - pStruct40->PathLength++; - } - - // HOTS: 1958BCA - pStruct40->NodeIndex = pHashEntry->NextIndex; - return true; - } - - // HOTS: 1958BE5 - ColTableIndex = CollisionTable.GetItem0(pStruct40->NodeIndex) + 1; - pStruct40->NodeIndex = (ColTableIndex - pStruct40->NodeIndex - 1); - HiBitsIndex = CASC_INVALID_INDEX; - - // Keep searching while we have a valid collision table entry - while(CollisionTable.IsItemPresent(ColTableIndex)) - { - // If we have high bits in the the bit at NodeIndex is set, it means that there is fragment offset - // If not, the byte in LoBitsTable is the character - if(IsPathFragmentString(pStruct40->NodeIndex)) - { - DWORD FragmentOffset = GetPathFragmentOffset2(HiBitsIndex, pStruct40->NodeIndex); - DWORD SavePathLength = pStruct40->PathLength; // HOTS: 1958C62 - - // Do we have a child database? - if(pChildDB != NULL) - { - // HOTS: 1958CCB - if(pChildDB->CompareAndCopyPathFragmentByIndex(pSearch, FragmentOffset)) - return true; - } - else - { - // HOTS: 1958CD6 - if(PathFragmentTable.CompareAndCopyPathFragment(pSearch, FragmentOffset)) - return true; - } - - // HOTS: 1958CED - if(SavePathLength != pStruct40->PathLength) - return false; - } - else - { - // HOTS: 1958CFB - if(LoBitsTable[pStruct40->NodeIndex] == pSearch->szSearchMask[pStruct40->PathLength]) - { - // HOTS: 1958D11 - pStruct40->PathBuffer.Insert(LoBitsTable[pStruct40->NodeIndex]); - pStruct40->PathLength++; - return true; - } - } - - // HOTS: 1958D11 - pStruct40->NodeIndex++; - ColTableIndex++; - } - - return false; - } - - // HOTS: 1959010 - bool CompareAndCopyPathFragmentByIndex(TMndxSearch * pSearch, DWORD TableIndex) - { - TStruct40 * pStruct40 = &pSearch->Struct40; - PHASH_ENTRY pHashEntry; - - // HOTS: 1959024 - for(;;) - { - pHashEntry = &HashTable[TableIndex & HashTableMask]; - if(TableIndex == pHashEntry->NextIndex) - { - // HOTS: 1959047 - if(!IsPathFragmentSingleChar(pHashEntry)) - { - // HOTS: 195905A - if(pChildDB != NULL) - { - if(!pChildDB->CompareAndCopyPathFragmentByIndex(pSearch, pHashEntry->ChildTableIndex)) - return false; - } - else - { - if(!PathFragmentTable.CompareAndCopyPathFragment(pSearch, pHashEntry->FragmentOffset)) - return false; - } - } - else - { - // HOTS: 1959092 - if(pHashEntry->SingleChar != pSearch->szSearchMask[pStruct40->PathLength]) - return false; - - // Insert the low 8 bits to the path being built - pStruct40->PathBuffer.Insert(pHashEntry->SingleChar); - pStruct40->PathLength++; - } - - // HOTS: 195912E - TableIndex = pHashEntry->NodeIndex; - if(TableIndex == 0) - return true; - } - else - { - // HOTS: 1959147 - if(IsPathFragmentString(TableIndex)) - { - // HOTS: 195917C - DWORD FragmentOffset = GetPathFragmentOffset1(TableIndex); - - if(pChildDB != NULL) - { - if(!pChildDB->CompareAndCopyPathFragmentByIndex(pSearch, FragmentOffset)) - return false; - } - else - { - if(!PathFragmentTable.CompareAndCopyPathFragment(pSearch, FragmentOffset)) - return false; - } - } - else - { - // HOTS: 195920E - if(LoBitsTable[TableIndex] != pSearch->szSearchMask[pStruct40->PathLength]) - return false; - - // Insert one character to the path being built - pStruct40->PathBuffer.Insert(LoBitsTable[TableIndex]); - pStruct40->PathLength++; - } - - // HOTS: 19592B6 - if(TableIndex <= field_214) - return true; - - TableIndex = 0xFFFFFFFF - TableIndex + CollisionTable.GetItem1(TableIndex); - } - - // HOTS: 19592D5 - if(pStruct40->PathLength >= pSearch->cchSearchMask) - break; - } - - CopyPathFragmentByIndex(pSearch, TableIndex); - return true; - } - - // HOTS: 1959460 - bool DoSearch(TMndxSearch * pSearch) - { - TStruct40 * pStruct40 = &pSearch->Struct40; - TPathStop * pPathStop; - DWORD edi; - - // Perform action based on the search phase - switch (pStruct40->SearchPhase) - { - case MNDX_SEARCH_INITIALIZING: - { - // HOTS: 1959489 - pStruct40->BeginSearch(); - - // If the caller passed a part of the search path, we need to find that one - while (pStruct40->PathLength < pSearch->cchSearchMask) - { - if (!CompareAndCopyPathFragment(pSearch)) - { - pStruct40->SearchPhase = MNDX_SEARCH_FINISHED; - return false; - } - } - - // HOTS: 19594b0 - TPathStop PathStop(pStruct40->NodeIndex, 0, pStruct40->PathBuffer.ItemCount); - pStruct40->PathStops.Insert(PathStop); - pStruct40->ItemCount = 1; - - if (FileNameIndexes.IsItemPresent(pStruct40->NodeIndex)) - { - pSearch->szFoundPath = &pStruct40->PathBuffer[0]; - pSearch->cchFoundPath = pStruct40->PathBuffer.ItemCount; - pSearch->nIndex = FileNameIndexes.GetItemValueAt(pStruct40->NodeIndex); - return true; - } - } - // No break here, go straight to the MNDX_SEARCH_SEARCHING - - case MNDX_SEARCH_SEARCHING: - { - // HOTS: 1959522 - for (;;) - { - // HOTS: 1959530 - if (pStruct40->ItemCount == pStruct40->PathStops.ItemCount) - { - TPathStop * pLastStop; - DWORD ColTableIndex; - - pLastStop = &pStruct40->PathStops[pStruct40->PathStops.ItemCount - 1]; - - ColTableIndex = CollisionTable.GetItem0(pLastStop->LoBitsIndex) + 1; - - // Insert a new structure - TPathStop PathStop(ColTableIndex - pLastStop->LoBitsIndex - 1, ColTableIndex, 0); - pStruct40->PathStops.Insert(PathStop); - } - - // HOTS: 19595BD - pPathStop = &pStruct40->PathStops[pStruct40->ItemCount]; - - // HOTS: 19595CC - if (CollisionTable.IsItemPresent(pPathStop->field_4++)) - { - // HOTS: 19595F2 - pStruct40->ItemCount++; - - if (IsPathFragmentString(pPathStop->LoBitsIndex)) - { - DWORD FragmentOffset = GetPathFragmentOffset2(pPathStop->HiBitsIndex_PathFragment, pPathStop->LoBitsIndex); - - // HOTS: 1959630 - if (pChildDB != NULL) - { - // HOTS: 1959649 - pChildDB->CopyPathFragmentByIndex(pSearch, FragmentOffset); - } - else - { - // HOTS: 1959654 - PathFragmentTable.CopyPathFragment(pSearch, FragmentOffset); - } - } - else - { - // HOTS: 1959665 - // Insert one character to the path being built - pStruct40->PathBuffer.Insert(LoBitsTable[pPathStop->LoBitsIndex]); - } - - // HOTS: 19596AE - pPathStop->Count = pStruct40->PathBuffer.ItemCount; - - // HOTS: 19596b6 - if (FileNameIndexes.IsItemPresent(pPathStop->LoBitsIndex)) - { - // HOTS: 19596D1 - if (pPathStop->field_10 == 0xFFFFFFFF) - { - // HOTS: 19596D9 - pPathStop->field_10 = FileNameIndexes.GetItemValueAt(pPathStop->LoBitsIndex); - } - else - { - pPathStop->field_10++; - } - - // HOTS: 1959755 - pSearch->szFoundPath = &pStruct40->PathBuffer[0]; - pSearch->cchFoundPath = pStruct40->PathBuffer.ItemCount; - pSearch->nIndex = pPathStop->field_10; - return true; - } - } - else - { - // HOTS: 19596E9 - if (pStruct40->ItemCount == 1) - { - pStruct40->SearchPhase = MNDX_SEARCH_FINISHED; - return false; - } - - // HOTS: 19596F5 - pStruct40->PathStops[pStruct40->ItemCount - 1].LoBitsIndex++; - edi = pStruct40->PathStops[pStruct40->ItemCount - 2].Count; - pStruct40->PathBuffer.SetMaxItemsIf(edi); - - // HOTS: 1959749 - pStruct40->PathBuffer.ItemCount = edi; - pStruct40->ItemCount--; - } - } - } - - case MNDX_SEARCH_FINISHED: - break; - } - - return false; - } - - // HOTS: 1957EF0 - bool FindFileInDatabase(TMndxSearch * pSearch) - { - TStruct40 * pStruct40 = &pSearch->Struct40; - - pStruct40->NodeIndex = 0; - pStruct40->PathLength = 0; - pStruct40->SearchPhase = MNDX_SEARCH_INITIALIZING; - - if(pSearch->cchSearchMask > 0) - { - while(pStruct40->PathLength < pSearch->cchSearchMask) - { - // HOTS: 01957F12 - if(!ComparePathFragment(pSearch)) - return false; - } - } - - // HOTS: 1957F26 - if(!FileNameIndexes.IsItemPresent(pStruct40->NodeIndex)) - return false; - - pSearch->szFoundPath = pSearch->szSearchMask; - pSearch->cchFoundPath = pSearch->cchSearchMask; - pSearch->nIndex = FileNameIndexes.GetItemValueAt(pStruct40->NodeIndex); - return true; - } - - // HOTS: 1959790 - int LoadFromStream(TByteStream & InStream) - { - DWORD dwBitMask; - int nError; - - nError = CollisionTable.LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - nError = FileNameIndexes.LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - nError = CollisionHiBitsIndexes.LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - // HOTS: 019597CD - nError = LoBitsTable.LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - nError = HiBitsTable.LoadBitsFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - // HOTS: 019597F5 - nError = PathFragmentTable.LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - // HOTS: 0195980A - if(CollisionHiBitsIndexes.ValidItemCount != 0 && PathFragmentTable.PathFragments.ItemCount == 0) - { - TFileNameDatabase * pNewDB; - - pNewDB = new TFileNameDatabase; - if (pNewDB == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - nError = SetChildDatabase(pNewDB); - if(nError != ERROR_SUCCESS) - return nError; - - nError = pChildDB->LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - } - - // HOTS: 0195986B - nError = HashTable.LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - HashTableMask = HashTable.ItemCount - 1; - - nError = InStream.GetValue(field_214); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.GetValue(dwBitMask); - if(nError != ERROR_SUCCESS) - return nError; - - return Struct10.sub_1957800(dwBitMask); - } - - TSparseArray CollisionTable; // Table of valid collisions, indexed by NodeIndex - TSparseArray FileNameIndexes; // Array of file name indexes - TSparseArray CollisionHiBitsIndexes; // Table of indexes of high bits (above 8 bits) for collisions - - // This pair of arrays serves for fast conversion from node index to FragmentOffset / FragmentChar - TGenericArray LoBitsTable; // Array of lower 8 bits of name fragment offset - TBitEntryArray HiBitsTable; // Array of upper x bits of name fragment offset - - TPathFragmentTable PathFragmentTable; - TFileNameDatabase * pChildDB; - - TGenericArray HashTable; // Hash table for searching name fragments - - DWORD HashTableMask; // Mask to get hash table index from hash value - DWORD field_214; - TStruct10 Struct10; -}; - -//----------------------------------------------------------------------------- -// Local functions - MAR file - -class TMndxMarFile -{ - public: - - TMndxMarFile() - { - pDatabase = NULL; - pbMarData = NULL; - cbMarData = 0; - } - - ~TMndxMarFile() - { - if(pDatabase != NULL) - delete pDatabase; - CASC_FREE(pbMarData); - } - - // HOTS: 00E94180 - int LoadRootData(FILE_MAR_INFO & MarInfo, LPBYTE pbRootFile, LPBYTE pbRootEnd) - { - // Allocate the MAR data - pbMarData = CASC_ALLOC(BYTE, MarInfo.MarDataSize); - cbMarData = MarInfo.MarDataSize; - if(pbMarData == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - // Capture the MAR data - if(!CaptureData(pbRootFile + MarInfo.MarDataOffset, pbRootEnd, pbMarData, cbMarData)) - return ERROR_FILE_CORRUPT; - - // Create the file name database - pDatabase = new TFileNameDatabase(); - if(pDatabase == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - return pDatabase->Load(pbMarData, cbMarData); - } - - // HOTS: 1956C60 - int SearchFile(TMndxSearch * pSearch) - { - int nError = ERROR_SUCCESS; - - if(pDatabase == NULL) - return ERROR_INVALID_PARAMETER; - - if(!pDatabase->FindFileInDatabase(pSearch)) - nError = ERROR_FILE_NOT_FOUND; - - return nError; - } - - // HOTS: 1956CE0 - int DoSearch(TMndxSearch * pSearch, bool * pbFindResult) - { - int nError = ERROR_SUCCESS; - - if(pDatabase == NULL) - return ERROR_INVALID_PARAMETER; - - *pbFindResult = pDatabase->DoSearch(pSearch); - return nError; - } - - // HOTS: 1956D20 - int GetFileNameCount(size_t * PtrFileNameCount) - { - if(pDatabase == NULL) - return ERROR_INVALID_PARAMETER; - - PtrFileNameCount[0] = pDatabase->FileNameIndexes.ValidItemCount; - return ERROR_SUCCESS; - } - -// protected: - TFileNameDatabase * pDatabase; - LPBYTE pbMarData; - size_t cbMarData; -}; - -//----------------------------------------------------------------------------- -// Implementation of root file functions - -typedef struct _FILE_MNDX_INFO -{ - BYTE RootFileName[MD5_HASH_SIZE]; // Name (aka MD5) of the root file - DWORD HeaderVersion; // Must be <= 2 - DWORD FormatVersion; - DWORD field_1C; - DWORD field_20; - DWORD MarInfoOffset; // Offset of the first MAR entry info - DWORD MarInfoCount; // Number of the MAR info entries - DWORD MarInfoSize; // Size of the MAR info entry - DWORD CKeyEntriesOffset; // Offset of the CKey entries, relative to begin of the root file - DWORD CKeyEntriesCount; // Number of CKeys (files) in the root file - DWORD FileNameCount; // Number of unique file names. More files with the same name in the different packages can exist - DWORD CKeyEntrySize; // Size of one CKey root entry - TMndxMarFile * MarFiles[MAR_COUNT]; // File name list for the packages - -} FILE_MNDX_INFO, *PFILE_MNDX_INFO; - -struct TMndxHandler -{ - public: - - // - // Constructor and destructor - // - - TMndxHandler() - { - memset(this, 0, sizeof(TMndxHandler)); - } - - ~TMndxHandler() - { - PMNDX_PACKAGE pPackage; - size_t i; - - for(i = 0; i < MAR_COUNT; i++) - delete MndxInfo.MarFiles[i]; - CASC_FREE(FileNameIndexToCKeyIndex); - pCKeyEntries = NULL; - - for(i = 0; i < Packages.ItemCount(); i++) - { - pPackage = (PMNDX_PACKAGE)Packages.ItemAt(i); - CASC_FREE(pPackage->szFileName); - } - Packages.Free(); - } - - // - // Helper functions - // - - static LPBYTE CaptureRootHeader(FILE_MNDX_HEADER & MndxHeader, LPBYTE pbRootPtr, LPBYTE pbRootEnd) - { - // Capture the root header - pbRootPtr = CaptureData(pbRootPtr, pbRootEnd, &MndxHeader, sizeof(FILE_MNDX_HEADER)); - if (pbRootPtr == NULL) - return NULL; - - // Check signature and version - if (MndxHeader.Signature != CASC_MNDX_ROOT_SIGNATURE || MndxHeader.FormatVersion > 2 || MndxHeader.FormatVersion < 1) - return NULL; - - // Passed - return pbRootPtr + sizeof(FILE_MNDX_HEADER); - } - - int LoadPackageNames() - { - TMndxMarFile * pMarFile = MndxInfo.MarFiles[MAR_PACKAGE_NAMES]; - TMndxSearch Search; - PMNDX_PACKAGE pPackage; - size_t nPackageCount = 0x40; - bool bFindResult = false; - int nError; - - // Prepare the file name search in the top level directory - Search.SetSearchMask("", 0); - - // Allocate initial name list structure - pMarFile->GetFileNameCount(&nPackageCount); - nError = Packages.Create(nPackageCount); - if(nError != ERROR_SUCCESS) - return nError; - - // Reset the package array - Packages.Reset(); - - // Keep searching as long as we find something - while(pMarFile->DoSearch(&Search, &bFindResult) == ERROR_SUCCESS && bFindResult) - { - // Insert new package to the array - assert(Search.nIndex < nPackageCount); - pPackage = (PMNDX_PACKAGE)Packages.InsertAt(Search.nIndex); - if (pPackage != NULL) - { - // The package mut not be initialized yet - assert(pPackage->szFileName == NULL); - - // Allocate space for the file name - pPackage->szFileName = CASC_ALLOC(char, Search.cchFoundPath + 1); - if (pPackage->szFileName == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - // Fill the package structure - memcpy(pPackage->szFileName, Search.szFoundPath, Search.cchFoundPath); - pPackage->szFileName[Search.cchFoundPath] = 0; - pPackage->nLength = Search.cchFoundPath; - pPackage->nIndex = Search.nIndex; - } - } - - // Give the packages to the caller - return ERROR_SUCCESS; - } - - int Load(const FILE_MNDX_HEADER & MndxHeader, LPBYTE pbRootFile, LPBYTE pbRootEnd) - { - TMndxMarFile * pMarFile; - FILE_MAR_INFO MarInfo; - size_t nFilePointer = 0; - DWORD i; - int nError = ERROR_SUCCESS; - - // Copy the header into the MNDX info - MndxInfo.HeaderVersion = MndxHeader.HeaderVersion; - MndxInfo.FormatVersion = MndxHeader.FormatVersion; - nFilePointer += sizeof(FILE_MNDX_HEADER); - - // Header version 2 has 2 extra fields that we need to load - if(MndxInfo.HeaderVersion == 2) - { - if(!CaptureData(pbRootFile + nFilePointer, pbRootEnd, &MndxInfo.field_1C, sizeof(DWORD) + sizeof(DWORD))) - return ERROR_FILE_CORRUPT; - nFilePointer += sizeof(DWORD) + sizeof(DWORD); - } - - // Load the rest of the file header - if(!CaptureData(pbRootFile + nFilePointer, pbRootEnd, &MndxInfo.MarInfoOffset, 0x1C)) - return ERROR_FILE_CORRUPT; - - // Verify the structure - if(MndxInfo.MarInfoCount > MAR_COUNT || MndxInfo.MarInfoSize != sizeof(FILE_MAR_INFO)) - return ERROR_FILE_CORRUPT; - - // Load all MAR infos - for(i = 0; i < MndxInfo.MarInfoCount; i++) - { - // Capture the n-th MAR info - nFilePointer = MndxInfo.MarInfoOffset + (MndxInfo.MarInfoSize * i); - if(!CaptureData(pbRootFile + nFilePointer, pbRootEnd, &MarInfo, sizeof(FILE_MAR_INFO))) - return ERROR_FILE_CORRUPT; - - // Allocate MAR_FILE structure - pMarFile = new TMndxMarFile(); - if(pMarFile == NULL) - { - nError = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Create the database from the MAR data - nError = pMarFile->LoadRootData(MarInfo, pbRootFile, pbRootEnd); - if(nError != ERROR_SUCCESS) - break; - - // Assign the MAR file to the MNDX info structure - MndxInfo.MarFiles[i] = pMarFile; - } - - // All three MAR files must be loaded - // HOTS: 00E9503B - if(nError == ERROR_SUCCESS) - { - if(MndxInfo.MarFiles[MAR_PACKAGE_NAMES] == NULL || MndxInfo.MarFiles[MAR_STRIPPED_NAMES] == NULL || MndxInfo.MarFiles[MAR_FULL_NAMES] == NULL) - nError = ERROR_BAD_FORMAT; - if(MndxInfo.CKeyEntrySize != sizeof(MNDX_CKEY_ENTRY)) - nError = ERROR_BAD_FORMAT; - } - - // Load the array of Ckey entries. All present files are in the array, - // the same names (differentiated by package ID) are groupped together - if(nError == ERROR_SUCCESS) - { - size_t CKeyEntriesSize; - size_t FileNameCount = 0; - - pMarFile = MndxInfo.MarFiles[MAR_STRIPPED_NAMES]; - nError = ERROR_FILE_CORRUPT; - - // Capture the array of CKey entries - if(pMarFile->GetFileNameCount(&FileNameCount) == ERROR_SUCCESS && FileNameCount == MndxInfo.FileNameCount) - { - CKeyEntriesSize = MndxInfo.CKeyEntriesCount * MndxInfo.CKeyEntrySize; - if ((pbRootFile + MndxInfo.CKeyEntriesOffset + CKeyEntriesSize) <= pbRootEnd) - { - pCKeyEntries = (PMNDX_CKEY_ENTRY)(pbRootFile + MndxInfo.CKeyEntriesOffset); - nError = ERROR_SUCCESS; - } - } - } - - // Pick the CKey entries that are the first with a given name - if(nError == ERROR_SUCCESS) - { - assert(MndxInfo.FileNameCount <= MndxInfo.CKeyEntriesCount); - FileNameIndexToCKeyIndex = CASC_ALLOC(PMNDX_CKEY_ENTRY, MndxInfo.FileNameCount + 1); - if(FileNameIndexToCKeyIndex != NULL) - { - PMNDX_CKEY_ENTRY pRootEntry = pCKeyEntries; - DWORD nFileNameIndex = 0; - - // The first entry is always beginning of a file name group - FileNameIndexToCKeyIndex[nFileNameIndex++] = pRootEntry; - - // Get the remaining file name groups - for(i = 0; i < MndxInfo.CKeyEntriesCount; i++, pRootEntry++) - { - if (nFileNameIndex > MndxInfo.FileNameCount) - break; - - if (pRootEntry->Flags & MNDX_LAST_CKEY_ENTRY) - { - FileNameIndexToCKeyIndex[nFileNameIndex++] = pRootEntry + 1; - } - } - - // Verify the final number of file names - if ((nFileNameIndex - 1) != MndxInfo.FileNameCount) - nError = ERROR_BAD_FORMAT; - } - else - nError = ERROR_NOT_ENOUGH_MEMORY; - } - - // Load the package names from the 0-th MAR file - if(nError == ERROR_SUCCESS) - { - nError = LoadPackageNames(); - } - - return nError; - } - - int LoadFileNames(TCascStorage * hs, CASC_FILE_TREE & FileTree) - { - PCASC_CKEY_ENTRY pCKeyEntry; - PMNDX_CKEY_ENTRY pRootEntry; - PMNDX_CKEY_ENTRY pRootEnd = pCKeyEntries + MndxInfo.CKeyEntriesCount; - PMNDX_PACKAGE pPackage; - TMndxMarFile * pMarFile = MndxInfo.MarFiles[MAR_STRIPPED_NAMES]; - TMndxSearch Search; - char szFileName[MAX_PATH]; - bool bFindResult = false; - int nError; - - // Setup the search mask - Search.SetSearchMask("", 0); - - // Keep searching ad long as we found something - while ((nError = pMarFile->DoSearch(&Search, &bFindResult)) == ERROR_SUCCESS && bFindResult) - { - // Sanity check - assert(Search.cchFoundPath < MAX_PATH); - - // The found file name index must fall into range of file names - if (Search.nIndex < MndxInfo.FileNameCount) - { - // Retrieve the first-in-group CKey entry of that name - pRootEntry = FileNameIndexToCKeyIndex[Search.nIndex]; - - // Now take all files of that name, prepend their package name and insert to file tree - while(pRootEntry < pRootEnd) - { - // Find the appropriate CKey entry in the central storage - pCKeyEntry = FindCKeyEntry_CKey(hs, pRootEntry->CKey); - if (pCKeyEntry != NULL) - { - size_t nPackageIndex = pRootEntry->Flags & 0x00FFFFFF; - - // Retrieve the package for this entry - pPackage = (PMNDX_PACKAGE)Packages.ItemAt(nPackageIndex); - if (pPackage != NULL) - { - // Sanity check - assert(pPackage->nIndex == nPackageIndex); - - // Merge the package name and file name - MakeFileName(szFileName, _countof(szFileName), pPackage, &Search); - - // Insert the entry to the file tree - FileTree.InsertByName(pCKeyEntry, szFileName); - } - } - - // Is this the last-in-group entry? - if (pRootEntry->Flags & MNDX_LAST_CKEY_ENTRY) - break; - pRootEntry++; - } - } - } - - return nError; - } - - // - // Helper functions - // - - void MakeFileName(char * szBuffer, size_t cchBuffer, PMNDX_PACKAGE pPackage, TMndxSearch * pSearch) - { - char * szBufferEnd = szBuffer + cchBuffer - 1; - - // Buffer length check - assert((pPackage->nLength + 1 + pSearch->cchFoundPath + 1) < cchBuffer); - - // Copy the package name - if ((szBuffer + pPackage->nLength) < szBufferEnd) - { - memcpy(szBuffer, pPackage->szFileName, pPackage->nLength); - szBuffer += pPackage->nLength; - } - - // Append slash - if ((szBuffer + 1) < szBufferEnd) - *szBuffer++ = '/'; - - // Append file name - if ((szBuffer + pSearch->cchFoundPath) < szBufferEnd) - { - memcpy(szBuffer, pSearch->szFoundPath, pSearch->cchFoundPath); - szBuffer += pSearch->cchFoundPath; - } - - szBuffer[0] = 0; - } - - protected: - - FILE_MNDX_INFO MndxInfo; - - PMNDX_CKEY_ENTRY * FileNameIndexToCKeyIndex; - PMNDX_CKEY_ENTRY pCKeyEntries; - CASC_ARRAY Packages; // Linear list of present packages -}; - -//----------------------------------------------------------------------------- -// Handler definition for MNDX root file - -struct TRootHandler_MNDX : public TFileTreeRoot -{ - public: - - TRootHandler_MNDX() : TFileTreeRoot(0) - { - // MNDX supports file names and CKeys - dwFeatures |= CASC_FEATURE_FILE_NAMES | CASC_FEATURE_ROOT_CKEY; - } - - int Load(TCascStorage * hs, const FILE_MNDX_HEADER & MndxHeader, LPBYTE pbRootFile, LPBYTE pbRootEnd) - { - TMndxHandler Handler; - int nError; - - // Load and parse the entire MNDX structure - nError = Handler.Load(MndxHeader, pbRootFile, pbRootEnd); - if (nError == ERROR_SUCCESS) - { - // Search all file names and insert them into the file tree - nError = Handler.LoadFileNames(hs, FileTree); - } - - return nError; - } -}; - -//----------------------------------------------------------------------------- -// Public functions - MNDX info - -int RootHandler_CreateMNDX(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile) -{ - TRootHandler_MNDX * pRootHandler = NULL; - FILE_MNDX_HEADER MndxHeader; - LPBYTE pbRootEnd = pbRootFile + cbRootFile; - int nError = ERROR_BAD_FORMAT; - - // Verify the header of the ROOT file - if(TMndxHandler::CaptureRootHeader(MndxHeader, pbRootFile, pbRootEnd) != NULL) - { - // Allocate the root handler object - pRootHandler = new TRootHandler_MNDX(); - if(pRootHandler != NULL) - { - // Load the root directory. If load failed, we free the object - nError = pRootHandler->Load(hs, MndxHeader, pbRootFile, pbRootEnd); - if(nError != ERROR_SUCCESS) - { - delete pRootHandler; - pRootHandler = NULL; - } - } - } - - // Assign the root directory (or NULL) and return error - hs->pRootHandler = pRootHandler; - return nError; -} diff --git a/dep/CascLib/src/common/Common.cpp b/dep/CascLib/src/common/Common.cpp index d545f52f84a..fafa00e7739 100644 --- a/dep/CascLib/src/common/Common.cpp +++ b/dep/CascLib/src/common/Common.cpp @@ -78,35 +78,6 @@ void SetLastError(DWORD dwErrCode) } #endif -//----------------------------------------------------------------------------- -// Overloaded "new" and "delete" operators - -void * operator new(size_t size) -{ - return CASC_ALLOC(BYTE, size); -} - -void * operator new[](size_t size) -{ - return CASC_ALLOC(BYTE, size); -} - -void operator delete(void * ptr) -{ - CASC_FREE(ptr); -} - -void operator delete[](void * ptr) -{ - CASC_FREE(ptr); -} - -// For some reason, VS2015 needs this -void operator delete(void * ptr, size_t) -{ - CASC_FREE(ptr); -} - //----------------------------------------------------------------------------- // Linear data stream manipulation diff --git a/dep/CascLib/src/common/Common.h b/dep/CascLib/src/common/Common.h index c7f189b91ac..705777b7b0b 100644 --- a/dep/CascLib/src/common/Common.h +++ b/dep/CascLib/src/common/Common.h @@ -122,15 +122,6 @@ void CASC_FREE(T *& ptr) ptr = NULL; } -//----------------------------------------------------------------------------- -// Overloaded "new" and "delete" operators - -void * operator new(size_t size); -void * operator new[](size_t size); -void operator delete(void * ptr); -void operator delete[](void * ptr); -void operator delete(void * ptr, size_t); // For some reason, VS2015 needs this - //----------------------------------------------------------------------------- // Big endian number manipulation diff --git a/dep/CascLib/src/common/Csv.h b/dep/CascLib/src/common/Csv.h index 2138255e74e..bf1a7413e13 100644 --- a/dep/CascLib/src/common/Csv.h +++ b/dep/CascLib/src/common/Csv.h @@ -16,7 +16,7 @@ #define CSV_INVALID_INDEX ((size_t)(-1)) #define CSV_ZERO ((size_t)(0)) // Use Csv[0][CSV_ZERO] instead of ambiguous Csv[0][0] -#define CSV_MAX_COLUMNS 0x10 +#define CSV_MAX_COLUMNS 0x20 #define CSV_HASH_TABLE_SIZE 0x80 //----------------------------------------------------------------------------- -- cgit v1.2.3