From 43642630c7cc8a96009a6cb7edbaa895c41f63c0 Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 8 Feb 2016 20:57:52 +0100 Subject: Dep/CascLib: Update to ladislav-zezula/CascLib@919a2d670cb749c501ee15887a88e9b9a538961b --- dep/CascLib/src/CascBuildCfg.cpp | 1032 ----- dep/CascLib/src/CascCommon.cpp | 23 + dep/CascLib/src/CascCommon.h | 251 +- dep/CascLib/src/CascDecompress.cpp | 41 +- dep/CascLib/src/CascDecrypt.cpp | 300 ++ dep/CascLib/src/CascDumpData.cpp | 334 +- dep/CascLib/src/CascFiles.cpp | 981 +++++ dep/CascLib/src/CascFindFile.cpp | 227 +- dep/CascLib/src/CascLib.def | 29 + dep/CascLib/src/CascLib.h | 16 +- dep/CascLib/src/CascMndx.h | 359 ++ dep/CascLib/src/CascMndxRoot.cpp | 3498 ---------------- dep/CascLib/src/CascMndxRoot.h | 365 -- dep/CascLib/src/CascMndxRoot_x86.asm | 4369 -------------------- dep/CascLib/src/CascOpenFile.cpp | 153 +- dep/CascLib/src/CascOpenStorage.cpp | 638 +-- dep/CascLib/src/CascPort.h | 1 + dep/CascLib/src/CascReadFile.cpp | 142 +- dep/CascLib/src/CascRootFile_Diablo3.cpp | 1189 ++++++ dep/CascLib/src/CascRootFile_Mndx.cpp | 3602 ++++++++++++++++ dep/CascLib/src/CascRootFile_Mndx_x86.asm | 4369 ++++++++++++++++++++ dep/CascLib/src/CascRootFile_Ovr.cpp | 199 + dep/CascLib/src/CascRootFile_WoW6.cpp | 531 +++ dep/CascLib/src/common/Common.cpp | 226 +- dep/CascLib/src/common/Common.h | 24 +- dep/CascLib/src/common/Directory.h | 29 + dep/CascLib/src/common/DumpContext.cpp | 153 + dep/CascLib/src/common/DumpContext.h | 38 + dep/CascLib/src/common/DynamicArray.cpp | 101 + dep/CascLib/src/common/DynamicArray.h | 37 + dep/CascLib/src/common/FileStream.cpp | 1 - dep/CascLib/src/common/ListFile.cpp | 320 +- dep/CascLib/src/common/ListFile.h | 4 + dep/CascLib/src/common/Map.cpp | 183 +- dep/CascLib/src/common/Map.h | 13 +- dep/CascLib/src/common/RootHandler.cpp | 78 + dep/CascLib/src/common/RootHandler.h | 88 + .../src/libtomcrypt/src/misc/crypt_argchk.c | 4 +- 38 files changed, 13193 insertions(+), 10755 deletions(-) delete mode 100644 dep/CascLib/src/CascBuildCfg.cpp create mode 100644 dep/CascLib/src/CascDecrypt.cpp create mode 100644 dep/CascLib/src/CascFiles.cpp create mode 100644 dep/CascLib/src/CascLib.def create mode 100644 dep/CascLib/src/CascMndx.h delete mode 100644 dep/CascLib/src/CascMndxRoot.cpp delete mode 100644 dep/CascLib/src/CascMndxRoot.h delete mode 100644 dep/CascLib/src/CascMndxRoot_x86.asm create mode 100644 dep/CascLib/src/CascRootFile_Diablo3.cpp create mode 100644 dep/CascLib/src/CascRootFile_Mndx.cpp create mode 100644 dep/CascLib/src/CascRootFile_Mndx_x86.asm create mode 100644 dep/CascLib/src/CascRootFile_Ovr.cpp create mode 100644 dep/CascLib/src/CascRootFile_WoW6.cpp create mode 100644 dep/CascLib/src/common/Directory.h create mode 100644 dep/CascLib/src/common/DumpContext.cpp create mode 100644 dep/CascLib/src/common/DumpContext.h create mode 100644 dep/CascLib/src/common/DynamicArray.cpp create mode 100644 dep/CascLib/src/common/DynamicArray.h create mode 100644 dep/CascLib/src/common/RootHandler.cpp create mode 100644 dep/CascLib/src/common/RootHandler.h (limited to 'dep/CascLib/src') diff --git a/dep/CascLib/src/CascBuildCfg.cpp b/dep/CascLib/src/CascBuildCfg.cpp deleted file mode 100644 index f39f09d886a..00000000000 --- a/dep/CascLib/src/CascBuildCfg.cpp +++ /dev/null @@ -1,1032 +0,0 @@ -/*****************************************************************************/ -/* CascBuildCfg.cpp Copyright (c) Ladislav Zezula 2014 */ -/*---------------------------------------------------------------------------*/ -/* Build configuration for CascLib */ -/*---------------------------------------------------------------------------*/ -/* Date Ver Who Comment */ -/* -------- ---- --- ------- */ -/* 29.04.14 1.00 Lad The first version of CascBuildCfg.cpp */ -/*****************************************************************************/ - -#define __CASCLIB_SELF__ -#include "CascLib.h" -#include "CascCommon.h" - -//----------------------------------------------------------------------------- -// Local functions - -static bool inline IsValueSeparator(LPBYTE pbVarValue) -{ - return ((0 <= pbVarValue[0] && pbVarValue[0] <= 0x20) || (pbVarValue[0] == '|')); -} - -static bool IsCharDigit(BYTE OneByte) -{ - return ('0' <= OneByte && OneByte <= '9'); -} - -static void FreeCascBlob(PQUERY_KEY pBlob) -{ - if(pBlob != NULL) - { - if(pBlob->pbData != NULL) - CASC_FREE(pBlob->pbData); - - pBlob->pbData = NULL; - pBlob->cbData = 0; - } -} - -static DWORD GetLocaleMask(const char * szTag) -{ - if(!strcmp(szTag, "enUS")) - return CASC_LOCALE_ENUS; - - if(!strcmp(szTag, "koKR")) - return CASC_LOCALE_KOKR; - - if(!strcmp(szTag, "frFR")) - return CASC_LOCALE_FRFR; - - if(!strcmp(szTag, "deDE")) - return CASC_LOCALE_DEDE; - - if(!strcmp(szTag, "zhCN")) - return CASC_LOCALE_ZHCN; - - if(!strcmp(szTag, "esES")) - return CASC_LOCALE_ESES; - - if(!strcmp(szTag, "zhTW")) - return CASC_LOCALE_ZHTW; - - if(!strcmp(szTag, "enGB")) - return CASC_LOCALE_ENGB; - - if(!strcmp(szTag, "enCN")) - return CASC_LOCALE_ENCN; - - if(!strcmp(szTag, "enTW")) - return CASC_LOCALE_ENTW; - - if(!strcmp(szTag, "esMX")) - return CASC_LOCALE_ESMX; - - if(!strcmp(szTag, "ruRU")) - return CASC_LOCALE_RURU; - - if(!strcmp(szTag, "ptBR")) - return CASC_LOCALE_PTBR; - - if(!strcmp(szTag, "itIT")) - return CASC_LOCALE_ITIT; - - if(!strcmp(szTag, "ptPT")) - return CASC_LOCALE_PTPT; - - return 0; -} - -static bool IsInfoVariable(const char * szLineBegin, const char * szLineEnd, const char * szVarName, const char * szVarType) -{ - size_t nLength; - - // Check the variable name - nLength = strlen(szVarName); - if((size_t)(szLineEnd - szLineBegin) > nLength) - { - // Check the variable name - if(!_strnicmp(szLineBegin, szVarName, nLength)) - { - // Skip variable name and the exclamation mark - szLineBegin += nLength; - if(szLineBegin < szLineEnd && szLineBegin[0] == '!') - { - // Skip the exclamation mark - szLineBegin++; - - // Check the variable type - nLength = strlen(szVarType); - if((size_t)(szLineEnd - szLineBegin) > nLength) - { - // Check the variable name - if(!_strnicmp(szLineBegin, szVarType, nLength)) - { - // Skip variable type and the doublecolon - szLineBegin += nLength; - return (szLineBegin < szLineEnd && szLineBegin[0] == ':'); - } - } - } - } - } - - return false; -} - -static const char * SkipInfoVariable(const char * szLineBegin, const char * szLineEnd) -{ - while(szLineBegin < szLineEnd) - { - if(szLineBegin[0] == '|') - return szLineBegin + 1; - - szLineBegin++; - } - - return NULL; -} - -static TCHAR * CheckForIndexDirectory(TCascStorage * hs, const TCHAR * szSubDir) -{ - TCHAR * szIndexPath; - - // Cpmbine the index path - szIndexPath = CombinePath(hs->szDataPath, szSubDir); - if(DirectoryExists(szIndexPath)) - { - hs->szIndexPath = szIndexPath; - return hs->szIndexPath; - } - - CASC_FREE(szIndexPath); - return NULL; -} - -TCHAR * AppendBlobText(TCHAR * szBuffer, LPBYTE pbData, DWORD cbData, TCHAR chSeparator) -{ - // Put the separator, if any - if(chSeparator != 0) - *szBuffer++ = chSeparator; - - // Copy the blob data as text - for(DWORD i = 0; i < cbData; i++) - { - *szBuffer++ = IntToHexChar[pbData[0] >> 0x04]; - *szBuffer++ = IntToHexChar[pbData[0] & 0x0F]; - pbData++; - } - - // Terminate the string - *szBuffer = 0; - - // Return new buffer position - return szBuffer; -} - -static int StringBlobToBinaryBlob( - PQUERY_KEY pBlob, - LPBYTE pbBlobBegin, - LPBYTE pbBlobEnd) -{ - // Sanity checks - assert(pBlob != NULL && pBlob->pbData != NULL); - - // Reset the blob length - pBlob->cbData = 0; - - // Convert the blob - while(pbBlobBegin < pbBlobEnd) - { - BYTE DigitOne; - BYTE DigitTwo; - - DigitOne = (BYTE)(AsciiToUpperTable_BkSlash[pbBlobBegin[0]] - '0'); - if(DigitOne > 9) - DigitOne -= 'A' - '9' - 1; - - DigitTwo = (BYTE)(AsciiToUpperTable_BkSlash[pbBlobBegin[1]] - '0'); - if(DigitTwo > 9) - DigitTwo -= 'A' - '9' - 1; - - if(DigitOne > 0x0F || DigitTwo > 0x0F || pBlob->cbData >= MAX_CASC_KEY_LENGTH) - return ERROR_BAD_FORMAT; - - pBlob->pbData[pBlob->cbData++] = (DigitOne << 0x04) | DigitTwo; - pbBlobBegin += 2; - } - - return ERROR_SUCCESS; -} - - -static LPBYTE FindNextSeparator(PQUERY_KEY pFileBlob, LPBYTE pbFilePtr) -{ - LPBYTE pbFileBegin = pFileBlob->pbData; - LPBYTE pbFileEnd = pFileBlob->pbData + pFileBlob->cbData; - - if(pbFileBegin <= pbFilePtr && pbFilePtr < pbFileEnd) - { - while(pbFilePtr < pbFileEnd && pbFilePtr[0] != '|') - pbFilePtr++; - - return pbFilePtr; - } - - return NULL; -} - -static bool GetNextFileLine(PQUERY_KEY pFileBlob, LPBYTE * ppbLineBegin, LPBYTE * ppbLineEnd) -{ - LPBYTE pbLineBegin = *ppbLineBegin; - LPBYTE pbLineEnd = *ppbLineEnd; - LPBYTE pbFileEnd = pFileBlob->pbData + pFileBlob->cbData; - - // If there was a previous line, skip all end-of-line chars - if(pbLineEnd != NULL) - { - // Go to the next line - while(pbLineEnd < pbFileEnd && (pbLineEnd[0] == 0x0A || pbLineEnd[0] == 0x0D)) - pbLineEnd++; - pbLineBegin = pbLineEnd; - - // If there is no more data, return false - if(pbLineEnd >= pbFileEnd) - return false; - } - - // Skip all spaces before the line begins - while(pbLineBegin < pbFileEnd && (pbLineBegin[0] == 0x09 || pbLineBegin[0] == 0x20)) - pbLineBegin++; - pbLineEnd = pbLineBegin; - - // Go to the end of the line - while(pbLineEnd < pbFileEnd && pbLineEnd[0] != 0x0A && pbLineEnd[0] != 0x0D) - pbLineEnd++; - - // Give the results to the caller - *ppbLineBegin = pbLineBegin; - *ppbLineEnd = pbLineEnd; - return true; -} - -static LPBYTE CheckLineVariable(LPBYTE pbLineBegin, LPBYTE pbLineEnd, const char * szVarName) -{ - size_t nLineLength = (size_t)(pbLineEnd - pbLineBegin); - size_t nNameLength = strlen(szVarName); - - // If the line longer than the variable name? - if(nLineLength > nNameLength) - { - if(!_strnicmp((const char *)pbLineBegin, szVarName, nNameLength)) - { - // Skip the variable name - pbLineBegin += nNameLength; - - // Skip the separator(s) - while(pbLineBegin < pbLineEnd && IsValueSeparator(pbLineBegin)) - pbLineBegin++; - - // Check if there is "=" - if(pbLineBegin >= pbLineEnd || pbLineBegin[0] != '=') - return NULL; - pbLineBegin++; - - // Skip the separator(s) - while(pbLineBegin < pbLineEnd && IsValueSeparator(pbLineBegin)) - pbLineBegin++; - - // Check if there is "=" - if(pbLineBegin >= pbLineEnd) - return NULL; - - // Return the begin of the variable - return pbLineBegin; - } - } - - return NULL; -} - -static int LoadInfoVariable(PQUERY_KEY pVarBlob, const char * szLineBegin, const char * szLineEnd, bool bHexaValue) -{ - const char * szLinePtr = szLineBegin; - - // Sanity checks - assert(pVarBlob->pbData == NULL); - assert(pVarBlob->cbData == 0); - - // Check length of the variable - while(szLinePtr < szLineEnd && szLinePtr[0] != '|') - szLinePtr++; - - // Allocate space for the blob - if(bHexaValue) - { - // Initialize the blob - pVarBlob->pbData = CASC_ALLOC(BYTE, (szLinePtr - szLineBegin) / 2); - return StringBlobToBinaryBlob(pVarBlob, (LPBYTE)szLineBegin, (LPBYTE)szLinePtr); - } - - // Initialize the blob - pVarBlob->pbData = CASC_ALLOC(BYTE, (szLinePtr - szLineBegin) + 1); - pVarBlob->cbData = (DWORD)(szLinePtr - szLineBegin); - - // Check for success - if(pVarBlob->pbData == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - // Copy the string - memcpy(pVarBlob->pbData, szLineBegin, pVarBlob->cbData); - pVarBlob->pbData[pVarBlob->cbData] = 0; - return ERROR_SUCCESS; -} - - -static void AppendConfigFilePath(TCHAR * szFileName, PQUERY_KEY pFileKey) -{ - // Get to the end of the file name - szFileName = szFileName + _tcslen(szFileName); - - // Append the "config" directory - _tcscat(szFileName, _T("/config")); - szFileName += 7; - - // Append the first level directory - szFileName = AppendBlobText(szFileName, pFileKey->pbData, 1, _T('/')); - szFileName = AppendBlobText(szFileName, pFileKey->pbData + 1, 1, _T('/')); - szFileName = AppendBlobText(szFileName, pFileKey->pbData, pFileKey->cbData, _T('/')); -} - -static DWORD GetBlobCount(LPBYTE pbLineBegin, LPBYTE pbLineEnd) -{ - DWORD dwBlobCount = 0; - - // Until we find an end of the line - while(pbLineBegin < pbLineEnd) - { - // Skip the blob - while(pbLineBegin < pbLineEnd && IsValueSeparator(pbLineBegin) == false) - pbLineBegin++; - - // Increment the number of blobs - dwBlobCount++; - - // Skip the separator - while(pbLineBegin < pbLineEnd && IsValueSeparator(pbLineBegin)) - pbLineBegin++; - } - - return dwBlobCount; -} - -static int LoadBlobArray( - PQUERY_KEY pBlob, - DWORD dwMaxBlobs, - LPBYTE pbLineBegin, - LPBYTE pbLineEnd, - LPBYTE pbBuffer, - DWORD dwBufferSize) -{ - LPBYTE pbBlobBegin = pbLineBegin; - LPBYTE pbBlobEnd = pbLineBegin; - int nError = ERROR_SUCCESS; - - // Sanity check - assert(pbBuffer != NULL); - - // Until we find an end of the line - while(pbBlobBegin < pbLineEnd) - { - // Convert the blob from string to binary - if(dwBufferSize < MAX_CASC_KEY_LENGTH) - return ERROR_NOT_ENOUGH_MEMORY; - - // Find the end of the text blob - while(pbBlobEnd < pbLineEnd && IsValueSeparator(pbBlobEnd) == false) - pbBlobEnd++; - - // Convert the blob from ANSI to binary - pBlob->pbData = pbBuffer; - nError = StringBlobToBinaryBlob(pBlob, pbBlobBegin, pbBlobEnd); - if(nError != ERROR_SUCCESS || dwMaxBlobs == 1) - break; - - // Move the blob, buffer, and limits - dwBufferSize -= MAX_CASC_KEY_LENGTH; - pbBuffer += MAX_CASC_KEY_LENGTH; - dwMaxBlobs--; - pBlob++; - - // Skip the separator - while(pbBlobEnd < pbLineEnd && IsValueSeparator(pbBlobEnd)) - pbBlobEnd++; - pbBlobBegin = pbBlobEnd; - } - - return nError; -} - -static int LoadSingleBlob(PQUERY_KEY pBlob, LPBYTE pbBlobBegin, LPBYTE pbBlobEnd) -{ - LPBYTE pbBuffer; - size_t nLength = (pbBlobEnd - pbBlobBegin) / 2; - - // Check maximum size - if(nLength > MAX_CASC_KEY_LENGTH) - return ERROR_INVALID_PARAMETER; - - // Allocate the blob buffer - pbBuffer = CASC_ALLOC(BYTE, MAX_CASC_KEY_LENGTH); - if(pbBuffer == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - return LoadBlobArray(pBlob, 1, pbBlobBegin, pbBlobEnd, pbBuffer, MAX_CASC_KEY_LENGTH); -} - -static PQUERY_KEY LoadMultipleBlobs(LPBYTE pbLineBegin, LPBYTE pbLineEnd, DWORD * pdwBlobCount) -{ - PQUERY_KEY pBlobArray = NULL; - LPBYTE pbBuffer = NULL; - DWORD dwBlobCount = GetBlobCount(pbLineBegin, pbLineEnd); - int nError; - - // Only if there is at least 1 blob - if(dwBlobCount != 0) - { - // Allocate the array of blobs - pBlobArray = CASC_ALLOC(QUERY_KEY, dwBlobCount); - if(pBlobArray != NULL) - { - // Zero the blob array - memset(pBlobArray, 0, dwBlobCount * sizeof(QUERY_KEY)); - - // Allocate buffer for the blobs - pbBuffer = CASC_ALLOC(BYTE, dwBlobCount * MAX_CASC_KEY_LENGTH); - if(pbBuffer != NULL) - { - // Zero the buffer - memset(pbBuffer, 0, dwBlobCount * MAX_CASC_KEY_LENGTH); - - // Load the entire blob array - nError = LoadBlobArray(pBlobArray, dwBlobCount, pbLineBegin, pbLineEnd, pbBuffer, dwBlobCount * MAX_CASC_KEY_LENGTH); - if(nError == ERROR_SUCCESS) - { - *pdwBlobCount = dwBlobCount; - return pBlobArray; - } - - // Free the buffer - CASC_FREE(pbBuffer); - } - - // Free the array of blobs - CASC_FREE(pBlobArray); - pBlobArray = NULL; - } - - // Reset the blob count - dwBlobCount = 0; - } - - *pdwBlobCount = dwBlobCount; - return pBlobArray; -} - -static int LoadTextFile(const TCHAR * szFileName, PQUERY_KEY pFileBlob) -{ - TFileStream * pStream; - ULONGLONG FileSize = 0; - int nError = ERROR_SUCCESS; - - // Open the agent file - pStream = FileStream_OpenFile(szFileName, STREAM_FLAG_READ_ONLY | STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE); - if(pStream != NULL) - { - // Retrieve its size - FileStream_GetSize(pStream, &FileSize); - - // Load the file to memory - if(0 < FileSize && FileSize < 0x100000) - { - // Initialize the blob - pFileBlob->cbData = (DWORD)FileSize; - pFileBlob->pbData = CASC_ALLOC(BYTE, pFileBlob->cbData + 1); - - // Load the file data into the blob - if(pFileBlob->pbData != NULL) - { - FileStream_Read(pStream, NULL, pFileBlob->pbData, (DWORD)FileSize); - pFileBlob->pbData[pFileBlob->cbData] = 0; - } - else - nError = ERROR_NOT_ENOUGH_MEMORY; - } - else - nError = ERROR_INVALID_PARAMETER; - - FileStream_Close(pStream); - } - else - nError = GetLastError(); - - return nError; -} - -static int GetGameType(TCascStorage * hs, LPBYTE pbVarBegin, LPBYTE pbLineEnd) -{ - // Alpha build of Heroes of the Storm - if((pbLineEnd - pbVarBegin) == 4 && !_strnicmp((const char *)pbVarBegin, "Hero", 4)) - { - hs->dwGameInfo = CASC_GAME_HOTS; - return ERROR_SUCCESS; - } - - // Alpha build of World of Warcraft - Warlords of Draenor - if((pbLineEnd - pbVarBegin) == 3 && !_strnicmp((const char *)pbVarBegin, "WoW", 3)) - { - hs->dwGameInfo = CASC_GAME_WOW6; - return ERROR_SUCCESS; - } - - // Diablo III BETA 2.2.0 - if((pbLineEnd - pbVarBegin) == 7 && !_strnicmp((const char *)pbVarBegin, "Diablo3", 7)) - { - hs->dwGameInfo = CASC_GAME_DIABLO3; - return ERROR_SUCCESS; - } - - // An unknown game - assert(false); - return ERROR_BAD_FORMAT; -} - -// "B29049" -// "WOW-18125patch6.0.1" -// "30013_Win32_2_2_0_Ptr_ptr" -static int GetBuildNumber(TCascStorage * hs, LPBYTE pbVarBegin, LPBYTE pbLineEnd) -{ - DWORD dwBuildNumber = 0; - - // Skip all non-digit characters - while(pbVarBegin < pbLineEnd && IsCharDigit(pbVarBegin[0]) == false) - pbVarBegin++; - - // Convert the build number - while(pbVarBegin < pbLineEnd && IsCharDigit(pbVarBegin[0])) - dwBuildNumber = (dwBuildNumber * 10) + (*pbVarBegin++ - '0'); - - assert(dwBuildNumber != 0); - hs->dwBuildNumber = dwBuildNumber; - return (dwBuildNumber != 0) ? ERROR_SUCCESS : ERROR_BAD_FORMAT; -} - -static int GetDefaultLocaleMask(TCascStorage * hs, PQUERY_KEY pTagsString) -{ - char * szTagEnd = (char *)pTagsString->pbData + pTagsString->cbData; - char * szTagPtr = (char *)pTagsString->pbData; - char * szNext; - DWORD dwLocaleMask = 0; - - while(szTagPtr < szTagEnd) - { - // Get the next part - szNext = strchr(szTagPtr, ' '); - if(szNext != NULL) - *szNext++ = 0; - - // Check whether the current tag is a language identifier - dwLocaleMask = dwLocaleMask | GetLocaleMask(szTagPtr); - - // Get the next part - if(szNext == NULL) - break; - - // Skip spaces - while(szNext < szTagEnd && szNext[0] == ' ') - szNext++; - szTagPtr = szNext; - } - - hs->dwDefaultLocale = dwLocaleMask; - return ERROR_SUCCESS; -} - -static int FetchAndVerifyConfigFile(TCascStorage * hs, PQUERY_KEY pFileKey, PQUERY_KEY pFileBlob) -{ - TCHAR * szFileName; - int nError; - - // Construct the local file name - szFileName = NewStr(hs->szDataPath, 8 + 3 + 3 + 32); - if(szFileName == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - // Add the part where the config file path is - AppendConfigFilePath(szFileName, pFileKey); - - // Load the config file - nError = LoadTextFile(szFileName, pFileBlob); - if(nError == ERROR_SUCCESS) - { - // Verify the blob's MD5 - if(!VerifyDataBlockHash(pFileBlob->pbData, pFileBlob->cbData, pFileKey->pbData)) - { - FreeCascBlob(pFileBlob); - nError = ERROR_BAD_FORMAT; - } - } - - CASC_FREE(szFileName); - return nError; -} - -static int ParseInfoFile(TCascStorage * hs, PQUERY_KEY pFileBlob) -{ - QUERY_KEY Active = {NULL, 0}; - QUERY_KEY TagString = {NULL, 0}; - QUERY_KEY CdnHost = {NULL, 0}; - QUERY_KEY CdnPath = {NULL, 0}; - const char * szLineBegin1 = NULL; - const char * szLinePtr1 = NULL; - const char * szLineBegin2 = NULL; - const char * szLineEnd1 = NULL; - const char * szLineEnd2 = NULL; - const char * szFileEnd = (const char *)(pFileBlob->pbData + pFileBlob->cbData); - const char * szFilePtr = (const char *)pFileBlob->pbData; - int nError = ERROR_BAD_FORMAT; - - // Find the first line - szLineBegin1 = szFilePtr; - while(szFilePtr < szFileEnd) - { - // Check for the end of the line - if(szFilePtr[0] == 0x0D || szFilePtr[0] == 0x0A) - { - szLineEnd1 = szFilePtr; - break; - } - - szFilePtr++; - } - - while (szFilePtr < szFileEnd) - { - szLinePtr1 = szLineBegin1; - - // Skip the newline character(s) - while (szFilePtr < szFileEnd && (szFilePtr[0] == 0x0D || szFilePtr[0] == 0x0A)) - szFilePtr++; - - // Find the next line - szLineBegin2 = szFilePtr; - while (szFilePtr < szFileEnd) - { - // Check for the end of the line - if (szFilePtr[0] == 0x0D || szFilePtr[0] == 0x0A) - { - szLineEnd2 = szFilePtr; - break; - } - - szFilePtr++; - } - - // Find the build key, CDN config key and the URL path - while (szLinePtr1 < szLineEnd1) - { - // Check for variables we need - if (IsInfoVariable(szLinePtr1, szLineEnd1, "Active", "DEC")) - LoadInfoVariable(&Active, szLineBegin2, szLineEnd2, false); - if (IsInfoVariable(szLinePtr1, szLineEnd1, "Build Key", "HEX")) - LoadInfoVariable(&hs->CdnBuildKey, szLineBegin2, szLineEnd2, true); - if (IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Key", "HEX")) - LoadInfoVariable(&hs->CdnConfigKey, szLineBegin2, szLineEnd2, true); - if (IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Hosts", "STRING")) - LoadInfoVariable(&CdnHost, szLineBegin2, szLineEnd2, false); - if (IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Path", "STRING")) - LoadInfoVariable(&CdnPath, szLineBegin2, szLineEnd2, false); - if (IsInfoVariable(szLinePtr1, szLineEnd1, "Tags", "STRING")) - LoadInfoVariable(&TagString, szLineBegin2, szLineEnd2, false); - - // Move both line pointers - szLinePtr1 = SkipInfoVariable(szLinePtr1, szLineEnd1); - if (szLineBegin1 == NULL) - break; - - szLineBegin2 = SkipInfoVariable(szLineBegin2, szLineEnd2); - if (szLineBegin2 == NULL) - break; - } - - // Stop parsing if found active config - if (Active.pbData != NULL && *Active.pbData == '1') - break; - } - - // All four must be present - if(hs->CdnBuildKey.pbData != NULL && - hs->CdnConfigKey.pbData != NULL && - CdnHost.pbData != NULL && - CdnPath.pbData != NULL) - { - // Merge the CDN host and CDN path - hs->szUrlPath = CASC_ALLOC(TCHAR, CdnHost.cbData + CdnPath.cbData + 1); - if(hs->szUrlPath != NULL) - { - CopyString(hs->szUrlPath, (char *)CdnHost.pbData, CdnHost.cbData); - CopyString(hs->szUrlPath + CdnHost.cbData, (char *)CdnPath.pbData, CdnPath.cbData); - nError = ERROR_SUCCESS; - } - } - - // If we found tags, we can extract language build from it - if(TagString.pbData != NULL) - GetDefaultLocaleMask(hs, &TagString); - - FreeCascBlob(&CdnHost); - FreeCascBlob(&CdnPath); - FreeCascBlob(&TagString); - return nError; -} - -static int ParseAgentFile(TCascStorage * hs, PQUERY_KEY pFileBlob) -{ - LPBYTE pbBlobBegin = pFileBlob->pbData; - LPBYTE pbBlobEnd; - int nError = ERROR_SUCCESS; - - // Extract the CDN build hash - pbBlobEnd = FindNextSeparator(pFileBlob, pbBlobBegin); - if(pbBlobEnd != NULL) - { - // Convert the string to a blob - nError = LoadSingleBlob(&hs->CdnBuildKey, pbBlobBegin, pbBlobEnd); - - // Move to the next part - if(pbBlobEnd[0] == _T('|')) - pbBlobEnd++; - pbBlobBegin = pbBlobEnd; - } - - // Extract the CDN config hash - pbBlobEnd = FindNextSeparator(pFileBlob, pbBlobBegin); - if(pbBlobEnd != NULL) - { - // Convert the string to a blob - nError = LoadSingleBlob(&hs->CdnConfigKey, pbBlobBegin, pbBlobEnd); - - // Move to the next part - if(pbBlobEnd[0] == _T('|')) - pbBlobEnd++; - pbBlobBegin = pbBlobEnd; - } - - // Skip the intermediate part - pbBlobEnd = FindNextSeparator(pFileBlob, pbBlobBegin); - if(pbBlobEnd != NULL) - { - // Move to the next part - if(pbBlobEnd[0] == _T('|')) - pbBlobEnd++; - pbBlobBegin = pbBlobEnd; - } - - // Extract the URL config hash - pbBlobEnd = FindNextSeparator(pFileBlob, pbBlobBegin); - if(pbBlobEnd != NULL) - { - // Convert the string to a blob - hs->szUrlPath = NewStrFromAnsi(pbBlobBegin, pbBlobEnd); - } - - // Verify all variables - if(hs->CdnBuildKey.pbData == NULL || hs->CdnConfigKey.pbData == NULL || hs->szUrlPath == NULL) - nError = ERROR_BAD_FORMAT; - return nError; -} - -static int LoadCdnConfigFile(TCascStorage * hs, PQUERY_KEY pFileBlob) -{ - LPBYTE pbLineBegin = pFileBlob->pbData; - LPBYTE pbVarBegin; - LPBYTE pbLineEnd = NULL; - int nError; - - while(pbLineBegin != NULL) - { - // Get the next line - if(!GetNextFileLine(pFileBlob, &pbLineBegin, &pbLineEnd)) - break; - - // Archive group - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "archive-group"); - if(pbVarBegin != NULL) - { - nError = LoadSingleBlob(&hs->ArchiveGroup, pbVarBegin, pbLineEnd); - if(nError != ERROR_SUCCESS) - return nError; - continue; - } - - // Archives - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "archives"); - if(pbVarBegin != NULL) - { - hs->pArchiveArray = LoadMultipleBlobs(pbVarBegin, pbLineEnd, &hs->ArchiveCount); - if(hs->pArchiveArray == NULL || hs->ArchiveCount == 0) - return ERROR_BAD_FORMAT; - continue; - } - - // Patch archive group - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "patch-archive-group"); - if(pbVarBegin != NULL) - { - LoadSingleBlob(&hs->PatchArchiveGroup, pbVarBegin, pbLineEnd); - continue; - } - - // Patch archives - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "patch-archives"); - if(pbVarBegin != NULL) - { - hs->pPatchArchiveArray = LoadMultipleBlobs(pbVarBegin, pbLineEnd, &hs->PatchArchiveCount); - continue; - } - } - - // Check if all required fields are present - if(hs->ArchiveGroup.pbData == NULL || hs->ArchiveGroup.cbData == 0 || hs->pArchiveArray == NULL || hs->ArchiveCount == 0) - return ERROR_BAD_FORMAT; - - return ERROR_SUCCESS; -} - -static int LoadCdnBuildFile(TCascStorage * hs, PQUERY_KEY pFileBlob) -{ - LPBYTE pbLineBegin = pFileBlob->pbData; - LPBYTE pbVarBegin; - LPBYTE pbLineEnd = NULL; - - while(pbLineBegin != NULL) - { - // Get the next line - if(!GetNextFileLine(pFileBlob, &pbLineBegin, &pbLineEnd)) - break; - - // Game name - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "build-product"); - if(pbVarBegin != NULL) - { - GetGameType(hs, pbVarBegin, pbLineEnd); - continue; - } - - // Game build number - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "build-name"); - if(pbVarBegin != NULL) - { - GetBuildNumber(hs, pbVarBegin, pbLineEnd); - continue; - } - - // Root - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "root"); - if(pbVarBegin != NULL) - { - LoadSingleBlob(&hs->RootKey, pbVarBegin, pbLineEnd); - continue; - } - - // Patch - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "patch"); - if(pbVarBegin != NULL) - { - LoadSingleBlob(&hs->PatchKey, pbVarBegin, pbLineEnd); - continue; - } - - // Download - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "download"); - if(pbVarBegin != NULL) - { - LoadSingleBlob(&hs->DownloadKey, pbVarBegin, pbLineEnd); - continue; - } - - // Install - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "install"); - if(pbVarBegin != NULL) - { - LoadSingleBlob(&hs->InstallKey, pbVarBegin, pbLineEnd); - continue; - } - - // Encoding keys - pbVarBegin = CheckLineVariable(pbLineBegin, pbLineEnd, "encoding"); - if(pbVarBegin != NULL) - { - hs->pEncodingKeys = LoadMultipleBlobs(pbVarBegin, pbLineEnd, &hs->EncodingKeys); - if(hs->pEncodingKeys == NULL || hs->EncodingKeys != 2) - return ERROR_BAD_FORMAT; - - hs->EncodingKey = hs->pEncodingKeys[0]; - hs->EncodingEKey = hs->pEncodingKeys[1]; - continue; - } - } - - // Check the encoding keys - if(hs->pEncodingKeys == NULL || hs->EncodingKeys == 0) - return ERROR_BAD_FORMAT; - return ERROR_SUCCESS; -} - -//----------------------------------------------------------------------------- -// Public functions - -int LoadBuildInfo(TCascStorage * hs) -{ - QUERY_KEY InfoFile = {NULL, 0}; - QUERY_KEY FileData = {NULL, 0}; - TCHAR * szAgentFile; - TCHAR * szInfoFile; - bool bBuildConfigComplete = false; - int nError = ERROR_SUCCESS; - - // Since HOTS build 30027, the game uses build.info file for storage info - if(bBuildConfigComplete == false) - { - szInfoFile = CombinePath(hs->szRootPath, _T(".build.info")); - if(szInfoFile != NULL) - { - nError = LoadTextFile(szInfoFile, &InfoFile); - if(nError == ERROR_SUCCESS) - { - // Parse the info file - nError = ParseInfoFile(hs, &InfoFile); - if(nError == ERROR_SUCCESS) - bBuildConfigComplete = true; - - // Free the loaded blob - FreeCascBlob(&InfoFile); - } - - CASC_FREE(szInfoFile); - } - } - - // If the info file has not been loaded, try the legacy .build.db - if(bBuildConfigComplete == false) - { - szAgentFile = CombinePath(hs->szRootPath, _T(".build.db")); - if(szAgentFile != NULL) - { - nError = LoadTextFile(szAgentFile, &FileData); - if(nError == ERROR_SUCCESS) - { - nError = ParseAgentFile(hs, &FileData); - if(nError == ERROR_SUCCESS) - bBuildConfigComplete = true; - - FreeCascBlob(&FileData); - } - CASC_FREE(szAgentFile); - } - } - - // If the .build.info and .build.db file hasn't been loaded, - if(nError == ERROR_SUCCESS && bBuildConfigComplete == false) - { - nError = ERROR_FILE_CORRUPT; - } - - // Load the configuration file - if(nError == ERROR_SUCCESS) - { - nError = FetchAndVerifyConfigFile(hs, &hs->CdnConfigKey, &FileData); - if(nError == ERROR_SUCCESS) - { - nError = LoadCdnConfigFile(hs, &FileData); - FreeCascBlob(&FileData); - } - } - - // Load the build file - if(nError == ERROR_SUCCESS) - { - nError = FetchAndVerifyConfigFile(hs, &hs->CdnBuildKey, &FileData); - if(nError == ERROR_SUCCESS) - { - nError = LoadCdnBuildFile(hs, &FileData); - FreeCascBlob(&FileData); - } - } - - // Fill the index directory - if(nError == ERROR_SUCCESS) - { - // First, check for more common "data" subdirectory - if((hs->szIndexPath = CheckForIndexDirectory(hs, _T("data"))) != NULL) - return ERROR_SUCCESS; - - // Second, try the "darch" subdirectory (older builds of HOTS - Alpha) - if((hs->szIndexPath = CheckForIndexDirectory(hs, _T("darch"))) != NULL) - return ERROR_SUCCESS; - - nError = ERROR_FILE_NOT_FOUND; - } - - return nError; -} diff --git a/dep/CascLib/src/CascCommon.cpp b/dep/CascLib/src/CascCommon.cpp index 8ad7d716b82..34c3df66b5c 100644 --- a/dep/CascLib/src/CascCommon.cpp +++ b/dep/CascLib/src/CascCommon.cpp @@ -65,3 +65,26 @@ ULONGLONG ConvertBytesToInteger_5(LPBYTE ValueAsBytes) return Value; } + +void ConvertIntegerToBytes_4(DWORD Value, LPBYTE ValueAsBytes) +{ + ValueAsBytes[0] = (Value >> 0x18) & 0xFF; + ValueAsBytes[1] = (Value >> 0x10) & 0xFF; + ValueAsBytes[2] = (Value >> 0x08) & 0xFF; + ValueAsBytes[3] = (Value >> 0x00) & 0xFF; +} + +//----------------------------------------------------------------------------- +// Common fre routine of a CASC blob + +void FreeCascBlob(PQUERY_KEY pBlob) +{ + if(pBlob != NULL) + { + if(pBlob->pbData != NULL) + CASC_FREE(pBlob->pbData); + + pBlob->pbData = NULL; + pBlob->cbData = 0; + } +} diff --git a/dep/CascLib/src/CascCommon.h b/dep/CascLib/src/CascCommon.h index 7a2b4071dc6..42e158bfcb2 100644 --- a/dep/CascLib/src/CascCommon.h +++ b/dep/CascLib/src/CascCommon.h @@ -23,9 +23,13 @@ #include "CascPort.h" #include "common/Common.h" +#include "common/DynamicArray.h" #include "common/Map.h" #include "common/FileStream.h" +#include "common/Directory.h" #include "common/ListFile.h" +#include "common/DumpContext.h" +#include "common/RootHandler.h" // Headers from LibTomCrypt #include "libtomcrypt/src/headers/tomcrypt.h" @@ -36,16 +40,17 @@ //----------------------------------------------------------------------------- // CascLib private defines -#define CASC_GAME_HOTS 0x00010000 // Heroes of the Storm -#define CASC_GAME_WOW6 0x00020000 // World of Warcraft - Warlords of Draenor -#define CASC_GAME_DIABLO3 0x00030000 // Diablo 3 Since PTR 2.2.0 -#define CASC_GAME_MASK 0xFFFF0000 // Mask for getting game ID +#define CASC_GAME_HOTS 0x00010000 // Heroes of the Storm +#define CASC_GAME_WOW6 0x00020000 // World of Warcraft - Warlords of Draenor +#define CASC_GAME_DIABLO3 0x00030000 // Diablo 3 since PTR 2.2.0 +#define CASC_GAME_OVERWATCH 0x00040000 // Overwatch since PTR 24919 +#define CASC_GAME_STARCRAFT2 0x00050000 // Starcraft II - Legacy of the Void, since build 38996 +#define CASC_GAME_MASK 0xFFFF0000 // Mask for getting game ID #define CASC_INDEX_COUNT 0x10 #define CASC_FILE_KEY_SIZE 0x09 // Size of the file key #define CASC_MAX_DATA_FILES 0x100 -#define CASC_MAX_MAR_FILES 3 // Maximum of 3 MAR files are supported -#define CASC_MNDX_SIGNATURE 0x58444E4D // 'MNDX' +#define CASC_EXTRA_FILES 0x20 // Number of extra entries to be reserved for additionally inserted files #define CASC_SEARCH_HAVE_NAME 0x0001 // Indicated that previous search found a name @@ -71,41 +76,28 @@ #define CASC_PACKAGE_BUFFER 0x1000 -//----------------------------------------------------------------------------- -// On-disk structures - -typedef struct _FILE_LOCALE_BLOCK -{ - DWORD NumberOfFiles; // Number of entries - DWORD Flags; - DWORD Locales; // File locale mask (CASC_LOCALE_XXX) +#ifndef _maxchars +#define _maxchars(buff) ((sizeof(buff) / sizeof(buff[0])) - 1) +#endif - // Followed by a block of 32-bit integers (count: NumberOfFiles) - // Followed by the MD5 and file name hash (count: NumberOfFiles) +//----------------------------------------------------------------------------- +// In-memory structures +// See http://pxr.dk/wowdev/wiki/index.php?title=CASC for more information -} FILE_LOCALE_BLOCK, *PFILE_LOCALE_BLOCK; +struct TFileStream; -typedef struct _FILE_ROOT_ENTRY +typedef enum _CBLD_TYPE { - DWORD EncodingKey[4]; // MD5 of the file - ULONGLONG FileNameHash; // Jenkins hash of the file name - -} FILE_ROOT_ENTRY, *PFILE_ROOT_ENTRY; + CascBuildNone = 0, // No build type found + CascBuildInfo, // .build.info + CascBuildDb, // .build.db (older storages) +} CBLD_TYPE, *PCBLD_TYPE; -typedef struct _ROOT_BLOCK_INFO +typedef struct _ENCODING_KEY { - PFILE_LOCALE_BLOCK pLocaleBlockHdr; // Pointer to the locale block - PDWORD pInt32Array; // Pointer to the array of 32-bit integers - PFILE_ROOT_ENTRY pRootEntries; - -} ROOT_BLOCK_INFO, *PROOT_BLOCK_INFO; - -//----------------------------------------------------------------------------- -// In-memory structures + BYTE Value[MD5_HASH_SIZE]; // MD5 of the file -class TMndxFindResult; -struct TFileStream; -struct _MAR_FILE; +} ENCODING_KEY, *PENCODING_KEY; typedef struct _CASC_INDEX_ENTRY { @@ -140,25 +132,34 @@ typedef struct _CASC_FILE_FRAME BYTE md5[MD5_HASH_SIZE]; // MD5 hash of the file sector } CASC_FILE_FRAME, *PCASC_FILE_FRAME; +// The encoding file is in the form of: +// * File header +// * String block #1 +// * Table A header +// * Table A entries +// * Table B header +// * Table B entries +// * String block #2 +// http://pxr.dk/wowdev/wiki/index.php?title=CASC#Key_CASC_Files typedef struct _CASC_ENCODING_HEADER { BYTE Magic[2]; // "EN" - BYTE field_2; - BYTE field_3; - BYTE field_4; - BYTE field_5[2]; - BYTE field_7[2]; - BYTE NumSegments[4]; // Number of entries (big endian) - BYTE field_D[4]; + BYTE Version; // Expected to be 1 by CascLib + BYTE ChecksumSizeA; // The length of the checksums in Encoding Table + BYTE ChecksumSizeB; // The length of the checksums in Encoding Layout Table + BYTE Flags_TableA[2]; // Flags for Encoding Table + BYTE Flags_TableB[2]; // Flags for Encoding Layout Table + BYTE Entries_TableA[4]; // Number of segments in Encoding Table (big endian) + BYTE Entries_TableB[4]; // Number of segments in Encoding Layout Table (big endian) BYTE field_11; - BYTE SegmentsPos[4]; // Offset of encoding segments + BYTE Size_StringTable1[4]; // Size of the string block #1 } CASC_ENCODING_HEADER, *PCASC_ENCODING_HEADER; typedef struct _CASC_ENCODING_ENTRY { - USHORT KeyCount; // Number of subitems - BYTE FileSizeBE[4]; // Compressed file size (header area + frame headers + compressed frames), in bytes + USHORT KeyCount; // Number of index keys + BYTE FileSizeBE[4]; // Compressed file size (header area + frame headers + compressed frames), in bytes BYTE EncodingKey[MD5_HASH_SIZE]; // File encoding key // Followed by the index keys @@ -166,87 +167,21 @@ typedef struct _CASC_ENCODING_ENTRY // Followed by the index keys (number of items = KeyCount) } CASC_ENCODING_ENTRY, *PCASC_ENCODING_ENTRY; -typedef struct _CASC_ROOT_LOCALE_BLOCK -{ - DWORD NumberOfFiles; // Number of entries - DWORD Flags; - DWORD FileLocales; // File locales (CASC_LOCALE_XXX) - - // Followed by a block of 32-bit integers (count: NumberOfFiles) - // Followed by the MD5 and file name hash (count: NumberOfFiles) - -} CASC_ROOT_LOCALE_BLOCK, *PCASC_ROOT_LOCALE_BLOCK; - -// Root file entry for CASC storages with MNDX root file (Heroes of the Storm) -// Corresponds to the in-file structure -typedef struct _CASC_ROOT_ENTRY_MNDX +// A version of CASC_ENCODING_ENTRY with one index key +typedef struct _CASC_ENCODING_ENTRY_1 { - DWORD Flags; // High 8 bits: Flags, low 24 bits: package index - BYTE EncodingKey[MD5_HASH_SIZE]; // Encoding key for the file - DWORD FileSize; // Uncompressed file size, in bytes - -} CASC_ROOT_ENTRY_MNDX, *PCASC_ROOT_ENTRY_MNDX; - -// Root file entry for CASC storages without MNDX root file (World of Warcraft 6.0+) -// Does not match to the in-file structure of the root entry -typedef struct _CASC_ROOT_ENTRY -{ - ULONGLONG FileNameHash; // Jenkins hash of the file name - DWORD SumValue; // Sum value - DWORD Locales; // Locale flags of the file - DWORD EncodingKey[4]; // File encoding key (MD5) - -} CASC_ROOT_ENTRY, *PCASC_ROOT_ENTRY; - -// Definition of the hash table for CASC root items -typedef struct _CASC_ROOT_HASH_TABLE -{ - PCASC_ROOT_ENTRY TablePtr; // Pointer to the CASC root table - DWORD TableSize; // Total size of the root table - DWORD ItemCount; // Number of items currently in the table - -} CASC_ROOT_HASH_TABLE, *PCASC_ROOT_HASH_TABLE; - -typedef struct _CASC_MNDX_INFO -{ - bool bRootFileLoaded; // true if the root info file was properly loaded - 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 MndxEntriesOffset; - DWORD MndxEntriesTotal; // Total number of MNDX root entries - DWORD MndxEntriesValid; // Number of valid MNDX root entries - DWORD MndxEntrySize; // Size of one MNDX root entry - struct _MAR_FILE * pMarFile1; // File name list for the packages - struct _MAR_FILE * pMarFile2; // File name list for names stripped of package names - struct _MAR_FILE * pMarFile3; // File name list for complete names - PCASC_ROOT_ENTRY_MNDX pMndxEntries; - PCASC_ROOT_ENTRY_MNDX * ppValidEntries; - -} CASC_MNDX_INFO, *PCASC_MNDX_INFO; - -typedef struct _CASC_PACKAGE -{ - char * szFileName; // Pointer to file name - size_t nLength; // Length of the file name - -} CASC_PACKAGE, *PCASC_PACKAGE; + USHORT KeyCount; // Number of index keys + BYTE FileSizeBE[4]; // Compressed file size (header area + frame headers + compressed frames), in bytes + BYTE EncodingKey[MD5_HASH_SIZE]; // File encoding key + BYTE IndexKey[MD5_HASH_SIZE]; // File index key -typedef struct _CASC_PACKAGES -{ - char * szNameBuffer; // Pointer to the buffer for file names - size_t NameEntries; // Number of name entries in Names - size_t NameBufferUsed; // Number of bytes used in the name buffer - size_t NameBufferMax; // Total size of the name buffer +} CASC_ENCODING_ENTRY_1, *PCASC_ENCODING_ENTRY_1; - CASC_PACKAGE Packages[1]; // List of packages +#define GET_INDEX_KEY(pEncodingEntry) (pEncodingEntry->EncodingKey + MD5_HASH_SIZE) +#define FAKE_ENCODING_ENTRY_SIZE (sizeof(CASC_ENCODING_ENTRY) + MD5_HASH_SIZE) -} CASC_PACKAGES, *PCASC_PACKAGES; +//----------------------------------------------------------------------------- +// Structures for CASC storage and CASC file typedef struct _TCascStorage { @@ -254,6 +189,7 @@ typedef struct _TCascStorage const TCHAR * szIndexFormat; // Format of the index file name TCHAR * szRootPath; // This is the game directory TCHAR * szDataPath; // This is the directory where data files are + TCHAR * szBuildFile; // Build file name (.build.info or .build.db) TCHAR * szIndexPath; // This is the directory where index files are TCHAR * szUrlPath; // URL to the Blizzard servers DWORD dwRefCount; // Number of references @@ -262,40 +198,29 @@ typedef struct _TCascStorage DWORD dwFileBeginDelta; // This is number of bytes to shift back from archive offset (from index entry) to actual begin of file data DWORD dwDefaultLocale; // Default locale, read from ".build.info" + CBLD_TYPE BuildFileType; // Type of the build file + QUERY_KEY CdnConfigKey; QUERY_KEY CdnBuildKey; - - PQUERY_KEY pArchiveArray; // Array of the archives - QUERY_KEY ArchiveGroup; // Name of the group archive file - DWORD ArchiveCount; // Number of archives in the array - - PQUERY_KEY pPatchArchiveArray; // Array of the patch archives - QUERY_KEY PatchArchiveGroup; // Name of the patch group archive file - DWORD PatchArchiveCount; // Number of patch archives in the array - + QUERY_KEY ArchivesGroup; // Key array of the "archive-group" + QUERY_KEY ArchivesKey; // Key array of the "archives" + QUERY_KEY PatchArchivesKey; // Key array of the "patch-archives" QUERY_KEY RootKey; QUERY_KEY PatchKey; QUERY_KEY DownloadKey; QUERY_KEY InstallKey; - - PQUERY_KEY pEncodingKeys; QUERY_KEY EncodingKey; - QUERY_KEY EncodingEKey; - DWORD EncodingKeys; TFileStream * DataFileArray[CASC_MAX_DATA_FILES]; // Data file handles CASC_MAPPING_TABLE KeyMapping[CASC_INDEX_COUNT]; // Key mapping PCASC_MAP pIndexEntryMap; // Map of index entries - PCASC_ENCODING_HEADER pEncodingHeader; // The encoding file - PCASC_ENCODING_ENTRY * ppEncodingEntries; // Map of encoding entries - size_t nEncodingEntries; + QUERY_KEY EncodingFile; // Content of the ENCODING file + PCASC_MAP pEncodingMap; // Map of encoding entries + DYNAMIC_ARRAY ExtraEntries; // Extra encoding entries - CASC_ROOT_HASH_TABLE RootTable; // Hash table for the root entries - - PCASC_MNDX_INFO pMndxInfo; // Used for storages which have MNDX/MAR file - PCASC_PACKAGES pPackages; // Linear list of present packages + TRootHandler * pRootHandler; // Common handler for various ROOT file formats } TCascStorage; @@ -336,16 +261,19 @@ typedef struct _TCascFile typedef struct _TCascSearch { TCascStorage * hs; // Pointer to the storage handle - const char * szClassName; - TCHAR * szListFile; + const char * szClassName; // Contains "TCascSearch" + TCHAR * szListFile; // Name of the listfile void * pCache; // Listfile cache - TMndxFindResult * pStruct1C; // Search structure for MNDX info - char * szMask; + char * szMask; // Search mask char szFileName[MAX_PATH]; // Buffer for the file name - char szNormName[MAX_PATH]; // Buffer for normalized file name - DWORD RootIndex; // Root index of the previously found item - DWORD dwState; // Pointer to the state (0 = listfile, 1 = nameless, 2 = done) - BYTE BitArray[1]; // Bit array of already-reported files + + // Provider-specific data + void * pRootContext; // Root-specific search context + size_t IndexLevel1; // Root-specific search context + size_t IndexLevel2; // Root-specific search context + DWORD dwState; // Pointer to the search state (0 = listfile, 1 = nameless, 2 = done) + + BYTE BitArray[1]; // Bit array of encoding keys. Set for each entry that has already been reported } TCascSearch; @@ -384,10 +312,15 @@ DWORD ConvertBytesToInteger_4(LPBYTE ValueAsBytes); DWORD ConvertBytesToInteger_4_LE(LPBYTE ValueAsBytes); ULONGLONG ConvertBytesToInteger_5(LPBYTE ValueAsBytes); +void ConvertIntegerToBytes_4(DWORD Value, LPBYTE ValueAsBytes); +void FreeCascBlob(PQUERY_KEY pQueryKey); + //----------------------------------------------------------------------------- -// Build configuration reading +// Text file parsing (CascFiles.cpp) int LoadBuildInfo(TCascStorage * hs); +int CheckGameDirectory(TCascStorage * hs, TCHAR * szDirectory); +int ParseRootFileLine(const char * szLinePtr, const char * szLineEnd, PQUERY_KEY pEncodingKey, char * szFileName, size_t nMaxChars); //----------------------------------------------------------------------------- // Internal file functions @@ -395,11 +328,20 @@ int LoadBuildInfo(TCascStorage * hs); TCascStorage * IsValidStorageHandle(HANDLE hStorage); TCascFile * IsValidFileHandle(HANDLE hFile); -PCASC_ROOT_ENTRY FindRootEntry(TCascStorage * hs, const char * szFileName, DWORD * PtrTableIndex); -PCASC_ENCODING_ENTRY FindEncodingEntry(TCascStorage * hs, PQUERY_KEY pEncodingKey, size_t * PtrIndex); +PCASC_ENCODING_ENTRY FindEncodingEntry(TCascStorage * hs, PQUERY_KEY pEncodingKey, PDWORD PtrIndex); PCASC_INDEX_ENTRY FindIndexEntry(TCascStorage * hs, PQUERY_KEY pIndexKey); -int CascDecompress(void * pvOutBuffer, PDWORD pcbOutBuffer, void * pvInBuffer, DWORD cbInBuffer); +int CascDecompress(LPBYTE pvOutBuffer, PDWORD pcbOutBuffer, LPBYTE pvInBuffer, DWORD cbInBuffer); +int CascDecrypt (LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer, DWORD dwFrameIndex); +int CascDirectCopy(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer); + +//----------------------------------------------------------------------------- +// Support for ROOT file + +int RootHandler_CreateMNDX(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile); +int RootHandler_CreateDiablo3(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile); +int RootHandler_CreateOverwatch(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile); +int RootHandler_CreateWoW6(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile, DWORD dwLocaleMask); //----------------------------------------------------------------------------- // Dumping CASC data structures @@ -409,8 +351,7 @@ void CascDumpSparseArray(const char * szFileName, void * pvSparseArray); void CascDumpNameFragTable(const char * szFileName, void * pvMarFile); void CascDumpFileNames(const char * szFileName, void * pvMarFile); void CascDumpIndexEntries(const char * szFileName, TCascStorage * hs); -void CascDumpMndxRoot(const char * szFileName, PCASC_MNDX_INFO pMndxInfo); -void CascDumpRootFile(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile, const char * szFormat, const TCHAR * szListFile, int nDumpLevel); +void CascDumpEncodingEntry(TCascStorage * hs, TDumpContext * dc, PCASC_ENCODING_ENTRY pEncodingEntry, int nDumpLevel); void CascDumpFile(const char * szFileName, HANDLE hFile); #endif // _DEBUG diff --git a/dep/CascLib/src/CascDecompress.cpp b/dep/CascLib/src/CascDecompress.cpp index 2858bcec5ab..290b08d64d8 100644 --- a/dep/CascLib/src/CascDecompress.cpp +++ b/dep/CascLib/src/CascDecompress.cpp @@ -13,9 +13,9 @@ #include "CascCommon.h" //----------------------------------------------------------------------------- -// Local functions +// Public functions -static int Decompress_ZLIB(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer) +int CascDecompress(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer) { z_stream z; // Stream information for zlib int nResult; @@ -44,40 +44,3 @@ static int Decompress_ZLIB(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInB // Return an error code return (nResult == Z_OK || nResult == Z_STREAM_END) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT; } - -//----------------------------------------------------------------------------- -// Public functions - -int CascDecompress(void * pvOutBuffer, PDWORD pcbOutBuffer, void * pvInBuffer, DWORD cbInBuffer) -{ - LPBYTE pbOutBuffer = (LPBYTE)pvOutBuffer; - LPBYTE pbInBuffer = (LPBYTE)pvInBuffer; - DWORD cbOutBuffer = *pcbOutBuffer; // Current size of the output buffer - BYTE uCompression; // Decompressions applied to the data - - // Verify buffer sizes - if(cbInBuffer <= 1) - return 0; - - // Get applied compression types and decrement data length - uCompression = *pbInBuffer++; - cbInBuffer--; - - // Perform the decompressions - switch(uCompression) - { - case 'N': // Uncompressed - - assert(cbOutBuffer == cbInBuffer); - memcpy(pbOutBuffer, pbInBuffer, cbInBuffer); - *pcbOutBuffer = cbOutBuffer; - return ERROR_SUCCESS; - - case 'Z': // ZLIB - - return Decompress_ZLIB(pbOutBuffer, pcbOutBuffer, pbInBuffer, cbInBuffer); - } - - assert(false); - return ERROR_NOT_SUPPORTED; -} diff --git a/dep/CascLib/src/CascDecrypt.cpp b/dep/CascLib/src/CascDecrypt.cpp new file mode 100644 index 00000000000..5f4dc77dfe8 --- /dev/null +++ b/dep/CascLib/src/CascDecrypt.cpp @@ -0,0 +1,300 @@ +/*****************************************************************************/ +/* CascDecrypt.cpp Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Decryption functions for CascLib */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 31.10.15 1.00 Lad The first version of CascDecrypt.cpp */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "CascLib.h" +#include "CascCommon.h" + +//----------------------------------------------------------------------------- +// Local structures + +typedef struct _CASC_ENCRYPTION_KEY +{ + ULONGLONG KeyName; // "Name" of the key + BYTE Key[0x10]; // The key itself +} CASC_ENCRYPTION_KEY, *PCASC_ENCRYPTION_KEY; + +typedef struct _CASC_SALSA20 +{ + DWORD Key[0x10]; + DWORD dwRounds; + +} CASC_SALSA20, *PCASC_SALSA20; + +//----------------------------------------------------------------------------- +// Local variables + +//keyName FB680CB6A8BF81F3 key 62D90EFA7F36D71C398AE2F1FE37BDB9 keyNameSize 8 keySize 16 +//keyName 402CD9D8D6BFED98 key AEB0EADEA47612FE6C041A03958DF241 keyNameSize 8 keySize 16 +//keyName 87AEBBC9C4E6B601 key 685E86C6063DFDA6C9E85298076B3D42 keyNameSize 8 keySize 16 +//keyName A19C4F859F6EFA54 key 0196CB6F5ECBAD7CB5283891B9712B4B keyNameSize 8 keySize 16 +//keyName 11A9203C9881710A key 2E2CB8C397C2F24ED0B5E452F18DC267 keyNameSize 8 keySize 16 +//keyName DBD3371554F60306 key 34E397ACE6DD30EEFDC98A2AB093CD3C keyNameSize 8 keySize 16 +//keyName DEE3A0521EFF6F03 key AD740CE3FFFF9231468126985708E1B9 keyNameSize 8 keySize 16 +//keyName 8C9106108AA84F07 key 53D859DDA2635A38DC32E72B11B32F29 keyNameSize 8 keySize 16 + +static CASC_ENCRYPTION_KEY CascKeys[] = +{ + {0xFB680CB6A8BF81F3ULL, {0x62, 0xD9, 0x0E, 0xFA, 0x7F, 0x36, 0xD7, 0x1C, 0x39, 0x8A, 0xE2, 0xF1, 0xFE, 0x37, 0xBD, 0xB9}}, + {0x402CD9D8D6BFED98ULL, {0xAE, 0xB0, 0xEA, 0xDE, 0xA4, 0x76, 0x12, 0xFE, 0x6C, 0x04, 0x1A, 0x03, 0x95, 0x8D, 0xF2, 0x41}}, + {0x87AEBBC9C4E6B601ULL, {0x68, 0x5E, 0x86, 0xC6, 0x06, 0x3D, 0xFD, 0xA6, 0xC9, 0xE8, 0x52, 0x98, 0x07, 0x6B, 0x3D, 0x42}}, + {0xA19C4F859F6EFA54ULL, {0x01, 0x96, 0xCB, 0x6F, 0x5E, 0xCB, 0xAD, 0x7C, 0xB5, 0x28, 0x38, 0x91, 0xB9, 0x71, 0x2B, 0x4B}}, + {0x11A9203C9881710AULL, {0x2E, 0x2C, 0xB8, 0xC3, 0x97, 0xC2, 0xF2, 0x4E, 0xD0, 0xB5, 0xE4, 0x52, 0xF1, 0x8D, 0xC2, 0x67}}, + {0xDBD3371554F60306ULL, {0x34, 0xE3, 0x97, 0xAC, 0xE6, 0xDD, 0x30, 0xEE, 0xFD, 0xC9, 0x8A, 0x2A, 0xB0, 0x93, 0xCD, 0x3C}}, + {0xDEE3A0521EFF6F03ULL, {0xAD, 0x74, 0x0C, 0xE3, 0xFF, 0xFF, 0x92, 0x31, 0x46, 0x81, 0x26, 0x98, 0x57, 0x08, 0xE1, 0xB9}}, + {0x8C9106108AA84F07ULL, {0x53, 0xD8, 0x59, 0xDD, 0xA2, 0x63, 0x5A, 0x38, 0xDC, 0x32, 0xE7, 0x2B, 0x11, 0xB3, 0x2F, 0x29}}, + {0x49166D358A34D815ULL, {0x66, 0x78, 0x68, 0xCD, 0x94, 0xEA, 0x01, 0x35, 0xB9, 0xB1, 0x6C, 0x93, 0xB1, 0x12, 0x4A, 0xBA}}, + {0, {0}} +}; + +static const char * szKeyConstant16 = "expand 16-byte k"; +static const char * szKeyConstant32 = "expand 32-byte k"; + +//----------------------------------------------------------------------------- +// Local functions + +static DWORD Rol32(DWORD dwValue, DWORD dwRolCount) +{ + return (dwValue << dwRolCount) | (dwValue >> (32 - dwRolCount)); +} + +static LPBYTE FindCascKey(ULONGLONG KeyName) +{ + // Search the known keys + for(size_t i = 0; CascKeys[i].KeyName != 0; i++) + { + if(CascKeys[i].KeyName == KeyName) + return CascKeys[i].Key; + } + + // Key not found + return NULL; +} + +static void Initialize(PCASC_SALSA20 pState, LPBYTE pbKey, DWORD cbKeyLength, LPBYTE pbVector) +{ + const char * szConstants = (cbKeyLength == 32) ? szKeyConstant32 : szKeyConstant16; + DWORD KeyIndex = cbKeyLength - 0x10; + + memset(pState, 0, sizeof(CASC_SALSA20)); + pState->Key[0] = *(PDWORD)(szConstants + 0x00); + pState->Key[1] = *(PDWORD)(pbKey + 0x00); + pState->Key[2] = *(PDWORD)(pbKey + 0x04); + pState->Key[3] = *(PDWORD)(pbKey + 0x08); + pState->Key[4] = *(PDWORD)(pbKey + 0x0C); + pState->Key[5] = *(PDWORD)(szConstants + 0x04); + pState->Key[6] = *(PDWORD)(pbVector + 0x00); + pState->Key[7] = *(PDWORD)(pbVector + 0x04); + pState->Key[8] = 0; + pState->Key[9] = 0; + pState->Key[10] = *(PDWORD)(szConstants + 0x08); + pState->Key[11] = *(PDWORD)(pbKey + KeyIndex + 0x00); + pState->Key[12] = *(PDWORD)(pbKey + KeyIndex + 0x04); + pState->Key[13] = *(PDWORD)(pbKey + KeyIndex + 0x08); + pState->Key[14] = *(PDWORD)(pbKey + KeyIndex + 0x0C); + pState->Key[15] = *(PDWORD)(szConstants + 0x0C); + + pState->dwRounds = 20; +} + +static int Decrypt(PCASC_SALSA20 pState, LPBYTE pbOutBuffer, LPBYTE pbInBuffer, size_t cbInBuffer) +{ + LPBYTE pbXorValue; + DWORD KeyMirror[0x10]; + DWORD XorValue[0x10]; + DWORD BlockSize; + DWORD i; + + // Repeat until we have data to read + while(cbInBuffer > 0) + { + // Create the copy of the key + memcpy(KeyMirror, pState->Key, sizeof(KeyMirror)); + + // Shuffle the key + for(i = 0; i < pState->dwRounds; i += 2) + { + KeyMirror[0x04] ^= Rol32((KeyMirror[0x00] + KeyMirror[0x0C]), 0x07); + KeyMirror[0x08] ^= Rol32((KeyMirror[0x04] + KeyMirror[0x00]), 0x09); + KeyMirror[0x0C] ^= Rol32((KeyMirror[0x08] + KeyMirror[0x04]), 0x0D); + KeyMirror[0x00] ^= Rol32((KeyMirror[0x0C] + KeyMirror[0x08]), 0x12); + + KeyMirror[0x09] ^= Rol32((KeyMirror[0x05] + KeyMirror[0x01]), 0x07); + KeyMirror[0x0D] ^= Rol32((KeyMirror[0x09] + KeyMirror[0x05]), 0x09); + KeyMirror[0x01] ^= Rol32((KeyMirror[0x0D] + KeyMirror[0x09]), 0x0D); + KeyMirror[0x05] ^= Rol32((KeyMirror[0x01] + KeyMirror[0x0D]), 0x12); + + KeyMirror[0x0E] ^= Rol32((KeyMirror[0x0A] + KeyMirror[0x06]), 0x07); + KeyMirror[0x02] ^= Rol32((KeyMirror[0x0E] + KeyMirror[0x0A]), 0x09); + KeyMirror[0x06] ^= Rol32((KeyMirror[0x02] + KeyMirror[0x0E]), 0x0D); + KeyMirror[0x0A] ^= Rol32((KeyMirror[0x06] + KeyMirror[0x02]), 0x12); + + KeyMirror[0x03] ^= Rol32((KeyMirror[0x0F] + KeyMirror[0x0B]), 0x07); + KeyMirror[0x07] ^= Rol32((KeyMirror[0x03] + KeyMirror[0x0F]), 0x09); + KeyMirror[0x0B] ^= Rol32((KeyMirror[0x07] + KeyMirror[0x03]), 0x0D); + KeyMirror[0x0F] ^= Rol32((KeyMirror[0x0B] + KeyMirror[0x07]), 0x12); + + KeyMirror[0x01] ^= Rol32((KeyMirror[0x00] + KeyMirror[0x03]), 0x07); + KeyMirror[0x02] ^= Rol32((KeyMirror[0x01] + KeyMirror[0x00]), 0x09); + KeyMirror[0x03] ^= Rol32((KeyMirror[0x02] + KeyMirror[0x01]), 0x0D); + KeyMirror[0x00] ^= Rol32((KeyMirror[0x03] + KeyMirror[0x02]), 0x12); + + KeyMirror[0x06] ^= Rol32((KeyMirror[0x05] + KeyMirror[0x04]), 0x07); + KeyMirror[0x07] ^= Rol32((KeyMirror[0x06] + KeyMirror[0x05]), 0x09); + KeyMirror[0x04] ^= Rol32((KeyMirror[0x07] + KeyMirror[0x06]), 0x0D); + KeyMirror[0x05] ^= Rol32((KeyMirror[0x04] + KeyMirror[0x07]), 0x12); + + KeyMirror[0x0B] ^= Rol32((KeyMirror[0x0A] + KeyMirror[0x09]), 0x07); + KeyMirror[0x08] ^= Rol32((KeyMirror[0x0B] + KeyMirror[0x0A]), 0x09); + KeyMirror[0x09] ^= Rol32((KeyMirror[0x08] + KeyMirror[0x0B]), 0x0D); + KeyMirror[0x0A] ^= Rol32((KeyMirror[0x09] + KeyMirror[0x08]), 0x12); + + KeyMirror[0x0C] ^= Rol32((KeyMirror[0x0F] + KeyMirror[0x0E]), 0x07); + KeyMirror[0x0D] ^= Rol32((KeyMirror[0x0C] + KeyMirror[0x0F]), 0x09); + KeyMirror[0x0E] ^= Rol32((KeyMirror[0x0D] + KeyMirror[0x0C]), 0x0D); + KeyMirror[0x0F] ^= Rol32((KeyMirror[0x0E] + KeyMirror[0x0D]), 0x12); + } + + // Set the number of remaining bytes + pbXorValue = (LPBYTE)XorValue; + BlockSize = (DWORD)CASCLIB_MIN(cbInBuffer, 0x40); + + // Prepare the XOR constants + for(i = 0; i < 16; i++) + { + XorValue[i] = KeyMirror[i] + pState->Key[i]; + } + + // Decrypt the block + for(i = 0; i < BlockSize; i++) + { + pbOutBuffer[i] = pbInBuffer[i] ^ pbXorValue[i]; + } + + pState->Key[8] = pState->Key[8] + 1; + if(pState->Key[8] == 0) + pState->Key[9] = pState->Key[9] + 1; + + // Adjust buffers + pbOutBuffer += BlockSize; + pbInBuffer += BlockSize; + cbInBuffer -= BlockSize; + } + + return ERROR_SUCCESS; +} + +static int Decrypt_Salsa20(LPBYTE pbOutBuffer, LPBYTE pbInBuffer, size_t cbInBuffer, LPBYTE pbKey, DWORD cbKeySize, LPBYTE pbVector) +{ + CASC_SALSA20 SalsaState; + + Initialize(&SalsaState, pbKey, cbKeySize, pbVector); + return Decrypt(&SalsaState, pbOutBuffer, pbInBuffer, cbInBuffer); +} + +//----------------------------------------------------------------------------- +// Public functions + +int CascDecrypt(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer, DWORD dwFrameIndex) +{ + ULONGLONG KeyName = 0; + LPBYTE pbBufferEnd = pbInBuffer + cbInBuffer; + LPBYTE pbKey; + DWORD KeyNameSize; + DWORD dwShift = 0; + DWORD IVSize; + BYTE Vector[0x08]; + BYTE EncryptionType; + int nError; + + // Verify and retrieve the key name size + if(pbInBuffer >= pbBufferEnd) + return ERROR_FILE_CORRUPT; + if(pbInBuffer[0] != 0 && pbInBuffer[0] != 8) + return ERROR_NOT_SUPPORTED; + KeyNameSize = *pbInBuffer++; + + // Copy the key name + if((pbInBuffer + KeyNameSize) >= pbBufferEnd) + return ERROR_FILE_CORRUPT; + memcpy(&KeyName, pbInBuffer, KeyNameSize); + pbInBuffer += KeyNameSize; + + // Verify and retrieve the Vector size + if(pbInBuffer >= pbBufferEnd) + return ERROR_FILE_CORRUPT; + if(pbInBuffer[0] != 4 && pbInBuffer[0] != 8) + return ERROR_NOT_SUPPORTED; + IVSize = *pbInBuffer++; + + // Copy the initialization vector + if((pbInBuffer + IVSize) >= pbBufferEnd) + return ERROR_FILE_CORRUPT; + memset(Vector, 0, sizeof(Vector)); + memcpy(Vector, pbInBuffer, IVSize); + pbInBuffer += IVSize; + + // Verify and retrieve the encryption type + if(pbInBuffer >= pbBufferEnd) + return ERROR_FILE_CORRUPT; + if(pbInBuffer[0] != 'S' && pbInBuffer[0] != 'A') + return ERROR_NOT_SUPPORTED; + EncryptionType = *pbInBuffer++; + + // Do we have enough space in the output buffer? + if((DWORD)(pbBufferEnd - pbInBuffer) > pcbOutBuffer[0]) + return ERROR_INSUFFICIENT_BUFFER; + + // Check if we know the key + pbKey = FindCascKey(KeyName); + if(pbKey == NULL) + return ERROR_UNKNOWN_FILE_KEY; + + // Shuffle the Vector with the block index + // Note that there's no point to go beyond 32 bits, unless the file has + // more than 0xFFFFFFFF frames. + for(int i = 0; i < sizeof(dwFrameIndex); i++) + { + Vector[i] = Vector[i] ^ (BYTE)((dwFrameIndex >> dwShift) & 0xFF); + dwShift += 8; + } + + // Perform the decryption-specific action + switch(EncryptionType) + { + case 'S': // Salsa20 + nError = Decrypt_Salsa20(pbOutBuffer, pbInBuffer, (pbBufferEnd - pbInBuffer), pbKey, 0x10, Vector); + if(nError != ERROR_SUCCESS) + return nError; + + // Supply the size of the output buffer + pcbOutBuffer[0] = (DWORD)(pbBufferEnd - pbInBuffer); + return ERROR_SUCCESS; + +// case 'A': +// return ERROR_NOT_SUPPORTED; + } + + assert(false); + return ERROR_NOT_SUPPORTED; +} + +int CascDirectCopy(LPBYTE pbOutBuffer, PDWORD pcbOutBuffer, LPBYTE pbInBuffer, DWORD cbInBuffer) +{ + // Check the buffer size + if((cbInBuffer - 1) > pcbOutBuffer[0]) + return ERROR_INSUFFICIENT_BUFFER; + + // Copy the data + memcpy(pbOutBuffer, pbInBuffer, cbInBuffer); + pcbOutBuffer[0] = cbInBuffer; + return ERROR_SUCCESS; +} + diff --git a/dep/CascLib/src/CascDumpData.cpp b/dep/CascLib/src/CascDumpData.cpp index 5dc9110b6cd..3c0e385ac07 100644 --- a/dep/CascLib/src/CascDumpData.cpp +++ b/dep/CascLib/src/CascDumpData.cpp @@ -11,14 +11,14 @@ #define __CASCLIB_SELF__ #include "CascLib.h" #include "CascCommon.h" -#include "CascMndxRoot.h" +#include "CascMndx.h" -#ifdef _DEBUG // The entire file is only valid for debug purposes +#ifdef _DEBUG // The entire feature is only valid for debug purposes //----------------------------------------------------------------------------- // Forward definitions -LPBYTE VerifyLocaleBlock(PROOT_BLOCK_INFO pBlockInfo, LPBYTE pbFilePointer, LPBYTE pbFileEnd); +//LPBYTE VerifyLocaleBlock(PROOT_BLOCK_INFO pBlockInfo, LPBYTE pbFilePointer, LPBYTE pbFileEnd); //----------------------------------------------------------------------------- // Sort compare functions @@ -49,160 +49,6 @@ static int CompareIndexEntries_FilePos(const void *, const void * pvIndexEntry1, return 0; } -//----------------------------------------------------------------------------- -// Local functions - -static char * StringFromMD5(LPBYTE md5, char * szBuffer) -{ - return StringFromBinary(md5, MD5_HASH_SIZE, szBuffer); -} - -static char * FormatFileName(const char * szFormat, TCascStorage * hs) -{ - char * szFileName; - char * szSrc; - char * szTrg; - - // Create copy of the file name - szFileName = szSrc = szTrg = NewStr(szFormat, 0); - if(szFileName != NULL) - { - // Format the file name - while(szSrc[0] != 0) - { - if(szSrc[0] == '%') - { - // Replace "%build%" with a build number - if(!strncmp(szSrc, "%build%", 7)) - { - szTrg += sprintf(szTrg, "%u", hs->dwBuildNumber); - szSrc += 7; - continue; - } - } - - // Just copy the character - *szTrg++ = *szSrc++; - } - - // Terminate the target file name - szTrg[0] = 0; - } - - return szFileName; -} - -FILE * CreateDumpFile(const char * szFormat, TCascStorage * hs) -{ - FILE * fp = NULL; - char * szFileName; - - // Validate the storage handle - if(hs != NULL) - { - // Format the real file name - szFileName = FormatFileName(szFormat, hs); - if(szFileName != NULL) - { - // Create the dump file - fp = fopen(szFileName, "wt"); - CASC_FREE(szFileName); - } - } - - return fp; -} - -static void DumpIndexKey( - FILE * fp, - TCascStorage * hs, - LPBYTE pbIndexKey, - int nDumpLevel) -{ - PCASC_INDEX_ENTRY pIndexEntry; - TCascFile * hf; - QUERY_KEY QueryKey; - HANDLE hFile; - BYTE HeaderArea[MAX_HEADER_AREA_SIZE]; - char szBuffer[0x20]; - - QueryKey.pbData = pbIndexKey; - QueryKey.cbData = MD5_HASH_SIZE; - pIndexEntry = FindIndexEntry(hs, &QueryKey); - if(pIndexEntry != NULL) - { - ULONGLONG FileOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffsetBE); - DWORD ArchIndex = (DWORD)(FileOffset >> 0x1E); - DWORD FileSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE); - - // Mask the file offset - FileOffset &= 0x3FFFFFFF; - fprintf(fp, " data.%03u at 0x%08x (0x%lx bytes)\n", - ArchIndex, - (DWORD)FileOffset, - FileSize); - - if(nDumpLevel > 2) - { - QueryKey.pbData = pIndexEntry->IndexKey; - QueryKey.cbData = MD5_HASH_SIZE; - if(CascOpenFileByIndexKey((HANDLE)hs, &QueryKey, 0, &hFile)) - { - // Make sure that the data file is open and frame header loaded - CascGetFileSize(hFile, NULL); - hf = IsValidFileHandle(hFile); - assert(hf->pStream != NULL); - - // Read the header area - FileOffset = hf->HeaderOffset - BLTE_HEADER_DELTA; - FileStream_Read(hf->pStream, &FileOffset, HeaderArea, sizeof(HeaderArea)); - CascCloseFile(hFile); - - // Dump the header area - fprintf(fp, " FileSize: %X Rest: %s\n", - ConvertBytesToInteger_4_LE(&HeaderArea[0x10]), - StringFromBinary(&HeaderArea[0x14], 10, szBuffer)); - } - } - } - else - { - fprintf(fp, " NO INDEX ENTRY\n"); - } -} - -static void DumpEncodingEntry( - FILE * fp, - TCascStorage * hs, - PCASC_ENCODING_ENTRY pEncodingEntry, - int nDumpLevel) -{ - LPBYTE pbIndexKey; - char szMd5[MD5_STRING_SIZE]; - - // If the encoding key exists - if(pEncodingEntry != NULL) - { - fprintf(fp, " Size %lx Key Count: %u\n", - ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE), - pEncodingEntry->KeyCount); - - // Dump all index keys - pbIndexKey = pEncodingEntry->EncodingKey + MD5_HASH_SIZE; - for(DWORD j = 0; j < pEncodingEntry->KeyCount; j++) - { - fprintf(fp, " %s\n", StringFromMD5(pbIndexKey, szMd5)); - DumpIndexKey(fp, hs, pbIndexKey, nDumpLevel); - pbIndexKey += MD5_HASH_SIZE; - } - - } - else - { - fprintf(fp, " NO ENCODING KEYS\n"); - } -} - //----------------------------------------------------------------------------- // Public functions @@ -323,27 +169,92 @@ void CascDumpFileNames(const char * szFileName, void * pvMarFile) Struct1C.FreeStruct40(); } -void CascDumpMndxRoot(const char * szFileName, PCASC_MNDX_INFO pMndxInfo) +void CascDumpIndexEntry( + TCascStorage * /* hs */, + TDumpContext * dc, + PCASC_INDEX_ENTRY pIndexEntry, + int /* nDumpLevel */) { - PCASC_ROOT_ENTRY_MNDX pRootEntry; - FILE * fp; - char szMd5[MD5_STRING_SIZE]; + if(pIndexEntry != NULL) + { + ULONGLONG FileOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffsetBE); + DWORD ArchIndex = (DWORD)(FileOffset >> 0x1E); + DWORD FileSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE); - // Create the dump file - fp = fopen(szFileName, "wt"); - if(fp != NULL) + // Mask the file offset + FileOffset &= 0x3FFFFFFF; + dump_print(dc, " data.%03u at 0x%08x (0x%lx bytes)\n", + ArchIndex, + (DWORD)FileOffset, + FileSize); + + //if(nDumpLevel > 2) + //{ + // QueryKey.pbData = pIndexEntry->IndexKey; + // QueryKey.cbData = MD5_HASH_SIZE; + // if(CascOpenFileByIndexKey((HANDLE)hs, &QueryKey, 0, &hFile)) + // { + // // Make sure that the data file is open and frame header loaded + // CascGetFileSize(hFile, NULL); + // hf = IsValidFileHandle(hFile); + // assert(hf->pStream != NULL); + + // // Read the header area + // FileOffset = hf->HeaderOffset - BLTE_HEADER_DELTA; + // FileStream_Read(hf->pStream, &FileOffset, HeaderArea, sizeof(HeaderArea)); + // CascCloseFile(hFile); + + // // Dump the header area + // dump_print(dc, " FileSize: %X Rest: %s\n", + // ConvertBytesToInteger_4_LE(&HeaderArea[0x10]), + // StringFromBinary(&HeaderArea[0x14], 10, szBuffer)); + // } + //} + } + else { - fprintf(fp, "Indx Fl+Asset EncodingKey FileSize\n==== ======== ================================ ========\n"); - for(DWORD i = 0; i < pMndxInfo->MndxEntriesValid; i++) - { - pRootEntry = pMndxInfo->ppValidEntries[i]; + dump_print(dc, " NO INDEX ENTRY\n"); + } +} + +void CascDumpEncodingEntry( + TCascStorage * hs, + TDumpContext * dc, + PCASC_ENCODING_ENTRY pEncodingEntry, + int nDumpLevel) +{ + PCASC_INDEX_ENTRY pIndexEntry; + QUERY_KEY QueryKey; + LPBYTE pbIndexKey; + char szMd5[MD5_STRING_SIZE+1]; - fprintf(fp, "%04X %08X %s %08X\n", i, - pRootEntry->Flags, - StringFromMD5(pRootEntry->EncodingKey, szMd5), - pRootEntry->FileSize); + // If the encoding key exists + if(pEncodingEntry != NULL) + { + dump_print(dc, " Size %lx Key Count: %u\n", + ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE), + pEncodingEntry->KeyCount); + + // Dump all index keys + pbIndexKey = pEncodingEntry->EncodingKey + MD5_HASH_SIZE; + for(DWORD j = 0; j < pEncodingEntry->KeyCount; j++, pbIndexKey += MD5_HASH_SIZE) + { + // Dump the index key + dump_print(dc, " %s\n", StringFromMD5(pbIndexKey, szMd5)); + + // Dump the index entry as well + if(nDumpLevel >= DUMP_LEVEL_INDEX_ENTRIES) + { + QueryKey.pbData = pbIndexKey; + QueryKey.cbData = MD5_HASH_SIZE; + pIndexEntry = FindIndexEntry(hs, &QueryKey); + CascDumpIndexEntry(hs, dc, pIndexEntry, nDumpLevel); + } } - fclose(fp); + } + else + { + dump_print(dc, " NO ENCODING KEYS\n"); } } @@ -380,7 +291,7 @@ void CascDumpIndexEntries(const char * szFileName, TCascStorage * hs) FileSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE); ArchOffset &= 0x3FFFFFFF; - fprintf(fp, " %02X %08X %08X %s\n", ArchIndex, ArchOffset, FileSize, StringFromBinary(pIndexEntry->IndexKey, CASC_FILE_KEY_SIZE, szIndexKey)); + fprintf(fp, " %02X %08X %08X %s\n", ArchIndex, (DWORD)ArchOffset, FileSize, StringFromBinary(pIndexEntry->IndexKey, CASC_FILE_KEY_SIZE, szIndexKey)); } CASC_FREE(ppIndexEntries); @@ -390,81 +301,6 @@ void CascDumpIndexEntries(const char * szFileName, TCascStorage * hs) } } -void CascDumpRootFile( - TCascStorage * hs, - LPBYTE pbRootFile, - DWORD cbRootFile, - const char * szFormat, - const TCHAR * szListFile, - int nDumpLevel) -{ - PCASC_ENCODING_ENTRY pEncodingEntry; - ROOT_BLOCK_INFO BlockInfo; - PLISTFILE_MAP pListMap; - QUERY_KEY EncodingKey; - LPBYTE pbRootFileEnd = pbRootFile + cbRootFile; - LPBYTE pbFilePointer; - FILE * fp; - char szOneLine[0x100]; - DWORD i; - - // This function only dumps WoW-style root file - assert(*(PDWORD)pbRootFile != CASC_MNDX_SIGNATURE); - - // Create the dump file - fp = CreateDumpFile(szFormat, hs); - if(fp != NULL) - { - // Create the listfile map -// DWORD dwTickCount = GetTickCount(); - pListMap = ListFile_CreateMap(szListFile); -// dwTickCount = GetTickCount() - dwTickCount; - - // Dump the root entries as-is - for(pbFilePointer = pbRootFile; pbFilePointer <= pbRootFileEnd; ) - { - // Validate the root block - pbFilePointer = VerifyLocaleBlock(&BlockInfo, pbFilePointer, pbRootFileEnd); - if(pbFilePointer == NULL) - break; - - // Dump the locale block - fprintf(fp, "Flags: %08X Locales: %08X NumberOfFiles: %u\n" - "=========================================================\n", - BlockInfo.pLocaleBlockHdr->Flags, - BlockInfo.pLocaleBlockHdr->Locales, - BlockInfo.pLocaleBlockHdr->NumberOfFiles); - - // Dump the hashes and encoding keys - for(i = 0; i < BlockInfo.pLocaleBlockHdr->NumberOfFiles; i++) - { - // Dump the entry - fprintf(fp, "%08X %08X-%08X %s %s\n", - (DWORD)(BlockInfo.pInt32Array[i]), - (DWORD)(BlockInfo.pRootEntries[i].FileNameHash >> 0x20), - (DWORD)(BlockInfo.pRootEntries[i].FileNameHash), - StringFromMD5((LPBYTE)BlockInfo.pRootEntries[i].EncodingKey, szOneLine), - ListFile_FindName(pListMap, BlockInfo.pRootEntries[i].FileNameHash)); - - // Find the encoding entry in the encoding table - if(nDumpLevel > 1) - { - EncodingKey.pbData = (LPBYTE)BlockInfo.pRootEntries[i].EncodingKey; - EncodingKey.cbData = MD5_HASH_SIZE; - pEncodingEntry = FindEncodingEntry(hs, &EncodingKey, NULL); - DumpEncodingEntry(fp, hs, pEncodingEntry, nDumpLevel); - } - } - - // Put extra newline - fprintf(fp, "\n"); - } - - ListFile_FreeMap(pListMap); - fclose(fp); - } -} - void CascDumpFile(const char * szFileName, HANDLE hFile) { FILE * fp; diff --git a/dep/CascLib/src/CascFiles.cpp b/dep/CascLib/src/CascFiles.cpp new file mode 100644 index 00000000000..8709ea09e36 --- /dev/null +++ b/dep/CascLib/src/CascFiles.cpp @@ -0,0 +1,981 @@ +/*****************************************************************************/ +/* CascFiles.cpp Copyright (c) Ladislav Zezula 2014 */ +/*---------------------------------------------------------------------------*/ +/* Various text file parsers */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 29.04.14 1.00 Lad The first version of CascBuildCfg.cpp */ +/* 30.10.15 1.00 Lad Renamed to CascFiles.cpp */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "CascLib.h" +#include "CascCommon.h" + +//----------------------------------------------------------------------------- +// Local functions + +typedef int (*PARSEINFOFILE)(TCascStorage * hs, void * pvListFile); + +//----------------------------------------------------------------------------- +// Local structures + +struct TBuildFileInfo +{ + const TCHAR * szFileName; + CBLD_TYPE BuildFileType; +}; + +struct TGameIdString +{ + const char * szGameInfo; + size_t cchGameInfo; + DWORD dwGameInfo; +}; + +static const TBuildFileInfo BuildTypes[] = +{ + {_T(".build.info"), CascBuildInfo}, // Since HOTS build 30027, the game uses .build.info file for storage info + {_T(".build.db"), CascBuildDb}, // Older CASC storages + {NULL, CascBuildNone} +}; + +static const TCHAR * DataDirs[] = +{ + _T("SC2Data"), // Starcraft II (Legacy of the Void) build 38749 + _T("Data\\Casc"), // Overwatch + _T("Data"), // World of Warcraft, Diablo + _T("HeroesData"), // Heroes of the Storm + _T("BNTData"), // Heroes of the Storm, until build 30414 + NULL, +}; + +static const TGameIdString GameIds[] = +{ + {"Hero", 0x04, CASC_GAME_HOTS}, // Alpha build of Heroes of the Storm + {"WoW", 0x03, CASC_GAME_WOW6}, // Alpha build of World of Warcraft - Warlords of Draenor + {"Diablo3", 0x07, CASC_GAME_DIABLO3}, // Diablo III BETA 2.2.0 + {"Prometheus", 0x0A, CASC_GAME_OVERWATCH}, // Overwatch BETA since build 24919 + {"SC2", 0x03, CASC_GAME_STARCRAFT2}, // Starcraft II - Legacy of the Void + {NULL, 0, 0}, +}; + +//----------------------------------------------------------------------------- +// Local functions + +static bool inline IsValueSeparator(const char * szVarValue) +{ + return ((0 <= szVarValue[0] && szVarValue[0] <= 0x20) || (szVarValue[0] == '|')); +} + +static bool IsCharDigit(BYTE OneByte) +{ + return ('0' <= OneByte && OneByte <= '9'); +} + +static DWORD GetLocaleMask(const char * szTag) +{ + if(!strcmp(szTag, "enUS")) + return CASC_LOCALE_ENUS; + + if(!strcmp(szTag, "koKR")) + return CASC_LOCALE_KOKR; + + if(!strcmp(szTag, "frFR")) + return CASC_LOCALE_FRFR; + + if(!strcmp(szTag, "deDE")) + return CASC_LOCALE_DEDE; + + if(!strcmp(szTag, "zhCN")) + return CASC_LOCALE_ZHCN; + + if(!strcmp(szTag, "esES")) + return CASC_LOCALE_ESES; + + if(!strcmp(szTag, "zhTW")) + return CASC_LOCALE_ZHTW; + + if(!strcmp(szTag, "enGB")) + return CASC_LOCALE_ENGB; + + if(!strcmp(szTag, "enCN")) + return CASC_LOCALE_ENCN; + + if(!strcmp(szTag, "enTW")) + return CASC_LOCALE_ENTW; + + if(!strcmp(szTag, "esMX")) + return CASC_LOCALE_ESMX; + + if(!strcmp(szTag, "ruRU")) + return CASC_LOCALE_RURU; + + if(!strcmp(szTag, "ptBR")) + return CASC_LOCALE_PTBR; + + if(!strcmp(szTag, "itIT")) + return CASC_LOCALE_ITIT; + + if(!strcmp(szTag, "ptPT")) + return CASC_LOCALE_PTPT; + + return 0; +} + +static bool IsInfoVariable(const char * szLineBegin, const char * szLineEnd, const char * szVarName, const char * szVarType) +{ + size_t nLength; + + // Check the variable name + nLength = strlen(szVarName); + if((size_t)(szLineEnd - szLineBegin) > nLength) + { + // Check the variable name + if(!_strnicmp(szLineBegin, szVarName, nLength)) + { + // Skip variable name and the exclamation mark + szLineBegin += nLength; + if(szLineBegin < szLineEnd && szLineBegin[0] == '!') + { + // Skip the exclamation mark + szLineBegin++; + + // Check the variable type + nLength = strlen(szVarType); + if((size_t)(szLineEnd - szLineBegin) > nLength) + { + // Check the variable name + if(!_strnicmp(szLineBegin, szVarType, nLength)) + { + // Skip variable type and the doublecolon + szLineBegin += nLength; + return (szLineBegin < szLineEnd && szLineBegin[0] == ':'); + } + } + } + } + } + + return false; +} + +static const char * SkipInfoVariable(const char * szLineBegin, const char * szLineEnd) +{ + while(szLineBegin < szLineEnd) + { + if(szLineBegin[0] == '|') + return szLineBegin + 1; + + szLineBegin++; + } + + return NULL; +} + +static TCHAR * CheckForIndexDirectory(TCascStorage * hs, const TCHAR * szSubDir) +{ + TCHAR * szIndexPath; + + // Cpmbine the index path + szIndexPath = CombinePath(hs->szDataPath, szSubDir); + if(DirectoryExists(szIndexPath)) + { + hs->szIndexPath = szIndexPath; + return hs->szIndexPath; + } + + CASC_FREE(szIndexPath); + return NULL; +} + +TCHAR * AppendBlobText(TCHAR * szBuffer, LPBYTE pbData, DWORD cbData, TCHAR chSeparator) +{ + // Put the separator, if any + if(chSeparator != 0) + *szBuffer++ = chSeparator; + + // Copy the blob data as text + for(DWORD i = 0; i < cbData; i++) + { + *szBuffer++ = IntToHexChar[pbData[0] >> 0x04]; + *szBuffer++ = IntToHexChar[pbData[0] & 0x0F]; + pbData++; + } + + // Terminate the string + *szBuffer = 0; + + // Return new buffer position + return szBuffer; +} + +static const char * CheckLineVariable(const char * szLineBegin, const char * szLineEnd, const char * szVarName) +{ + size_t nLineLength = (size_t)(szLineEnd - szLineBegin); + size_t nNameLength = strlen(szVarName); + + // If the line longer than the variable name? + if(nLineLength > nNameLength) + { + if(!_strnicmp((const char *)szLineBegin, szVarName, nNameLength)) + { + // Skip the variable name + szLineBegin += nNameLength; + + // Skip the separator(s) + while(szLineBegin < szLineEnd && IsValueSeparator(szLineBegin)) + szLineBegin++; + + // Check if there is "=" + if(szLineBegin >= szLineEnd || szLineBegin[0] != '=') + return NULL; + szLineBegin++; + + // Skip the separator(s) + while(szLineBegin < szLineEnd && IsValueSeparator(szLineBegin)) + szLineBegin++; + + // Check if there is "=" + if(szLineBegin >= szLineEnd) + return NULL; + + // Return the begin of the variable + return szLineBegin; + } + } + + return NULL; +} + +static int LoadInfoVariable(PQUERY_KEY pVarBlob, const char * szLineBegin, const char * szLineEnd, bool bHexaValue) +{ + const char * szLinePtr = szLineBegin; + + // Sanity checks + assert(pVarBlob->pbData == NULL); + assert(pVarBlob->cbData == 0); + + // Check length of the variable + while(szLinePtr < szLineEnd && szLinePtr[0] != '|') + szLinePtr++; + + // Allocate space for the blob + if(bHexaValue) + { + // Initialize the blob + pVarBlob->pbData = CASC_ALLOC(BYTE, (szLinePtr - szLineBegin) / 2); + pVarBlob->cbData = (DWORD)((szLinePtr - szLineBegin) / 2); + return ConvertStringToBinary(szLineBegin, (size_t)(szLinePtr - szLineBegin), pVarBlob->pbData); + } + + // Initialize the blob + pVarBlob->pbData = CASC_ALLOC(BYTE, (szLinePtr - szLineBegin) + 1); + pVarBlob->cbData = (DWORD)(szLinePtr - szLineBegin); + + // Check for success + if(pVarBlob->pbData == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Copy the string + memcpy(pVarBlob->pbData, szLineBegin, pVarBlob->cbData); + pVarBlob->pbData[pVarBlob->cbData] = 0; + return ERROR_SUCCESS; +} + +static void AppendConfigFilePath(TCHAR * szFileName, PQUERY_KEY pFileKey) +{ + size_t nLength = _tcslen(szFileName); + + // If there is no slash, append if + if(nLength > 0 && szFileName[nLength - 1] != '\\' && szFileName[nLength - 1] != '/') + szFileName[nLength++] = _T('/'); + + // Get to the end of the file name + szFileName = szFileName + nLength; + + // Append the "config" directory + _tcscpy(szFileName, _T("config")); + szFileName += 6; + + // Append the first level directory + szFileName = AppendBlobText(szFileName, pFileKey->pbData, 1, _T('/')); + szFileName = AppendBlobText(szFileName, pFileKey->pbData + 1, 1, _T('/')); + szFileName = AppendBlobText(szFileName, pFileKey->pbData, pFileKey->cbData, _T('/')); +} + +static DWORD GetBlobCount(const char * szLineBegin, const char * szLineEnd) +{ + DWORD dwBlobCount = 0; + + // Until we find an end of the line + while(szLineBegin < szLineEnd) + { + // Skip the blob + while(szLineBegin < szLineEnd && IsValueSeparator(szLineBegin) == false) + szLineBegin++; + + // Increment the number of blobs + dwBlobCount++; + + // Skip the separator + while(szLineBegin < szLineEnd && IsValueSeparator(szLineBegin)) + szLineBegin++; + } + + return dwBlobCount; +} + +static int LoadBlobArray( + PQUERY_KEY pBlob, + const char * szLineBegin, + const char * szLineEnd, + DWORD dwMaxBlobs) +{ + LPBYTE pbBufferEnd = pBlob->pbData + pBlob->cbData; + LPBYTE pbBuffer = pBlob->pbData; + int nError = ERROR_SUCCESS; + + // Sanity check + assert(pBlob->pbData != NULL); + assert(pBlob->cbData != 0); + + // Until we find an end of the line + while(szLineBegin < szLineEnd && dwMaxBlobs > 0) + { + const char * szBlobEnd = szLineBegin; + + // Find the end of the text blob + while(szBlobEnd < szLineEnd && IsValueSeparator(szBlobEnd) == false) + szBlobEnd++; + + // Verify the length of the found blob + if((szBlobEnd - szLineBegin) != MD5_STRING_SIZE) + return ERROR_BAD_FORMAT; + + // Verify if there is enough space in the buffer + if((pbBufferEnd - pbBuffer) < MD5_HASH_SIZE) + return ERROR_NOT_ENOUGH_MEMORY; + + // Perform the conversion + nError = ConvertStringToBinary(szLineBegin, MD5_STRING_SIZE, pbBuffer); + if(nError != ERROR_SUCCESS) + return nError; + + // Move pointers + pbBuffer += MD5_HASH_SIZE; + dwMaxBlobs--; + + // Skip the separator + while(szBlobEnd < szLineEnd && IsValueSeparator(szBlobEnd)) + szBlobEnd++; + szLineBegin = szBlobEnd; + } + + return nError; +} + +static int LoadMultipleBlobs(PQUERY_KEY pBlob, const char * szLineBegin, const char * szLineEnd, DWORD dwBlobCount) +{ + size_t nLength = (szLineEnd - szLineBegin); + + // We expect each blob to have length of the encoding key and one space between + if(nLength > (dwBlobCount * MD5_STRING_SIZE) + ((dwBlobCount - 1) * sizeof(char))) + return ERROR_INVALID_PARAMETER; + + // Allocate the blob buffer + pBlob->pbData = CASC_ALLOC(BYTE, dwBlobCount * MD5_HASH_SIZE); + if(pBlob->pbData == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Set the buffer size and load the blob array + pBlob->cbData = dwBlobCount * MD5_HASH_SIZE; + return LoadBlobArray(pBlob, szLineBegin, szLineEnd, dwBlobCount); +} + +static int LoadMultipleBlobs(PQUERY_KEY pBlob, const char * szLineBegin, const char * szLineEnd) +{ + return LoadMultipleBlobs(pBlob, szLineBegin, szLineEnd, GetBlobCount(szLineBegin, szLineEnd)); +} + +static int LoadSingleBlob(PQUERY_KEY pBlob, const char * szLineBegin, const char * szLineEnd) +{ + return LoadMultipleBlobs(pBlob, szLineBegin, szLineEnd, 1); +} + +static int GetGameType(TCascStorage * hs, const char * szVarBegin, const char * szLineEnd) +{ + // Go through all games that we support + for(size_t i = 0; GameIds[i].szGameInfo != NULL; i++) + { + // Check the length of the variable + if((size_t)(szLineEnd - szVarBegin) == GameIds[i].cchGameInfo) + { + // Check the string + if(!_strnicmp(szVarBegin, GameIds[i].szGameInfo, GameIds[i].cchGameInfo)) + { + hs->dwGameInfo = GameIds[i].dwGameInfo; + return ERROR_SUCCESS; + } + } + } + + // Unknown/unsupported game + assert(false); + return ERROR_BAD_FORMAT; +} + +// "B29049" +// "WOW-18125patch6.0.1" +// "30013_Win32_2_2_0_Ptr_ptr" +// "prometheus-0_8_0_0-24919" +static int GetBuildNumber(TCascStorage * hs, const char * szVarBegin, const char * szLineEnd) +{ + DWORD dwBuildNumber = 0; + + // Skip all non-digit characters + while(szVarBegin < szLineEnd) + { + // There must be at least three digits (build 99 anyone?) + if(IsCharDigit(szVarBegin[0]) && IsCharDigit(szVarBegin[1]) && IsCharDigit(szVarBegin[2])) + { + // Convert the build number string to value + while(szVarBegin < szLineEnd && IsCharDigit(szVarBegin[0])) + dwBuildNumber = (dwBuildNumber * 10) + (*szVarBegin++ - '0'); + break; + } + + // Move to the next + szVarBegin++; + } + + assert(dwBuildNumber != 0); + hs->dwBuildNumber = dwBuildNumber; + return (dwBuildNumber != 0) ? ERROR_SUCCESS : ERROR_BAD_FORMAT; +} + +static int GetDefaultLocaleMask(TCascStorage * hs, PQUERY_KEY pTagsString) +{ + char * szTagEnd = (char *)pTagsString->pbData + pTagsString->cbData; + char * szTagPtr = (char *)pTagsString->pbData; + char * szNext; + DWORD dwLocaleMask = 0; + + while(szTagPtr < szTagEnd) + { + // Get the next part + szNext = strchr(szTagPtr, ' '); + if(szNext != NULL) + *szNext++ = 0; + + // Check whether the current tag is a language identifier + dwLocaleMask = dwLocaleMask | GetLocaleMask(szTagPtr); + + // Get the next part + if(szNext == NULL) + break; + + // Skip spaces + while(szNext < szTagEnd && szNext[0] == ' ') + szNext++; + szTagPtr = szNext; + } + + hs->dwDefaultLocale = dwLocaleMask; + return ERROR_SUCCESS; +} + +static void * FetchAndVerifyConfigFile(TCascStorage * hs, PQUERY_KEY pFileKey) +{ + TCHAR * szFileName; + void * pvListFile = NULL; + + // Construct the local file name + szFileName = CascNewStr(hs->szDataPath, 8 + 3 + 3 + 32); + if(szFileName != NULL) + { + // Add the part where the config file path is + AppendConfigFilePath(szFileName, pFileKey); + + // Load and verify the external listfile + pvListFile = ListFile_OpenExternal(szFileName); + if(pvListFile != NULL) + { + if(!ListFile_VerifyMD5(pvListFile, pFileKey->pbData)) + { + ListFile_Free(pvListFile); + pvListFile = NULL; + } + } + + // Free the file name + CASC_FREE(szFileName); + } + + return pvListFile; +} + +static int ParseFile_BuildInfo(TCascStorage * hs, void * pvListFile) +{ + QUERY_KEY Active = {NULL, 0}; + QUERY_KEY TagString = {NULL, 0}; + QUERY_KEY CdnHost = {NULL, 0}; + QUERY_KEY CdnPath = {NULL, 0}; + char szOneLine1[0x200]; + char szOneLine2[0x200]; + size_t nLength1; + size_t nLength2; + int nError = ERROR_BAD_FORMAT; + + // Extract the first line, cotaining the headers + nLength1 = ListFile_GetNextLine(pvListFile, szOneLine1, _maxchars(szOneLine1)); + if(nLength1 == 0) + return ERROR_BAD_FORMAT; + + // Now parse the second and the next lines. We are looking for line + // with "Active" set to 1 + for(;;) + { + const char * szLinePtr1 = szOneLine1; + const char * szLineEnd1 = szOneLine1 + nLength1; + const char * szLinePtr2 = szOneLine2; + const char * szLineEnd2; + + // Read the next line + nLength2 = ListFile_GetNextLine(pvListFile, szOneLine2, _maxchars(szOneLine2)); + if(nLength2 == 0) + break; + szLineEnd2 = szLinePtr2 + nLength2; + + // Parse all variables + while(szLinePtr1 < szLineEnd1) + { + // Check for variables we need + if(IsInfoVariable(szLinePtr1, szLineEnd1, "Active", "DEC")) + LoadInfoVariable(&Active, szLinePtr2, szLineEnd2, false); + if(IsInfoVariable(szLinePtr1, szLineEnd1, "Build Key", "HEX")) + LoadInfoVariable(&hs->CdnBuildKey, szLinePtr2, szLineEnd2, true); + if(IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Key", "HEX")) + LoadInfoVariable(&hs->CdnConfigKey, szLinePtr2, szLineEnd2, true); + if(IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Hosts", "STRING")) + LoadInfoVariable(&CdnHost, szLinePtr2, szLineEnd2, false); + if(IsInfoVariable(szLinePtr1, szLineEnd1, "CDN Path", "STRING")) + LoadInfoVariable(&CdnPath, szLinePtr2, szLineEnd2, false); + if(IsInfoVariable(szLinePtr1, szLineEnd1, "Tags", "STRING")) + LoadInfoVariable(&TagString, szLinePtr2, szLineEnd2, false); + + // Move both line pointers + szLinePtr1 = SkipInfoVariable(szLinePtr1, szLineEnd1); + if(szLinePtr1 == NULL) + break; + + szLinePtr2 = SkipInfoVariable(szLinePtr2, szLineEnd2); + if(szLinePtr2 == NULL) + break; + } + + // Stop parsing if found active config + if(Active.pbData != NULL && *Active.pbData == '1') + break; + + // Free the blobs + FreeCascBlob(&Active); + FreeCascBlob(&hs->CdnBuildKey); + FreeCascBlob(&hs->CdnConfigKey); + FreeCascBlob(&CdnHost); + FreeCascBlob(&CdnPath); + FreeCascBlob(&TagString); + } + + // All four must be present + if(hs->CdnBuildKey.pbData != NULL && + hs->CdnConfigKey.pbData != NULL && + CdnHost.pbData != NULL && + CdnPath.pbData != NULL) + { + // Merge the CDN host and CDN path + hs->szUrlPath = CASC_ALLOC(TCHAR, CdnHost.cbData + CdnPath.cbData + 1); + if(hs->szUrlPath != NULL) + { + CopyString(hs->szUrlPath, (char *)CdnHost.pbData, CdnHost.cbData); + CopyString(hs->szUrlPath + CdnHost.cbData, (char *)CdnPath.pbData, CdnPath.cbData); + nError = ERROR_SUCCESS; + } + } + + // If we found tags, we can extract language build from it + if(TagString.pbData != NULL) + GetDefaultLocaleMask(hs, &TagString); + + FreeCascBlob(&CdnHost); + FreeCascBlob(&CdnPath); + FreeCascBlob(&TagString); + FreeCascBlob(&Active); + return nError; +} + +static int ParseFile_BuildDb(TCascStorage * hs, void * pvListFile) +{ + const char * szLinePtr; + const char * szLineEnd; + char szOneLine[0x200]; + size_t nLength; + int nError; + + // Load the single line from the text file + nLength = ListFile_GetNextLine(pvListFile, szOneLine, _maxchars(szOneLine)); + if(nLength == 0) + return ERROR_BAD_FORMAT; + + // Set the line range + szLinePtr = szOneLine; + szLineEnd = szOneLine + nLength; + + // Extract the CDN build key + nError = LoadInfoVariable(&hs->CdnBuildKey, szLinePtr, szLineEnd, true); + if(nError == ERROR_SUCCESS) + { + // Skip the variable + szLinePtr = SkipInfoVariable(szLinePtr, szLineEnd); + + // Load the CDN config hash + nError = LoadInfoVariable(&hs->CdnConfigKey, szLinePtr, szLineEnd, true); + if(nError == ERROR_SUCCESS) + { + // Skip the variable + szLinePtr = SkipInfoVariable(szLinePtr, szLineEnd); + + // Skip the Locale/OS/code variable + szLinePtr = SkipInfoVariable(szLinePtr, szLineEnd); + + // Load the URL + hs->szUrlPath = CascNewStrFromAnsi(szLinePtr, szLineEnd); + if(hs->szUrlPath == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + } + + // Verify all variables + if(hs->CdnBuildKey.pbData == NULL || hs->CdnConfigKey.pbData == NULL || hs->szUrlPath == NULL) + nError = ERROR_BAD_FORMAT; + return nError; +} + +static int LoadCdnConfigFile(TCascStorage * hs, void * pvListFile) +{ + const char * szLineBegin; + const char * szVarBegin; + const char * szLineEnd; + int nError = ERROR_SUCCESS; + + // Keep parsing the listfile while there is something in there + for(;;) + { + // Get the next line + if(!ListFile_GetNextLine(pvListFile, &szLineBegin, &szLineEnd)) + break; + + // Archive group + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "archive-group"); + if(szVarBegin != NULL) + { + nError = LoadSingleBlob(&hs->ArchivesGroup, szVarBegin, szLineEnd); + continue; + } + + // Archives + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "archives"); + if(szVarBegin != NULL) + { + nError = LoadMultipleBlobs(&hs->ArchivesKey, szVarBegin, szLineEnd); + continue; + } + + // Patch archive group + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "patch-archive-group"); + if(szVarBegin != NULL) + { + LoadSingleBlob(&hs->PatchArchivesKey, szVarBegin, szLineEnd); + continue; + } + + // Patch archives + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "patch-archives"); + if(szVarBegin != NULL) + { + nError = LoadMultipleBlobs(&hs->PatchArchivesKey, szVarBegin, szLineEnd); + continue; + } + } + + // Check if all required fields are present + if(hs->ArchivesKey.pbData == NULL || hs->ArchivesKey.cbData == 0) + return ERROR_BAD_FORMAT; + + return nError; +} + +static int LoadCdnBuildFile(TCascStorage * hs, void * pvListFile) +{ + const char * szLineBegin; + const char * szVarBegin; + const char * szLineEnd = NULL; + int nError = ERROR_SUCCESS; + + for(;;) + { + // Get the next line + if(!ListFile_GetNextLine(pvListFile, &szLineBegin, &szLineEnd)) + break; + + // Game name + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "build-product"); + if(szVarBegin != NULL) + { + GetGameType(hs, szVarBegin, szLineEnd); + continue; + } + + // Game build number + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "build-name"); + if(szVarBegin != NULL) + { + GetBuildNumber(hs, szVarBegin, szLineEnd); + continue; + } + + // Root + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "root"); + if(szVarBegin != NULL) + { + LoadSingleBlob(&hs->RootKey, szVarBegin, szLineEnd); + continue; + } + + // Patch + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "patch"); + if(szVarBegin != NULL) + { + LoadSingleBlob(&hs->PatchKey, szVarBegin, szLineEnd); + continue; + } + + // Download + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "download"); + if(szVarBegin != NULL) + { + LoadSingleBlob(&hs->DownloadKey, szVarBegin, szLineEnd); + continue; + } + + // Install + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "install"); + if(szVarBegin != NULL) + { + LoadSingleBlob(&hs->InstallKey, szVarBegin, szLineEnd); + continue; + } + + // Encoding keys + szVarBegin = CheckLineVariable(szLineBegin, szLineEnd, "encoding"); + if(szVarBegin != NULL) + { + nError = LoadMultipleBlobs(&hs->EncodingKey, szVarBegin, szLineEnd, 2); + continue; + } + } + + // Check the encoding keys + if(hs->EncodingKey.pbData == NULL || hs->EncodingKey.cbData != MD5_HASH_SIZE * 2) + return ERROR_BAD_FORMAT; + return nError; +} + +static int CheckDataDirectory(TCascStorage * hs, TCHAR * szDirectory) +{ + TCHAR * szDataPath; + int nError = ERROR_FILE_NOT_FOUND; + + // Try all known subdirectories + for(size_t i = 0; DataDirs[i] != NULL; i++) + { + // Create the eventual data path + szDataPath = CombinePath(szDirectory, DataDirs[i]); + if(szDataPath != NULL) + { + // Does that directory exist? + if(DirectoryExists(szDataPath)) + { + hs->szDataPath = szDataPath; + return ERROR_SUCCESS; + } + + // Free the data path + CASC_FREE(szDataPath); + } + } + + return nError; +} + + +//----------------------------------------------------------------------------- +// Public functions + +int LoadBuildInfo(TCascStorage * hs) +{ + PARSEINFOFILE PfnParseProc = NULL; + void * pvListFile; + int nError = ERROR_SUCCESS; + + switch(hs->BuildFileType) + { + case CascBuildInfo: + PfnParseProc = ParseFile_BuildInfo; + break; + + case CascBuildDb: + PfnParseProc = ParseFile_BuildDb; + break; + + default: + nError = ERROR_NOT_SUPPORTED; + break; + } + + // Parse the appropriate build file + if(nError == ERROR_SUCCESS) + { + pvListFile = ListFile_OpenExternal(hs->szBuildFile); + if(pvListFile != NULL) + { + // Parse the info file + nError = PfnParseProc(hs, pvListFile); + ListFile_Free(pvListFile); + } + else + nError = ERROR_FILE_NOT_FOUND; + } + + // If the .build.info OR .build.db file has been loaded, + // proceed with loading the CDN config file and CDN build file + if(nError == ERROR_SUCCESS) + { + // Load the configuration file + pvListFile = FetchAndVerifyConfigFile(hs, &hs->CdnConfigKey); + if(pvListFile != NULL) + { + nError = LoadCdnConfigFile(hs, pvListFile); + ListFile_Free(pvListFile); + } + else + nError = ERROR_FILE_NOT_FOUND; + } + + // Load the build file + if(nError == ERROR_SUCCESS) + { + pvListFile = FetchAndVerifyConfigFile(hs, &hs->CdnBuildKey); + if(pvListFile != NULL) + { + nError = LoadCdnBuildFile(hs, pvListFile); + ListFile_Free(pvListFile); + } + else + nError = ERROR_FILE_NOT_FOUND; + } + + // Fill the index directory + if(nError == ERROR_SUCCESS) + { + // First, check for more common "data" subdirectory + if((hs->szIndexPath = CheckForIndexDirectory(hs, _T("data"))) != NULL) + return ERROR_SUCCESS; + + // Second, try the "darch" subdirectory (older builds of HOTS - Alpha) + if((hs->szIndexPath = CheckForIndexDirectory(hs, _T("darch"))) != NULL) + return ERROR_SUCCESS; + + nError = ERROR_FILE_NOT_FOUND; + } + + return nError; +} + +// Checks whether there is a ".agent.db". If yes, the function +// sets "szRootPath" and "szDataPath" in the storage structure +// and returns ERROR_SUCCESS +int CheckGameDirectory(TCascStorage * hs, TCHAR * szDirectory) +{ + TFileStream * pStream; + TCHAR * szBuildFile; + int nError = ERROR_FILE_NOT_FOUND; + + // Try to find any of the root files used in the history + for(size_t i = 0; BuildTypes[i].szFileName != NULL; i++) + { + // Create the full name of the .agent.db file + szBuildFile = CombinePath(szDirectory, BuildTypes[i].szFileName); + if(szBuildFile != NULL) + { + // Attempt to open the file + pStream = FileStream_OpenFile(szBuildFile, 0); + if(pStream != NULL) + { + // Free the stream + FileStream_Close(pStream); + + // Check for the data directory + nError = CheckDataDirectory(hs, szDirectory); + if(nError == ERROR_SUCCESS) + { + hs->szBuildFile = szBuildFile; + hs->BuildFileType = BuildTypes[i].BuildFileType; + return ERROR_SUCCESS; + } + } + + CASC_FREE(szBuildFile); + } + } + + return nError; +} + +// Parses single line from Overwatch. +// The line structure is: "#MD5|CHUNK_ID|FILENAME|INSTALLPATH" +// The line has all preceding spaces removed +int ParseRootFileLine(const char * szLinePtr, const char * szLineEnd, PQUERY_KEY PtrEncodingKey, char * szFileName, size_t nMaxChars) +{ + size_t nLength; + int nError; + + // Check the MD5 (aka encoding key) + if(szLinePtr[MD5_STRING_SIZE] != '|') + return ERROR_BAD_FORMAT; + + // Convert the encoding key to binary + PtrEncodingKey->cbData = MD5_HASH_SIZE; + nError = ConvertStringToBinary(szLinePtr, MD5_STRING_SIZE, PtrEncodingKey->pbData); + if(nError != ERROR_SUCCESS) + return nError; + + // Skip the MD5 + szLinePtr += MD5_STRING_SIZE+1; + + // Skip the chunk ID + szLinePtr = SkipInfoVariable(szLinePtr, szLineEnd); + + // Get the archived file name + szLineEnd = SkipInfoVariable(szLinePtr, szLineEnd); + nLength = (size_t)(szLineEnd - szLinePtr - 1); + + // Get the file name + if(nLength > nMaxChars) + return ERROR_INSUFFICIENT_BUFFER; + + memcpy(szFileName, szLinePtr, nLength); + szFileName[nLength] = 0; + return ERROR_SUCCESS; +} diff --git a/dep/CascLib/src/CascFindFile.cpp b/dep/CascLib/src/CascFindFile.cpp index 0bfe16cae1d..bea2e308747 100644 --- a/dep/CascLib/src/CascFindFile.cpp +++ b/dep/CascLib/src/CascFindFile.cpp @@ -11,7 +11,6 @@ #define __CASCLIB_SELF__ #include "CascLib.h" #include "CascCommon.h" -#include "CascMndxRoot.h" //----------------------------------------------------------------------------- // Local functions @@ -30,16 +29,22 @@ static void FreeSearchHandle(TCascSearch * pSearch) // Close (dereference) the archive handle if(pSearch->hs != NULL) + { + // Give root handler chance to free their stuff + RootHandler_EndSearch(pSearch->hs->pRootHandler, pSearch); + + // Dereference the storage handle CascCloseStorage((HANDLE)pSearch->hs); - pSearch->hs = NULL; + pSearch->hs = NULL; + } // Free the file cache and frame array if(pSearch->szMask != NULL) CASC_FREE(pSearch->szMask); if(pSearch->szListFile != NULL) CASC_FREE(pSearch->szListFile); - if(pSearch->pStruct1C != NULL) - delete pSearch->pStruct1C; +// if(pSearch->pStruct1C != NULL) +// delete pSearch->pStruct1C; if(pSearch->pCache != NULL) ListFile_Free(pSearch->pCache); @@ -47,58 +52,6 @@ static void FreeSearchHandle(TCascSearch * pSearch) pSearch->szClassName = NULL; CASC_FREE(pSearch); } -/* -DWORD dwRootEntries = 0; -DWORD dwEncoEntries = 0; -DWORD dwIndexEntries = 0; -*/ -static bool VerifyRootEntry(TCascSearch * pSearch, PCASC_ROOT_ENTRY pRootEntry, PCASC_FIND_DATA pFindData, size_t nRootIndex) -{ - PCASC_ENCODING_ENTRY pEncodingEntry; - PCASC_INDEX_ENTRY pIndexEntry; - TCascStorage * hs = pSearch->hs; - QUERY_KEY QueryKey; - DWORD dwByteIndex = (DWORD)(nRootIndex / 0x08); - DWORD dwBitIndex = (DWORD)(nRootIndex & 0x07); - - // First of all, check if that entry has been reported before - // If the bit is set, then the file has already been reported - // by a previous search iteration - if(pSearch->BitArray[dwByteIndex] & (1 << dwBitIndex)) - return false; - pSearch->BitArray[dwByteIndex] |= (1 << dwBitIndex); - - // Increment the number of root entries -// dwRootEntries++; - - // Now try to find that encoding key in the array of encoding keys - QueryKey.pbData = (LPBYTE)pRootEntry->EncodingKey; - QueryKey.cbData = MD5_HASH_SIZE; - pEncodingEntry = FindEncodingEntry(hs, &QueryKey, NULL); - if(pEncodingEntry == NULL) - return false; - -// dwEncoEntries++; - - // Now try to find the index entry. Note that we take the first key - QueryKey.pbData = pEncodingEntry->EncodingKey + MD5_HASH_SIZE; - QueryKey.cbData = MD5_HASH_SIZE; - pIndexEntry = FindIndexEntry(hs, &QueryKey); - if(pIndexEntry == NULL) - return false; - -// dwIndexEntries++; - - // Fill the name hash and the MD5 - memcpy(pFindData->EncodingKey, pRootEntry->EncodingKey, MD5_HASH_SIZE); - pFindData->FileNameHash = pRootEntry->FileNameHash; - pFindData->dwPackageIndex = 0; - pFindData->dwLocaleFlags = pRootEntry->Locales; - - // Fill-in the file size - pFindData->dwFileSize = ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE); - return true; -} static TCascSearch * AllocateSearchHandle(TCascStorage * hs, const TCHAR * szListFile, const char * szMask) { @@ -106,7 +59,7 @@ static TCascSearch * AllocateSearchHandle(TCascStorage * hs, const TCHAR * szLis size_t cbToAllocate; // When using the MNDX info, do not allocate the extra bit array - cbToAllocate = sizeof(TCascSearch) + ((hs->pMndxInfo == NULL) ? (hs->RootTable.TableSize / 8) : 0); + cbToAllocate = sizeof(TCascSearch) + ((hs->pEncodingMap->TableSize + 7) / 8); pSearch = (TCascSearch *)CASC_ALLOC(BYTE, cbToAllocate); if(pSearch != NULL) { @@ -125,7 +78,7 @@ static TCascSearch * AllocateSearchHandle(TCascStorage * hs, const TCHAR * szLis // Save the other variables if(szListFile != NULL) { - pSearch->szListFile = NewStr(szListFile, 0); + pSearch->szListFile = CascNewStr(szListFile, 0); if(pSearch->szListFile == NULL) { FreeSearchHandle(pSearch); @@ -134,7 +87,7 @@ static TCascSearch * AllocateSearchHandle(TCascStorage * hs, const TCHAR * szLis } // Allocate the search mask - pSearch->szMask = NewStr(szMask, 0); + pSearch->szMask = CascNewStr(szMask, 0); if(pSearch->szMask == NULL) { FreeSearchHandle(pSearch); @@ -145,64 +98,106 @@ static TCascSearch * AllocateSearchHandle(TCascStorage * hs, const TCHAR * szLis return pSearch; } -static bool DoStorageSearch_ListFile(TCascSearch * pSearch, PCASC_FIND_DATA pFindData) +// Perform searching using root-specific provider. +// The provider may need the listfile +static bool DoStorageSearch_RootFile(TCascSearch * pSearch, PCASC_FIND_DATA pFindData) { - PCASC_ROOT_ENTRY pRootEntry; - TCascStorage * hs = pSearch->hs; - char szFileName2[MAX_PATH + 1]; - DWORD TableIndex = 0; - - // Get next file from the listfile - while(ListFile_GetNext(pSearch->pCache, pSearch->szMask, pSearch->szFileName, MAX_PATH)) + PCASC_ENCODING_ENTRY pEncodingEntry; + PCASC_INDEX_ENTRY pIndexEntry; + QUERY_KEY EncodingKey; + QUERY_KEY IndexKey; + LPBYTE pbEncodingKey; + DWORD EncodingIndex = 0; + DWORD LocaleFlags = 0; + DWORD FileSize = CASC_INVALID_SIZE; + DWORD ByteIndex; + DWORD BitMask; + + for(;;) { -#ifdef _DEBUG -// if(!_stricmp(pSearch->szFileName, "Character\\BloodElf\\Female\\DeathKnightEyeGlow.blp")) -// DebugBreak(); -#endif - - // Normalize the file name found in the list file - NormalizeFileName_UpperBkSlash(szFileName2, pSearch->szFileName, MAX_PATH); - - // Find the root entry - pRootEntry = FindRootEntry(hs, szFileName2, &TableIndex); - if(pRootEntry != NULL) + // Attempt to find (the next) file from the root entry + pbEncodingKey = RootHandler_Search(pSearch->hs->pRootHandler, pSearch, &FileSize, &LocaleFlags); + if(pbEncodingKey == NULL) + return false; + + // Verify whether the encoding key exists in the encoding table + EncodingKey.pbData = pbEncodingKey; + EncodingKey.cbData = MD5_HASH_SIZE; + pEncodingEntry = FindEncodingEntry(pSearch->hs, &EncodingKey, &EncodingIndex); + if(pEncodingEntry != NULL) { - // Verify whether the file exists in the storage - if(VerifyRootEntry(pSearch, pRootEntry, pFindData, TableIndex)) - { - strcpy(pFindData->szFileName, pSearch->szFileName); - pFindData->szPlainName = (char *)GetPlainFileName(pFindData->szFileName); - return true; - } + // Mark the item as already found + // Note: Duplicate items are allowed while we are searching using file names + // Do not exclude items from search if they were found before + ByteIndex = (DWORD)(EncodingIndex / 8); + BitMask = 1 << (EncodingIndex & 0x07); + pSearch->BitArray[ByteIndex] |= BitMask; + + // Locate the index entry + IndexKey.pbData = GET_INDEX_KEY(pEncodingEntry); + IndexKey.cbData = MD5_HASH_SIZE; + pIndexEntry = FindIndexEntry(pSearch->hs, &IndexKey); + if(pIndexEntry == NULL) + continue; + + // If we retrieved the file size directly from the root provider, use it + // Otherwise, we need to retrieve it from the encoding entry + if(FileSize == CASC_INVALID_SIZE) + FileSize = ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE); + + // Fill-in the found file + strcpy(pFindData->szFileName, pSearch->szFileName); + memcpy(pFindData->EncodingKey, pEncodingEntry->EncodingKey, MD5_HASH_SIZE); + pFindData->szPlainName = (char *)GetPlainFileName(pFindData->szFileName); + pFindData->dwLocaleFlags = LocaleFlags; + pFindData->dwFileSize = FileSize; + return true; } } - - // Listfile search ended - return false; } -static bool DoStorageSearch_Hash(TCascSearch * pSearch, PCASC_FIND_DATA pFindData) +static bool DoStorageSearch_EncodingKey(TCascSearch * pSearch, PCASC_FIND_DATA pFindData) { - PCASC_ROOT_ENTRY pRootEntry; + PCASC_ENCODING_ENTRY pEncodingEntry; + PCASC_INDEX_ENTRY pIndexEntry; TCascStorage * hs = pSearch->hs; + QUERY_KEY IndexKey; + DWORD ByteIndex; + DWORD BitMask; - // Check if there is more files with the same name hash - while(pSearch->RootIndex < hs->RootTable.TableSize) + // Check for encoding keys that haven't been found yet + while(pSearch->IndexLevel1 < hs->pEncodingMap->TableSize) { - // Get the pointer to the root entry - pRootEntry = hs->RootTable.TablePtr + pSearch->RootIndex; - - // Verify if that root entry exists in the CASC storage - // and was not found before - if(VerifyRootEntry(pSearch, pRootEntry, pFindData, pSearch->RootIndex)) + // Check if that entry has been reported before + ByteIndex = (DWORD)(pSearch->IndexLevel1 / 8); + BitMask = 1 << (pSearch->IndexLevel1 & 0x07); + if((pSearch->BitArray[ByteIndex] & BitMask) == 0) { - pFindData->szFileName[0] = 0; - pFindData->szPlainName = NULL; - return true; + // Locate the index entry + pEncodingEntry = (PCASC_ENCODING_ENTRY)hs->pEncodingMap->HashTable[pSearch->IndexLevel1]; + if(pEncodingEntry != NULL) + { + IndexKey.pbData = GET_INDEX_KEY(pEncodingEntry); + IndexKey.cbData = MD5_HASH_SIZE; + pIndexEntry = FindIndexEntry(pSearch->hs, &IndexKey); + if(pIndexEntry != NULL) + { + // Fill-in the found file + memcpy(pFindData->EncodingKey, pEncodingEntry->EncodingKey, MD5_HASH_SIZE); + pFindData->szFileName[0] = 0; + pFindData->szPlainName = NULL; + pFindData->dwLocaleFlags = CASC_LOCALE_NONE; + pFindData->dwFileSize = ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE); + + // Mark the entry as already-found + pSearch->BitArray[ByteIndex] |= BitMask; + return true; + } + } } - // Move to the next entry - pSearch->RootIndex++; + // Go to the next encoding entry + pSearch->IndexLevel1++; } // Nameless search ended @@ -211,10 +206,6 @@ static bool DoStorageSearch_Hash(TCascSearch * pSearch, PCASC_FIND_DATA pFindDat static bool DoStorageSearch(TCascSearch * pSearch, PCASC_FIND_DATA pFindData) { - // Are we searching using the MNDX ? - if(pSearch->hs->pMndxInfo != NULL) - return DoStorageSearch_MNDX(pSearch, pFindData); - // State 0: No search done yet if(pSearch->dwState == 0) { @@ -223,30 +214,25 @@ static bool DoStorageSearch(TCascSearch * pSearch, PCASC_FIND_DATA pFindData) pSearch->pCache = ListFile_OpenExternal(pSearch->szListFile); // Move the search phase to the listfile searching - pSearch->RootIndex = 0; + pSearch->IndexLevel1 = 0; pSearch->dwState++; - - // If either file stream or listfile cache are invalid, - // move to the next phase - if(pSearch->pCache == NULL) - pSearch->dwState++; } // State 1: Searching the list file if(pSearch->dwState == 1) { - if(DoStorageSearch_ListFile(pSearch, pFindData)) + if(DoStorageSearch_RootFile(pSearch, pFindData)) return true; // Move to the nameless search state - assert(pSearch->RootIndex == 0); + pSearch->IndexLevel1 = 0; pSearch->dwState++; } // State 2: Searching the remaining entries if(pSearch->dwState == 2) { - if(DoStorageSearch_Hash(pSearch, pFindData)) + if(DoStorageSearch_EncodingKey(pSearch, pFindData)) return true; // Move to the final search state @@ -275,19 +261,12 @@ HANDLE WINAPI CascFindFirstFile( if(szMask == NULL || pFindData == NULL) nError = ERROR_INVALID_PARAMETER; - // Allocate the structure for archive search + // Init the search structure and search handle if(nError == ERROR_SUCCESS) { // Clear the entire search structure memset(pFindData, 0, sizeof(CASC_FIND_DATA)); - // We must have listfile for non-MNDX storages - if(hs->pMndxInfo == NULL && szListFile == NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - return NULL; - } - // Allocate the search handle pSearch = AllocateSearchHandle(hs, szListFile, szMask); if(pSearch == NULL) diff --git a/dep/CascLib/src/CascLib.def b/dep/CascLib/src/CascLib.def new file mode 100644 index 00000000000..cb5f9166e49 --- /dev/null +++ b/dep/CascLib/src/CascLib.def @@ -0,0 +1,29 @@ +; +; Export file for Windows +; Copyright (c) 2015 Ladislav Zezula +; ladik@zezula.net +; + +LIBRARY CascLib.dll + +EXPORTS + + CascOpenStorage + CascGetStorageInfo + CascCloseStorage + + CascOpenFileByIndexKey + CascOpenFileByEncodingKey + CascOpenFile + CascGetFileSize + CascSetFilePointer + CascReadFile + CascCloseFile + + CascFindFirstFile + CascFindNextFile + CascFindClose + + GetLastError=Kernel32.GetLastError + SetLastError=Kernel32.SetLastError + \ No newline at end of file diff --git a/dep/CascLib/src/CascLib.h b/dep/CascLib/src/CascLib.h index 330a4b2bb49..bad32eb2dba 100644 --- a/dep/CascLib/src/CascLib.h +++ b/dep/CascLib/src/CascLib.h @@ -39,7 +39,7 @@ extern "C" { #define CASC_STOR_XXXXX 0x00000001 // Not used // Values for CascOpenFile -#define CASC_FILE_XXXXX 0x00000001 // Not used +#define CASC_OPEN_BY_ENCODING_KEY 0x00000001 // The name is just the encoding key; skip ROOT file processing // Flags for file stream #define BASE_PROVIDER_FILE 0x00000000 // Base data source is a file @@ -103,7 +103,7 @@ extern "C" { #ifndef MD5_HASH_SIZE #define MD5_HASH_SIZE 0x10 -#define MD5_STRING_SIZE 0x21 +#define MD5_STRING_SIZE 0x20 #endif #ifndef SHA1_DIGEST_SIZE @@ -146,9 +146,7 @@ typedef struct _CASC_FIND_DATA { char szFileName[MAX_PATH]; // Full name of the found file char * szPlainName; // Plain name of the found file - ULONGLONG FileNameHash; // File name hash BYTE EncodingKey[MD5_HASH_SIZE]; // Encoding key - DWORD dwPackageIndex; // File package index (HOTS only) DWORD dwLocaleFlags; // Locale flags (WoW only) DWORD dwFileSize; // Size of the file @@ -184,6 +182,16 @@ HANDLE WINAPI CascFindFirstFile(HANDLE hStorage, const char * szMask, PCASC_FIND bool WINAPI CascFindNextFile(HANDLE hFind, PCASC_FIND_DATA pFindData); bool WINAPI CascFindClose(HANDLE hFind); +//----------------------------------------------------------------------------- +// GetLastError/SetLastError support for non-Windows platform + +#ifndef PLATFORM_WINDOWS + +int GetLastError(); +void SetLastError(int nError); + +#endif // PLATFORM_WINDOWS + #ifdef __cplusplus } // extern "C" #endif diff --git a/dep/CascLib/src/CascMndx.h b/dep/CascLib/src/CascMndx.h new file mode 100644 index 00000000000..d1b6653d4fe --- /dev/null +++ b/dep/CascLib/src/CascMndx.h @@ -0,0 +1,359 @@ +/*****************************************************************************/ +/* CascMndxRoot.h Copyright (c) Ladislav Zezula 2014 */ +/*---------------------------------------------------------------------------*/ +/* Interface file for MNDX structures */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 15.05.14 1.00 Lad Created */ +/*****************************************************************************/ + +#ifndef __CASC_MNDX_ROOT__ +#define __CASC_MNDX_ROOT__ + +class TFileNameDatabase; + +#define CASC_MAX_MAR_FILES 3 // Maximum of 3 MAR files are supported +#define CASC_MNDX_SIGNATURE 0x58444E4D // 'MNDX' + +#define CASC_MAX_ENTRIES(type) (0xFFFFFFFF / sizeof(type)) + +#define CASC_SEARCH_INITIALIZING 0 +#define CASC_SEARCH_SEARCHING 2 +#define CASC_SEARCH_FINISHED 4 + +typedef struct _TRIPLET +{ + DWORD BaseValue; + DWORD Value2; + DWORD Value3; +} TRIPLET, *PTRIPLET; + +typedef struct _NAME_FRAG +{ + DWORD ItemIndex; // Back index to various tables + DWORD NextIndex; // The following item index + DWORD FragOffs; // Higher 24 bits are 0xFFFFFF00 --> A single matching character + // Otherwise --> Offset to the name fragment table +} NAME_FRAG, *PNAME_FRAG; + +typedef struct _PATH_STOP +{ + DWORD ItemIndex; + DWORD field_4; + DWORD field_8; + DWORD field_C; + DWORD field_10; +} PATH_STOP, *PPATH_STOP; + +typedef union _ARRAY_POINTER +{ + LPBYTE Bytes; // Pointer to an octet + char * Chars; // Pointer to a character + PDWORD Uint32s; // Pointer to a DWORD + PTRIPLET Triplets; // Pointer to TRIPLET + PNAME_FRAG NameFrags; // Pointer to name fragment entry + PPATH_STOP PathStopPtr; // Pointer to path checkpoint + PULONGLONG Int64Ptr; // Pointer to 64-bit integer + +} ARRAY_POINTER, *PARRAY_POINTER; + +// Simple access to various tables within TGenericArray +#define ByteArray ArrayPointer.Bytes +#define CharArray ArrayPointer.Chars +#define Uint32Array ArrayPointer.Uint32s +#define TripletArray ArrayPointer.Triplets +#define NameFragArray ArrayPointer.NameFrags + +class TByteStream +{ + public: + + TByteStream(); + + void ExchangeWith(TByteStream & Target); + int GetBytes(DWORD cbByteCount, PARRAY_POINTER PtrArray); + int SkipBytes(DWORD cbByteCount); + int SetByteBuffer(LPBYTE pbNewMarData, DWORD cbNewMarData); + int GetValue_DWORD(DWORD & Value); + int GetValue_ItemCount(DWORD & NumberOfBytes, DWORD & ItemCount, DWORD ItemSize); + int GetArray_DWORDs(PARRAY_POINTER PtrArray, DWORD ItemCount); + int GetArray_Triplets(PARRAY_POINTER PtrArray, DWORD ItemCount); + int GetArray_NameTable(PARRAY_POINTER PtrArray, DWORD ItemCount); + int GetArray_BYTES(PARRAY_POINTER PtrArray, DWORD ItemCount); + + LPBYTE pbByteData; + void * pvMappedFile; + DWORD cbByteData; + DWORD field_C; + HANDLE hFile; + HANDLE hMap; +}; + +class TGenericArray +{ + public: + + TGenericArray(); + ~TGenericArray(); + + int SetArrayValid(); + + void ExchangeWith(TGenericArray & Target); + void CopyFrom(TGenericArray & Source); + + void SetMaxItems_CHARS(DWORD NewMaxItemCount); + void SetMaxItems_PATH_STOP(DWORD NewMaxItemCount); + + void InsertOneItem_CHAR(char OneChar); + void InsertOneItem_PATH_STOP(PATH_STOP & NewItem); + + void sub_19583A0(DWORD NewItemCount); + + int LoadDwordsArray(TByteStream & InStream); + int LoadTripletsArray(TByteStream & InStream); + int LoadByteArray(TByteStream & InStream); + int LoadFragmentInfos(TByteStream & InStream); + int LoadStrings(TByteStream & InStream); + + int LoadDwordsArray_Copy(TByteStream & InStream); + int LoadTripletsArray_Copy(TByteStream & InStream); + int LoadBytes_Copy(TByteStream & InStream); + int LoadFragmentInfos_Copy(TByteStream & InStream); + int LoadStringsWithCopy(TByteStream & InStream); + + ARRAY_POINTER DataBuffer; + ARRAY_POINTER FirstValid; + + ARRAY_POINTER ArrayPointer; + DWORD ItemCount; // Number of items in the array + DWORD MaxItemCount; // Capacity of the array + bool bIsValidArray; +}; + +class TBitEntryArray : public TGenericArray +{ + public: + + TBitEntryArray(); + ~TBitEntryArray(); + + DWORD GetBitEntry(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 = (Uint32Array[dwItemIndex + 1] << (0x20 - dwStartBit)) | (Uint32Array[dwItemIndex] >> dwStartBit); + } + else + { + dwResult = Uint32Array[dwItemIndex] >> dwStartBit; + } + + // Now we also need to mask the result by the bit mask + return dwResult & EntryBitMask; + } + + void ExchangeWith(TBitEntryArray & Target); + int LoadFromStream(TByteStream & InStream); + int LoadFromStream_Exchange(TByteStream & InStream); + + DWORD BitsPerEntry; + DWORD EntryBitMask; + DWORD TotalEntries; +}; + +class TStruct40 +{ + public: + + TStruct40(); + + void InitSearchBuffers(); + + TGenericArray array_00; + TGenericArray PathStops; // Array of path checkpoints + DWORD ItemIndex; // Current name fragment: Index to various tables + DWORD CharIndex; + DWORD ItemCount; + DWORD SearchPhase; // 0 = initializing, 2 = searching, 4 = finished +}; + +class TMndxFindResult +{ + public: + + TMndxFindResult(); + ~TMndxFindResult(); + + int CreateStruct40(); + void FreeStruct40(); + + int SetSearchPath(const char * szNewSearchPath, size_t cchNewSearchPath); + + const char * szSearchMask; // Search mask without wioldcards + size_t cchSearchMask; // Length of the search mask + DWORD field_8; + const char * szFoundPath; // Found path name + size_t cchFoundPath; // Length of the found path name + DWORD FileNameIndex; // Index of the file name + TStruct40 * pStruct40; +}; + +class TSparseArray +{ + public: + + TSparseArray(); + + void ExchangeWith(TSparseArray & TargetObject); + int LoadFromStream(TByteStream & InStream); + int LoadFromStream_Exchange(TByteStream & InStream); + + // Returns true if the item at n-th position is present + DWORD IsItemPresent(DWORD ItemIndex) + { + return (ItemBits.Uint32Array[ItemIndex >> 0x05] & (1 << (ItemIndex & 0x1F))); + } + + DWORD GetItemValue(DWORD ItemIndex); + + TGenericArray ItemBits; // Bit array for each item (1 = item is present) + DWORD TotalItemCount; // Total number of items in the array + DWORD ValidItemCount; // Number of present items in the array + TGenericArray BaseValues; // Array of base values for item indexes >= 0x200 + TGenericArray ArrayDwords_38; + TGenericArray ArrayDwords_50; +}; + +class TNameIndexStruct +{ + public: + + TNameIndexStruct(); + ~TNameIndexStruct(); + + bool CheckNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs); + bool CheckAndCopyNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs); + void CopyNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs); + + void ExchangeWith(TNameIndexStruct & Target); + int LoadFromStream(TByteStream & InStream); + int LoadFromStream_Exchange(TByteStream & InStream); + + TGenericArray NameFragments; + TSparseArray Struct68; +}; + +class TStruct10 +{ + public: + + TStruct10(); + + void CopyFrom(TStruct10 & Target); + int sub_1956FD0(DWORD dwBitMask); + int sub_1957050(DWORD dwBitMask); + int sub_19572E0(DWORD dwBitMask); + int sub_1957800(DWORD dwBitMask); + + DWORD field_0; + DWORD field_4; + DWORD field_8; + DWORD field_C; +}; + +class TFileNameDatabasePtr +{ + public: + + TFileNameDatabasePtr(); + ~TFileNameDatabasePtr(); + + int FindFileInDatabase(TMndxFindResult * pStruct1C); + int sub_1956CE0(TMndxFindResult * pStruct1C, bool * pbFindResult); + + int GetFileNameCount(PDWORD PtrFileNameCount); + int CreateDatabase(LPBYTE pbMarData, DWORD cbMarData); + int SetDatabase(TFileNameDatabase * pNewDB); + + TFileNameDatabase * pDB; +}; + +class TFileNameDatabase +{ + public: + + TFileNameDatabase(); + + void ExchangeWith(TFileNameDatabase & Target); + int LoadFromStream(TByteStream & InStream); + int LoadFromStream_Exchange(TByteStream & InStream); + + DWORD sub_1959CB0(DWORD dwHashValue); + DWORD sub_1959F50(DWORD arg_0); + + // Retrieves the name fragment distance + // HOTS: 19573D0/inlined + DWORD GetNameFragmentOffsetEx(DWORD LoBitsIndex, DWORD HiBitsIndex) + { + return (FrgmDist_HiBits.GetBitEntry(HiBitsIndex) << 0x08) | FrgmDist_LoBits.ByteArray[LoBitsIndex]; + } + + // HOTS: 1957350, inlined + DWORD GetNameFragmentOffset(DWORD LoBitsIndex) + { + return GetNameFragmentOffsetEx(LoBitsIndex, Struct68_D0.GetItemValue(LoBitsIndex)); + } + + bool sub_1957B80(TMndxFindResult * pStruct1C, DWORD dwKey); + bool CheckNextPathFragment(TMndxFindResult * pStruct1C); + bool FindFileInDatabase(TMndxFindResult * pStruct1C); + + void sub_1958D70(TMndxFindResult * pStruct1C, DWORD arg_4); + bool sub_1959010(TMndxFindResult * pStruct1C, DWORD arg_4); + bool sub_1958B00(TMndxFindResult * pStruct1C); + bool sub_1959460(TMndxFindResult * pStruct1C); + + TSparseArray Struct68_00; + TSparseArray FileNameIndexes; // Array of file name indexes + TSparseArray Struct68_D0; + + // This pair of arrays serves for fast conversion from name hash to fragment offset + TGenericArray FrgmDist_LoBits; // Array of lower 8 bits of name fragment offset + TBitEntryArray FrgmDist_HiBits; // Array of upper x bits of name fragment offset + + TNameIndexStruct IndexStruct_174; + TFileNameDatabasePtr NextDB; + + TGenericArray NameFragTable; + + DWORD NameFragIndexMask; + DWORD field_214; + TStruct10 Struct10; + TByteStream MarStream; +}; + +typedef struct _MAR_FILE +{ + TFileNameDatabasePtr * pDatabasePtr; + LPBYTE pbMarData; + DWORD cbMarData; +} MAR_FILE, *PMAR_FILE; + +//----------------------------------------------------------------------------- +// Macros + +// Returns nonzero if the name fragment match is a single-char match +inline bool IS_SINGLE_CHAR_MATCH(TGenericArray & Table, DWORD ItemIndex) +{ + return ((Table.NameFragArray[ItemIndex].FragOffs & 0xFFFFFF00) == 0xFFFFFF00); +} + +#endif // __CASC_MNDX_ROOT__ diff --git a/dep/CascLib/src/CascMndxRoot.cpp b/dep/CascLib/src/CascMndxRoot.cpp deleted file mode 100644 index 328afee8ba5..00000000000 --- a/dep/CascLib/src/CascMndxRoot.cpp +++ /dev/null @@ -1,3498 +0,0 @@ -/*****************************************************************************/ -/* CascMndxRoot.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 CascMndxRoot.cpp */ -/*****************************************************************************/ - -#define __CASCLIB_SELF__ -#include "CascLib.h" -#include "CascCommon.h" -#include "CascMndxRoot.h" - -//----------------------------------------------------------------------------- -// Local defines - -#define CASC_MAR_SIGNATURE 0x0052414d // 'MAR\0' - -//----------------------------------------------------------------------------- -// Local structures - -typedef struct _FILE_MNDX_HEADER -{ - DWORD Signature; // 'MNDX' - DWORD HeaderVersion; // Must be <= 2 - DWORD FormatVersion; - -} FILE_MNDX_HEADER, *PFILE_MNDX_HEADER; - -typedef struct _FILE_MAR_INFO -{ - DWORD MarIndex; - DWORD MarDataSize; - DWORD MarDataSizeHi; - DWORD MarDataOffset; - DWORD MarDataOffsetHi; -} FILE_MAR_INFO, *PFILE_MAR_INFO; - -//----------------------------------------------------------------------------- -// Testing functions prototypes - -#if defined(_DEBUG) && defined(_X86_) && defined(CASCLIB_TEST) -extern "C" bool _cdecl sub_1958B00_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C); -void TestMndxRootFile(PCASC_MNDX_INFO pMndxInfo); -#endif - -//----------------------------------------------------------------------------- -// 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 -DWORD GetNumberOfSetBits(DWORD Value32) -{ - Value32 = ((Value32 >> 1) & 0x55555555) + (Value32 & 0x55555555); - Value32 = ((Value32 >> 2) & 0x33333333) + (Value32 & 0x33333333); - Value32 = ((Value32 >> 4) & 0x0F0F0F0F) + (Value32 & 0x0F0F0F0F); - - return (Value32 * 0x01010101); -} - -#define GetNumbrOfSetBits32(x) (GetNumberOfSetBits(x) >> 0x18) - -//----------------------------------------------------------------------------- -// Local functions - common - -static bool RootFileRead(LPBYTE pbFilePointer, LPBYTE pbFileEnd, void * pvBuffer, size_t dwBytesToRead) -{ - // False if the file pointer is beyond the end - if(pbFilePointer > pbFileEnd) - return false; - - // False if there is not enough bytes available - if((size_t)(pbFileEnd - pbFilePointer) < dwBytesToRead) - return false; - - memcpy(pvBuffer, pbFilePointer, dwBytesToRead); - return true; -} - -//----------------------------------------------------------------------------- -// Local functions - TMndxFindResult - -// HOTS: 01956EE0 -TMndxFindResult::TMndxFindResult() -{ - szSearchMask = NULL; - cchSearchMask = 0; - field_8 = 0; - szFoundPath = NULL; - cchFoundPath = 0; - FileNameIndex = 0; - pStruct40 = NULL; -} - -// HOTS: 01956F00 -TMndxFindResult::~TMndxFindResult() -{ - FreeStruct40(); -} - -// HOTS: 01956F30 -int TMndxFindResult::CreateStruct40() -{ - if(pStruct40 != NULL) - return ERROR_INVALID_PARAMETER; - - pStruct40 = new TStruct40(); - return (pStruct40 != NULL) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY; -} - -void TMndxFindResult::FreeStruct40() -{ - if(pStruct40 != NULL) - delete pStruct40; - pStruct40 = NULL; -} - -// HOTS: 01956E70 -int TMndxFindResult::SetSearchPath( - const char * szNewSearchMask, - size_t cchNewSearchMask) -{ - if(szSearchMask == NULL && cchSearchMask != 0) - return ERROR_INVALID_PARAMETER; - - if(pStruct40 != NULL) - pStruct40->SearchPhase = CASC_SEARCH_INITIALIZING; - - szSearchMask = szNewSearchMask; - cchSearchMask = cchNewSearchMask; - return ERROR_SUCCESS; -} - -//----------------------------------------------------------------------------- -// TByteStream functions - -// HOTS: 01959990 -TByteStream::TByteStream() -{ - pbByteData = NULL; - pvMappedFile = NULL; - cbByteData = 0; - field_C = 0; - hFile = 0; - hMap = 0; -} - -// HOTS: 19599F0 -void TByteStream::ExchangeWith(TByteStream & Target) -{ - TByteStream WorkBuff; - - WorkBuff = *this; - *this = Target; - Target = WorkBuff; -} - -// HOTS: 19599F0 -int TByteStream::GetBytes(DWORD cbByteCount, PARRAY_POINTER PtrArray) -{ - if(cbByteData < cbByteCount) - return ERROR_BAD_FORMAT; - - // Give the buffer to the caller - PtrArray->Bytes = pbByteData; - - // Move pointers - pbByteData += cbByteCount; - cbByteData -= cbByteCount; - return ERROR_SUCCESS; -} - -// HOTS: 1957190 -int TByteStream::GetArray_DWORDs(PARRAY_POINTER PtrArray, DWORD ItemCount) -{ - if(PtrArray == NULL && ItemCount != 0) - return ERROR_INVALID_PARAMETER; - if(ItemCount > CASC_MAX_ENTRIES(DWORD)) - return ERROR_NOT_ENOUGH_MEMORY; - - return GetBytes(ItemCount * 4, PtrArray); -} - -// HOTS: 19571E0 -int TByteStream::GetArray_Triplets(PARRAY_POINTER PtrArray, DWORD ItemCount) -{ - if(PtrArray == NULL && ItemCount != 0) - return ERROR_INVALID_PARAMETER; - if(ItemCount > CASC_MAX_ENTRIES(TRIPLET)) - return ERROR_NOT_ENOUGH_MEMORY; - - return GetBytes(ItemCount * sizeof(TRIPLET), PtrArray); -} - -// HOTS: 1957230 -int TByteStream::GetArray_BYTES(PARRAY_POINTER PtrArray, DWORD ItemCount) -{ - if(PtrArray == NULL && ItemCount != 0) - return ERROR_INVALID_PARAMETER; - if(ItemCount > CASC_MAX_ENTRIES(BYTE)) - return ERROR_NOT_ENOUGH_MEMORY; - - return GetBytes(ItemCount, PtrArray); -} - -// HOTS: 1957280 -int TByteStream::GetArray_NameTable(PARRAY_POINTER PtrArray, DWORD ItemCount) -{ - if(PtrArray == NULL && ItemCount != 0) - return ERROR_INVALID_PARAMETER; - if(ItemCount > CASC_MAX_ENTRIES(NAME_FRAG)) - return ERROR_NOT_ENOUGH_MEMORY; - - return GetBytes(ItemCount * sizeof(NAME_FRAG), PtrArray); -} - -// HOTS: 1959A60 -int TByteStream::SkipBytes(DWORD cbByteCount) -{ - ARRAY_POINTER Dummy; - - return GetBytes(cbByteCount, &Dummy); -} - -// HOTS: 1959AF0 -int TByteStream::SetByteBuffer(LPBYTE pbNewByteData, DWORD cbNewByteData) -{ - if(pbNewByteData != NULL || cbNewByteData == 0) - { - pbByteData = pbNewByteData; - cbByteData = cbNewByteData; - return ERROR_SUCCESS; - } - - return ERROR_INVALID_PARAMETER; -} - - -// HOTS: 1957160 -int TByteStream::GetValue_DWORD(DWORD & Value) -{ - ARRAY_POINTER Pointer; - int nError; - - nError = GetBytes(sizeof(DWORD), &Pointer); - if(nError != ERROR_SUCCESS) - return nError; - - Value = Pointer.Uint32s[0]; - return ERROR_SUCCESS; -} - -int TByteStream::GetValue_ItemCount(DWORD & NumberOfBytes, DWORD & ItemCount, DWORD ItemSize) -{ - ARRAY_POINTER Pointer; - ULONGLONG ByteCount; - int nError; - - // Verify if there is at least - 8 bytes - nError = GetBytes(sizeof(ULONGLONG), &Pointer); - if(nError != ERROR_SUCCESS) - return nError; - - // Extract the number of bytes - ByteCount = Pointer.Int64Ptr[0]; - if(ByteCount > 0xFFFFFFFF || (ByteCount % ItemSize) != 0) - return ERROR_BAD_FORMAT; - - // Give the result to the caller - NumberOfBytes = (DWORD)ByteCount; - ItemCount = (DWORD)(ByteCount / ItemSize); - return ERROR_SUCCESS; -} - -//----------------------------------------------------------------------------- -// TGenericArray functions - -TGenericArray::TGenericArray() -{ - DataBuffer.Bytes = NULL; - FirstValid.Bytes = NULL; - ArrayPointer.Bytes = NULL; - ItemCount = 0; - MaxItemCount = 0; - bIsValidArray = false; -} - -TGenericArray::~TGenericArray() -{ - if(DataBuffer.Bytes != NULL) - CASC_FREE(DataBuffer.Bytes); -} - -// HOTS: inlined -void TGenericArray::ExchangeWith(TGenericArray & Target) -{ - TGenericArray WorkBuff; - - WorkBuff = *this; - *this = Target; - Target = WorkBuff; -} - -// HOTS: Inlined -void TGenericArray::CopyFrom(TGenericArray & Source) -{ - if(DataBuffer.Bytes != NULL) - CASC_FREE(DataBuffer.Bytes); - *this = Source; -} - -// HOTS: 1957090 (SetDwordsValid) -// HOTS: 19570B0 (SetTripletsValid) -// HOTS: 19570D0 (? SetBitsValid ?) -// HOTS: 19570F0 (SetNameFragmentsValid) -int TGenericArray::SetArrayValid() -{ - if(bIsValidArray != 0) - return 1; - - bIsValidArray = true; - return ERROR_SUCCESS; -} - - -// HOTS: 19575A0 -void TGenericArray::SetMaxItems_CHARS(DWORD NewMaxItemCount) -{ - ARRAY_POINTER OldDataBuffer = DataBuffer; - ARRAY_POINTER NewDataBuffer; - - // Allocate new data buffer - NewDataBuffer.Chars = CASC_ALLOC(char, NewMaxItemCount); - if(NewDataBuffer.Chars != NULL) - { - // Copy the old items to the buffer - for(DWORD i = 0; i < ItemCount; i++) - { - NewDataBuffer.Chars[i] = FirstValid.Chars[i]; - } - } - - DataBuffer = NewDataBuffer; - FirstValid = NewDataBuffer; - ArrayPointer = NewDataBuffer; - MaxItemCount = NewMaxItemCount; - CASC_FREE(OldDataBuffer.Chars); -} - -// HOTS: 1957600 -void TGenericArray::SetMaxItems_PATH_STOP(DWORD NewMaxItemCount) -{ - ARRAY_POINTER OldDataBuffer = DataBuffer; - ARRAY_POINTER NewDataBuffer; - - // Allocate new data buffer - NewDataBuffer.PathStopPtr = CASC_ALLOC(PATH_STOP, NewMaxItemCount); - if(NewDataBuffer.PathStopPtr != NULL) - { - // Copy the old items to the buffer - for(DWORD i = 0; i < ItemCount; i++) - { - NewDataBuffer.PathStopPtr[i] = FirstValid.PathStopPtr[i]; - } - } - - DataBuffer = NewDataBuffer; - FirstValid = NewDataBuffer; - ArrayPointer = NewDataBuffer; - MaxItemCount = NewMaxItemCount; - CASC_FREE(OldDataBuffer.PathStopPtr); -} - -// HOTS: inline -void TGenericArray::InsertOneItem_CHAR(char NewItem) -{ - DWORD NewMaxItemCount; - DWORD NewItemCount; - - NewItemCount = ItemCount + 1; - if(NewItemCount > MaxItemCount) - { - NewMaxItemCount = NewItemCount; - - if(MaxItemCount > (NewItemCount / 2)) - { - if(MaxItemCount <= (CASC_MAX_ENTRIES(BYTE) / 2)) - NewMaxItemCount = MaxItemCount + MaxItemCount; - else - NewMaxItemCount = CASC_MAX_ENTRIES(BYTE); - } - - SetMaxItems_CHARS(NewMaxItemCount); - } - - // Put the character to the slot that has been reserved - FirstValid.Chars[ItemCount++] = NewItem; -} - -// HOTS: 1958330, inline -void TGenericArray::InsertOneItem_PATH_STOP(PATH_STOP & NewItem) -{ - DWORD NewMaxItemCount; - DWORD NewItemCount; - - NewItemCount = ItemCount + 1; - if(NewItemCount > MaxItemCount) - { - NewMaxItemCount = NewItemCount; - - if(MaxItemCount > (NewItemCount / 2)) - { - if(MaxItemCount <= (CASC_MAX_ENTRIES(PATH_STOP) / 2)) - NewMaxItemCount = MaxItemCount + MaxItemCount; - else - NewMaxItemCount = CASC_MAX_ENTRIES(PATH_STOP); - } - - SetMaxItems_PATH_STOP(NewMaxItemCount); - } - - // Put the structure to the slot that has been reserved - FirstValid.PathStopPtr[ItemCount++] = NewItem; -} - -// HOTS: 19583A0 -void TGenericArray::sub_19583A0(DWORD NewItemCount) -{ - DWORD OldMaxItemCount = MaxItemCount; - - if(NewItemCount > MaxItemCount) - { - DWORD NewMaxItemCount = NewItemCount; - - if(MaxItemCount > (NewItemCount / 2)) - { - if(MaxItemCount <= (CASC_MAX_ENTRIES(PATH_STOP) / 2)) - NewMaxItemCount = MaxItemCount + MaxItemCount; - else - NewMaxItemCount = CASC_MAX_ENTRIES(PATH_STOP); - } - - SetMaxItems_PATH_STOP(NewMaxItemCount); - } - - // Initialize the newly inserted items - for(DWORD i = OldMaxItemCount; i < NewItemCount; i++) - { - FirstValid.PathStopPtr[i].ItemIndex = 0; - FirstValid.PathStopPtr[i].field_4 = 0; - FirstValid.PathStopPtr[i].field_8 = 0; - FirstValid.PathStopPtr[i].field_C = 0xFFFFFFFF; - FirstValid.PathStopPtr[i].field_10 = 0xFFFFFFFF; - } - - ItemCount = NewItemCount; -} - -// HOTS: 1957440 -int TGenericArray::LoadDwordsArray(TByteStream & InStream) -{ - DWORD NumberOfBytes; - int nError; - - // Get and verify the number of items - nError = InStream.GetValue_ItemCount(NumberOfBytes, ItemCount, sizeof(DWORD)); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.GetArray_DWORDs(&ArrayPointer, ItemCount); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07); - if(nError != ERROR_SUCCESS) - return nError; - - return SetArrayValid(); -} - -// HOTS: 19574E0 -int TGenericArray::LoadTripletsArray(TByteStream & InStream) -{ - DWORD NumberOfBytes; - int nError; - - // Get and verify the number of items - nError = InStream.GetValue_ItemCount(NumberOfBytes, ItemCount, sizeof(TRIPLET)); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.GetArray_Triplets(&ArrayPointer, ItemCount); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07); - if(nError != ERROR_SUCCESS) - return nError; - - return SetArrayValid(); -} - -// HOTS: 1957690 -int TGenericArray::LoadByteArray(TByteStream & InStream) -{ - DWORD NumberOfBytes; - int nError; - - // Get and verify the number of items - nError = InStream.GetValue_ItemCount(NumberOfBytes, ItemCount, sizeof(BYTE)); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.GetArray_BYTES(&ArrayPointer, ItemCount); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07); - if(nError != ERROR_SUCCESS) - return nError; - - return SetArrayValid(); -} - -// HOTS: 1957700 -int TGenericArray::LoadFragmentInfos(TByteStream & InStream) -{ - DWORD NumberOfBytes; - int nError; - - // Get and verify the number of items - nError = InStream.GetValue_ItemCount(NumberOfBytes, ItemCount, sizeof(NAME_FRAG)); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.GetArray_NameTable(&ArrayPointer, ItemCount); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07); - if(nError != ERROR_SUCCESS) - return nError; - - return SetArrayValid(); -} - -// HOTS: 195A220 -int TGenericArray::LoadStrings(TByteStream & InStream) -{ - DWORD NumberOfBytes; - int nError; - - // Get and verify the number of items - nError = InStream.GetValue_ItemCount(NumberOfBytes, ItemCount, sizeof(char)); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.GetArray_BYTES(&ArrayPointer, ItemCount); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07); - if(nError != ERROR_SUCCESS) - return nError; - - return SetArrayValid(); -} - -// HOTS: 19581C0 -int TGenericArray::LoadDwordsArray_Copy(TByteStream & InStream) -{ - TGenericArray TempArray; - int nError; - - nError = TempArray.LoadDwordsArray(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - CopyFrom(TempArray); - return ERROR_SUCCESS; -} - -// HOTS: 1958250 -int TGenericArray::LoadTripletsArray_Copy(TByteStream & InStream) -{ - TGenericArray TempArray; - int nError; - - nError = TempArray.LoadTripletsArray(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - CopyFrom(TempArray); - return ERROR_SUCCESS; -} - -// HOTS: 1958420 -int TGenericArray::LoadBytes_Copy(TByteStream & InStream) -{ - TGenericArray TempArray; - int nError; - - nError = TempArray.LoadByteArray(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - CopyFrom(TempArray); - return 0; -} - -// HOTS: 19584F0 -int TGenericArray::LoadFragmentInfos_Copy(TByteStream & InStream) -{ - TGenericArray TempArray; - int nError; - - nError = TempArray.LoadFragmentInfos(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - CopyFrom(TempArray); - return ERROR_SUCCESS; -} - -// HOTS: 195A360 -int TGenericArray::LoadStringsWithCopy(TByteStream & InStream) -{ - TGenericArray TempArray; - int nError; - - nError = TempArray.LoadStrings(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - CopyFrom(TempArray); - return ERROR_SUCCESS; -} - -//----------------------------------------------------------------------------- -// TBitEntryArray functions - -TBitEntryArray::TBitEntryArray() -{ - BitsPerEntry = 0; - EntryBitMask = 0; - TotalEntries = 0; -} - -TBitEntryArray::~TBitEntryArray() -{} - -// HOTS: 01957D20 -void TBitEntryArray::ExchangeWith(TBitEntryArray & Target) -{ - TBitEntryArray WorkBuff; - - WorkBuff = *this; - *this = Target; - Target = WorkBuff; -} - -// HOTS: 1958580 -int TBitEntryArray::LoadFromStream(TByteStream & InStream) -{ - ARRAY_POINTER Pointer; - ULONGLONG Value = 0; - int nError; - - nError = LoadDwordsArray_Copy(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.GetBytes(sizeof(DWORD), &Pointer); - if(nError != ERROR_SUCCESS) - return nError; - - BitsPerEntry = Pointer.Uint32s[0]; - if(BitsPerEntry > 0x20) - return ERROR_BAD_FORMAT; - - nError = InStream.GetBytes(sizeof(DWORD), &Pointer); - if(nError != ERROR_SUCCESS) - return nError; - EntryBitMask = Pointer.Uint32s[0]; - - nError = InStream.GetBytes(sizeof(ULONGLONG), &Pointer); - if(nError == ERROR_SUCCESS) - Value = Pointer.Int64Ptr[0]; - if(Value > 0xFFFFFFFF) - return ERROR_BAD_FORMAT; - TotalEntries = (DWORD)Value; - - assert((BitsPerEntry * TotalEntries) / 32 <= ItemCount); - return ERROR_SUCCESS; -} - -// HOTS: 1959300 -int TBitEntryArray::LoadFromStream_Exchange(TByteStream & InStream) -{ - TBitEntryArray TempArray; - int nError; - - nError = TempArray.LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - ExchangeWith(TempArray); - return ERROR_SUCCESS; -} - -//----------------------------------------------------------------------------- -// TStruct40 functions - -TStruct40::TStruct40() -{ - ItemIndex = 0; - CharIndex = 0; - ItemCount = 0; - SearchPhase = CASC_SEARCH_INITIALIZING; -} - -// HOTS: 19586B0 -void TStruct40::InitSearchBuffers() -{ - DWORD NewMaxItemCount; - - array_00.ItemCount = 0; - - // HOTS: 19586BD - if(array_00.MaxItemCount < 0x40) - { - // HOTS: 19586C2 - NewMaxItemCount = 0x40; - - if(array_00.MaxItemCount > 0x20) - { - if(array_00.MaxItemCount <= 0x7FFFFFFF) - NewMaxItemCount = array_00.MaxItemCount + array_00.MaxItemCount; - else - NewMaxItemCount = CASC_MAX_ENTRIES(BYTE); - } - - array_00.SetMaxItems_CHARS(NewMaxItemCount); - } - - // HOTS: 19586E1 - // Set the new item count - PathStops.sub_19583A0(0); - - if(PathStops.MaxItemCount < 4) - { - // HOTS: 19586F2 - NewMaxItemCount = 4; - - // HOTS: 19586EA - if(PathStops.MaxItemCount > 2) - { - if(PathStops.MaxItemCount <= 0x6666666) - NewMaxItemCount = PathStops.MaxItemCount + PathStops.MaxItemCount; - else - NewMaxItemCount = CASC_MAX_ENTRIES(PATH_STOP); - } - - // HOTS: 195870B - PathStops.SetMaxItems_PATH_STOP(NewMaxItemCount); - } - - ItemIndex = 0; - CharIndex = 0; - ItemCount = 0; - SearchPhase = CASC_SEARCH_SEARCHING; -} - -//----------------------------------------------------------------------------- -// TSparseArray functions - -TSparseArray::TSparseArray() -{ - TotalItemCount = 0; - ValidItemCount = 0; -} - -// HOTS: 1957DA0 -void TSparseArray::ExchangeWith(TSparseArray & Target) -{ - TSparseArray WorkBuff; - - WorkBuff = *this; - *this = Target; - Target = WorkBuff; -} - -// HOTS: 1958630 -int TSparseArray::LoadFromStream(TByteStream & InStream) -{ - ARRAY_POINTER Pointer; - int nError; - - nError = ItemBits.LoadDwordsArray_Copy(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.GetBytes(sizeof(DWORD), &Pointer); - if(nError != ERROR_SUCCESS) - return nError; - TotalItemCount = Pointer.Uint32s[0]; - - nError = InStream.GetBytes(sizeof(DWORD), &Pointer); - if(nError != ERROR_SUCCESS) - return nError; - ValidItemCount = Pointer.Uint32s[0]; - - if(ValidItemCount > TotalItemCount) - return ERROR_FILE_CORRUPT; - - nError = BaseValues.LoadTripletsArray_Copy(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - nError = ArrayDwords_38.LoadDwordsArray_Copy(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - nError = ArrayDwords_50.LoadDwordsArray_Copy(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - return ERROR_SUCCESS; -} - -// HOTS: 1959380 -int TSparseArray::LoadFromStream_Exchange(TByteStream & InStream) -{ - TSparseArray NewStruct68; - int nError; - - nError = NewStruct68.LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - ExchangeWith(NewStruct68); - return ERROR_SUCCESS; -} - -// HOTS: 1959B60 -DWORD TSparseArray::GetItemValue(DWORD ItemIndex) -{ - PTRIPLET pTriplet; - DWORD DwordIndex; - DWORD BaseValue; - DWORD BitMask; - - // - // Divide the low-8-bits index to four parts: - // - // |-----------------------|---|------------| - // | A (23 bits) | B | C | - // |-----------------------|---|------------| - // - // A (23-bits): Index to the table (60 bits per entry) - // - // Layout of the table entry: - // |--------------------------------|-------|--------|--------|---------|---------|---------|---------|-----| - // | Base Value | val[0]| val[1] | val[2] | val[3] | val[4] | val[5] | val[6] | - | - // | 32 bits | 7 bits| 8 bits | 8 bits | 9 bits | 9 bits | 9 bits | 9 bits |5bits| - // |--------------------------------|-------|--------|--------|---------|---------|---------|---------|-----| - // - // B (3 bits) : Index of the variable-bit value in the array (val[#], see above) - // - // C (32 bits): Number of bits to be checked (up to 0x3F bits). - // Number of set bits is then added to the values obtained from A and B - - // Upper 23 bits contain index to the table - pTriplet = BaseValues.TripletArray + (ItemIndex >> 0x09); - BaseValue = pTriplet->BaseValue; - - // Next 3 bits contain the index to the VBR - switch(((ItemIndex >> 0x06) & 0x07) - 1) - { - case 0: // Add the 1st value (7 bits) - BaseValue += (pTriplet->Value2 & 0x7F); - break; - - case 1: // Add the 2nd value (8 bits) - BaseValue += (pTriplet->Value2 >> 0x07) & 0xFF; - break; - - case 2: // Add the 3rd value (8 bits) - BaseValue += (pTriplet->Value2 >> 0x0F) & 0xFF; - break; - - case 3: // Add the 4th value (9 bits) - BaseValue += (pTriplet->Value2 >> 0x17); - break; - - case 4: // Add the 5th value (9 bits) - BaseValue += (pTriplet->Value3 & 0x1FF); - break; - - case 5: // Add the 6th value (9 bits) - BaseValue += (pTriplet->Value3 >> 0x09) & 0x1FF; - break; - - case 6: // Add the 7th value (9 bits) - BaseValue += (pTriplet->Value3 >> 0x12) & 0x1FF; - break; - } - - // - // Take the upper 27 bits as an index to DWORD array, take lower 5 bits - // as number of bits to mask. Then calculate number of set bits in the value - // masked value. - // - - // Get the index into the array of DWORDs - DwordIndex = (ItemIndex >> 0x05); - - // Add number of set bits in the masked value up to 0x3F bits - if(ItemIndex & 0x20) - BaseValue += GetNumbrOfSetBits32(ItemBits.Uint32Array[DwordIndex - 1]); - - BitMask = (1 << (ItemIndex & 0x1F)) - 1; - return BaseValue + GetNumbrOfSetBits32(ItemBits.Uint32Array[DwordIndex] & BitMask); -} - -//----------------------------------------------------------------------------- -// TNameIndexStruct functions - -// HOTS: 0195A290 -TNameIndexStruct::TNameIndexStruct() -{} - -// HOTS: inlined -TNameIndexStruct::~TNameIndexStruct() -{} - -// HOTS: 195A180 -bool TNameIndexStruct::CheckNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs) -{ - TStruct40 * pStruct40 = pStruct1C->pStruct40; - const char * szPathFragment; - const char * szSearchMask; - - if(!Struct68.TotalItemCount) - { - // Get the offset of the fragment to compare. For convenience with pStruct40->CharIndex, - // subtract the CharIndex from the fragment offset - szPathFragment = (NameFragments.CharArray + dwFragOffs - pStruct40->CharIndex); - szSearchMask = pStruct1C->szSearchMask; - - // Keep searching as long as the name matches with the fragment - while(szPathFragment[pStruct40->CharIndex] == szSearchMask[pStruct40->CharIndex]) - { - // Move to the next character - pStruct40->CharIndex++; - - // Is it the end of the fragment or end of the path? - if(szPathFragment[pStruct40->CharIndex] == 0) - return true; - if(pStruct40->CharIndex >= pStruct1C->cchSearchMask) - return false; - } - - return false; - } - else - { - // Get the offset of the fragment to compare. - szPathFragment = (const char *)(NameFragments.CharArray); - szSearchMask = pStruct1C->szSearchMask; - - // Keep searching as long as the name matches with the fragment - while(szPathFragment[dwFragOffs] == szSearchMask[pStruct40->CharIndex]) - { - // Move to the next character - pStruct40->CharIndex++; - - // Is it the end of the fragment or end of the path? - if(Struct68.IsItemPresent(dwFragOffs++)) - return true; - if(dwFragOffs >= pStruct1C->cchSearchMask) - return false; - } - - return false; - } -} - -// HOTS: 195A570 -bool TNameIndexStruct::CheckAndCopyNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs) -{ - TStruct40 * pStruct40 = pStruct1C->pStruct40; - const char * szPathFragment; - const char * szSearchMask; - - if(!Struct68.TotalItemCount) - { - // Get the offset of the fragment to compare. For convenience with pStruct40->CharIndex, - // subtract the CharIndex from the fragment offset - szPathFragment = (const char *)(NameFragments.CharArray + dwFragOffs - pStruct40->CharIndex); - szSearchMask = pStruct1C->szSearchMask; - - // Keep copying as long as we don't reach the end of the search mask - while(pStruct40->CharIndex < pStruct1C->cchSearchMask) - { - // HOTS: 195A5A0 - if(szPathFragment[pStruct40->CharIndex] != szSearchMask[pStruct40->CharIndex]) - return false; - - // HOTS: 195A5B7 - pStruct40->array_00.InsertOneItem_CHAR(szPathFragment[pStruct40->CharIndex]); - pStruct40->CharIndex++; - - if(szPathFragment[pStruct40->CharIndex] == 0) - return true; - } - - // Fixup the address of the fragment - szPathFragment += pStruct40->CharIndex; - - // HOTS: 195A660 - // Now we need to copy the rest of the fragment - while(szPathFragment[0] != 0) - { - pStruct40->array_00.InsertOneItem_CHAR(szPathFragment[0]); - szPathFragment++; - } - } - else - { - // Get the offset of the fragment to compare - // HOTS: 195A6B7 - szPathFragment = NameFragments.CharArray; - szSearchMask = pStruct1C->szSearchMask; - - // Keep copying as long as we don't reach the end of the search mask - while(dwFragOffs < pStruct1C->cchSearchMask) - { - if(szPathFragment[dwFragOffs] != szSearchMask[pStruct40->CharIndex]) - return false; - - pStruct40->array_00.InsertOneItem_CHAR(szPathFragment[dwFragOffs]); - pStruct40->CharIndex++; - - // Keep going as long as the given bit is not set - if(Struct68.IsItemPresent(dwFragOffs++)) - return true; - } - - // Fixup the address of the fragment - szPathFragment += dwFragOffs; - - // Now we need to copy the rest of the fragment - while(Struct68.IsItemPresent(dwFragOffs++) == 0) - { - // HOTS: 195A7A6 - pStruct40->array_00.InsertOneItem_CHAR(szPathFragment[0]); - szPathFragment++; - } - } - - return true; -} - -// HOTS: 195A3F0 -void TNameIndexStruct::CopyNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs) -{ - TStruct40 * pStruct40 = pStruct1C->pStruct40; - const char * szPathFragment; - - // HOTS: 195A3FA - if(!Struct68.TotalItemCount) - { - // HOTS: 195A40C - szPathFragment = NameFragments.CharArray + dwFragOffs; - while(szPathFragment[0] != 0) - { - // Insert the character to the path being built - pStruct40->array_00.InsertOneItem_CHAR(*szPathFragment++); - } - } - else - { - // HOTS: 195A4B3 - for(;;) - { - // Insert the character to the path being built - pStruct40->array_00.InsertOneItem_CHAR(NameFragments.CharArray[dwFragOffs]); - - // Keep going as long as the given bit is not set - if(Struct68.IsItemPresent(dwFragOffs++)) - break; - } - } -} - -// HOTS: 0195A300 -void TNameIndexStruct::ExchangeWith(TNameIndexStruct & Target) -{ - TNameIndexStruct WorkBuff; - - WorkBuff = *this; - *this = Target; - Target = WorkBuff; -} - -// HOTS: 0195A820 -int TNameIndexStruct::LoadFromStream(TByteStream & InStream) -{ - int nError; - - nError = NameFragments.LoadStringsWithCopy(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - return Struct68.LoadFromStream_Exchange(InStream); -} - -// HOTS: 195A850 -int TNameIndexStruct::LoadFromStream_Exchange(TByteStream & InStream) -{ - TNameIndexStruct TempIndexStruct; - int nError; - - nError = TempIndexStruct.LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - ExchangeWith(TempIndexStruct); - return ERROR_SUCCESS; -} - -//----------------------------------------------------------------------------- -// TStruct10 functions - -TStruct10::TStruct10() -{ - field_0 = 0x03; - field_4 = 0x200; - field_8 = 0x1000; - field_C = 0x20000; -} - -// HOTS: inline -void TStruct10::CopyFrom(TStruct10 & Target) -{ - field_0 = Target.field_0; - field_4 = Target.field_4; - field_8 = Target.field_8; - field_C = Target.field_C; -} - -// HOTS: 1956FD0 -int TStruct10::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 TStruct10::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 TStruct10::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 TStruct10::sub_1957800(DWORD dwBitMask) -{ - TStruct10 TempStruct; - int nError; - - nError = TempStruct.sub_19572E0(dwBitMask); - if(nError != ERROR_SUCCESS) - return nError; - - CopyFrom(TempStruct); - return ERROR_SUCCESS; -} - -//----------------------------------------------------------------------------- -// TFileNameDatabase functions - -// HOTS: 01958730 -TFileNameDatabase::TFileNameDatabase() -{ - NameFragIndexMask = 0; - field_214 = 0; -} - -// HOTS: inlined -void TFileNameDatabase::ExchangeWith(TFileNameDatabase & Target) -{ - TFileNameDatabasePtr TempPtr; - DWORD dwTemp; - - Struct68_00.ExchangeWith(Target.Struct68_00); - FileNameIndexes.ExchangeWith(Target.FileNameIndexes); - Struct68_D0.ExchangeWith(Target.Struct68_D0); - - FrgmDist_LoBits.ExchangeWith(Target.FrgmDist_LoBits); - FrgmDist_HiBits.ExchangeWith(Target.FrgmDist_HiBits); - - IndexStruct_174.ExchangeWith(Target.IndexStruct_174); - - TempPtr = NextDB; - NextDB = Target.NextDB; - Target.NextDB = TempPtr; - - NameFragTable.ExchangeWith(Target.NameFragTable); - - dwTemp = NameFragIndexMask; - NameFragIndexMask = Target.NameFragIndexMask; - Target.NameFragIndexMask = dwTemp; - - dwTemp = field_214; - field_214 = Target.field_214; - Target.field_214 = dwTemp; - - Struct10.CopyFrom(Target.Struct10); -} - -// HOTS: 1959CB0 -DWORD TFileNameDatabase::sub_1959CB0(DWORD dwItemIndex) -{ - PTRIPLET pTriplet; - DWORD dwKeyShifted = (dwItemIndex >> 9); - DWORD eax, ebx, ecx, edx, esi, edi; - - // If lower 9 is zero - edx = dwItemIndex; - if((edx & 0x1FF) == 0) - return Struct68_00.ArrayDwords_38.Uint32Array[dwKeyShifted]; - - eax = Struct68_00.ArrayDwords_38.Uint32Array[dwKeyShifted] >> 9; - esi = (Struct68_00.ArrayDwords_38.Uint32Array[dwKeyShifted + 1] + 0x1FF) >> 9; - dwItemIndex = esi; - - if((eax + 0x0A) >= esi) - { - // HOTS: 1959CF7 - pTriplet = Struct68_00.BaseValues.TripletArray + eax + 1; - edi = (eax << 0x09); - ebx = edi - pTriplet->BaseValue + 0x200; - while(edx >= ebx) - { - // HOTS: 1959D14 - edi += 0x200; - pTriplet++; - - ebx = edi - pTriplet->BaseValue + 0x200; - eax++; - } - } - else - { - // HOTS: 1959D2E - while((eax + 1) < esi) - { - // HOTS: 1959D38 - // ecx = Struct68_00.BaseValues.TripletArray; - esi = (esi + eax) >> 1; - ebx = (esi << 0x09) - Struct68_00.BaseValues.TripletArray[esi].BaseValue; - if(edx < ebx) - { - // HOTS: 01959D4B - dwItemIndex = esi; - } - else - { - // HOTS: 1959D50 - eax = esi; - esi = dwItemIndex; - } - } - } - - // HOTS: 1959D5F - pTriplet = Struct68_00.BaseValues.TripletArray + eax; - edx += pTriplet->BaseValue - (eax << 0x09); - edi = (eax << 4); - - eax = pTriplet->Value2; - ecx = (eax >> 0x17); - ebx = 0x100 - ecx; - if(edx < ebx) - { - // HOTS: 1959D8C - ecx = ((eax >> 0x07) & 0xFF); - esi = 0x80 - ecx; - if(edx < esi) - { - // HOTS: 01959DA2 - eax = eax & 0x7F; - ecx = 0x40 - eax; - if(edx >= ecx) - { - // HOTS: 01959DB7 - edi += 2; - edx = edx + eax - 0x40; - } - } - else - { - // HOTS: 1959DC0 - eax = (eax >> 0x0F) & 0xFF; - esi = 0xC0 - eax; - if(edx < esi) - { - // HOTS: 1959DD3 - edi += 4; - edx = edx + ecx - 0x80; - } - else - { - // HOTS: 1959DD3 - edi += 6; - edx = edx + eax - 0xC0; - } - } - } - else - { - // HOTS: 1959DE8 - esi = pTriplet->Value3; - eax = ((esi >> 0x09) & 0x1FF); - ebx = 0x180 - eax; - if(edx < ebx) - { - // HOTS: 01959E00 - esi = esi & 0x1FF; - eax = (0x140 - esi); - if(edx < eax) - { - // HOTS: 1959E11 - edi = edi + 8; - edx = edx + ecx - 0x100; - } - else - { - // HOTS: 1959E1D - edi = edi + 0x0A; - edx = edx + esi - 0x140; - } - } - else - { - // HOTS: 1959E29 - esi = (esi >> 0x12) & 0x1FF; - ecx = (0x1C0 - esi); - if(edx < ecx) - { - // HOTS: 1959E3D - edi = edi + 0x0C; - edx = edx + eax - 0x180; - } - else - { - // HOTS: 1959E49 - edi = edi + 0x0E; - edx = edx + esi - 0x1C0; - } - } - } - - // HOTS: 1959E53: - // Calculate the number of bits set in the value of "ecx" - ecx = ~Struct68_00.ItemBits.Uint32Array[edi]; - eax = GetNumberOfSetBits(ecx); - esi = eax >> 0x18; - - if(edx >= esi) - { - // HOTS: 1959ea4 - ecx = ~Struct68_00.ItemBits.Uint32Array[++edi]; - edx = edx - esi; - eax = GetNumberOfSetBits(ecx); - } - - // HOTS: 1959eea - // ESI gets the number of set bits in the lower 16 bits of ECX - esi = (eax >> 0x08) & 0xFF; - edi = edi << 0x05; - if(edx < esi) - { - // HOTS: 1959EFC - eax = eax & 0xFF; - if(edx >= eax) - { - // HOTS: 1959F05 - ecx >>= 0x08; - edi += 0x08; - edx -= eax; - } - } - else - { - // HOTS: 1959F0D - eax = (eax >> 0x10) & 0xFF; - if(edx < eax) - { - // HOTS: 1959F19 - ecx >>= 0x10; - edi += 0x10; - edx -= esi; - } - else - { - // HOTS: 1959F23 - ecx >>= 0x18; - edi += 0x18; - edx -= eax; - } - } - - // HOTS: 1959f2b - edx = edx << 0x08; - ecx = ecx & 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((ecx + edx) < sizeof(table_1BA1818)); - return table_1BA1818[ecx + edx] + edi; -} - -DWORD TFileNameDatabase::sub_1959F50(DWORD arg_0) -{ - PTRIPLET pTriplet; - PDWORD ItemArray; - DWORD eax, ebx, ecx, edx, esi, edi; - - edx = arg_0; - eax = arg_0 >> 0x09; - if((arg_0 & 0x1FF) == 0) - return Struct68_00.ArrayDwords_50.Uint32Array[eax]; - - ItemArray = Struct68_00.ArrayDwords_50.Uint32Array + eax; - eax = (ItemArray[0] >> 0x09); - edi = (ItemArray[1] + 0x1FF) >> 0x09; - - if((eax + 0x0A) > edi) - { - // HOTS: 01959F94 - pTriplet = Struct68_00.BaseValues.TripletArray + eax + 1; - while(edx >= pTriplet->BaseValue) - { - // HOTS: 1959FA3 - pTriplet++; - eax++; - } - } - else - { - // Binary search - // HOTS: 1959FAD - if((eax + 1) < edi) - { - // HOTS: 1959FB4 - esi = (edi + eax) >> 1; - if(edx < Struct68_00.BaseValues.TripletArray[esi].BaseValue) - { - // HOTS: 1959FC4 - edi = esi; - } - else - { - // HOTS: 1959FC8 - eax = esi; - } - } - } - - // HOTS: 1959FD4 - pTriplet = Struct68_00.BaseValues.TripletArray + eax; - edx = edx - pTriplet->BaseValue; - edi = eax << 0x04; - eax = pTriplet->Value2; - ebx = (eax >> 0x17); - if(edx < ebx) - { - // HOTS: 1959FF1 - esi = (eax >> 0x07) & 0xFF; - if(edx < esi) - { - // HOTS: 0195A000 - eax = eax & 0x7F; - if(edx >= eax) - { - // HOTS: 195A007 - edi = edi + 2; - edx = edx - eax; - } - } - else - { - // HOTS: 195A00E - eax = (eax >> 0x0F) & 0xFF; - if(edx < eax) - { - // HOTS: 195A01A - edi += 4; - edx = edx - esi; - } - else - { - // HOTS: 195A01F - edi += 6; - edx = edx - eax; - } - } - } - else - { - // HOTS: 195A026 - esi = pTriplet->Value3; - eax = (pTriplet->Value3 >> 0x09) & 0x1FF; - if(edx < eax) - { - // HOTS: 195A037 - esi = esi & 0x1FF; - if(edx < esi) - { - // HOTS: 195A041 - edi = edi + 8; - edx = edx - ebx; - } - else - { - // HOTS: 195A048 - edi = edi + 0x0A; - edx = edx - esi; - } - } - else - { - // HOTS: 195A04D - esi = (esi >> 0x12) & 0x1FF; - if(edx < esi) - { - // HOTS: 195A05A - edi = edi + 0x0C; - edx = edx - eax; - } - else - { - // HOTS: 195A061 - edi = edi + 0x0E; - edx = edx - esi; - } - } - } - - // HOTS: 195A066 - esi = Struct68_00.ItemBits.Uint32Array[edi]; - eax = GetNumberOfSetBits(esi); - ecx = eax >> 0x18; - - if(edx >= ecx) - { - // HOTS: 195A0B2 - esi = Struct68_00.ItemBits.Uint32Array[++edi]; - edx = edx - ecx; - eax = GetNumberOfSetBits(esi); - } - - // HOTS: 195A0F6 - ecx = (eax >> 0x08) & 0xFF; - - edi = (edi << 0x05); - if(edx < ecx) - { - // HOTS: 195A111 - eax = eax & 0xFF; - if(edx >= eax) - { - // HOTS: 195A111 - edi = edi + 0x08; - esi = esi >> 0x08; - edx = edx - eax; - } - } - else - { - // HOTS: 195A119 - eax = (eax >> 0x10) & 0xFF; - if(edx < eax) - { - // HOTS: 195A125 - esi = esi >> 0x10; - edi = edi + 0x10; - edx = edx - ecx; - } - else - { - // HOTS: 195A12F - esi = esi >> 0x18; - edi = edi + 0x18; - edx = edx - eax; - } - } - - esi = esi & 0xFF; - edx = edx << 0x08; - - // BUGBUG: Potential buffer overflow - // Happens in Heroes of the Storm when arg_0 == 0x5B - assert((esi + edx) < sizeof(table_1BA1818)); - return table_1BA1818[esi + edx] + edi; -} - -// HOTS: 1957970 -bool TFileNameDatabase::CheckNextPathFragment(TMndxFindResult * pStruct1C) -{ - TStruct40 * pStruct40 = pStruct1C->pStruct40; - LPBYTE pbPathName = (LPBYTE)pStruct1C->szSearchMask; - DWORD CollisionIndex; - DWORD NameFragIndex; - DWORD SaveCharIndex; - DWORD HiBitsIndex; - DWORD FragOffs; - - // Calculate index of the next name fragment in the name fragment table - NameFragIndex = ((pStruct40->ItemIndex << 0x05) ^ pStruct40->ItemIndex ^ pbPathName[pStruct40->CharIndex]) & NameFragIndexMask; - - // Does the hash value match? - if(NameFragTable.NameFragArray[NameFragIndex].ItemIndex == pStruct40->ItemIndex) - { - // Check if there is single character match - if(IS_SINGLE_CHAR_MATCH(NameFragTable, NameFragIndex)) - { - pStruct40->ItemIndex = NameFragTable.NameFragArray[NameFragIndex].NextIndex; - pStruct40->CharIndex++; - return true; - } - - // Check if there is a name fragment match - if(NextDB.pDB != NULL) - { - if(!NextDB.pDB->sub_1957B80(pStruct1C, NameFragTable.NameFragArray[NameFragIndex].FragOffs)) - return false; - } - else - { - if(!IndexStruct_174.CheckNameFragment(pStruct1C, NameFragTable.NameFragArray[NameFragIndex].FragOffs)) - return false; - } - - pStruct40->ItemIndex = NameFragTable.NameFragArray[NameFragIndex].NextIndex; - return true; - } - - // - // Conflict: Multiple hashes give the same table index - // - - // HOTS: 1957A0E - CollisionIndex = sub_1959CB0(pStruct40->ItemIndex) + 1; - if(!Struct68_00.IsItemPresent(CollisionIndex)) - return false; - - pStruct40->ItemIndex = (CollisionIndex - pStruct40->ItemIndex - 1); - HiBitsIndex = 0xFFFFFFFF; - -// CascDumpSparseArray("E:\\casc-array-68.txt", &FileNameIndexes); -// CascDumpSparseArray("E:\\casc-array-D0.txt", &Struct68_D0); - - // HOTS: 1957A41: - do - { - // HOTS: 1957A41 - // Check if the low 8 bits if the fragment offset contain a single character - // or an offset to a name fragment - if(Struct68_D0.IsItemPresent(pStruct40->ItemIndex)) - { - if(HiBitsIndex == 0xFFFFFFFF) - { - // HOTS: 1957A6C - HiBitsIndex = Struct68_D0.GetItemValue(pStruct40->ItemIndex); - } - else - { - // HOTS: 1957A7F - HiBitsIndex++; - } - - // HOTS: 1957A83 - SaveCharIndex = pStruct40->CharIndex; - - // Get the name fragment offset as combined value from lower 8 bits and upper bits - FragOffs = GetNameFragmentOffsetEx(pStruct40->ItemIndex, HiBitsIndex); - - // Compare the string with the fragment name database - if(NextDB.pDB != NULL) - { - // HOTS: 1957AEC - if(NextDB.pDB->sub_1957B80(pStruct1C, FragOffs)) - return true; - } - else - { - // HOTS: 1957AF7 - if(IndexStruct_174.CheckNameFragment(pStruct1C, FragOffs)) - return true; - } - - // HOTS: 1957B0E - // If there was partial match with the fragment, end the search - if(pStruct40->CharIndex != SaveCharIndex) - return false; - } - else - { - // HOTS: 1957B1C - if(FrgmDist_LoBits.ByteArray[pStruct40->ItemIndex] == pStruct1C->szSearchMask[pStruct40->CharIndex]) - { - pStruct40->CharIndex++; - return true; - } - } - - // HOTS: 1957B32 - pStruct40->ItemIndex++; - CollisionIndex++; - } - while(Struct68_00.IsItemPresent(CollisionIndex)); - return false; -} - -// HOTS: 1957B80 -bool TFileNameDatabase::sub_1957B80(TMndxFindResult * pStruct1C, DWORD arg_4) -{ - TStruct40 * pStruct40 = pStruct1C->pStruct40; - PNAME_FRAG pNameEntry; - DWORD FragOffs; - DWORD eax, edi; - - edi = arg_4; - - // HOTS: 1957B95 - for(;;) - { - pNameEntry = NameFragTable.NameFragArray + (edi & NameFragIndexMask); - if(edi == pNameEntry->NextIndex) - { - // HOTS: 01957BB4 - if((pNameEntry->FragOffs & 0xFFFFFF00) != 0xFFFFFF00) - { - // HOTS: 1957BC7 - if(NextDB.pDB != NULL) - { - // HOTS: 1957BD3 - if(!NextDB.pDB->sub_1957B80(pStruct1C, pNameEntry->FragOffs)) - return false; - } - else - { - // HOTS: 1957BE0 - if(!IndexStruct_174.CheckNameFragment(pStruct1C, pNameEntry->FragOffs)) - return false; - } - } - else - { - // HOTS: 1957BEE - if(pStruct1C->szSearchMask[pStruct40->CharIndex] != (char)pNameEntry->FragOffs) - return false; - pStruct40->CharIndex++; - } - - // HOTS: 1957C05 - edi = pNameEntry->ItemIndex; - if(edi == 0) - return true; - - if(pStruct40->CharIndex >= pStruct1C->cchSearchMask) - return false; - } - else - { - // HOTS: 1957C30 - if(Struct68_D0.IsItemPresent(edi)) - { - // HOTS: 1957C4C - if(NextDB.pDB != NULL) - { - // HOTS: 1957C58 - FragOffs = GetNameFragmentOffset(edi); - if(!NextDB.pDB->sub_1957B80(pStruct1C, FragOffs)) - return false; - } - else - { - // HOTS: 1957350 - FragOffs = GetNameFragmentOffset(edi); - if(!IndexStruct_174.CheckNameFragment(pStruct1C, FragOffs)) - return false; - } - } - else - { - // HOTS: 1957C8E - if(FrgmDist_LoBits.ByteArray[edi] != pStruct1C->szSearchMask[pStruct40->CharIndex]) - return false; - - pStruct40->CharIndex++; - } - - // HOTS: 1957CB2 - if(edi <= field_214) - return true; - - if(pStruct40->CharIndex >= pStruct1C->cchSearchMask) - return false; - - eax = sub_1959F50(edi); - edi = (eax - edi - 1); - } - } -} - -// HOTS: 1958D70 -void TFileNameDatabase::sub_1958D70(TMndxFindResult * pStruct1C, DWORD arg_4) -{ - TStruct40 * pStruct40 = pStruct1C->pStruct40; - PNAME_FRAG pNameEntry; - - // HOTS: 1958D84 - for(;;) - { - pNameEntry = NameFragTable.NameFragArray + (arg_4 & NameFragIndexMask); - if(arg_4 == pNameEntry->NextIndex) - { - // HOTS: 1958DA6 - if((pNameEntry->FragOffs & 0xFFFFFF00) != 0xFFFFFF00) - { - // HOTS: 1958DBA - if(NextDB.pDB != NULL) - { - NextDB.pDB->sub_1958D70(pStruct1C, pNameEntry->FragOffs); - } - else - { - IndexStruct_174.CopyNameFragment(pStruct1C, pNameEntry->FragOffs); - } - } - else - { - // HOTS: 1958DE7 - // Insert the low 8 bits to the path being built - pStruct40->array_00.InsertOneItem_CHAR((char)(pNameEntry->FragOffs & 0xFF)); - } - - // HOTS: 1958E71 - arg_4 = pNameEntry->ItemIndex; - if(arg_4 == 0) - return; - } - else - { - // HOTS: 1958E8E - if(Struct68_D0.IsItemPresent(arg_4)) - { - DWORD FragOffs; - - // HOTS: 1958EAF - FragOffs = GetNameFragmentOffset(arg_4); - if(NextDB.pDB != NULL) - { - NextDB.pDB->sub_1958D70(pStruct1C, FragOffs); - } - else - { - IndexStruct_174.CopyNameFragment(pStruct1C, FragOffs); - } - } - else - { - // HOTS: 1958F50 - // Insert one character to the path being built - pStruct40->array_00.InsertOneItem_CHAR(FrgmDist_LoBits.CharArray[arg_4]); - } - - // HOTS: 1958FDE - if(arg_4 <= field_214) - return; - - arg_4 = 0xFFFFFFFF - arg_4 + sub_1959F50(arg_4); - } - } -} - -// HOTS: 1959010 -bool TFileNameDatabase::sub_1959010(TMndxFindResult * pStruct1C, DWORD arg_4) -{ - TStruct40 * pStruct40 = pStruct1C->pStruct40; - PNAME_FRAG pNameEntry; - - // HOTS: 1959024 - for(;;) - { - pNameEntry = NameFragTable.NameFragArray + (arg_4 & NameFragIndexMask); - if(arg_4 == pNameEntry->NextIndex) - { - // HOTS: 1959047 - if((pNameEntry->FragOffs & 0xFFFFFF00) != 0xFFFFFF00) - { - // HOTS: 195905A - if(NextDB.pDB != NULL) - { - if(!NextDB.pDB->sub_1959010(pStruct1C, pNameEntry->FragOffs)) - return false; - } - else - { - if(!IndexStruct_174.CheckAndCopyNameFragment(pStruct1C, pNameEntry->FragOffs)) - return false; - } - } - else - { - // HOTS: 1959092 - if((char)(pNameEntry->FragOffs & 0xFF) != pStruct1C->szSearchMask[pStruct40->CharIndex]) - return false; - - // Insert the low 8 bits to the path being built - pStruct40->array_00.InsertOneItem_CHAR((char)(pNameEntry->FragOffs & 0xFF)); - pStruct40->CharIndex++; - } - - // HOTS: 195912E - arg_4 = pNameEntry->ItemIndex; - if(arg_4 == 0) - return true; - } - else - { - // HOTS: 1959147 - if(Struct68_D0.IsItemPresent(arg_4)) - { - DWORD FragOffs; - - // HOTS: 195917C - FragOffs = GetNameFragmentOffset(arg_4); - if(NextDB.pDB != NULL) - { - if(!NextDB.pDB->sub_1959010(pStruct1C, FragOffs)) - return false; - } - else - { - if(!IndexStruct_174.CheckAndCopyNameFragment(pStruct1C, FragOffs)) - return false; - } - } - else - { - // HOTS: 195920E - if(FrgmDist_LoBits.CharArray[arg_4] != pStruct1C->szSearchMask[pStruct40->CharIndex]) - return false; - - // Insert one character to the path being built - pStruct40->array_00.InsertOneItem_CHAR(FrgmDist_LoBits.CharArray[arg_4]); - pStruct40->CharIndex++; - } - - // HOTS: 19592B6 - if(arg_4 <= field_214) - return true; - - arg_4 = 0xFFFFFFFF - arg_4 + sub_1959F50(arg_4); - } - - // HOTS: 19592D5 - if(pStruct40->CharIndex >= pStruct1C->cchSearchMask) - break; - } - - sub_1958D70(pStruct1C, arg_4); - return true; -} - -// HOTS: 1959460 -bool TFileNameDatabase::sub_1959460(TMndxFindResult * pStruct1C) -{ - TStruct40 * pStruct40 = pStruct1C->pStruct40; - PPATH_STOP pPathStop; - PATH_STOP PathStop; - DWORD NewMaxItemCount; - DWORD FragOffs; - DWORD edi; - - if(pStruct40->SearchPhase == CASC_SEARCH_FINISHED) - return false; - - if(pStruct40->SearchPhase != CASC_SEARCH_SEARCHING) - { - // HOTS: 1959489 - pStruct40->InitSearchBuffers(); - - // If the caller passed a part of the search path, we need to find that one - while(pStruct40->CharIndex < pStruct1C->cchSearchMask) - { - if(!sub_1958B00(pStruct1C)) - { - pStruct40->SearchPhase = CASC_SEARCH_FINISHED; - return false; - } - } - - // HOTS: 19594b0 - PathStop.ItemIndex = pStruct40->ItemIndex; - PathStop.field_4 = 0; - PathStop.field_8 = pStruct40->array_00.ItemCount; - PathStop.field_C = 0xFFFFFFFF; - PathStop.field_10 = 0xFFFFFFFF; - pStruct40->PathStops.InsertOneItem_PATH_STOP(PathStop); - pStruct40->ItemCount = 1; - - if(FileNameIndexes.IsItemPresent(pStruct40->ItemIndex)) - { - pStruct1C->szFoundPath = pStruct40->array_00.FirstValid.Chars; - pStruct1C->cchFoundPath = pStruct40->array_00.ItemCount; - pStruct1C->FileNameIndex = FileNameIndexes.GetItemValue(pStruct40->ItemIndex); - return true; - } - } - - // HOTS: 1959522 - for(;;) - { - // HOTS: 1959530 - if(pStruct40->ItemCount == pStruct40->PathStops.ItemCount) - { - PPATH_STOP pLastStop; - DWORD CollisionIndex; - - pLastStop = pStruct40->PathStops.FirstValid.PathStopPtr + pStruct40->PathStops.ItemCount - 1; - CollisionIndex = sub_1959CB0(pLastStop->ItemIndex) + 1; - - // Insert a new structure - PathStop.ItemIndex = CollisionIndex - pLastStop->ItemIndex - 1;; - PathStop.field_4 = CollisionIndex; - PathStop.field_8 = 0; - PathStop.field_C = 0xFFFFFFFF; - PathStop.field_10 = 0xFFFFFFFF; - pStruct40->PathStops.InsertOneItem_PATH_STOP(PathStop); - } - - // HOTS: 19595BD - pPathStop = pStruct40->PathStops.FirstValid.PathStopPtr + pStruct40->ItemCount; - - // HOTS: 19595CC - if(Struct68_00.IsItemPresent(pPathStop->field_4++)) - { - // HOTS: 19595F2 - pStruct40->ItemCount++; - - if(Struct68_D0.IsItemPresent(pPathStop->ItemIndex)) - { - // HOTS: 1959617 - if(pPathStop->field_C == 0xFFFFFFFF) - pPathStop->field_C = Struct68_D0.GetItemValue(pPathStop->ItemIndex); - else - pPathStop->field_C++; - - // HOTS: 1959630 - FragOffs = GetNameFragmentOffsetEx(pPathStop->ItemIndex, pPathStop->field_C); - if(NextDB.pDB != NULL) - { - // HOTS: 1959649 - NextDB.pDB->sub_1958D70(pStruct1C, FragOffs); - } - else - { - // HOTS: 1959654 - IndexStruct_174.CopyNameFragment(pStruct1C, FragOffs); - } - } - else - { - // HOTS: 1959665 - // Insert one character to the path being built - pStruct40->array_00.InsertOneItem_CHAR(FrgmDist_LoBits.CharArray[pPathStop->ItemIndex]); - } - - // HOTS: 19596AE - pPathStop->field_8 = pStruct40->array_00.ItemCount; - - // HOTS: 19596b6 - if(FileNameIndexes.IsItemPresent(pPathStop->ItemIndex)) - { - // HOTS: 19596D1 - if(pPathStop->field_10 == 0xFFFFFFFF) - { - // HOTS: 19596D9 - pPathStop->field_10 = FileNameIndexes.GetItemValue(pPathStop->ItemIndex); - } - else - { - pPathStop->field_10++; - } - - // HOTS: 1959755 - pStruct1C->szFoundPath = pStruct40->array_00.FirstValid.Chars; - pStruct1C->cchFoundPath = pStruct40->array_00.ItemCount; - pStruct1C->FileNameIndex = pPathStop->field_10; - return true; - } - } - else - { - // HOTS: 19596E9 - if(pStruct40->ItemCount == 1) - { - pStruct40->SearchPhase = CASC_SEARCH_FINISHED; - return false; - } - - // HOTS: 19596F5 - pPathStop = pStruct40->PathStops.FirstValid.PathStopPtr + pStruct40->ItemCount - 1; - pPathStop->ItemIndex++; - - pPathStop = pStruct40->PathStops.FirstValid.PathStopPtr + pStruct40->ItemCount - 2; - edi = pPathStop->field_8; - - if(edi > pStruct40->array_00.MaxItemCount) - { - // HOTS: 1959717 - NewMaxItemCount = edi; - - if(pStruct40->array_00.MaxItemCount > (edi / 2)) - { - if(pStruct40->array_00.MaxItemCount > 0x7FFFFFFF) - { - NewMaxItemCount = 0xFFFFFFFF; - } - else - { - NewMaxItemCount = pStruct40->array_00.MaxItemCount + pStruct40->array_00.MaxItemCount; - } - } - - pStruct40->array_00.SetMaxItems_CHARS(NewMaxItemCount); - } - - // HOTS: 1959749 - pStruct40->array_00.ItemCount = edi; - pStruct40->ItemCount--; - } - } -} - -// HOTS: 1958B00 -bool TFileNameDatabase::sub_1958B00(TMndxFindResult * pStruct1C) -{ - TStruct40 * pStruct40 = pStruct1C->pStruct40; - LPBYTE pbPathName = (LPBYTE)pStruct1C->szSearchMask; - DWORD CollisionIndex; - DWORD FragmentOffset; - DWORD SaveCharIndex; - DWORD ItemIndex; - DWORD FragOffs; - DWORD var_4; - - ItemIndex = pbPathName[pStruct40->CharIndex] ^ (pStruct40->ItemIndex << 0x05) ^ pStruct40->ItemIndex; - ItemIndex = ItemIndex & NameFragIndexMask; - if(pStruct40->ItemIndex == NameFragTable.NameFragArray[ItemIndex].ItemIndex) - { - // HOTS: 1958B45 - FragmentOffset = NameFragTable.NameFragArray[ItemIndex].FragOffs; - if((FragmentOffset & 0xFFFFFF00) == 0xFFFFFF00) - { - // HOTS: 1958B88 - pStruct40->array_00.InsertOneItem_CHAR((char)FragmentOffset); - pStruct40->ItemIndex = NameFragTable.NameFragArray[ItemIndex].NextIndex; - pStruct40->CharIndex++; - return true; - } - - // HOTS: 1958B59 - if(NextDB.pDB != NULL) - { - if(!NextDB.pDB->sub_1959010(pStruct1C, FragmentOffset)) - return false; - } - else - { - if(!IndexStruct_174.CheckAndCopyNameFragment(pStruct1C, FragmentOffset)) - return false; - } - - // HOTS: 1958BCA - pStruct40->ItemIndex = NameFragTable.NameFragArray[ItemIndex].NextIndex; - return true; - } - - // HOTS: 1958BE5 - CollisionIndex = sub_1959CB0(pStruct40->ItemIndex) + 1; - if(!Struct68_00.IsItemPresent(CollisionIndex)) - return false; - - pStruct40->ItemIndex = (CollisionIndex - pStruct40->ItemIndex - 1); - var_4 = 0xFFFFFFFF; - - // HOTS: 1958C20 - for(;;) - { - if(Struct68_D0.IsItemPresent(pStruct40->ItemIndex)) - { - // HOTS: 1958C0E - if(var_4 == 0xFFFFFFFF) - { - // HOTS: 1958C4B - var_4 = Struct68_D0.GetItemValue(pStruct40->ItemIndex); - } - else - { - var_4++; - } - - // HOTS: 1958C62 - SaveCharIndex = pStruct40->CharIndex; - - FragOffs = GetNameFragmentOffsetEx(pStruct40->ItemIndex, var_4); - if(NextDB.pDB != NULL) - { - // HOTS: 1958CCB - if(NextDB.pDB->sub_1959010(pStruct1C, FragOffs)) - return true; - } - else - { - // HOTS: 1958CD6 - if(IndexStruct_174.CheckAndCopyNameFragment(pStruct1C, FragOffs)) - return true; - } - - // HOTS: 1958CED - if(SaveCharIndex != pStruct40->CharIndex) - return false; - } - else - { - // HOTS: 1958CFB - if(FrgmDist_LoBits.ByteArray[pStruct40->ItemIndex] == pStruct1C->szSearchMask[pStruct40->CharIndex]) - { - // HOTS: 1958D11 - pStruct40->array_00.InsertOneItem_CHAR(FrgmDist_LoBits.ByteArray[pStruct40->ItemIndex]); - pStruct40->CharIndex++; - return true; - } - } - - // HOTS: 1958D11 - pStruct40->ItemIndex++; - CollisionIndex++; - - if(!Struct68_00.IsItemPresent(CollisionIndex)) - break; - } - - return false; -} - -// HOTS: 1957EF0 -bool TFileNameDatabase::FindFileInDatabase(TMndxFindResult * pStruct1C) -{ - TStruct40 * pStruct40 = pStruct1C->pStruct40; - - pStruct40->ItemIndex = 0; - pStruct40->CharIndex = 0; - pStruct40->SearchPhase = CASC_SEARCH_INITIALIZING; - - if(pStruct1C->cchSearchMask > 0) - { - while(pStruct40->CharIndex < pStruct1C->cchSearchMask) - { - // HOTS: 01957F12 - if(!CheckNextPathFragment(pStruct1C)) - return false; - } - } - - // HOTS: 1957F26 - if(!FileNameIndexes.IsItemPresent(pStruct40->ItemIndex)) - return false; - - pStruct1C->szFoundPath = pStruct1C->szSearchMask; - pStruct1C->cchFoundPath = pStruct1C->cchSearchMask; - pStruct1C->FileNameIndex = FileNameIndexes.GetItemValue(pStruct40->ItemIndex); - return true; -} - -// HOTS: 1959790 -int TFileNameDatabase::LoadFromStream(TByteStream & InStream) -{ - DWORD dwBitMask; - int nError; - - nError = Struct68_00.LoadFromStream_Exchange(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - nError = FileNameIndexes.LoadFromStream_Exchange(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - nError = Struct68_D0.LoadFromStream_Exchange(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - // HOTS: 019597CD - nError = FrgmDist_LoBits.LoadBytes_Copy(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - nError = FrgmDist_HiBits.LoadFromStream_Exchange(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - // HOTS: 019597F5 - nError = IndexStruct_174.LoadFromStream_Exchange(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - // HOTS: 0195980A - if(Struct68_D0.ValidItemCount != 0 && IndexStruct_174.NameFragments.ItemCount == 0) - { - TFileNameDatabase * pNextDB = new TFileNameDatabase; - - nError = NextDB.SetDatabase(pNextDB); - if(nError != ERROR_SUCCESS) - return nError; - - if(NextDB.pDB == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - nError = NextDB.pDB->LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - } - - // HOTS: 0195986B - nError = NameFragTable.LoadFragmentInfos_Copy(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - NameFragIndexMask = NameFragTable.ItemCount - 1; - - nError = InStream.GetValue_DWORD(field_214); - if(nError != ERROR_SUCCESS) - return nError; - - nError = InStream.GetValue_DWORD(dwBitMask); - if(nError != ERROR_SUCCESS) - return nError; - - return Struct10.sub_1957800(dwBitMask); -} - -// HOTS: 19598D0 -int TFileNameDatabase::LoadFromStream_Exchange(TByteStream & InStream) -{ - TFileNameDatabase TempDatabase; - ARRAY_POINTER Pointer; - DWORD dwSignature; - int nError; - - // Get pointer to MAR signature - nError = InStream.GetBytes(sizeof(DWORD), &Pointer); - if(nError != ERROR_SUCCESS) - return nError; - - // Verify the signature - dwSignature = Pointer.Uint32s[0]; - if(dwSignature != CASC_MAR_SIGNATURE) - return ERROR_BAD_FORMAT; - - nError = TempDatabase.LoadFromStream(InStream); - if(nError != ERROR_SUCCESS) - return nError; - - MarStream.ExchangeWith(InStream); - ExchangeWith(TempDatabase); - return ERROR_SUCCESS; -} - -//----------------------------------------------------------------------------- -// TFileNameDatabasePtr functions - -// HOTS: 01956D70 -TFileNameDatabasePtr::TFileNameDatabasePtr() -{ - pDB = NULL; -} - -TFileNameDatabasePtr::~TFileNameDatabasePtr() -{ - delete pDB; -} - -// HOTS: 1956C60 -int TFileNameDatabasePtr::FindFileInDatabase(TMndxFindResult * pStruct1C) -{ - int nError = ERROR_SUCCESS; - - if(pDB == NULL) - return ERROR_INVALID_PARAMETER; - - nError = pStruct1C->CreateStruct40(); - if(nError != ERROR_SUCCESS) - return nError; - - if(!pDB->FindFileInDatabase(pStruct1C)) - nError = ERROR_FILE_NOT_FOUND; - - pStruct1C->FreeStruct40(); - return nError; -} - -// HOTS: 1956CE0 -int TFileNameDatabasePtr::sub_1956CE0(TMndxFindResult * pStruct1C, bool * pbFindResult) -{ - int nError = ERROR_SUCCESS; - - if(pDB == NULL) - return ERROR_INVALID_PARAMETER; - - // Create the pStruct40, if not initialized yet - if(pStruct1C->pStruct40 == NULL) - { - nError = pStruct1C->CreateStruct40(); - if(nError != ERROR_SUCCESS) - return nError; - } - - *pbFindResult = pDB->sub_1959460(pStruct1C); - return nError; -} - -// HOTS: 1956D20 -int TFileNameDatabasePtr::GetFileNameCount(PDWORD PtrFileNameCount) -{ - if(pDB == NULL) - return ERROR_INVALID_PARAMETER; - - PtrFileNameCount[0] = pDB->FileNameIndexes.ValidItemCount; - return ERROR_SUCCESS; -} - -// HOTS: 1956DA0 -int TFileNameDatabasePtr::CreateDatabase(LPBYTE pbMarData, DWORD cbMarData) -{ - TFileNameDatabase * pDatabase; - TByteStream ByteStream; - int nError; - - if(pbMarData == NULL && cbMarData != 0) - return ERROR_INVALID_PARAMETER; - - pDatabase = new TFileNameDatabase; - if(pDatabase == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - nError = ByteStream.SetByteBuffer(pbMarData, cbMarData); - if(nError != ERROR_SUCCESS) - return nError; - - // HOTS: 1956E11 - nError = pDatabase->LoadFromStream_Exchange(ByteStream); - if(nError != ERROR_SUCCESS) - return nError; - - pDB = pDatabase; - return ERROR_SUCCESS; -} - -// HOTS: 19584B0 -int TFileNameDatabasePtr::SetDatabase(TFileNameDatabase * pNewDB) -{ - if(pNewDB != NULL && pDB == pNewDB) - return ERROR_INVALID_PARAMETER; - - if(pDB != NULL) - delete pDB; - pDB = pNewDB; - return ERROR_SUCCESS; -} - -//----------------------------------------------------------------------------- -// Local functions - MAR file - -// HOTS: 00E94180 -static void MAR_FILE_CreateDatabase(PMAR_FILE pMarFile) -{ - pMarFile->pDatabasePtr = new TFileNameDatabasePtr; - if(pMarFile->pDatabasePtr != NULL) - pMarFile->pDatabasePtr->CreateDatabase(pMarFile->pbMarData, pMarFile->cbMarData); -} - -static int MAR_FILE_SearchFile(PMAR_FILE pMarFile, TMndxFindResult * pStruct1C) -{ - return pMarFile->pDatabasePtr->FindFileInDatabase(pStruct1C); -} - -static void MAR_FILE_Destructor(PMAR_FILE pMarFile) -{ - if(pMarFile != NULL) - { - if(pMarFile->pDatabasePtr != NULL) - delete pMarFile->pDatabasePtr; - if(pMarFile->pbMarData != NULL) - CASC_FREE(pMarFile->pbMarData); - - CASC_FREE(pMarFile); - } -} - -//----------------------------------------------------------------------------- -// Package functions - -// TODO: When working, increment these values to lower number of (re)allocations -#define CASC_PACKAGES_INIT 0x10 -#define CASC_PACKAGES_DELTA 0x10 - -static PCASC_PACKAGES AllocatePackages(size_t nNameEntries, size_t nNameBufferMax) -{ - PCASC_PACKAGES pPackages; - size_t cbToAllocate; - - // Allocate space - cbToAllocate = sizeof(CASC_PACKAGES) + (nNameEntries * sizeof(CASC_PACKAGE)) + nNameBufferMax; - pPackages = (PCASC_PACKAGES)CASC_ALLOC(BYTE, cbToAllocate); - if(pPackages != NULL) - { - // Fill the structure - memset(pPackages, 0, cbToAllocate); - - // Init the list entries - pPackages->szNameBuffer = (char *)(&pPackages->Packages[nNameEntries]); - pPackages->NameEntries = nNameEntries; - pPackages->NameBufferUsed = 0; - pPackages->NameBufferMax = nNameBufferMax; - } - - return pPackages; -} - -static PCASC_PACKAGES InsertToPackageList( - PCASC_PACKAGES pPackages, - const char * szFileName, - size_t cchFileName, - size_t nPackageIndex) -{ - size_t nNewNameEntries = pPackages->NameEntries; - size_t nNewNameBufferMax = pPackages->NameBufferMax; - size_t cbToAllocate; - char * szNameBuffer; - - // Need to reallocate? - while(nPackageIndex >= nNewNameEntries) - nNewNameEntries = nNewNameEntries + CASC_PACKAGES_DELTA; - if((pPackages->NameBufferUsed + cchFileName + 1) > nNewNameBufferMax) - nNewNameBufferMax = nNewNameBufferMax + 0x1000; - - // If any of the two variables overflowed, we need to reallocate the name list - if(nNewNameEntries > pPackages->NameEntries || nNewNameBufferMax > pPackages->NameBufferMax) - { - PCASC_PACKAGES pOldPackages = pPackages; - - // Allocate new name list - cbToAllocate = sizeof(CASC_PACKAGES) + (nNewNameEntries * sizeof(CASC_PACKAGE)) + nNewNameBufferMax; - pPackages = (PCASC_PACKAGES)CASC_ALLOC(BYTE, cbToAllocate); - if(pPackages == NULL) - return NULL; - - // Copy the old entries - memset(pPackages, 0, cbToAllocate); - pPackages->szNameBuffer = szNameBuffer = (char *)(&pPackages->Packages[nNewNameEntries]); - memcpy(pPackages->szNameBuffer, pOldPackages->szNameBuffer, pOldPackages->NameBufferUsed); - - // Copy the old entries - for(size_t i = 0; i < pOldPackages->NameEntries; i++) - { - if(pOldPackages->Packages[i].szFileName != NULL) - { - pPackages->Packages[i].szFileName = pPackages->szNameBuffer + (pOldPackages->Packages[i].szFileName - pOldPackages->szNameBuffer); - pPackages->Packages[i].nLength = pOldPackages->Packages[i].nLength; - } - } - - // Fill the limits - pPackages->NameEntries = nNewNameEntries; - pPackages->NameBufferUsed = pOldPackages->NameBufferUsed; - pPackages->NameBufferMax = nNewNameBufferMax; - - // Switch the name lists - CASC_FREE(pOldPackages); - } - - // The slot is expected to be empty at the moment - assert(pPackages->Packages[nPackageIndex].szFileName == NULL); - assert(pPackages->Packages[nPackageIndex].nLength == 0); - - // Set the file name entry - szNameBuffer = pPackages->szNameBuffer + pPackages->NameBufferUsed; - pPackages->Packages[nPackageIndex].szFileName = szNameBuffer; - pPackages->Packages[nPackageIndex].nLength = cchFileName; - memcpy(szNameBuffer, szFileName, cchFileName); - pPackages->NameBufferUsed += (cchFileName + 1); - return pPackages; -} - -static int LoadPackageNames(TCascStorage * hs) -{ - TMndxFindResult Struct1C; - PCASC_PACKAGES pPackages = NULL; - PMAR_FILE pMarFile; - - // Sanity checks - assert(hs->pMndxInfo != NULL); - - // Prepare the file name search in the top level directory - pMarFile = hs->pMndxInfo->pMarFile1; - Struct1C.SetSearchPath("", 0); - - // Allocate initial name list structure - pPackages = AllocatePackages(CASC_PACKAGES_INIT, 0x1000); - if(pPackages == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - // Keep searching as long as we find something - for(;;) - { - bool bFindResult = false; - - // Search the next file name - pMarFile->pDatabasePtr->sub_1956CE0(&Struct1C, &bFindResult); - if(bFindResult == false) - break; - - // Insert the found name to the top level directory list - pPackages = InsertToPackageList(pPackages, Struct1C.szFoundPath, Struct1C.cchFoundPath, Struct1C.FileNameIndex); - if(pPackages == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - } - - // Set the name list to the CASC storage structure - hs->pPackages = pPackages; - return ERROR_SUCCESS; -} - -PCASC_PACKAGE FindMndxPackage(TCascStorage * hs, const char * szFileName) -{ - PCASC_PACKAGE pMatching = NULL; - PCASC_PACKAGE pPackage; - size_t nMaxLength = 0; - size_t nLength = strlen(szFileName); - - // Packages must be loaded - assert(hs->pPackages != NULL); - pPackage = hs->pPackages->Packages; - - //FILE * fp = fopen("E:\\packages.txt", "wt"); - //for(size_t i = 0; i < hs->pPackages->NameEntries; i++, pPackage++) - //{ - // if(pPackage->szFileName != NULL) - // fprintf(fp, "%s\n", pPackage->szFileName); - //} - //fclose(fp); - - // Find the longest matching name - for(size_t i = 0; i < hs->pPackages->NameEntries; i++, pPackage++) - { - if(pPackage->szFileName != NULL && pPackage->nLength < nLength && pPackage->nLength > nMaxLength) - { - // Compare the package name - if(!strncmp(szFileName, pPackage->szFileName, pPackage->nLength)) - { - pMatching = pPackage; - nMaxLength = pPackage->nLength; - } - } - } - - // Give the package pointer or NULL if not found - return pMatching; -} - -static bool FillFindData(TCascSearch * pSearch, PCASC_FIND_DATA pFindData, TMndxFindResult * pStruct1C) -{ - PCASC_ROOT_ENTRY_MNDX pRootEntry = NULL; - TCascStorage * hs = pSearch->hs; - PCASC_PACKAGE pPackage; - char * szStrippedPtr; - char szStrippedName[MAX_PATH+1]; - int nError; - - // Sanity check - assert(pStruct1C->cchFoundPath < MAX_PATH); - - // Fill the file name - memcpy(pFindData->szFileName, pStruct1C->szFoundPath, pStruct1C->cchFoundPath); - pFindData->szFileName[pStruct1C->cchFoundPath] = 0; - pFindData->szPlainName = (char *)GetPlainFileName(pFindData->szFileName); - pFindData->dwFileSize = CASC_INVALID_SIZE; - - // Fill the file size - pPackage = FindMndxPackage(hs, pFindData->szFileName); - if(pPackage != NULL) - { - // Cut the package name off the full path - szStrippedPtr = pFindData->szFileName + pPackage->nLength; - while(szStrippedPtr[0] == '/') - szStrippedPtr++; - - // We need to convert the stripped name to lowercase, replacing backslashes with slashes - NormalizeFileName_LowerSlash(szStrippedName, szStrippedPtr, MAX_PATH); - - // Search the package - nError = SearchMndxInfo(hs->pMndxInfo, szStrippedName, (DWORD)(pPackage - hs->pPackages->Packages), &pRootEntry); - if(nError == ERROR_SUCCESS) - { - pFindData->dwFileSize = pRootEntry->FileSize; - } - } - return true; -} - -//----------------------------------------------------------------------------- -// Public functions - MNDX info - -int LoadMndxRootFile(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile) -{ - PFILE_MNDX_HEADER pMndxHeader = (PFILE_MNDX_HEADER)pbRootFile; - PCASC_MNDX_INFO pMndxInfo; - FILE_MAR_INFO MarInfo; - PMAR_FILE pMarFile; - LPBYTE pbRootFileEnd = pbRootFile + cbRootFile; - DWORD cbToAllocate; - DWORD dwFilePointer = 0; - DWORD i; - int nError = ERROR_SUCCESS; - - // Check signature and the other variables - if(pMndxHeader->Signature != CASC_MNDX_SIGNATURE || pMndxHeader->FormatVersion > 2 || pMndxHeader->FormatVersion < 1) - return ERROR_BAD_FORMAT; - - // Allocate space for the CASC_MNDX_INFO structure - pMndxInfo = CASC_ALLOC(CASC_MNDX_INFO, 1); - if(pMndxInfo == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - // Copy the header into the MNDX info - memset(pMndxInfo, 0, sizeof(CASC_MNDX_INFO)); - pMndxInfo->HeaderVersion = pMndxHeader->HeaderVersion; - pMndxInfo->FormatVersion = pMndxHeader->FormatVersion; - dwFilePointer += sizeof(FILE_MNDX_HEADER); - - // Header version 2 has 2 extra fields that we need to load - if(pMndxInfo->HeaderVersion == 2) - { - if(!RootFileRead(pbRootFile + dwFilePointer, pbRootFileEnd, &pMndxInfo->field_1C, sizeof(DWORD) + sizeof(DWORD))) - return ERROR_FILE_CORRUPT; - dwFilePointer += sizeof(DWORD) + sizeof(DWORD); - } - - // Load the rest of the file header - if(!RootFileRead(pbRootFile + dwFilePointer, pbRootFileEnd, &pMndxInfo->MarInfoOffset, 0x1C)) - return ERROR_FILE_CORRUPT; - - // Verify the structure - if(pMndxInfo->MarInfoCount > CASC_MAX_MAR_FILES || pMndxInfo->MarInfoSize != sizeof(FILE_MAR_INFO)) - return ERROR_FILE_CORRUPT; - - // Load all MAR infos - for(i = 0; i < pMndxInfo->MarInfoCount; i++) - { - // Load the n-th MAR info - dwFilePointer = pMndxInfo->MarInfoOffset + (pMndxInfo->MarInfoSize * i); - if(!RootFileRead(pbRootFile + dwFilePointer, pbRootFileEnd, &MarInfo, sizeof(FILE_MAR_INFO))) - return ERROR_FILE_CORRUPT; - - // Allocate MAR_FILE structure - pMarFile = CASC_ALLOC(MAR_FILE, 1); - if(pMarFile == NULL) - { - nError = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Allocate space for the MAR data - pMarFile->pDatabasePtr = NULL; - pMarFile->pbMarData = CASC_ALLOC(BYTE, MarInfo.MarDataSize); - pMarFile->cbMarData = MarInfo.MarDataSize; - if(pMarFile->pbMarData == NULL) - { - nError = ERROR_NOT_ENOUGH_MEMORY; - break; - } - - // Read the MAR data - if(!RootFileRead(pbRootFile + MarInfo.MarDataOffset, pbRootFileEnd, pMarFile->pbMarData, pMarFile->cbMarData)) - { - nError = ERROR_FILE_CORRUPT; - break; - } - - // HOTS: 00E94FF1 - MAR_FILE_CreateDatabase(pMarFile); - if(i == 0) - pMndxInfo->pMarFile1 = pMarFile; - if(i == 1) - pMndxInfo->pMarFile2 = pMarFile; - if(i == 2) - pMndxInfo->pMarFile3 = pMarFile; - } - - // All three MAR files must be loaded - // HOTS: 00E9503B - if(nError == ERROR_SUCCESS) - { - if(pMndxInfo->pMarFile1 == NULL || pMndxInfo->pMarFile2 == NULL || pMndxInfo->pMarFile3 == NULL) - nError = ERROR_BAD_FORMAT; - if(pMndxInfo->MndxEntrySize != sizeof(CASC_ROOT_ENTRY_MNDX)) - nError = ERROR_BAD_FORMAT; - } - - // Load the complete array of MNDX entries - if(nError == ERROR_SUCCESS) - { - TFileNameDatabasePtr * pDbPtr = pMndxInfo->pMarFile2->pDatabasePtr; - DWORD FileNameCount; - - nError = pDbPtr->GetFileNameCount(&FileNameCount); - if(nError == ERROR_SUCCESS && FileNameCount == pMndxInfo->MndxEntriesValid) - { - cbToAllocate = pMndxInfo->MndxEntriesTotal * pMndxInfo->MndxEntrySize; - pMndxInfo->pMndxEntries = (PCASC_ROOT_ENTRY_MNDX)CASC_ALLOC(BYTE, cbToAllocate); - if(pMndxInfo->pMndxEntries != NULL) - { - if(!RootFileRead(pbRootFile + pMndxInfo->MndxEntriesOffset, pbRootFileEnd, pMndxInfo->pMndxEntries, cbToAllocate)) - nError = ERROR_FILE_CORRUPT; - } - else - nError = ERROR_NOT_ENOUGH_MEMORY; - } - else - nError = ERROR_FILE_CORRUPT; - } - - // Pick the valid MNDX entries and put them to a separate array - if(nError == ERROR_SUCCESS) - { - assert(pMndxInfo->MndxEntriesValid <= pMndxInfo->MndxEntriesTotal); - pMndxInfo->ppValidEntries = CASC_ALLOC(PCASC_ROOT_ENTRY_MNDX, pMndxInfo->MndxEntriesValid + 1); - if(pMndxInfo->ppValidEntries != NULL) - { - PCASC_ROOT_ENTRY_MNDX pRootEntry = pMndxInfo->pMndxEntries; - DWORD ValidEntryCount = 1; // edx - DWORD nIndex1 = 0; - - // The first entry is always valid - pMndxInfo->ppValidEntries[nIndex1++] = pMndxInfo->pMndxEntries; - - // Put the remaining entries - for(i = 0; i < pMndxInfo->MndxEntriesTotal; i++, pRootEntry++) - { - if(ValidEntryCount > pMndxInfo->MndxEntriesValid) - break; - - if(pRootEntry->Flags & 0x80000000) - { - pMndxInfo->ppValidEntries[nIndex1++] = pRootEntry + 1; - ValidEntryCount++; - } - } - - // Verify the final number of valid entries - if((ValidEntryCount - 1) != pMndxInfo->MndxEntriesValid) - nError = ERROR_BAD_FORMAT; - - // Mark the MNDX info as fully loaded - pMndxInfo->bRootFileLoaded = true; - } - else - nError = ERROR_NOT_ENOUGH_MEMORY; - } - - // Save the MNDX info to the archive storage - if(nError == ERROR_SUCCESS) - { - // Store the MNDX database into the archive - hs->pMndxInfo = pMndxInfo; - pMndxInfo = NULL; - -#if defined(_DEBUG) && defined(_X86_) && defined(CASCLIB_TEST) -// CascDumpNameFragTable("E:\\casc-name-fragment-table.txt", hs->pMndxInfo->pMarFile1); -// CascDumpFileNames("E:\\casc-listfile.txt", hs->pMndxInfo->pMarFile1); - TestMndxRootFile(hs->pMndxInfo); -#endif - // Load the top level entries - nError = LoadPackageNames(hs); - } - - // If anything failed, free the memory remaining allocated - if(nError != ERROR_SUCCESS) - { - if(pMndxInfo != NULL) - FreeMndxInfo(pMndxInfo); - pMndxInfo = NULL; - } - - return nError; -} - -int SearchMndxInfo(PCASC_MNDX_INFO pMndxInfo, const char * szFileName, DWORD dwPackage, PCASC_ROOT_ENTRY_MNDX * ppRootEntry) -{ - PCASC_ROOT_ENTRY_MNDX pRootEntry; - TMndxFindResult Struct1C; - - // Search the database for the file name - if(pMndxInfo->bRootFileLoaded) - { - Struct1C.SetSearchPath(szFileName, strlen(szFileName)); - - // Search the file name in the second MAR info (the one with stripped package names) - if(MAR_FILE_SearchFile(pMndxInfo->pMarFile2, &Struct1C) != ERROR_SUCCESS) - return ERROR_FILE_NOT_FOUND; - - // The found MNDX index must fall into range of valid MNDX entries - if(Struct1C.FileNameIndex < pMndxInfo->MndxEntriesValid) - { - // HOTS: E945F4 - pRootEntry = pMndxInfo->ppValidEntries[Struct1C.FileNameIndex]; - while((pRootEntry->Flags & 0x00FFFFFF) != dwPackage) - { - // The highest bit serves as a terminator if set - if(pRootEntry->Flags & 0x80000000) - return ERROR_FILE_NOT_FOUND; - - pRootEntry++; - } - - // Give the root entry pointer to the caller - if(ppRootEntry != NULL) - ppRootEntry[0] = pRootEntry; - return ERROR_SUCCESS; - } - } - - return ERROR_FILE_NOT_FOUND; -} - -bool DoStorageSearch_MNDX(TCascSearch * pSearch, PCASC_FIND_DATA pFindData) -{ - TMndxFindResult * pStruct1C = NULL; - PCASC_MNDX_INFO pMndxInfo = pSearch->hs->pMndxInfo; - PMAR_FILE pMarFile = pMndxInfo->pMarFile3; - bool bFindResult = false; - - // Sanity checks - assert(pMndxInfo != NULL); - - // If the first time, allocate the structure for the search result - if(pSearch->pStruct1C == NULL) - { - // Create the new search structure - pSearch->pStruct1C = pStruct1C = new TMndxFindResult; - if(pSearch->pStruct1C == NULL) - return false; - - // Setup the search mask - pStruct1C->SetSearchPath("", 0); - } - - // Make shortcut for the search structure - assert(pSearch->pStruct1C != NULL); - pStruct1C = (TMndxFindResult *)pSearch->pStruct1C; - - // Search the next file name (our code) - pMarFile->pDatabasePtr->sub_1956CE0(pStruct1C, &bFindResult); - if(bFindResult) - return FillFindData(pSearch, pFindData, pStruct1C); - - return false; -} - -void FreeMndxInfo(PCASC_MNDX_INFO pMndxInfo) -{ - if(pMndxInfo != NULL) - { - if(pMndxInfo->pMarFile1 != NULL) - MAR_FILE_Destructor(pMndxInfo->pMarFile1); - if(pMndxInfo->pMarFile2 != NULL) - MAR_FILE_Destructor(pMndxInfo->pMarFile2); - if(pMndxInfo->pMarFile3 != NULL) - MAR_FILE_Destructor(pMndxInfo->pMarFile3); - if(pMndxInfo->ppValidEntries != NULL) - CASC_FREE(pMndxInfo->ppValidEntries); - if(pMndxInfo->pMndxEntries != NULL) - CASC_FREE(pMndxInfo->pMndxEntries); - CASC_FREE(pMndxInfo); - } -} - -//---------------------------------------------------------------------------- -// Unit tests - -#if defined(_DEBUG) && defined(_X86_) && defined(CASCLIB_TEST) - -extern "C" { - DWORD _cdecl sub_19573D0_x86(TFileNameDatabase * pDB, DWORD arg_0, DWORD arg_4); - DWORD _cdecl sub_1957EF0_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C); - bool _cdecl sub_1959460_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C); - DWORD _cdecl GetItemValue_x86(TSparseArray * pStruct, DWORD dwKey); - DWORD _cdecl sub_1959CB0_x86(TFileNameDatabase * pDB, DWORD dwKey); - DWORD _cdecl sub_1959F50_x86(TFileNameDatabase * pDB, DWORD arg_0); -} - -extern "C" void * allocate_zeroed_memory_x86(size_t bytes) -{ - void * ptr = CASC_ALLOC(BYTE, bytes); - - if(ptr != NULL) - memset(ptr, 0, bytes); - return ptr; -} - -extern "C" void free_memory_x86(void * ptr) -{ - if(ptr != NULL) - { - CASC_FREE(ptr); - } -} - -static int sub_1956CE0_x86(TFileNameDatabasePtr * pDatabasePtr, TMndxFindResult * pStruct1C, bool * pbFindResult) -{ - int nError = ERROR_SUCCESS; - - if(pDatabasePtr->pDB == NULL) - return ERROR_INVALID_PARAMETER; - - // Create the pStruct40, if not initialized yet - if(pStruct1C->pStruct40 == NULL) - { - nError = pStruct1C->CreateStruct40(); - if(nError != ERROR_SUCCESS) - return nError; - } - - *pbFindResult = sub_1959460_x86(pDatabasePtr->pDB, pStruct1C); - return nError; -} -/* -static void TestFileSearch_SubStrings(PMAR_FILE pMarFile, char * szFileName, size_t nLength) -{ - TMndxFindResult Struct1C_1; - TMndxFindResult Struct1C_2; - -// if(strcmp(szFileName, "mods/heroes.stormmod/base.stormassets/assets/textures/storm_temp_war3_btnstatup.dds")) -// return; - - // Perform search on anything, that is longer than 4 chars - while(nLength >= 4) - { - // Set a substring as search name - Struct1C_1.SetSearchPath(szFileName, nLength); - Struct1C_2.SetSearchPath(szFileName, nLength); - szFileName[nLength] = 0; - - // Keep searching - for(;;) - { - bool bFindResult1 = false; - bool bFindResult2 = false; - - // Search the next file name (orig HOTS code) - sub_1956CE0_x86(pMarFile->pDatabasePtr, &Struct1C_1, &bFindResult1); - - // Search the next file name (our code) - pMarFile->pDatabasePtr->sub_1956CE0(&Struct1C_2, &bFindResult2); - - // Check the result - assert(bFindResult1 == bFindResult2); - assert(Struct1C_1.cchFoundPath == Struct1C_1.cchFoundPath); - assert(Struct1C_1.FileNameIndex == Struct1C_2.FileNameIndex); - assert(strncmp(Struct1C_1.szFoundPath, Struct1C_2.szFoundPath, Struct1C_1.cchFoundPath) == 0); - assert(Struct1C_1.cchFoundPath < MAX_PATH); - - // Stop the search in case of failure - if(bFindResult1 == false || bFindResult2 == false) - break; - } - - // Free the search structures - Struct1C_1.FreeStruct40(); - Struct1C_2.FreeStruct40(); - nLength--; - } -} -*/ - -static void TestFindPackage(PMAR_FILE pMarFile, const char * szPackageName) -{ - TMndxFindResult Struct1C; - - // Search the database for the file name - Struct1C.SetSearchPath(szPackageName, strlen(szPackageName)); - - // Search the file name in the second MAR info (the one with stripped package names) - MAR_FILE_SearchFile(pMarFile, &Struct1C); -} - -static void TestFileSearch(PMAR_FILE pMarFile, const char * szFileName) -{ - TMndxFindResult Struct1C_1; - TMndxFindResult Struct1C_2; - size_t nLength = strlen(szFileName); - char szNameBuff[MAX_PATH + 1]; - - // Set an empty path as search mask (?) - Struct1C_1.SetSearchPath(szFileName, nLength); - Struct1C_2.SetSearchPath(szFileName, nLength); - - // Keep searching - for(;;) - { - bool bFindResult1 = false; - bool bFindResult2 = false; - - // Search the next file name (orig HOTS code) - sub_1956CE0_x86(pMarFile->pDatabasePtr, &Struct1C_1, &bFindResult1); - - // Search the next file name (our code) - pMarFile->pDatabasePtr->sub_1956CE0(&Struct1C_2, &bFindResult2); - - assert(bFindResult1 == bFindResult2); - assert(Struct1C_1.cchFoundPath == Struct1C_1.cchFoundPath); - assert(Struct1C_1.FileNameIndex == Struct1C_2.FileNameIndex); - assert(strncmp(Struct1C_1.szFoundPath, Struct1C_2.szFoundPath, Struct1C_1.cchFoundPath) == 0); - assert(Struct1C_1.cchFoundPath < MAX_PATH); - - // Stop the search in case of failure - if(bFindResult1 == false || bFindResult2 == false) - break; - - // Printf the found file name - memcpy(szNameBuff, Struct1C_2.szFoundPath, Struct1C_2.cchFoundPath); - szNameBuff[Struct1C_2.cchFoundPath] = 0; -// printf("%s \r", szNameBuff); - - // Perform sub-searches on this string and its substrings that are longer than 4 chars -// TestFileSearch_SubStrings(pMarFile, szNameBuff, Struct1C_2.cchFoundPath); - } - - // Free the search structures - Struct1C_1.FreeStruct40(); - Struct1C_2.FreeStruct40(); -} - -static void TestMarFile(PMAR_FILE pMarFile, const char * szFileName, size_t nLength) -{ - TFileNameDatabase * pDB = pMarFile->pDatabasePtr->pDB; - DWORD dwFileNameIndex1 = 0xFFFFFFFF; - DWORD dwFileNameIndex2 = 0xFFFFFFFF; - - // Perform the search using original HOTS code - { - TMndxFindResult Struct1C; - - Struct1C.CreateStruct40(); - Struct1C.SetSearchPath(szFileName, nLength); - - // Call the original HOTS function - sub_1957EF0_x86(pDB, &Struct1C); - dwFileNameIndex1 = Struct1C.FileNameIndex; - } - - // Perform the search using our code - { - TMndxFindResult Struct1C; - - Struct1C.CreateStruct40(); - Struct1C.SetSearchPath(szFileName, nLength); - - // Call our function - pDB->FindFileInDatabase(&Struct1C); - dwFileNameIndex2 = Struct1C.FileNameIndex; - } - - // Compare both - assert(dwFileNameIndex1 == dwFileNameIndex2); -} - -static void TestMndxFunctions(PMAR_FILE pMarFile) -{ - TFileNameDatabase * pDB = pMarFile->pDatabasePtr->pDB; - - // Exercise function sub_19573D0 - for(DWORD arg_0 = 0; arg_0 < 0x100; arg_0++) - { - for(DWORD arg_4 = 0; arg_4 < 0x100; arg_4++) - { - DWORD dwResult1 = sub_19573D0_x86(pDB, arg_0, arg_4); - DWORD dwResult2 = pDB->GetNameFragmentOffsetEx(arg_0, arg_4); - - assert(dwResult1 == dwResult2); - } - } - - // Exercise function GetItemValue - for(DWORD i = 0; i < 0x10000; i++) - { - DWORD dwResult1 = GetItemValue_x86(&pDB->Struct68_D0, i); - DWORD dwResult2 = pDB->Struct68_D0.GetItemValue(i); - - assert(dwResult1 == dwResult2); - } - - // Exercise function sub_1959CB0 - for(DWORD i = 0; i < 0x9C; i++) - { - DWORD dwResult1 = sub_1959CB0_x86(pDB, i); - DWORD dwResult2 = pDB->sub_1959CB0(i); - - assert(dwResult1 == dwResult2); - } - - // Exercise function sub_1959F50 - for(DWORD i = 0; i < 0x40; i++) - { - DWORD dwResult1 = sub_1959F50_x86(pDB, i); - DWORD dwResult2 = pDB->sub_1959F50(i); - - assert(dwResult1 == dwResult2); - } -} - -void TestMndxRootFile(PCASC_MNDX_INFO pMndxInfo) -{ - size_t nLength; - char szFileName[MAX_PATH+1]; - void * pvListFile; - - // Exercise low level functions and compare their results - // with original code from Heroes of the Storm - TestMndxFunctions(pMndxInfo->pMarFile1); - TestMndxFunctions(pMndxInfo->pMarFile2); - TestMndxFunctions(pMndxInfo->pMarFile3); - - // Find a "mods" in the package array - TestFindPackage(pMndxInfo->pMarFile3, "mods/heroes.stormmod/base.stormassets/assets/textures/glow_green2.dds"); - TestMarFile(pMndxInfo->pMarFile3, "mods/heroes.stormmod/base.stormassets/assets/textures/glow_green2.dds", 69); - - // Search the package MAR file aith a path shorter than a fragment - TestFileSearch(pMndxInfo->pMarFile1, "mods/heroes.s"); - - // Test the file search - TestFileSearch(pMndxInfo->pMarFile1, ""); - TestFileSearch(pMndxInfo->pMarFile2, ""); - TestFileSearch(pMndxInfo->pMarFile3, ""); - - // False file search - TestFileSearch(pMndxInfo->pMarFile2, "assets/textures/storm_temp_hrhu"); - - // Open the listfile stream and initialize the listfile cache - pvListFile = ListFile_OpenExternal(_T("e:\\Ladik\\Appdir\\CascLib\\listfile\\listfile-hots-29049.txt")); - if(pvListFile != NULL) - { - // Check every file in the database - while((nLength = ListFile_GetNext(pvListFile, "*", szFileName, MAX_PATH)) != 0) - { - // Normalize the file name: ToLower + BackSlashToSlash - NormalizeFileName_LowerSlash(szFileName, szFileName, MAX_PATH); - - // Check the file with all three MAR files - TestMarFile(pMndxInfo->pMarFile1, szFileName, nLength); - TestMarFile(pMndxInfo->pMarFile2, szFileName, nLength); - TestMarFile(pMndxInfo->pMarFile3, szFileName, nLength); - } - - ListFile_Free(pvListFile); - } -} -#endif // defined(_DEBUG) && defined(_X86_) && defined(CASCLIB_TEST) diff --git a/dep/CascLib/src/CascMndxRoot.h b/dep/CascLib/src/CascMndxRoot.h deleted file mode 100644 index bd93f230845..00000000000 --- a/dep/CascLib/src/CascMndxRoot.h +++ /dev/null @@ -1,365 +0,0 @@ -/*****************************************************************************/ -/* CascMndxRoot.h Copyright (c) Ladislav Zezula 2014 */ -/*---------------------------------------------------------------------------*/ -/* Interface file for MNDX structures */ -/*---------------------------------------------------------------------------*/ -/* Date Ver Who Comment */ -/* -------- ---- --- ------- */ -/* 15.05.14 1.00 Lad Created */ -/*****************************************************************************/ - -#ifndef __CASC_MNDX_ROOT__ -#define __CASC_MNDX_ROOT__ - -class TFileNameDatabase; - -#define CASC_MAX_ENTRIES(type) (0xFFFFFFFF / sizeof(type)) - -#define CASC_SEARCH_INITIALIZING 0 -#define CASC_SEARCH_SEARCHING 2 -#define CASC_SEARCH_FINISHED 4 - -typedef struct _TRIPLET -{ - DWORD BaseValue; - DWORD Value2; - DWORD Value3; -} TRIPLET, *PTRIPLET; - -typedef struct _NAME_FRAG -{ - DWORD ItemIndex; // Back index to various tables - DWORD NextIndex; // The following item index - DWORD FragOffs; // Higher 24 bits are 0xFFFFFF00 --> A single matching character - // Otherwise --> Offset to the name fragment table -} NAME_FRAG, *PNAME_FRAG; - -typedef struct _PATH_STOP -{ - DWORD ItemIndex; - DWORD field_4; - DWORD field_8; - DWORD field_C; - DWORD field_10; -} PATH_STOP, *PPATH_STOP; - -typedef union _ARRAY_POINTER -{ - LPBYTE Bytes; // Pointer to an octet - char * Chars; // Pointer to a character - PDWORD Uint32s; // Pointer to a DWORD - PTRIPLET Triplets; // Pointer to TRIPLET - PNAME_FRAG NameFrags; // Pointer to name fragment entry - PPATH_STOP PathStopPtr; // Pointer to path checkpoint - PULONGLONG Int64Ptr; // Pointer to 64-bit integer - -} ARRAY_POINTER, *PARRAY_POINTER; - -// Simple access to various tables within TGenericArray -#define ByteArray ArrayPointer.Bytes -#define CharArray ArrayPointer.Chars -#define Uint32Array ArrayPointer.Uint32s -#define TripletArray ArrayPointer.Triplets -#define NameFragArray ArrayPointer.NameFrags - -class TByteStream -{ - public: - - TByteStream(); - - void ExchangeWith(TByteStream & Target); - int GetBytes(DWORD cbByteCount, PARRAY_POINTER PtrArray); - int SkipBytes(DWORD cbByteCount); - int SetByteBuffer(LPBYTE pbNewMarData, DWORD cbNewMarData); - int GetValue_DWORD(DWORD & Value); - int GetValue_ItemCount(DWORD & NumberOfBytes, DWORD & ItemCount, DWORD ItemSize); - int GetArray_DWORDs(PARRAY_POINTER PtrArray, DWORD ItemCount); - int GetArray_Triplets(PARRAY_POINTER PtrArray, DWORD ItemCount); - int GetArray_NameTable(PARRAY_POINTER PtrArray, DWORD ItemCount); - int GetArray_BYTES(PARRAY_POINTER PtrArray, DWORD ItemCount); - - LPBYTE pbByteData; - void * pvMappedFile; - DWORD cbByteData; - DWORD field_C; - HANDLE hFile; - HANDLE hMap; -}; - -class TGenericArray -{ - public: - - TGenericArray(); - ~TGenericArray(); - - int SetArrayValid(); - - void ExchangeWith(TGenericArray & Target); - void CopyFrom(TGenericArray & Source); - - void SetMaxItems_CHARS(DWORD NewMaxItemCount); - void SetMaxItems_PATH_STOP(DWORD NewMaxItemCount); - - void InsertOneItem_CHAR(char OneChar); - void InsertOneItem_PATH_STOP(PATH_STOP & NewItem); - - void sub_19583A0(DWORD NewItemCount); - - int LoadDwordsArray(TByteStream & InStream); - int LoadTripletsArray(TByteStream & InStream); - int LoadByteArray(TByteStream & InStream); - int LoadFragmentInfos(TByteStream & InStream); - int LoadStrings(TByteStream & InStream); - - int LoadDwordsArray_Copy(TByteStream & InStream); - int LoadTripletsArray_Copy(TByteStream & InStream); - int LoadBytes_Copy(TByteStream & InStream); - int LoadFragmentInfos_Copy(TByteStream & InStream); - int LoadStringsWithCopy(TByteStream & InStream); - - ARRAY_POINTER DataBuffer; - ARRAY_POINTER FirstValid; - - ARRAY_POINTER ArrayPointer; - DWORD ItemCount; // Number of items in the array - DWORD MaxItemCount; // Capacity of the array - bool bIsValidArray; -}; - -class TBitEntryArray : public TGenericArray -{ - public: - - TBitEntryArray(); - ~TBitEntryArray(); - - DWORD GetBitEntry(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 = (Uint32Array[dwItemIndex + 1] << (0x20 - dwStartBit)) | (Uint32Array[dwItemIndex] >> dwStartBit); - } - else - { - dwResult = Uint32Array[dwItemIndex] >> dwStartBit; - } - - // Now we also need to mask the result by the bit mask - return dwResult & EntryBitMask; - } - - void ExchangeWith(TBitEntryArray & Target); - int LoadFromStream(TByteStream & InStream); - int LoadFromStream_Exchange(TByteStream & InStream); - - DWORD BitsPerEntry; - DWORD EntryBitMask; - DWORD TotalEntries; -}; - -class TStruct40 -{ - public: - - TStruct40(); - - void InitSearchBuffers(); - - TGenericArray array_00; - TGenericArray PathStops; // Array of path checkpoints - DWORD ItemIndex; // Current name fragment: Index to various tables - DWORD CharIndex; - DWORD ItemCount; - DWORD SearchPhase; // 0 = initializing, 2 = searching, 4 = finished -}; - -class TMndxFindResult -{ - public: - - TMndxFindResult(); - ~TMndxFindResult(); - - int CreateStruct40(); - void FreeStruct40(); - - int SetSearchPath(const char * szNewSearchPath, size_t cchNewSearchPath); - - const char * szSearchMask; // Search mask without wioldcards - size_t cchSearchMask; // Length of the search mask - DWORD field_8; - const char * szFoundPath; // Found path name - size_t cchFoundPath; // Length of the found path name - DWORD FileNameIndex; // Index of the file name - TStruct40 * pStruct40; -}; - -class TSparseArray -{ - public: - - TSparseArray(); - - void ExchangeWith(TSparseArray & TargetObject); - int LoadFromStream(TByteStream & InStream); - int LoadFromStream_Exchange(TByteStream & InStream); - - // Returns true if the item at n-th position is present - DWORD IsItemPresent(DWORD ItemIndex) - { - return (ItemBits.Uint32Array[ItemIndex >> 0x05] & (1 << (ItemIndex & 0x1F))); - } - - DWORD GetItemValue(DWORD ItemIndex); - - TGenericArray ItemBits; // Bit array for each item (1 = item is present) - DWORD TotalItemCount; // Total number of items in the array - DWORD ValidItemCount; // Number of present items in the array - TGenericArray BaseValues; // Array of base values for item indexes >= 0x200 - TGenericArray ArrayDwords_38; - TGenericArray ArrayDwords_50; -}; - -class TNameIndexStruct -{ - public: - - TNameIndexStruct(); - ~TNameIndexStruct(); - - bool CheckNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs); - bool CheckAndCopyNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs); - void CopyNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs); - - void ExchangeWith(TNameIndexStruct & Target); - int LoadFromStream(TByteStream & InStream); - int LoadFromStream_Exchange(TByteStream & InStream); - - TGenericArray NameFragments; - TSparseArray Struct68; -}; - -class TStruct10 -{ - public: - - TStruct10(); - - void CopyFrom(TStruct10 & Target); - int sub_1956FD0(DWORD dwBitMask); - int sub_1957050(DWORD dwBitMask); - int sub_19572E0(DWORD dwBitMask); - int sub_1957800(DWORD dwBitMask); - - DWORD field_0; - DWORD field_4; - DWORD field_8; - DWORD field_C; -}; - -class TFileNameDatabasePtr -{ - public: - - TFileNameDatabasePtr(); - ~TFileNameDatabasePtr(); - - int FindFileInDatabase(TMndxFindResult * pStruct1C); - int sub_1956CE0(TMndxFindResult * pStruct1C, bool * pbFindResult); - - int GetFileNameCount(PDWORD PtrFileNameCount); - int CreateDatabase(LPBYTE pbMarData, DWORD cbMarData); - int SetDatabase(TFileNameDatabase * pNewDB); - - TFileNameDatabase * pDB; -}; - -class TFileNameDatabase -{ - public: - - TFileNameDatabase(); - - void ExchangeWith(TFileNameDatabase & Target); - int LoadFromStream(TByteStream & InStream); - int LoadFromStream_Exchange(TByteStream & InStream); - - DWORD sub_1959CB0(DWORD dwHashValue); - DWORD sub_1959F50(DWORD arg_0); - - // Retrieves the name fragment distance - // HOTS: 19573D0/inlined - DWORD GetNameFragmentOffsetEx(DWORD LoBitsIndex, DWORD HiBitsIndex) - { - return (FrgmDist_HiBits.GetBitEntry(HiBitsIndex) << 0x08) | FrgmDist_LoBits.ByteArray[LoBitsIndex]; - } - - // HOTS: 1957350, inlined - DWORD GetNameFragmentOffset(DWORD LoBitsIndex) - { - return GetNameFragmentOffsetEx(LoBitsIndex, Struct68_D0.GetItemValue(LoBitsIndex)); - } - - bool sub_1957B80(TMndxFindResult * pStruct1C, DWORD dwKey); - bool CheckNextPathFragment(TMndxFindResult * pStruct1C); - bool FindFileInDatabase(TMndxFindResult * pStruct1C); - - void sub_1958D70(TMndxFindResult * pStruct1C, DWORD arg_4); - bool sub_1959010(TMndxFindResult * pStruct1C, DWORD arg_4); - bool sub_1958B00(TMndxFindResult * pStruct1C); - bool sub_1959460(TMndxFindResult * pStruct1C); - - TSparseArray Struct68_00; - TSparseArray FileNameIndexes; // Array of file name indexes - TSparseArray Struct68_D0; - - // This pair of arrays serves for fast conversion from name hash to fragment offset - TGenericArray FrgmDist_LoBits; // Array of lower 8 bits of name fragment offset - TBitEntryArray FrgmDist_HiBits; // Array of upper x bits of name fragment offset - - TNameIndexStruct IndexStruct_174; - TFileNameDatabasePtr NextDB; - - TGenericArray NameFragTable; - - DWORD NameFragIndexMask; - DWORD field_214; - TStruct10 Struct10; - TByteStream MarStream; -}; - -typedef struct _MAR_FILE -{ - TFileNameDatabasePtr * pDatabasePtr; - LPBYTE pbMarData; - DWORD cbMarData; -} MAR_FILE, *PMAR_FILE; - -//----------------------------------------------------------------------------- -// Macros - -// Returns nonzero if the name fragment match is a single-char match -inline bool IS_SINGLE_CHAR_MATCH(TGenericArray & Table, DWORD ItemIndex) -{ - return ((Table.NameFragArray[ItemIndex].FragOffs & 0xFFFFFF00) == 0xFFFFFF00); -} - -//----------------------------------------------------------------------------- -// CASC functions related to MNDX - -int LoadMndxRootFile(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile); -PCASC_PACKAGE FindMndxPackage(TCascStorage * hs, const char * szFileName); -int SearchMndxInfo(PCASC_MNDX_INFO pMndxInfo, const char * szFileName, DWORD dwPackage, PCASC_ROOT_ENTRY_MNDX * ppFoundInfo); -bool DoStorageSearch_MNDX(TCascSearch * pSearch, PCASC_FIND_DATA pFindData); -void FreeMndxInfo(PCASC_MNDX_INFO pMndxInfo); - -#endif // __CASC_MNDX_ROOT__ diff --git a/dep/CascLib/src/CascMndxRoot_x86.asm b/dep/CascLib/src/CascMndxRoot_x86.asm deleted file mode 100644 index c0e787d0872..00000000000 --- a/dep/CascLib/src/CascMndxRoot_x86.asm +++ /dev/null @@ -1,4369 +0,0 @@ -.686P -.MODEL FLAT -ASSUME FS: NOTHING - -; --------------------------------------------------------------------------- - -TMndxFindResult struc ; (sizeof=0x1C) ; XREF: GAME_OBJECT_03F7E848::sub_E94500_r -szSearchMask dd ? ; XREF: TMndxFindResult__SetPath+2D_w - ; TMndxFindResult__Constructor+4_w ... -cchSearchMask dd ? ; XREF: TMndxFindResult__SetPath:loc_1956E9A_w - ; TMndxFindResult__Constructor+6_w ... -field_8 dd ? ; XREF: TMndxFindResult__Constructor+9_w -szFoundPath dd ? ; XREF: TMndxFindResult__Constructor+C_w - ; TFileNameDatabase__FindFileInDatabase+55_w -cchFoundPath dd ? ; XREF: TMndxFindResult__Constructor+F_w - ; TFileNameDatabase__FindFileInDatabase+5B_w -FileNameIndex dd ? ; XREF: TMndxFindResult__Constructor+12_w - ; TFileNameDatabase__FindFileInDatabase+6B_w -pStruct40 dd ? ; XREF: MAR_FILE__FindFileInDatabase+19_r - ; TMndxFindResult__SetPath:loc_1956E8C_r ... -TMndxFindResult ends - -; --------------------------------------------------------------------------- - -TRIPLET struc ; (sizeof=0xC) -BitIndex dd ? ; XREF: TFileNameDatabase__CheckNextPathFragment+39_r -NextKey dd ? ; XREF: TFileNameDatabase__CheckNextPathFragment+8C_r - ; TSparseArray__GetItemValue:loc_1959B8F_r ... -Distance dd ? ; XREF: TFileNameDatabase__CheckNextPathFragment+3E_r - ; TSparseArray__GetItemValue:loc_1959BBE_r ... -TRIPLET ends - -; --------------------------------------------------------------------------- - -NAME_ENTRY struc ; (sizeof=0xC) -ExpectedHashModifier dd ? -NextHashModifier dd ? ; XREF: TArchiveDatabase__sub_1958B00+D3r - ; sub_1958D70+2Cr -FragmentOffset dd ? ; XREF: TArchiveDatabase__sub_1958B00+45r - ; sub_1958D70+36r -NAME_ENTRY ends - -; --------------------------------------------------------------------------- - -TStruct14 struc ; (sizeof=0x14) ; XREF: TFileNameDatabase::sub_1959460r -HashValue dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+44r - ; TGenericArray__InsertItem_STRUCT14+46w ... -field_4 dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+48r - ; TGenericArray__InsertItem_STRUCT14+4Bw ... -field_8 dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+4Er - ; TGenericArray__InsertItem_STRUCT14+51w ... -field_C dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+54r - ; TGenericArray__InsertItem_STRUCT14+57w ... -field_10 dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+5Ar - ; TGenericArray__InsertItem_STRUCT14+5Dw ... -TStruct14 ends - -; --------------------------------------------------------------------------- - -TGenericArray struc ; (sizeof=0x15) ; XREF: TGenericArray::LoadDwordsArrayWithCopyr - ; TFileNameDatabase::LoadBytesr ... -DataBuffer dd ? ; XREF: TMndxFindResult__CreateStruct40+24w - ; TMndxFindResult__CreateStruct40+35w ... -field_4 dd ? ; XREF: TMndxFindResult__CreateStruct40+26w - ; TMndxFindResult__CreateStruct40+38w ... -ItemArray dd ? ; XREF: TMndxFindResult__CreateStruct40+29w - ; TMndxFindResult__CreateStruct40+3Bw ... -ItemCount dd ? ; XREF: TMndxFindResult__CreateStruct40+2Cw - ; TMndxFindResult__CreateStruct40+3Ew ... -MaxItemCount dd ? ; XREF: TFileNameDatabasePtr__CreateDatabase+27o - ; TMndxFindResult__CreateStruct40+2Fw ... -bIsValidArray db ? ; XREF: LoadAndVerifyIndexFileHeader+31w - ; TMndxFindResult__CreateStruct40+32w ... -TGenericArray ends - -; --------------------------------------------------------------------------- - -TBitEntryArray struc ; (sizeof=0x24) ; XREF: TGenericArrayEx::LoadFromStream_Exchanger - ; TFileNameDatabaser -DataBuffer dd ? ; XREF: TArchiveDatabase__Destructor+64r - ; TArchiveDatabase__Constructor+1A3w -field_4 dd ? ; XREF: TArchiveDatabase__Constructor+1A9w -ItemArray dd ? ; XREF: sub_1957350+31r - ; sub_19573D0+1Fr ... -ItemCount dd ? ; XREF: TArchiveDatabase__Constructor+1B5w -MaxItemCount dd ? ; XREF: TArchiveDatabase__Constructor+1BBw -bIsValidArray db ? ; XREF: TArchiveDatabase__Constructor+1C1w - db ? ; undefined - db ? ; undefined - db ? ; undefined -BitsPerEntry dd ? ; XREF: sub_1957350+1Fr - ; sub_19573D0+6r ... -EntryBitMask dd ? ; XREF: sub_1957350:loc_19573B1r - ; sub_19573D0:loc_1957419r ... -TotalEntries dd ? ; XREF: TGenericArrayEx__LoadFromStream:loc_195861Bw - ; TArchiveDatabase__Constructor+1D3w -TBitEntryArray ends - ; TFileNameDatabase__Constructor+1D3_w -; --------------------------------------------------------------------------- - -TStruct40 struc ; (sizeof=0x40) -array_00 TGenericArray <> ; XREF: TMndxFindResult__CreateStruct40+24w - ; TMndxFindResult__CreateStruct40+26w ... - db ? ; undefined - db ? ; undefined - db ? ; undefined -array_18 TGenericArray <> ; XREF: TMndxFindResult__CreateStruct40+35w - ; TMndxFindResult__CreateStruct40+38w ... - db ? ; undefined - db ? ; undefined - db ? ; undefined -HashValue dd ? ; XREF: TMndxFindResult__CreateStruct40+47w - ; TFileNameDatabase__CheckNextPathFragment+1Ar ... -CharIndex dd ? ; XREF: TMndxFindResult__CreateStruct40+4Aw - ; TFileNameDatabase__CheckNextPathFragment+11r ... -ItemCount dd ? ; XREF: TMndxFindResult__CreateStruct40+4Dw - ; TStruct40__InitSearchBuffers+6Bw ... -SearchPhase dd ? ; XREF: TMndxFindResult__CreateStruct40+50w - ; TFileNameDatabase__FindFileInDatabase+17w ... -TStruct40 ends - -; --------------------------------------------------------------------------- - -TSparseArray struc ; (sizeof=0x65) ; XREF: TSparseArray::LoadFromStream_Exchange_r - ; TNameIndexStruct_r ... -ItemIsPresent TGenericArray <> ; XREF: LoadAndVerifyIndexFileHeader+31_w - ; TFileNameDatabase__Destructor+4C_r ... - db ? ; undefined - db ? ; undefined - db ? ; undefined -TotalItemCount dd ? ; XREF: TSparseArray__ExchangeWith+4D_r - ; TSparseArray__ExchangeWith+56_w ... -ValidItemCount dd ? ; XREF: TFileNameDatabasePtr__GetFileNameCount:loc_1956D32_r - ; TSparseArray__ExchangeWith+59_r ... -ArrayTriplets_20 TGenericArray <> ; XREF: TFileNameDatabase__Destructor+40_r - ; TFileNameDatabase__Destructor+94_r ... - db ? ; undefined - db ? ; undefined - db ? ; undefined -ArrayDwords_38 TGenericArray <> ; XREF: TFileNameDatabasePtr__CreateDatabase+27_o - ; TFileNameDatabase__Destructor+34_r ... - db ? ; undefined - db ? ; undefined - db ? ; undefined -ArrayDwords_50 TGenericArray <> ; XREF: TFileNameDatabase__Destructor+28_r - ; TFileNameDatabase__Destructor+7C_r ... -TSparseArray ends - -; --------------------------------------------------------------------------- - -TNameIndexStruct struc ; (sizeof=0x7D) ; XREF: TNameIndexStruct::LoadFromStream_Exchange_r - ; TFileNameDatabaser -NameFragments TGenericArray <> ; XREF: TFileNameDatabase__Destructor+58_r - ; TFileNameDatabase__LoadFromStream+82_r ... - db ? ; undefined - db ? ; undefined - db ? ; undefined -Struct68 TSparseArray <> ; XREF: LoadAndVerifyIndexFileHeader+31_w - ; TFileNameDatabase__Destructor+28_r ... -TNameIndexStruct ends - -; --------------------------------------------------------------------------- - -TByteStream struc ; (sizeof=0x18) ; XREF: TFileNameDatabasePtr::CreateDatabase_r - ; TFileNameDatabase_r -pbData dd ? ; XREF: TByteStream__Constructor+4_w - ; TByteStream__IsMarDataValid+2_r ... -pvMappedFile dd ? ; XREF: TByteStream__Constructor+6_w - ; TByteStream__Destructor+3_r -cbData dd ? ; XREF: TByteStream__Constructor+9_w - ; TByteStream__GetBytes:loc_1959A05_r ... -field_C dd ? ; XREF: TByteStream__Constructor+C_w -hFile dd ? ; XREF: TByteStream__Constructor+F_w - ; TByteStream__Destructor:loc_19599D2_r -hMap dd ? ; XREF: TByteStream__Constructor+12_w - ; TByteStream__Destructor:loc_19599C2_r -TByteStream ends - -; --------------------------------------------------------------------------- - -TStruct10 struc ; (sizeof=0x10) ; XREF: TStruct10::sub_1957800_r - ; TFileNameDatabase_r -field_0 dd ? ; XREF: sub_19572E0+24_w - ; TFileNameDatabase__Constructor+21A_w -field_4 dd ? ; XREF: sub_1956FD0+28_w - ; sub_1956FD0:loc_1957001_w ... -field_8 dd ? ; XREF: sub_19572E0+4A_w - ; sub_19572E0+5B_w ... -field_C dd ? ; XREF: sub_1957050:loc_1957074_w - ; sub_1957050:loc_1957081_w ... -TStruct10 ends - -; --------------------------------------------------------------------------- - -TFileNameDatabasePtr struc ; (sizeof=0x4) ; XREF: TFileNameDatabase_r - ; MAR_FILE_r -pDatabase dd ? ; XREF: MAR_FILE__Constructor+1D_w - ; MAR_FILE__CreateDatabase+22_w ... -TFileNameDatabasePtr ends - -; --------------------------------------------------------------------------- - -TFileNameDatabase struc ; (sizeof=0x240) ; XREF: TFileNameDatabase::LoadFromStream_Exchange_r -Struct68_00 TSparseArray <> ; XREF: TFileNameDatabasePtr__CreateDatabase+27_o - ; TFileNameDatabase__Destructor+D9_r ... - db ? ; undefined - db ? ; undefined - db ? ; undefined -FileNameIndexes TSparseArray <> ; XREF: TFileNameDatabasePtr__GetFileNameCount:loc_1956D32_r - ; TFileNameDatabase__Destructor+AC_r ... - db ? ; undefined - db ? ; undefined - db ? ; undefined -Struct68_D0 TSparseArray <> ; XREF: TFileNameDatabase__Destructor+7C_r - ; TFileNameDatabase__Destructor+88_r ... - db ? ; undefined - db ? ; undefined - db ? ; undefined -FrgmDist_LoBits TGenericArray <> ; XREF: TFileNameDatabase__Destructor+70_r - ; TFileNameDatabase__CheckNextPathFragment:loc_1957AC9_r ... - db ? ; undefined - db ? ; undefined - db ? ; undefined -FrgmDist_HiBits TBitEntryArray <> ; XREF: TFileNameDatabase__Destructor+64_r - ; TFileNameDatabase__CheckNextPathFragment+119_r ... -IndexStruct_174 TNameIndexStruct <> ; XREF: TFileNameDatabase__Destructor+28_r - ; TFileNameDatabase__Destructor+34_r ... - db ? ; undefined - db ? ; undefined - db ? ; undefined -NextDB TFileNameDatabasePtr <> ; XREF: TFileNameDatabase__Destructor+1D_o - ; TFileNameDatabase__CheckNextPathFragment+52_r ... -NameFragTable TGenericArray <> ; XREF: TFileNameDatabase__Destructor+E_r - ; TFileNameDatabase__CheckNextPathFragment+2F_r ... - db ? ; undefined - db ? ; undefined - db ? ; undefined -NameFragIndexMask dd ? ; XREF: TFileNameDatabase__CheckNextPathFragment+26_r - ; sub_1957B80:loc_1957B95_r ... -field_214 dd ? ; XREF: TFileNameDatabase__Constructor+20E_w - ; TFileNameDatabase__LoadFromStream+110_w -Struct10 TStruct10 <> ; XREF: TFileNameDatabase__Constructor+21A_w - ; TFileNameDatabase__Constructor+224_w ... -MarStream TByteStream <> ; XREF: TFileNameDatabase__Destructor+3_o - ; TFileNameDatabase__Constructor+214_o -TFileNameDatabase ends - -; --------------------------------------------------------------------------- - -MAR_FILE struc ; (sizeof=0xC) -pDatabasePtr TFileNameDatabasePtr <> ; XREF: MAR_FILE__Constructor+1D_w - ; MAR_FILE__CreateDatabase+22_w ... -pbMarFileData dd ? ; XREF: MAR_FILE__Constructor+1A_w - ; MAR_FILE__CreateDatabase+1B_r ... -cbMarFileData dd ? ; XREF: MAR_FILE__Constructor+12_w - ; MAR_FILE__CreateDatabase+18_r ... -MAR_FILE ends - -.DATA -table_1BA1818 db 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0 - db 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0 - db 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0 - db 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0 - db 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0 - db 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0 - db 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0 - db 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 - db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0 - db 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0 - db 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0 - db 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0 - db 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0 - db 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0 - db 2, 0, 1, 0, 3 dup(7), 1, 7, 2 dup(2), 1, 7, 2 dup(3) - db 1, 3, 2 dup(2), 1, 7, 2 dup(4), 1, 4, 2 dup(2), 1, 4 - db 2 dup(3), 1, 3, 2 dup(2), 1, 7, 2 dup(5), 1, 5, 2 dup(2) - db 1, 5, 2 dup(3), 1, 3, 2 dup(2), 1, 5, 2 dup(4), 1, 4 - db 2 dup(2), 1, 4, 2 dup(3), 1, 3, 2 dup(2), 1, 7, 2 dup(6) - db 1, 6, 2 dup(2), 1, 6, 2 dup(3), 1, 3, 2 dup(2), 1, 6 - db 2 dup(4), 1, 4, 2 dup(2), 1, 4, 2 dup(3), 1, 3, 2 dup(2) - db 1, 6, 2 dup(5), 1, 5, 2 dup(2), 1, 5, 2 dup(3), 1, 3 - db 2 dup(2), 1, 5, 2 dup(4), 1, 4, 2 dup(2), 1, 4, 2 dup(3) - db 1, 3, 2 dup(2), 1, 3 dup(7), 1, 7, 2 dup(2), 1, 7, 2 dup(3) - db 1, 3, 2 dup(2), 1, 7, 2 dup(4), 1, 4, 2 dup(2), 1, 4 - db 2 dup(3), 1, 3, 2 dup(2), 1, 7, 2 dup(5), 1, 5, 2 dup(2) - db 1, 5, 2 dup(3), 1, 3, 2 dup(2), 1, 5, 2 dup(4), 1, 4 - db 2 dup(2), 1, 4, 2 dup(3), 1, 3, 2 dup(2), 1, 7, 2 dup(6) - db 1, 6, 2 dup(2), 1, 6, 2 dup(3), 1, 3, 2 dup(2), 1, 6 - db 2 dup(4), 1, 4, 2 dup(2), 1, 4, 2 dup(3), 1, 3, 2 dup(2) - db 1, 6, 2 dup(5), 1, 5, 2 dup(2), 1, 5, 2 dup(3), 1, 3 - db 2 dup(2), 1, 5, 2 dup(4), 1, 4, 2 dup(2), 1, 4, 2 dup(3) - db 1, 3, 2 dup(2), 1, 7 dup(7), 2, 3 dup(7), 3, 7, 2 dup(3) - db 2, 3 dup(7), 4, 7, 2 dup(4), 2, 7, 2 dup(4), 3, 4, 2 dup(3) - db 2, 3 dup(7), 5, 7, 2 dup(5), 2, 7, 2 dup(5), 3, 5, 2 dup(3) - db 2, 7, 2 dup(5), 4, 5, 2 dup(4), 2, 5, 2 dup(4), 3, 4 - db 2 dup(3), 2, 3 dup(7), 6, 7, 2 dup(6), 2, 7, 2 dup(6) - db 3, 6, 2 dup(3), 2, 7, 2 dup(6), 4, 6, 2 dup(4), 2, 6 - db 2 dup(4), 3, 4, 2 dup(3), 2, 7, 2 dup(6), 5, 6, 2 dup(5) - db 2, 6, 2 dup(5), 3, 5, 2 dup(3), 2, 6, 2 dup(5), 4, 5 - db 2 dup(4), 2, 5, 2 dup(4), 3, 4, 2 dup(3), 2, 7 dup(7) - db 2, 3 dup(7), 3, 7, 2 dup(3), 2, 3 dup(7), 4, 7, 2 dup(4) - db 2, 7, 2 dup(4), 3, 4, 2 dup(3), 2, 3 dup(7), 5, 7, 2 dup(5) - db 2, 7, 2 dup(5), 3, 5, 2 dup(3), 2, 7, 2 dup(5), 4, 5 - db 2 dup(4), 2, 5, 2 dup(4), 3, 4, 2 dup(3), 2, 3 dup(7) - db 6, 7, 2 dup(6), 2, 7, 2 dup(6), 3, 6, 2 dup(3), 2, 7 - db 2 dup(6), 4, 6, 2 dup(4), 2, 6, 2 dup(4), 3, 4, 2 dup(3) - db 2, 7, 2 dup(6), 5, 6, 2 dup(5), 2, 6, 2 dup(5), 3, 5 - db 2 dup(3), 2, 6, 2 dup(5), 4, 5, 2 dup(4), 2, 5, 2 dup(4) - db 3, 4, 2 dup(3), 2, 0Fh dup(7), 3, 7 dup(7), 4, 3 dup(7) - db 4, 7, 2 dup(4), 3, 7 dup(7), 5, 3 dup(7), 5, 7, 2 dup(5) - db 3, 3 dup(7), 5, 7, 2 dup(5), 4, 7, 2 dup(5), 4, 5, 2 dup(4) - db 3, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6), 3, 3 dup(7) - db 6, 7, 2 dup(6), 4, 7, 2 dup(6), 4, 6, 2 dup(4), 3, 3 dup(7) - db 6, 7, 2 dup(6), 5, 7, 2 dup(6), 5, 6, 2 dup(5), 3, 7 - db 2 dup(6), 5, 6, 2 dup(5), 4, 6, 2 dup(5), 4, 5, 2 dup(4) - db 3, 0Fh dup(7), 3, 7 dup(7), 4, 3 dup(7), 4, 7, 2 dup(4) - db 3, 7 dup(7), 5, 3 dup(7), 5, 7, 2 dup(5), 3, 3 dup(7) - db 5, 7, 2 dup(5), 4, 7, 2 dup(5), 4, 5, 2 dup(4), 3, 7 dup(7) - db 6, 3 dup(7), 6, 7, 2 dup(6), 3, 3 dup(7), 6, 7, 2 dup(6) - db 4, 7, 2 dup(6), 4, 6, 2 dup(4), 3, 3 dup(7), 6, 7, 2 dup(6) - db 5, 7, 2 dup(6), 5, 6, 2 dup(5), 3, 7, 2 dup(6), 5, 6 - db 2 dup(5), 4, 6, 2 dup(5), 4, 5, 2 dup(4), 3, 1Fh dup(7) - db 4, 0Fh dup(7), 5, 7 dup(7), 5, 3 dup(7), 5, 7, 2 dup(5) - db 4, 0Fh dup(7), 6, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6) - db 4, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6), 5, 3 dup(7) - db 6, 7, 2 dup(6), 5, 7, 2 dup(6), 5, 6, 2 dup(5), 4, 1Fh dup(7) - db 4, 0Fh dup(7), 5, 7 dup(7), 5, 3 dup(7), 5, 7, 2 dup(5) - db 4, 0Fh dup(7), 6, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6) - db 4, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6), 5, 3 dup(7) - db 6, 7, 2 dup(6), 5, 7, 2 dup(6), 5, 6, 2 dup(5), 4, 3Fh dup(7) - db 5, 1Fh dup(7), 6, 0Fh dup(7), 6, 7 dup(7), 6, 3 dup(7) - db 6, 7, 2 dup(6), 5, 3Fh dup(7), 5, 1Fh dup(7), 6, 0Fh dup(7) - db 6, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6), 5, 7Fh dup(7) - db 6, 7Fh dup(7), 6, 100h dup(7) - -unk_53ABE00 db 0 - -.CODE - -; -; void * operator_new_safe(size_t ByteCount, void * unk_53ABE00); -; - -EXTERN _allocate_zeroed_memory_x86:PROC -EXTERN _free_memory_x86:PROC - -j_operator_new_safe PROC - push ebp - mov ebp, esp - push [ebp+08] - call _allocate_zeroed_memory_x86 - add esp, 4 - mov esp, ebp - pop ebp - ret -j_operator_new_safe ENDP - -operator_delete PROC - push ebp - mov ebp, esp - push [ebp+08] - call _free_memory_x86 - add esp, 4 - mov esp, ebp - pop ebp - ret -operator_delete ENDP - - -TSparseArray__GetItemValue proc near ; CODE XREF: sub_1957350+1A_p - ; TFileNameDatabase__CheckNextPathFragment+103_p ... - -arg_0 = dword ptr 8 - - push ebp - mov ebp, esp - mov edx, [ecx+28h] - push ebx - push esi - push edi - mov edi, [ebp+arg_0] - mov eax, edi - shr eax, 9 - lea eax, [eax+eax*2] - mov esi, [edx+eax*4] - lea eax, [edx+eax*4] - mov edx, edi - shr edx, 6 - and edx, 7 - dec edx - cmp edx, 6 ; switch 7 cases - ja short loc_1959BE0 ; jumptable 01959B88 default case - jmp ds:off_1959C90[edx*4] ; switch jump - -loc_1959B8F: ; DATA XREF: .text:off_1959C90o - mov eax, [eax+4] ; jumptable 01959B88 case 0 - and eax, 7Fh - jmp short loc_1959BDE -; --------------------------------------------------------------------------- - -loc_1959B97: ; CODE XREF: TSparseArray__GetItemValue+28_j - ; DATA XREF: .text:off_1959C90o - mov edx, [eax+4] ; jumptable 01959B88 case 1 - shr edx, 7 - and edx, 0FFh - add esi, edx - jmp short loc_1959BE0 ; jumptable 01959B88 default case -; --------------------------------------------------------------------------- - -loc_1959BA7: ; CODE XREF: TSparseArray__GetItemValue+28_j - ; DATA XREF: .text:off_1959C90o - mov eax, [eax+4] ; jumptable 01959B88 case 2 - shr eax, 0Fh - and eax, 0FFh - jmp short loc_1959BDE -; --------------------------------------------------------------------------- - -loc_1959BB4: ; CODE XREF: TSparseArray__GetItemValue+28_j - ; DATA XREF: .text:off_1959C90o - mov edx, [eax+4] ; jumptable 01959B88 case 3 - shr edx, 17h - add esi, edx - jmp short loc_1959BE0 ; jumptable 01959B88 default case -; --------------------------------------------------------------------------- - -loc_1959BBE: ; CODE XREF: TSparseArray__GetItemValue+28_j - ; DATA XREF: .text:off_1959C90o - mov eax, [eax+8] ; jumptable 01959B88 case 4 - jmp short loc_1959BD9 -; --------------------------------------------------------------------------- - -loc_1959BC3: ; CODE XREF: TSparseArray__GetItemValue+28_j - ; DATA XREF: .text:off_1959C90o - mov edx, [eax+8] ; jumptable 01959B88 case 5 - shr edx, 9 - and edx, 1FFh - add esi, edx - jmp short loc_1959BE0 ; jumptable 01959B88 default case -; --------------------------------------------------------------------------- - -loc_1959BD3: ; CODE XREF: TSparseArray__GetItemValue+28_j - ; DATA XREF: .text:off_1959C90o - mov eax, [eax+8] ; jumptable 01959B88 case 6 - shr eax, 12h - -loc_1959BD9: ; CODE XREF: TSparseArray__GetItemValue+61_j - and eax, 1FFh - -loc_1959BDE: ; CODE XREF: TSparseArray__GetItemValue+35_j - ; TSparseArray__GetItemValue+52_j - add esi, eax - -loc_1959BE0: ; CODE XREF: TSparseArray__GetItemValue+26_j - ; TSparseArray__GetItemValue+45_j ... - mov ebx, edi ; jumptable 01959B88 default case - shr ebx, 5 - test bl, 1 - jz short loc_1959C31 - mov edx, [ecx+8] - mov edx, [edx+ebx*4-4] - mov eax, edx - shr eax, 1 - and eax, 55555555h - and edx, 55555555h - add eax, edx - mov edx, eax - and eax, 33333333h - shr edx, 2 - and edx, 33333333h - add edx, eax - mov eax, edx - shr eax, 4 - and eax, 0F0F0F0Fh - and edx, 0F0F0F0Fh - add eax, edx - imul eax, 1010101h - shr eax, 18h - add esi, eax - -loc_1959C31: ; CODE XREF: TSparseArray__GetItemValue+88_j - mov edx, [ecx+8] - mov ecx, edi - and ecx, 1Fh - mov eax, 1 - shl eax, cl - mov ecx, [edx+ebx*4] - pop edi - dec eax - and ecx, eax - mov eax, ecx - shr eax, 1 - and eax, 55555555h - and ecx, 55555555h - add eax, ecx - mov ecx, eax - and eax, 33333333h - shr ecx, 2 - and ecx, 33333333h - add ecx, eax - mov eax, ecx - shr eax, 4 - and eax, 0F0F0F0Fh - and ecx, 0F0F0F0Fh - add eax, ecx - imul eax, 1010101h - shr eax, 18h - add eax, esi - pop esi - pop ebx - pop ebp - retn 4 - -off_1959C90 dd offset loc_1959B8F ; DATA XREF: TSparseArray__GetItemValue+28_r - dd offset loc_1959B97 ; jump table for switch statement - dd offset loc_1959BA7 - dd offset loc_1959BB4 - dd offset loc_1959BBE - dd offset loc_1959BC3 - dd offset loc_1959BD3 - -TSparseArray__GetItemValue endp - -;------------------------------------------------------------------------------ -; TArchiveDatabase__sub_1959CB0 - -TArchiveDatabase__sub_1959CB0 proc near - ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+A1_p - ; sub_1958B00+E8_p ... - -pThis = dword ptr -4 -dwKey = dword ptr 8 - - push ebp - mov ebp, esp - push ecx - mov edx, [ebp+dwKey] - mov eax, edx - shr eax, 9 - mov [ebp+pThis], ecx - test edx, 1FFh ; if(dwKey & 0x01FF) - jnz short loc_1959CD3 - mov ecx, [ecx+40h] - mov eax, [ecx+eax*4] ; EAX = pDatabase->NextKeyTable[dwKey >> 0x09] - mov esp, ebp - pop ebp - retn 4 -; --------------------------------------------------------------------------- - -loc_1959CD3: ; CODE XREF: TFileNameDatabase__FindNextMatch+15_j - push ebx - push esi - mov esi, [ecx+40h] - lea esi, [esi+eax*4] - mov eax, [esi] - mov esi, [esi+4] - shr eax, 9 - add esi, 1FFh - push edi - shr esi, 9 - lea edi, [eax+0Ah] - mov [ebp+dwKey], esi - cmp edi, esi - jb short loc_1959D2E - mov edi, [ecx+28h] - lea esi, [eax+eax*2+3] - lea esi, [edi+esi*4] - mov edi, eax - shl edi, 9 - mov ebx, edi - sub ebx, [esi] - add ebx, 200h - cmp edx, ebx - jb short loc_1959D5F - -loc_1959D14: ; CODE XREF: TFileNameDatabase__FindNextMatch+7Aj - add edi, 200h - add esi, 0Ch - mov ebx, edi - sub ebx, [esi] - inc eax - add ebx, 200h - cmp edx, ebx - jnb short loc_1959D14 - jmp short loc_1959D5F -; --------------------------------------------------------------------------- - -loc_1959D2E: ; CODE XREF: TFileNameDatabase__FindNextMatch+45_j - lea edi, [eax+1] - cmp edi, esi - jnb short loc_1959D5F - mov ecx, [ecx+28h] - -loc_1959D38: ; CODE XREF: TFileNameDatabase__FindNextMatch+AAj - add esi, eax - shr esi, 1 - mov ebx, esi - shl ebx, 9 - lea edi, [esi+esi*2] - sub ebx, [ecx+edi*4] - cmp edx, ebx - jnb short loc_1959D50 - mov [ebp+dwKey], esi - jmp short loc_1959D55 -; --------------------------------------------------------------------------- - -loc_1959D50: ; CODE XREF: TFileNameDatabase__FindNextMatch+99_j - mov eax, esi - mov esi, [ebp+dwKey] - -loc_1959D55: ; CODE XREF: TFileNameDatabase__FindNextMatch+9E_j - lea edi, [eax+1] - cmp edi, esi - jb short loc_1959D38 - mov ecx, [ebp+pThis] - -loc_1959D5F: ; CODE XREF: TFileNameDatabase__FindNextMatch+62_j - ; TFileNameDatabase__FindNextMatch+7C_j ... - mov ecx, [ecx+28h] - lea esi, [eax+eax*2] - mov edi, [ecx+esi*4] ; EDI = Struct68_00.ArrayTriplets_20.ItemArray[eax] - lea esi, [ecx+esi*4] ; ESI = Struct68_00.ArrayTriplets_20.ItemArray + eax - mov ecx, eax - shl ecx, 9 - sub edi, ecx - shl eax, 4 - add edx, edi - mov edi, eax - mov eax, [esi+4] - mov ecx, eax - shr ecx, 17h - mov ebx, 100h - sub ebx, ecx - cmp edx, ebx - jnb short loc_1959DE8 - mov ecx, eax - shr ecx, 7 - and ecx, 0FFh - mov esi, 80h - sub esi, ecx - cmp edx, esi - jnb short loc_1959DC0 - and eax, 7Fh - mov ecx, 40h - sub ecx, eax - cmp edx, ecx - jb loc_1959E53 - add edi, 2 - lea edx, [edx+eax-40h] - jmp loc_1959E53 -; --------------------------------------------------------------------------- - -loc_1959DC0: ; CODE XREF: TFileNameDatabase__FindNextMatch+F0_j - shr eax, 0Fh - and eax, 0FFh - mov esi, 0C0h - sub esi, eax - cmp edx, esi - jnb short loc_1959DDC - add edi, 4 - lea edx, [edx+ecx-80h] - jmp short loc_1959E53 -; --------------------------------------------------------------------------- - -loc_1959DDC: ; CODE XREF: TFileNameDatabase__FindNextMatch+121_j - add edi, 6 - lea edx, [edx+eax-0C0h] - jmp short loc_1959E53 -; --------------------------------------------------------------------------- - -loc_1959DE8: ; CODE XREF: TFileNameDatabase__FindNextMatch+DA_j - mov esi, [esi+8] - mov eax, esi - shr eax, 9 - and eax, 1FFh - mov ebx, 180h - sub ebx, eax - cmp edx, ebx - jnb short loc_1959E29 - and esi, 1FFh - mov eax, 140h - sub eax, esi - cmp edx, eax - jnb short loc_1959E1D - add edi, 8 - lea edx, [edx+ecx-100h] - jmp short loc_1959E53 -; --------------------------------------------------------------------------- - -loc_1959E1D: ; CODE XREF: TFileNameDatabase__FindNextMatch+15F_j - add edi, 0Ah - lea edx, [edx+esi-140h] - jmp short loc_1959E53 -; --------------------------------------------------------------------------- - -loc_1959E29: ; CODE XREF: TFileNameDatabase__FindNextMatch+14E_j - shr esi, 12h - and esi, 1FFh - mov ecx, 1C0h - sub ecx, esi - cmp edx, ecx - jnb short loc_1959E49 - add edi, 0Ch - lea edx, [edx+eax-180h] - jmp short loc_1959E53 -; --------------------------------------------------------------------------- - -loc_1959E49: ; CODE XREF: TFileNameDatabase__FindNextMatch+18B_j - add edi, 0Eh - lea edx, [edx+esi-1C0h] - -loc_1959E53: ; CODE XREF: TFileNameDatabase__FindNextMatch+FE_j - ; TFileNameDatabase__FindNextMatch+10B_j ... - mov eax, [ebp+pThis] - mov ebx, [eax+8] - mov ecx, [ebx+edi*4] - not ecx - mov eax, ecx - shr eax, 1 - and eax, 55555555h - mov esi, ecx - and esi, 55555555h - add eax, esi - mov esi, eax - shr esi, 2 - and eax, 33333333h - and esi, 33333333h - add esi, eax - mov eax, esi - shr eax, 4 - and esi, 0F0F0F0Fh - and eax, 0F0F0F0Fh - add eax, esi - imul eax, 1010101h - mov esi, eax - shr esi, 18h - cmp edx, esi - jb short loc_1959EEA - mov ecx, [ebx+edi*4+4] - inc edi - sub edx, esi - not ecx - mov eax, ecx - shr eax, 1 - and eax, 55555555h - mov esi, ecx - and esi, 55555555h - add eax, esi - mov esi, eax - shr esi, 2 - and eax, 33333333h - and esi, 33333333h - add esi, eax - mov eax, esi - shr eax, 4 - and eax, 0F0F0F0Fh - and esi, 0F0F0F0Fh - add eax, esi - imul eax, 1010101h - -loc_1959EEA: ; CODE XREF: TFileNameDatabase__FindNextMatch+1F2_j - mov esi, eax - shr esi, 8 - and esi, 0FFh - shl edi, 5 - cmp edx, esi - jnb short loc_1959F0D - and eax, 0FFh - cmp edx, eax - jb short loc_1959F2B - add edi, 8 - shr ecx, 8 - jmp short loc_1959F29 -; --------------------------------------------------------------------------- - -loc_1959F0D: ; CODE XREF: TFileNameDatabase__FindNextMatch+24A_j - shr eax, 10h - and eax, 0FFh - cmp edx, eax - jnb short loc_1959F23 - add edi, 10h - shr ecx, 10h - sub edx, esi - jmp short loc_1959F2B -; --------------------------------------------------------------------------- - -loc_1959F23: ; CODE XREF: TFileNameDatabase__FindNextMatch+267_j - add edi, 18h - shr ecx, 18h - -loc_1959F29: ; CODE XREF: TFileNameDatabase__FindNextMatch+25B_j - sub edx, eax - -loc_1959F2B: ; CODE XREF: TFileNameDatabase__FindNextMatch+253_j - ; TFileNameDatabase__FindNextMatch+271_j - and ecx, 0FFh - shl edx, 8 - movzx eax, byte ptr ds:table_1BA1818[ecx+edx] - add eax, edi - pop edi - pop esi - pop ebx - mov esp, ebp - pop ebp - retn 4 -TArchiveDatabase__sub_1959CB0 endp - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -TNameIndexStruct__CheckNameFragment proc near ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+6B_p - ; TFileNameDatabase__CheckNextPathFragment+191_p ... - -pThis = dword ptr -4 -pUnknownStruct1C= dword ptr 8 -dwDistance = dword ptr 0Ch - - push ebp - mov ebp, esp - push ecx - push ebx - push esi - push edi - mov edi, ecx - cmp [edi+TNameIndexStruct.Struct68.TotalItemCount], 0 - mov ecx, [ebp+pUnknownStruct1C] - mov edx, [ecx+TMndxFindResult.pStruct40] - mov [ebp+pThis], edi - jnz short loc_195A1C8 - mov edi, [edi+TNameIndexStruct.NameFragments.ItemArray] ; Pointer to name table - sub edi, [edx+TStruct40.CharIndex] - add edi, [ebp+dwDistance] ; EDI = szPathFragment - -loc_195A1A1: ; CODE XREF: TNameIndexStruct__CheckNameFragment+3Bj - mov eax, [edx+TStruct40.CharIndex] - mov esi, [ecx+TMndxFindResult.szSearchMask] - mov bl, [eax+edi] - cmp bl, [eax+esi] - jnz short loc_195A1BD - inc eax - mov [edx+TStruct40.CharIndex], eax - cmp byte ptr [eax+edi], 0 - jz short loc_195A215 - cmp eax, [ecx+TMndxFindResult.cchSearchMask] - jb short loc_195A1A1 - -loc_195A1BD: ; CODE XREF: TNameIndexStruct__CheckNameFragment+2C_j - ; TNameIndexStruct__CheckNameFragment+5Ej ... - pop edi - pop esi - xor al, al - pop ebx - mov esp, ebp - pop ebp - retn 8 -; --------------------------------------------------------------------------- - -loc_195A1C8: ; CODE XREF: TNameIndexStruct__CheckNameFragment+16_j - mov eax, [ebp+dwDistance] - jmp short loc_195A1D0 -; --------------------------------------------------------------------------- - align 10h - -loc_195A1D0: ; CODE XREF: TNameIndexStruct__CheckNameFragment+4B_j - ; TNameIndexStruct__CheckNameFragment+93j - mov ebx, [edi+TNameIndexStruct.NameFragments.ItemArray] - mov esi, [edx+TStruct40.CharIndex] - mov ecx, [ecx+TMndxFindResult.szSearchMask] - mov bl, [eax+ebx] ; pNameList[dwNameOffset] == szPathName[nCharIndex] - cmp bl, [esi+ecx] - jnz short loc_195A1BD - lea ecx, [esi+1] - mov [edx+TStruct40.CharIndex], ecx - mov edi, [edi+TNameIndexStruct.Struct68.ItemIsPresent.ItemArray] - mov [ebp+dwDistance], ecx - mov ecx, eax - and ecx, 1Fh ; ecx = (dwNameOffset & 0x1F) - mov esi, eax - mov ebx, 1 - shl ebx, cl ; ebx = 1 << (dwNameOffset & 0x1F); - shr esi, 5 ; esi = (dwNameOffset >> 0x05) - mov ecx, [edi+esi*4] - inc eax - and ecx, ebx - jnz short loc_195A215 - mov esi, [ebp+dwDistance] - mov ecx, [ebp+pUnknownStruct1C] - cmp esi, [ecx+4] - jnb short loc_195A1BD - mov edi, [ebp+pThis] - jmp short loc_195A1D0 -; --------------------------------------------------------------------------- - -loc_195A215: ; CODE XREF: TNameIndexStruct__CheckNameFragment+36_j - ; TNameIndexStruct__CheckNameFragment+83_j - pop edi - pop esi - mov al, 1 - pop ebx - mov esp, ebp - pop ebp - retn 8 -TNameIndexStruct__CheckNameFragment endp - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -sub_1957350 proc near ; CODE XREF: sub_1957B80+D8p - ; sub_1957B80:loc_1957C73p ... - -arg_0 = dword ptr 8 - - push ebp - mov ebp, esp - mov eax, [ebp+arg_0] - push ebx - push esi - mov esi, ecx - mov ebx, [esi+140h] - push edi - push eax - lea ecx, [esi+0D0h] - add ebx, eax - call TSparseArray__GetItemValue - mov edi, [esi+168h] - mov ecx, edi - imul ecx, eax - mov eax, ecx - and ecx, 1Fh - mov edx, ecx - mov ecx, [esi+158h] - add edi, edx - shr eax, 5 - cmp edi, 20h - ja short loc_195739A - mov eax, [ecx+eax*4] - mov ecx, edx - shr eax, cl - jmp short loc_19573B1 -; --------------------------------------------------------------------------- - -loc_195739A: ; CODE XREF: sub_1957350+3F_j - lea edi, [ecx+eax*4] - mov eax, [edi+4] - mov edi, [edi] - mov ecx, 20h - sub ecx, edx - shl eax, cl - mov ecx, edx - shr edi, cl - or eax, edi - -loc_19573B1: ; CODE XREF: sub_1957350+48_j - and eax, [esi+16Ch] - movzx edx, byte ptr [ebx] - pop edi - shl eax, 8 - pop esi - or eax, edx - pop ebx - pop ebp - retn 4 -sub_1957350 endp - -; --------------------------------------------------------------------------- - - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -sub_1959F50 proc near ; CODE XREF: sub_1957B80+14C_p - ; sub_1958980+62_p ... - -var_4 = dword ptr -4 -arg_0 = dword ptr 8 - - push ebp - mov ebp, esp - push ecx - mov edx, [ebp+arg_0] - mov eax, edx - shr eax, 9 - mov [ebp+var_4], ecx - test edx, 1FFh - jnz short loc_1959F73 - mov ecx, [ecx+58h] - mov eax, [ecx+eax*4] - mov esp, ebp - pop ebp - retn 4 -; --------------------------------------------------------------------------- - -loc_1959F73: ; CODE XREF: sub_1959F50+15_j - push ebx - push esi - mov esi, [ecx+58h] - lea esi, [esi+eax*4] - mov eax, [esi] - push edi - mov edi, [esi+4] - shr eax, 9 - add edi, 1FFh - shr edi, 9 - lea esi, [eax+0Ah] - cmp esi, edi - jb short loc_1959FAD - mov edi, [ecx+28h] - lea esi, [eax+eax*2+3] - cmp edx, [edi+esi*4] - lea esi, [edi+esi*4] - jb short loc_1959FD4 - -loc_1959FA3: ; CODE XREF: sub_1959F50+59j - add esi, 0Ch - inc eax - cmp edx, [esi] - jnb short loc_1959FA3 - jmp short loc_1959FD4 -; --------------------------------------------------------------------------- - -loc_1959FAD: ; CODE XREF: sub_1959F50+42_j - lea esi, [eax+1] - cmp esi, edi - jnb short loc_1959FD4 - mov ecx, [ecx+28h] - -loc_1959FB7: ; CODE XREF: sub_1959F50+7Fj - lea esi, [edi+eax] - shr esi, 1 - lea ebx, [esi+esi*2] - cmp edx, [ecx+ebx*4] - jnb short loc_1959FC8 - mov edi, esi - jmp short loc_1959FCA -; --------------------------------------------------------------------------- - -loc_1959FC8: ; CODE XREF: sub_1959F50+72_j - mov eax, esi - -loc_1959FCA: ; CODE XREF: sub_1959F50+76_j - lea esi, [eax+1] - cmp esi, edi - jb short loc_1959FB7 - mov ecx, [ebp+var_4] - -loc_1959FD4: ; CODE XREF: sub_1959F50+51_j - ; sub_1959F50+5B_j ... - mov edi, [ecx+28h] - lea esi, [eax+eax*2] - sub edx, [edi+esi*4] - shl eax, 4 - lea esi, [edi+esi*4] - mov edi, eax - mov eax, [esi+4] - mov ebx, eax - shr ebx, 17h - cmp edx, ebx - jnb short loc_195A026 - mov esi, eax - shr esi, 7 - and esi, 0FFh - cmp edx, esi - jnb short loc_195A00E - and eax, 7Fh - cmp edx, eax - jb short loc_195A066 - add edi, 2 - sub edx, eax - jmp short loc_195A066 -; --------------------------------------------------------------------------- - -loc_195A00E: ; CODE XREF: sub_1959F50+AE_j - shr eax, 0Fh - and eax, 0FFh - cmp edx, eax - jnb short loc_195A01F - add edi, 4 - jmp short loc_195A064 -; --------------------------------------------------------------------------- - -loc_195A01F: ; CODE XREF: sub_1959F50+C8_j - add edi, 6 - sub edx, eax - jmp short loc_195A066 -; --------------------------------------------------------------------------- - -loc_195A026: ; CODE XREF: sub_1959F50+9F_j - mov esi, [esi+8] - mov eax, esi - shr eax, 9 - and eax, 1FFh - cmp edx, eax - jnb short loc_195A04D - and esi, 1FFh - cmp edx, esi - jnb short loc_195A048 - add edi, 8 - sub edx, ebx - jmp short loc_195A066 -; --------------------------------------------------------------------------- - -loc_195A048: ; CODE XREF: sub_1959F50+EF_j - add edi, 0Ah - jmp short loc_195A064 -; --------------------------------------------------------------------------- - -loc_195A04D: ; CODE XREF: sub_1959F50+E5_j - shr esi, 12h - and esi, 1FFh - cmp edx, esi - jnb short loc_195A061 - add edi, 0Ch - sub edx, eax - jmp short loc_195A066 -; --------------------------------------------------------------------------- - -loc_195A061: ; CODE XREF: sub_1959F50+108_j - add edi, 0Eh - -loc_195A064: ; CODE XREF: sub_1959F50+CD_j - ; sub_1959F50+FB_j - sub edx, esi - -loc_195A066: ; CODE XREF: sub_1959F50+B5_j - ; sub_1959F50+BC_j ... - mov ebx, [ecx+8] - mov esi, [ebx+edi*4] - mov eax, esi - shr eax, 1 - and eax, 55555555h - mov ecx, esi - and ecx, 55555555h - add eax, ecx - mov ecx, eax - shr ecx, 2 - and eax, 33333333h - and ecx, 33333333h - add ecx, eax - mov eax, ecx - shr eax, 4 - and ecx, 0F0F0F0Fh - and eax, 0F0F0F0Fh - add eax, ecx - imul eax, 1010101h - mov ecx, eax - shr ecx, 18h - cmp edx, ecx - jb short loc_195A0F6 - mov esi, [ebx+edi*4+4] - sub edx, ecx - inc edi - mov eax, esi - shr eax, 1 - and eax, 55555555h - mov ecx, esi - and ecx, 55555555h - add eax, ecx - mov ecx, eax - shr ecx, 2 - and eax, 33333333h - and ecx, 33333333h - add ecx, eax - mov eax, ecx - shr eax, 4 - and eax, 0F0F0F0Fh - and ecx, 0F0F0F0Fh - add eax, ecx - imul eax, 1010101h - -loc_195A0F6: ; CODE XREF: sub_1959F50+160_j - mov ecx, eax - shr ecx, 8 - and ecx, 0FFh - shl edi, 5 - cmp edx, ecx - jnb short loc_195A119 - and eax, 0FFh - cmp edx, eax - jb short loc_195A137 - add edi, 8 - shr esi, 8 - jmp short loc_195A135 -; --------------------------------------------------------------------------- - -loc_195A119: ; CODE XREF: sub_1959F50+1B6_j - shr eax, 10h - and eax, 0FFh - cmp edx, eax - jnb short loc_195A12F - add edi, 10h - shr esi, 10h - sub edx, ecx - jmp short loc_195A137 -; --------------------------------------------------------------------------- - -loc_195A12F: ; CODE XREF: sub_1959F50+1D3_j - add edi, 18h - shr esi, 18h - -loc_195A135: ; CODE XREF: sub_1959F50+1C7_j - sub edx, eax - -loc_195A137: ; CODE XREF: sub_1959F50+1BF_j - ; sub_1959F50+1DD_j - and esi, 0FFh - shl edx, 8 - movzx eax, ds:table_1BA1818[esi+edx] - add eax, edi - pop edi - pop esi - pop ebx - mov esp, ebp - pop ebp - retn 4 -sub_1959F50 endp - -; --------------------------------------------------------------------------- - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -sub_1957B80 proc near ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+5E_p - ; TFileNameDatabase__CheckNextPathFragment+180_p ... - -pStruct40 = dword ptr -4 -arg_0 = dword ptr 8 -arg_4 = dword ptr 0Ch - - push ebp - mov ebp, esp - push ecx - push ebx - mov ebx, [ebp+arg_0] - mov eax, [ebx+18h] - push esi - push edi - mov edi, [ebp+arg_4] - mov esi, ecx - mov [ebp+pStruct40], eax - -loc_1957B95: ; CODE XREF: sub_1957B80+9Fj - ; sub_1957B80+156j - mov eax, [esi+TFileNameDatabase.NameFragIndexMask] - and eax, edi - lea ecx, [eax+eax*2] - mov eax, [esi+TFileNameDatabase.NameFragTable.ItemArray] - add ecx, ecx - add ecx, ecx - add eax, ecx - mov [ebp+arg_4], ecx - cmp edi, [eax+4] - jnz short loc_1957C30 - mov edx, [eax+8] - mov edi, edx - and edi, 0FFFFFF00h - cmp edi, 0FFFFFF00h - jz short loc_1957BEE - mov ecx, [esi+TFileNameDatabase.NextDB.pDatabase] - push edx - push ebx - test ecx, ecx - jz short loc_1957BDA - call sub_1957B80 - jmp short loc_1957BE5 -; --------------------------------------------------------------------------- - -loc_1957BDA: ; CODE XREF: sub_1957B80+51_j - lea ecx, [esi+TFileNameDatabase.IndexStruct_174] - call TNameIndexStruct__CheckNameFragment - -loc_1957BE5: ; CODE XREF: sub_1957B80+58_j - test al, al - jz short loc_1957C25 - mov ecx, [ebp+arg_4] - jmp short loc_1957C05 -; --------------------------------------------------------------------------- - -loc_1957BEE: ; CODE XREF: sub_1957B80+45_j - mov edx, [ebp+pStruct40] - mov edi, [edx+34h] - mov edx, [ebx] - mov al, [eax+8] - cmp al, [edi+edx] - jnz short loc_1957C25 - mov edx, [ebp+pStruct40] - inc edi - mov [edx+34h], edi - -loc_1957C05: ; CODE XREF: sub_1957B80+6C_j - mov eax, [esi+200h] - mov edi, [ecx+eax] - test edi, edi - jz loc_1957CDB - mov ecx, [ebp+pStruct40] - mov edx, [ecx+34h] - cmp edx, [ebx+4] - jb loc_1957B95 - -loc_1957C25: ; CODE XREF: sub_1957B80+67_j - ; sub_1957B80+7C_j ... - pop edi - pop esi - xor al, al - pop ebx - mov esp, ebp - pop ebp - retn 8 -; --------------------------------------------------------------------------- - -loc_1957C30: ; CODE XREF: sub_1957B80+32_j - mov edx, [esi+0D8h] - mov ecx, edi - and ecx, 1Fh - mov ebx, 1 - shl ebx, cl - mov eax, edi - shr eax, 5 - test [edx+eax*4], ebx - jz short loc_1957C8E - cmp dword ptr [esi+1F4h], 0 - push edi - mov ecx, esi - jz short loc_1957C73 - call sub_1957350 - mov ecx, [esi+1F4h] - mov ebx, [ebp+arg_0] - push eax - push ebx - test ecx, ecx - jz short loc_1957C7D - call sub_1957B80 - jmp short loc_1957C88 -; --------------------------------------------------------------------------- - -loc_1957C73: ; CODE XREF: sub_1957B80+D6_j - call sub_1957350 - mov ebx, [ebp+arg_0] - push eax - push ebx - -loc_1957C7D: ; CODE XREF: sub_1957B80+EA_j - lea ecx, [esi+174h] - call TNameIndexStruct__CheckNameFragment - -loc_1957C88: ; CODE XREF: sub_1957B80+F1_j - test al, al - jz short loc_1957C25 - jmp short loc_1957CB2 -; --------------------------------------------------------------------------- - -loc_1957C8E: ; CODE XREF: sub_1957B80+CA_j - mov eax, [ebp+pStruct40] - mov ecx, [esi+140h] - mov ebx, [ebp+arg_0] - mov eax, [eax+34h] - mov edx, [ebx] - mov cl, [edi+ecx] - cmp cl, [eax+edx] - jnz loc_1957C25 - mov edx, [ebp+pStruct40] - inc eax - mov [edx+34h], eax - -loc_1957CB2: ; CODE XREF: sub_1957B80+10C_j - cmp edi, [esi+214h] - jbe short loc_1957CDB - mov eax, [ebp+pStruct40] - mov ecx, [eax+34h] - cmp ecx, [ebx+4] - jnb loc_1957C25 - push edi - mov ecx, esi - call sub_1959F50 - sub eax, edi - lea edi, [eax-1] - jmp loc_1957B95 -; --------------------------------------------------------------------------- - -loc_1957CDB: ; CODE XREF: sub_1957B80+90_j - ; sub_1957B80+138_j - pop edi - pop esi - mov al, 1 - pop ebx - mov esp, ebp - pop ebp - retn 8 -sub_1957B80 endp - - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -sub_19573D0 proc near ; CODE XREF: TFileNameDatabase__sub_1959460+1D9p - -arg_0 = dword ptr 8 -arg_4 = dword ptr 0Ch - - push ebp - mov ebp, esp - push esi - mov esi, ecx - mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry] - mov eax, edx - imul eax, [ebp+arg_4] - mov ecx, eax - and eax, 1Fh - add edx, eax - shr ecx, 5 - cmp edx, 20h - mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.ItemArray] - ja short loc_1957400 - mov edx, [edx+ecx*4] - mov ecx, eax - shr edx, cl - jmp short loc_1957419 -; --------------------------------------------------------------------------- - -loc_1957400: ; CODE XREF: sub_19573D0+25j - push edi - lea edi, [edx+ecx*4] - mov edx, [edi+4] - mov edi, [edi] - mov ecx, 20h - sub ecx, eax - shl edx, cl - mov ecx, eax - shr edi, cl - or edx, edi - pop edi - -loc_1957419: ; CODE XREF: sub_19573D0+2Ej - and edx, [esi+TFileNameDatabase.FrgmDist_HiBits.EntryBitMask] - mov eax, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] - mov ecx, [ebp+arg_0] - movzx eax, byte ptr [eax+ecx] - shl edx, 8 - or eax, edx - pop esi - pop ebp - retn 8 -sub_19573D0 endp - -; --------------------------------------------------------------------------- - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -TFileNameDatabase__CheckNextPathFragment proc near ; CODE XREF: TFileNameDatabase__FindFileInDatabase+25p - -var_C = dword ptr -0Ch -CollisionIndex = dword ptr -8 -var_4 = dword ptr -4 -pStruct1C = dword ptr 8 - - push ebp - mov ebp, esp - mov edx, [ebp+pStruct1C] - sub esp, 0Ch - push ebx - mov ebx, [edx+TMndxFindResult.szSearchMask] - push esi - push edi - mov edi, [edx+TMndxFindResult.pStruct40] - mov eax, [edi+TStruct40.CharIndex] - movzx eax, byte ptr [eax+ebx] ; EAX = szPathName[nCharIndex] - mov esi, ecx - mov ecx, [edi+TStruct40.HashValue] - mov ebx, ecx - shl ebx, 5 - xor eax, ebx - xor eax, ecx - and eax, [esi+TFileNameDatabase.NameFragIndexMask] ; (000000ff) - Mask value - lea ebx, [eax+eax*2] - mov eax, [esi+TFileNameDatabase.NameFragTable.ItemArray] ; (7f3ae128) - Array of 256 triplets - add ebx, ebx - add ebx, ebx ; EBX = Offset of the triplet we want to know - cmp ecx, [eax+ebx+TRIPLET.BitIndex] - jnz short loc_1957A0E - mov eax, [eax+ebx+TRIPLET.Distance] - mov ecx, eax - and ecx, 0FFFFFF00h - cmp ecx, 0FFFFFF00h - jz short loc_19579EF - mov ecx, [esi+TFileNameDatabase.NextDB.pDatabase] - push eax - push edx - test ecx, ecx - jz short loc_19579D5 - call sub_1957B80 - jmp short loc_19579E0 -; --------------------------------------------------------------------------- - -loc_19579D5: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+5C_j - lea ecx, [esi+TFileNameDatabase.IndexStruct_174] - call TNameIndexStruct__CheckNameFragment - -loc_19579E0: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+63_j - test al, al - jnz short loc_19579F6 - -loc_19579E4: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+C1j - ; TFileNameDatabase__CheckNextPathFragment+1A4j - pop edi - pop esi - xor al, al - pop ebx - mov esp, ebp - pop ebp - retn 4 -; --------------------------------------------------------------------------- - -loc_19579EF: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+50_j - mov eax, [edi+TStruct40.CharIndex] ; nCharIndex = nCharIndex + 1 - inc eax - mov [edi+TStruct40.CharIndex], eax - -loc_19579F6: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+72_j - mov edx, [esi+TFileNameDatabase.NameFragTable.ItemArray] ; EDX = pTripletArray - mov eax, [edx+ebx+TRIPLET.NextKey] - mov [edi+TStruct40.HashValue], eax - -loc_1957A03: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+198j - pop edi - pop esi - mov al, 1 - pop ebx - mov esp, ebp - pop ebp - retn 4 -; --------------------------------------------------------------------------- - -loc_1957A0E: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+3C_j - push ecx ; dwKey - mov ecx, esi ; pDatabase - call TArchiveDatabase__sub_1959CB0 - mov ebx, [esi+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray] - inc eax - mov ecx, eax - and ecx, 1Fh - mov edx, 1 - shl edx, cl - mov ecx, eax - shr ecx, 5 - mov [ebp+CollisionIndex], eax - test [ebx+ecx*4], edx - jz short loc_19579E4 - sub eax, [edi+TStruct40.HashValue] - mov [ebp+var_4], 0FFFFFFFFh - dec eax - mov [edi+TStruct40.HashValue], eax - -loc_1957A41: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+1E1j - mov eax, [edi+TStruct40.HashValue] - mov ebx, [esi+TFileNameDatabase.Struct68_D0.ItemIsPresent.ItemArray] - mov ecx, eax - and ecx, 1Fh - mov edx, 1 - shl edx, cl - mov ecx, eax - shr ecx, 5 - test [ebx+ecx*4], edx - jz loc_1957B1C - mov ecx, [ebp+var_4] - cmp ecx, 0FFFFFFFFh - jnz short loc_1957A7F - push eax - lea ecx, [esi+TFileNameDatabase.Struct68_D0] - call TSparseArray__GetItemValue - mov ecx, eax - mov [ebp+var_4], eax - jmp short loc_1957A83 -; --------------------------------------------------------------------------- - -loc_1957A7F: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+FA_j - inc ecx - mov [ebp+var_4], ecx - -loc_1957A83: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+10D_j - mov edx, [edi+TStruct40.CharIndex] - mov [ebp+var_C], edx - mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry] - mov eax, edx - imul eax, ecx - mov ecx, eax - and eax, 1Fh - add edx, eax - shr ecx, 5 - cmp edx, 20h - mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.ItemArray] - ja short loc_1957AB2 - mov edx, [edx+ecx*4] - mov ecx, eax - shr edx, cl - jmp short loc_1957AC9 -; --------------------------------------------------------------------------- - -loc_1957AB2: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+137_j - lea ebx, [edx+ecx*4] - mov edx, [ebx+4] - mov ebx, [ebx] - mov ecx, 20h - sub ecx, eax - shl edx, cl - mov ecx, eax - shr ebx, cl - or edx, ebx - -loc_1957AC9: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+140_j - mov ecx, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] - and edx, [esi+TFileNameDatabase.FrgmDist_HiBits.EntryBitMask] - mov eax, [edi+TStruct40.HashValue] - movzx eax, byte ptr [ecx+eax] - mov ecx, [esi+TFileNameDatabase.NextDB.pDatabase] - shl edx, 8 - or eax, edx - push eax - test ecx, ecx - jz short loc_1957AF7 - mov edx, [ebp+pStruct1C] - push edx - call sub_1957B80 - jmp short loc_1957B06 -; --------------------------------------------------------------------------- - -loc_1957AF7: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+17A_j - mov eax, [ebp+pStruct1C] - push eax - lea ecx, [esi+TFileNameDatabase.IndexStruct_174] - call TNameIndexStruct__CheckNameFragment - -loc_1957B06: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+185_j - test al, al - jnz loc_1957A03 - mov ecx, [ebp+var_C] - cmp [edi+TStruct40.CharIndex], ecx - jnz loc_19579E4 - jmp short loc_1957B32 -; --------------------------------------------------------------------------- - -loc_1957B1C: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+EE_j - mov edx, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] - mov ebx, [ebp+pStruct1C] - mov ecx, [edi+TStruct40.CharIndex] - mov ebx, [ebx+TMndxFindResult.szSearchMask] - mov dl, [eax+edx] - cmp dl, [ecx+ebx] - jz short loc_1957B62 - -loc_1957B32: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+1AA_j - mov eax, [ebp+CollisionIndex] - inc [edi+TStruct40.HashValue] - inc eax - mov ecx, eax - and ecx, 1Fh - mov edx, 1 - shl edx, cl - mov ecx, [esi+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray] - mov [ebp+CollisionIndex], eax - shr eax, 5 - test [ecx+eax*4], edx - jnz loc_1957A41 - pop edi - pop esi - xor al, al - pop ebx - mov esp, ebp - pop ebp - retn 4 -; --------------------------------------------------------------------------- - -loc_1957B62: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+1C0_j - mov eax, 1 - add [edi+TStruct40.CharIndex], eax - pop edi - pop esi - pop ebx - mov esp, ebp - pop ebp - retn 4 -TFileNameDatabase__CheckNextPathFragment endp - - -TFileNameDatabase__FindFileInDatabase proc near - ; CODE XREF: MAR_FILE__FindFileInDatabase+2D_p - -pThis = dword ptr -4 -pStruct1C = dword ptr 8 - - push ebp ; ecx = Pointer to ARCHIVE_DATABASE - mov ebp, esp - push ecx - push ebx - push esi - mov esi, [ebp+pStruct1C] - xor eax, eax - push edi - mov edi, [esi+TMndxFindResult.pStruct40] - mov ebx, ecx - mov [edi+TStruct40.HashValue], eax - mov [edi+TStruct40.CharIndex], eax - mov [edi+TStruct40.SearchPhase], eax - mov [ebp+pThis], ebx - cmp [esi+TMndxFindResult.cchSearchMask], eax - jbe short loc_1957F26 - -label_process_all_characters: ; CODE XREF: TFileNameDatabase__FindFileInDatabase+34j - push esi - mov ecx, ebx - call TFileNameDatabase__CheckNextPathFragment - test al, al - jz short label_return_false - mov eax, [edi+TStruct40.CharIndex] - cmp eax, [esi+TMndxFindResult.cchSearchMask] - jb short label_process_all_characters - -loc_1957F26: ; CODE XREF: TFileNameDatabase__FindFileInDatabase+20_j - mov ecx, [edi+TStruct40.HashValue] - mov eax, [ebx+TFileNameDatabase.FileNameIndexes.ItemIsPresent.ItemArray] - mov edx, ecx - and ecx, 1Fh - mov ebx, 1 - shl ebx, cl - shr edx, 5 - test [eax+edx*4], ebx - jz short label_return_false - mov ecx, [esi+TMndxFindResult.szSearchMask] - mov eax, [esi+TMndxFindResult.cchSearchMask] - mov [esi+TMndxFindResult.szFoundPath], ecx - mov ecx, [ebp+pThis] - mov [esi+TMndxFindResult.cchFoundPath], eax - mov edi, [edi+TStruct40.HashValue] - push edi - add ecx, TFileNameDatabase.FileNameIndexes - call TSparseArray__GetItemValue - pop edi - mov [esi+TMndxFindResult.FileNameIndex], eax - pop esi - mov al, 1 - pop ebx - mov esp, ebp - pop ebp - retn 4 -; --------------------------------------------------------------------------- - -label_return_false: ; CODE XREF: TFileNameDatabase__FindFileInDatabase+2C_j - ; TFileNameDatabase__FindFileInDatabase+4E_j - pop edi - pop esi - xor al, al - pop ebx - mov esp, ebp - pop ebp - retn 4 -TFileNameDatabase__FindFileInDatabase endp - - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -TGenericArray__SetMaxItems_BYTE proc near ; CODE XREF: sub_19582E0+2Cp - ; TStruct40__InitSearchBuffers+2Cp ... - -ByteCount = dword ptr 8 - - push ebp - mov ebp, esp - push ebx - mov ebx, [ebp+ByteCount] - push esi - push edi - push offset unk_53ABE00 - push ebx - mov esi, ecx - call j_operator_new_safe - xor ecx, ecx - add esp, 8 - mov edi, eax - cmp [esi+TGenericArray.ItemCount], ecx - jbe short loc_19575D7 - -loc_19575C2: ; CODE XREF: TGenericArray__SetMaxItems_BYTE+35j - lea edx, [ecx+edi] - test edx, edx - jz short loc_19575D1 - mov eax, [esi+TGenericArray.field_4] - mov al, [ecx+eax] - mov [edx], al - -loc_19575D1: ; CODE XREF: TGenericArray__SetMaxItems_BYTE+27j - inc ecx - cmp ecx, [esi+TGenericArray.ItemCount] - jb short loc_19575C2 - -loc_19575D7: ; CODE XREF: TGenericArray__SetMaxItems_BYTE+20j - mov eax, [esi+TGenericArray.DataBuffer] - push eax - mov [esi+TGenericArray.DataBuffer], edi - mov [esi+TGenericArray.field_4], edi - mov [esi+TGenericArray.ItemArray], edi - mov [esi+TGenericArray.MaxItemCount], ebx - call operator_delete - add esp, 4 - pop edi - pop esi - pop ebx - pop ebp - retn 4 -TGenericArray__SetMaxItems_BYTE endp - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -TGenericArray__SetMaxItems_STRUCT14 proc near - ; CODE XREF: TGenericArray__InsertItem_STRUCT14+2Cp - ; TGenericArray__sub_19583A0+2Dp ... - -var_4 = dword ptr -4 -ItemCount = dword ptr 8 - - push ebp - mov ebp, esp - push ecx - push esi - push edi - mov edi, [ebp+ItemCount] - lea eax, [edi+edi*4] ; EAX = (ItemCount * 5) - add eax, eax ; EAX = (ItemCount * 10) - add eax, eax ; EAX = (ItemCount * 20) - push offset unk_53ABE00 - push eax - mov esi, ecx - call j_operator_new_safe - mov ecx, eax - xor eax, eax - add esp, 8 - mov [ebp+var_4], ecx - cmp [esi+0Ch], eax - jbe short loc_195766A - xor edi, edi - mov edx, ecx - push ebx - -loc_1957631: ; CODE XREF: TGenericArray__SetMaxItems_STRUCT14+64j - test edx, edx - jz short loc_195765A - mov ecx, [esi+4] - mov ebx, [ecx+edi] - add ecx, edi - mov [edx], ebx - mov ebx, [ecx+4] - mov [edx+4], ebx - mov ebx, [ecx+8] - mov [edx+8], ebx - mov ebx, [ecx+0Ch] - mov [edx+0Ch], ebx - mov ecx, [ecx+10h] - mov [edx+10h], ecx - mov ecx, [ebp+var_4] - -loc_195765A: ; CODE XREF: TGenericArray__SetMaxItems_STRUCT14+33j - inc eax - add edi, 14h - add edx, 14h - cmp eax, [esi+0Ch] - jb short loc_1957631 - mov edi, [ebp+ItemCount] - pop ebx - -loc_195766A: ; CODE XREF: TGenericArray__SetMaxItems_STRUCT14+2Aj - mov eax, [esi+TGenericArray.DataBuffer] - push eax - mov [esi+TGenericArray.DataBuffer], ecx - mov [esi+TGenericArray.field_4], ecx - mov [esi+TGenericArray.ItemArray], ecx - mov [esi+TGenericArray.MaxItemCount], edi - call operator_delete - add esp, 4 - pop edi - pop esi - mov esp, ebp - pop ebp - retn 4 -TGenericArray__SetMaxItems_STRUCT14 endp - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -TGenericArray__sub_19583A0 proc near ; CODE XREF: TStruct40__InitSearchBuffers+35p - -NewItemCount = dword ptr 8 - - push ebp - mov ebp, esp - push esi - mov esi, ecx - mov eax, [esi+TGenericArray.MaxItemCount] - push edi - mov edi, [ebp+NewItemCount] - cmp edi, eax - jbe short loc_19583D2 - mov edx, edi - shr edx, 1 - mov ecx, edi - cmp eax, edx - jbe short loc_19583CA - mov ecx, 0CCCCCCCh - cmp eax, 6666666h - ja short loc_19583CA - lea ecx, [eax+eax] - -loc_19583CA: ; CODE XREF: TGenericArray__sub_19583A0+19j - ; TGenericArray__sub_19583A0+25j - push ecx - mov ecx, esi - call TGenericArray__SetMaxItems_STRUCT14 - -loc_19583D2: ; CODE XREF: TGenericArray__sub_19583A0+Fj - mov eax, [esi+TGenericArray.ItemCount] - cmp eax, edi - jnb short loc_1958410 - lea ecx, [eax+eax*4] - add ecx, ecx - mov edx, edi - push ebx - add ecx, ecx - sub edx, eax - or ebx, 0FFFFFFFFh - -loc_19583E8: ; CODE XREF: TGenericArray__sub_19583A0+6Dj - mov eax, [esi+TGenericArray.field_4] - add eax, ecx - jz short loc_1958409 - mov dword ptr [eax], 0 - mov dword ptr [eax+4], 0 - mov dword ptr [eax+8], 0 - mov [eax+0Ch], ebx - mov [eax+10h], ebx - -loc_1958409: ; CODE XREF: TGenericArray__sub_19583A0+4Dj - add ecx, 14h - dec edx - jnz short loc_19583E8 - pop ebx - -loc_1958410: ; CODE XREF: TGenericArray__sub_19583A0+37j - mov [esi+TGenericArray.ItemCount], edi - pop edi - pop esi - pop ebp - retn 4 -TGenericArray__sub_19583A0 endp - -; =============== S U B R O U T I N E ======================================= - - -TStruct40__InitSearchBuffers proc near ; CODE XREF: TFileNameDatabase__sub_1959460+2Bp - push ebx - push esi - mov esi, ecx - mov eax, [esi+TStruct40.array_00.MaxItemCount] - xor ebx, ebx - push edi - mov [esi+TStruct40.array_00.ItemCount], ebx - cmp eax, 40h - jnb short loc_19586E1 - lea ecx, [ebx+40h] ; ECX = 0x40 - cmp eax, 20h - jbe short loc_19586D9 - cmp eax, 7FFFFFFFh - jbe short loc_19586D6 - or ecx, 0FFFFFFFFh - jmp short loc_19586D9 -; --------------------------------------------------------------------------- - -loc_19586D6: ; CODE XREF: TStruct40__InitSearchBuffers+1Fj - lea ecx, [eax+eax] - -loc_19586D9: ; CODE XREF: TStruct40__InitSearchBuffers+18j - ; TStruct40__InitSearchBuffers+24j - push ecx - mov ecx, esi - call TGenericArray__SetMaxItems_BYTE - -loc_19586E1: ; CODE XREF: TStruct40__InitSearchBuffers+10j - push ebx - lea ecx, [esi+TStruct40.array_18] - call TGenericArray__sub_19583A0 - mov eax, [esi+TStruct40.array_18.MaxItemCount] - cmp eax, 4 - jnb short loc_1958714 - mov ecx, 4 - cmp eax, 2 - jbe short loc_195870B - mov ecx, 0CCCCCCCh - cmp eax, 6666666h - ja short loc_195870B - lea ecx, [eax+eax] - -loc_195870B: ; CODE XREF: TStruct40__InitSearchBuffers+4Aj - ; TStruct40__InitSearchBuffers+56j - push ecx - lea ecx, [esi+TStruct40.array_18] - call TGenericArray__SetMaxItems_STRUCT14 - -loc_1958714: ; CODE XREF: TStruct40__InitSearchBuffers+40j - pop edi - mov [esi+TStruct40.HashValue], ebx - mov [esi+TStruct40.CharIndex], ebx - mov [esi+TStruct40.ItemCount], ebx - mov [esi+TStruct40.SearchPhase], 2 - pop esi - pop ebx - retn -TStruct40__InitSearchBuffers endp - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -TGenericArray__InsertItem_STRUCT14 proc near - ; CODE XREF: TFileNameDatabase__sub_1959460+73p - -pStruct14 = dword ptr 8 - - push ebp - mov ebp, esp - push esi - mov esi, ecx - mov eax, [esi+TGenericArray.ItemCount] - mov ecx, [esi+TGenericArray.MaxItemCount] - inc eax - cmp eax, ecx - jbe short loc_1958361 - mov edx, eax - shr eax, 1 - cmp ecx, eax - jbe short loc_1958359 - mov edx, 0CCCCCCCh - cmp ecx, 6666666h - ja short loc_1958359 - lea edx, [ecx+ecx] - -loc_1958359: ; CODE XREF: TGenericArray__InsertItem_STRUCT14+17j - ; TGenericArray__InsertItem_STRUCT14+24j - push edx - mov ecx, esi - call TGenericArray__SetMaxItems_STRUCT14 - -loc_1958361: ; CODE XREF: TGenericArray__InsertItem_STRUCT14+Fj - mov eax, [esi+TGenericArray.ItemCount] - mov ecx, [esi+TGenericArray.field_4] - lea eax, [eax+eax*4] - lea eax, [ecx+eax*4] - test eax, eax - jz short loc_1958390 - mov ecx, [ebp+pStruct14] - mov edx, [ecx+TStruct14.HashValue] - mov [eax+TStruct14.HashValue], edx - mov edx, [ecx+TStruct14.field_4] - mov [eax+TStruct14.field_4], edx - mov edx, [ecx+TStruct14.field_8] - mov [eax+TStruct14.field_8], edx - mov edx, [ecx+TStruct14.field_C] - mov [eax+TStruct14.field_C], edx - mov ecx, [ecx+TStruct14.field_10] - mov [eax+TStruct14.field_10], ecx - -loc_1958390: ; CODE XREF: TGenericArray__InsertItem_STRUCT14+3Fj - inc [esi+TGenericArray.ItemCount] - pop esi - pop ebp - retn 4 -TGenericArray__InsertItem_STRUCT14 endp - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -CopyNameFragment proc near ; CODE XREF: sub_1958980+DAp - ; sub_1958D70+6Dp ... - -pThis = dword ptr -4 -pStruct1C = dword ptr 8 -dwDistance = dword ptr 0Ch - - push ebp - mov ebp, esp - push ecx - mov eax, [ebp+pStruct1C] - push ebx - mov ebx, ecx - cmp [ebx+TNameIndexStruct.Struct68.TotalItemCount], 0 - push esi - mov esi, [eax+TMndxFindResult.pStruct40] - push edi - mov [ebp+pThis], ebx - jnz loc_195A4B3 - mov ebx, [ebx+TNameIndexStruct.NameFragments.ItemArray] - add ebx, [ebp+dwDistance] - cmp byte ptr [ebx], 0 - mov [ebp+dwDistance], ebx - jz loc_195A55E - mov edi, edi - -loc_195A420: ; CODE XREF: CopyNameFragment+B4j - mov eax, [esi+TStruct40.array_00.ItemCount] - mov ecx, [esi+TStruct40.array_00.MaxItemCount] - inc eax - cmp eax, ecx - jbe short loc_195A48E - mov ebx, eax - shr eax, 1 - cmp ecx, eax - jbe short loc_195A443 - cmp ecx, 7FFFFFFFh - jbe short loc_195A440 - or ebx, 0FFFFFFFFh - jmp short loc_195A443 -; --------------------------------------------------------------------------- - -loc_195A440: ; CODE XREF: CopyNameFragment+49j - lea ebx, [ecx+ecx] - -loc_195A443: ; CODE XREF: CopyNameFragment+41j - ; CopyNameFragment+4Ej - push offset unk_53ABE00 - push ebx - call j_operator_new_safe - xor ecx, ecx - add esp, 8 - mov edi, eax - cmp [esi+TStruct40.array_00.ItemCount], ecx - jbe short loc_195A475 - lea ebx, [ebx+0] - -loc_195A460: ; CODE XREF: CopyNameFragment+83j - lea edx, [ecx+edi] - test edx, edx - jz short loc_195A46F - mov eax, [esi+TStruct40.array_00.field_4] - mov al, [ecx+eax] - mov [edx], al - -loc_195A46F: ; CODE XREF: CopyNameFragment+75j - inc ecx - cmp ecx, [esi+TStruct40.array_00.ItemCount] - jb short loc_195A460 - -loc_195A475: ; CODE XREF: CopyNameFragment+68j - mov eax, [esi+TStruct40.array_00.DataBuffer] - push eax - mov [esi+TStruct40.array_00.DataBuffer], edi - mov [esi+TStruct40.array_00.field_4], edi - mov [esi+TStruct40.array_00.ItemArray], edi - mov [esi+TStruct40.array_00.MaxItemCount], ebx - call operator_delete - mov ebx, [ebp+dwDistance] - add esp, 4 - -loc_195A48E: ; CODE XREF: CopyNameFragment+39j - mov eax, [esi+TStruct40.array_00.ItemCount] - add eax, [esi+TStruct40.array_00.field_4] - jz short loc_195A49A - mov cl, [ebx] - mov [eax], cl - -loc_195A49A: ; CODE XREF: CopyNameFragment+A4j - inc [esi+TStruct40.array_00.ItemCount] - inc ebx - cmp byte ptr [ebx], 0 - mov [ebp+dwDistance], ebx - jnz loc_195A420 - pop edi - pop esi - pop ebx - mov esp, ebp - pop ebp - retn 8 -; --------------------------------------------------------------------------- - -loc_195A4B3: ; CODE XREF: CopyNameFragment+16j - ; CopyNameFragment+168j - mov eax, [esi+TStruct40.array_00.ItemCount] - mov edx, [ebx+TNameIndexStruct.NameFragments.ItemArray] - mov edi, [ebp+dwDistance] - mov ecx, [esi+TStruct40.array_00.MaxItemCount] - add edx, edi - inc eax - mov [ebp+pStruct1C], edx - cmp eax, ecx - jbe short loc_195A52C - mov ebx, eax - shr eax, 1 - cmp ecx, eax - jbe short loc_195A4E1 - cmp ecx, 7FFFFFFFh - jbe short loc_195A4DE - or ebx, 0FFFFFFFFh - jmp short loc_195A4E1 -; --------------------------------------------------------------------------- - -loc_195A4DE: ; CODE XREF: CopyNameFragment+E7j - lea ebx, [ecx+ecx] - -loc_195A4E1: ; CODE XREF: CopyNameFragment+DFj - ; CopyNameFragment+ECj - push offset unk_53ABE00 - push ebx - call j_operator_new_safe - xor ecx, ecx - add esp, 8 - mov edi, eax - cmp [esi+TStruct40.array_00.ItemCount], ecx - jbe short loc_195A50D - -loc_195A4F8: ; CODE XREF: CopyNameFragment+11Bj - lea edx, [ecx+edi] - test edx, edx - jz short loc_195A507 - mov eax, [esi+TStruct40.array_00.field_4] - mov al, [ecx+eax] - mov [edx], al - -loc_195A507: ; CODE XREF: CopyNameFragment+10Dj - inc ecx - cmp ecx, [esi+TStruct40.array_00.ItemCount] - jb short loc_195A4F8 - -loc_195A50D: ; CODE XREF: CopyNameFragment+106j - mov eax, [esi+TStruct40.array_00.DataBuffer] - push eax - mov [esi+TStruct40.array_00.DataBuffer], edi - mov [esi+TStruct40.array_00.field_4], edi - mov [esi+TStruct40.array_00.ItemArray], edi - mov [esi+TStruct40.array_00.MaxItemCount], ebx - call operator_delete - mov edx, [ebp+pStruct1C] - mov edi, [ebp+dwDistance] - mov ebx, [ebp+pThis] - add esp, 4 - -loc_195A52C: ; CODE XREF: CopyNameFragment+D7j - mov eax, [esi+TStruct40.array_00.ItemCount] - add eax, [esi+TStruct40.array_00.field_4] - jz short loc_195A538 - mov cl, [edx] - mov [eax], cl - -loc_195A538: ; CODE XREF: CopyNameFragment+142j - inc [esi+TStruct40.array_00.ItemCount] - mov ecx, edi - and ecx, 1Fh - mov edx, 1 - shl edx, cl - mov ecx, [ebx+TNameIndexStruct.Struct68.ItemIsPresent.ItemArray] - mov eax, edi - shr eax, 5 - and edx, [ecx+eax*4] - inc edi - mov [ebp+dwDistance], edi - test edx, edx - jz loc_195A4B3 - -loc_195A55E: ; CODE XREF: CopyNameFragment+28j - pop edi - pop esi - pop ebx - mov esp, ebp - pop ebp - retn 8 -CopyNameFragment endp - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -sub_1958D70 proc near ; CODE XREF: sub_1958980+C9p - ; sub_1958D70+59p ... - -var_C = dword ptr -0Ch -var_8 = dword ptr -8 -var_1 = byte ptr -1 -pStruct1C = dword ptr 8 -arg_4 = dword ptr 0Ch - - push ebp - mov ebp, esp - mov eax, [ebp+pStruct1C] - sub esp, 0Ch - push ebx - push esi - mov esi, [eax+TMndxFindResult.pStruct40] - push edi - mov edi, ecx - mov ecx, [ebp+arg_4] - -loc_1958D84: ; CODE XREF: sub_1958D70+10Fj - ; sub_1958D70+28Fj - mov eax, [edi+TFileNameDatabase.NameFragIndexMask] - and eax, ecx - lea ebx, [eax+eax*2] - mov eax, [edi+TFileNameDatabase.NameFragTable.ItemArray] - add ebx, ebx - add ebx, ebx - mov [ebp+var_C], ebx - cmp ecx, [eax+ebx+4] - jnz loc_1958E8E - mov edx, [eax+ebx+8] - mov ecx, edx - and ecx, 0FFFFFF00h - cmp ecx, 0FFFFFF00h - jz short loc_1958DE7 - mov ecx, [edi+TFileNameDatabase.NextDB.pDatabase] - push edx - test ecx, ecx - jz short loc_1958DD3 - mov edx, [ebp+pStruct1C] - push edx - call sub_1958D70 - jmp loc_1958E71 -; --------------------------------------------------------------------------- - -loc_1958DD3: ; CODE XREF: sub_1958D70+53j - mov eax, [ebp+pStruct1C] - push eax - lea ecx, [edi+TFileNameDatabase.IndexStruct_174] - call CopyNameFragment - jmp loc_1958E71 -; --------------------------------------------------------------------------- - -loc_1958DE7: ; CODE XREF: sub_1958D70+48j - mov eax, [esi+TStruct40.array_00.ItemCount] - mov ecx, [esi+TStruct40.array_00.MaxItemCount] - inc eax - mov byte ptr [ebp+arg_4+3], dl - cmp eax, ecx - jbe short loc_1958E61 - mov [ebp+var_8], eax - shr eax, 1 - cmp ecx, eax - jbe short loc_1958E15 - cmp ecx, 7FFFFFFFh - jbe short loc_1958E0F - mov [ebp+var_8], 0FFFFFFFFh - jmp short loc_1958E15 -; --------------------------------------------------------------------------- - -loc_1958E0F: ; CODE XREF: sub_1958D70+94j - lea edx, [ecx+ecx] - mov [ebp+var_8], edx - -loc_1958E15: ; CODE XREF: sub_1958D70+8Cj - ; sub_1958D70+9Dj - mov eax, [ebp+var_8] - push offset unk_53ABE00 - push eax - call j_operator_new_safe - xor ecx, ecx - add esp, 8 - cmp [esi+TStruct40.array_00.ItemCount], ecx - jbe short loc_1958E48 - lea ecx, [ecx+0] - -loc_1958E30: ; CODE XREF: sub_1958D70+D6j - lea edx, [ecx+eax] - test edx, edx - jz short loc_1958E42 - mov ebx, [esi+4] - mov bl, [ecx+ebx] - mov [edx], bl - mov ebx, [ebp+var_C] - -loc_1958E42: ; CODE XREF: sub_1958D70+C5j - inc ecx - cmp ecx, [esi+TStruct40.array_00.ItemCount] - jb short loc_1958E30 - -loc_1958E48: ; CODE XREF: sub_1958D70+BBj - mov ecx, [esi] - mov edx, [ebp+var_8] - push ecx - mov [esi+TStruct40.array_00.DataBuffer], eax - mov [esi+TStruct40.array_00.field_4], eax - mov [esi+TStruct40.array_00.ItemArray], eax - mov [esi+TStruct40.array_00.MaxItemCount], edx - call operator_delete - add esp, 4 - -loc_1958E61: ; CODE XREF: sub_1958D70+83j - mov eax, [esi+TStruct40.array_00.field_4] - add eax, [esi+TStruct40.array_00.ItemCount] - jz short loc_1958E6E - mov cl, byte ptr [ebp+arg_4+3] - mov [eax], cl - -loc_1958E6E: ; CODE XREF: sub_1958D70+F7j - inc [esi+TStruct40.array_00.ItemCount] - -loc_1958E71: ; CODE XREF: sub_1958D70+5Ej - ; sub_1958D70+72j - mov edx, [edi+TFileNameDatabase.NameFragTable.ItemArray] - mov ecx, [ebx+edx] - mov [ebp+arg_4], ecx - test ecx, ecx - jnz loc_1958D84 - -loc_1958E85: ; CODE XREF: sub_1958D70+277j - pop edi - pop esi - pop ebx - mov esp, ebp - pop ebp - retn 8 -; --------------------------------------------------------------------------- - -loc_1958E8E: ; CODE XREF: sub_1958D70+30j - mov edx, [edi+TFileNameDatabase.Struct68_D0.ItemIsPresent.ItemArray] - mov eax, ecx - and ecx, 1Fh - mov ebx, 1 - shl ebx, cl - shr eax, 5 - test [edx+eax*4], ebx - mov eax, [ebp+arg_4] - jz loc_1958F50 - mov ebx, [edi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] - push eax - lea ecx, [edi+TFileNameDatabase.Struct68_D0] - add ebx, eax - call TSparseArray__GetItemValue - mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry] - imul ecx, eax - mov eax, ecx - and ecx, 1Fh - mov edx, ecx - mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry] - add ecx, edx - shr eax, 5 - cmp ecx, 20h - mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.ItemArray] - ja short loc_1958EF2 - mov eax, [ecx+eax*4] - mov ecx, edx - shr eax, cl - jmp short loc_1958F15 -; --------------------------------------------------------------------------- - -loc_1958EF2: ; CODE XREF: sub_1958D70+177j - lea eax, [ecx+eax*4] - mov [ebp+var_C], eax - mov eax, [eax+4] - mov ecx, 20h - sub ecx, edx - shl eax, cl - mov ecx, [ebp+var_C] - mov ecx, [ecx] - mov [ebp+var_C], ecx - mov ecx, edx - mov edx, [ebp+var_C] - shr edx, cl - or eax, edx - -loc_1958F15: ; CODE XREF: sub_1958D70+180j - and eax, [edi+TFileNameDatabase.FrgmDist_HiBits.EntryBitMask] - movzx edx, byte ptr [ebx] - mov ecx, [edi+TFileNameDatabase.NextDB.pDatabase] - shl eax, 8 - or eax, edx - push eax - test ecx, ecx - jz short loc_1958F3C - mov eax, [ebp+pStruct1C] - push eax - call sub_1958D70 - jmp loc_1958FDE -; --------------------------------------------------------------------------- - -loc_1958F3C: ; CODE XREF: sub_1958D70+1BCj - mov ecx, [ebp+pStruct1C] - push ecx - lea ecx, [edi+TFileNameDatabase.IndexStruct_174] - call CopyNameFragment - jmp loc_1958FDE -; --------------------------------------------------------------------------- - -loc_1958F50: ; CODE XREF: sub_1958D70+139j - mov edx, [edi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] - mov cl, [eax+edx] - mov eax, [esi+TStruct40.array_00.ItemCount] - mov [ebp+var_1], cl - mov ecx, [esi+TStruct40.array_00.MaxItemCount] - inc eax - cmp eax, ecx - jbe short loc_1958FCE - mov ebx, eax - shr eax, 1 - mov [ebp+var_8], ebx - cmp ecx, eax - jbe short loc_1958F85 - cmp ecx, 7FFFFFFFh - jbe short loc_1958F7F - or ebx, 0FFFFFFFFh - jmp short loc_1958F82 -; --------------------------------------------------------------------------- - -loc_1958F7F: ; CODE XREF: sub_1958D70+208j - lea ebx, [ecx+ecx] - -loc_1958F82: ; CODE XREF: sub_1958D70+20Dj - mov [ebp+var_8], ebx - -loc_1958F85: ; CODE XREF: sub_1958D70+200j - push offset unk_53ABE00 - push ebx - call j_operator_new_safe - xor ecx, ecx - add esp, 8 - cmp [esi+TStruct40.array_00.ItemCount], ecx - jbe short loc_1958FB8 - lea ebx, [ebx+0] - -loc_1958FA0: ; CODE XREF: sub_1958D70+243j - lea edx, [ecx+eax] - test edx, edx - jz short loc_1958FAF - mov ebx, [esi+TStruct40.array_00.field_4] - mov bl, [ecx+ebx] - mov [edx], bl - -loc_1958FAF: ; CODE XREF: sub_1958D70+235j - inc ecx - cmp ecx, [esi+TStruct40.array_00.ItemCount] - jb short loc_1958FA0 - mov ebx, [ebp+var_8] - -loc_1958FB8: ; CODE XREF: sub_1958D70+228j - mov ecx, [esi+TStruct40.array_00.DataBuffer] - push ecx - mov [esi+TStruct40.array_00.DataBuffer], eax - mov [esi+TStruct40.array_00.field_4], eax - mov [esi+TStruct40.array_00.ItemArray], eax - mov [esi+TStruct40.array_00.MaxItemCount], ebx - call operator_delete - add esp, 4 - -loc_1958FCE: ; CODE XREF: sub_1958D70+1F5j - mov eax, [esi+TStruct40.array_00.field_4] - add eax, [esi+TStruct40.array_00.ItemCount] - jz short loc_1958FDB - mov dl, [ebp+var_1] - mov [eax], dl - -loc_1958FDB: ; CODE XREF: sub_1958D70+264j - inc [esi+TStruct40.array_00.ItemCount] - -loc_1958FDE: ; CODE XREF: sub_1958D70+1C7j - ; sub_1958D70+1DBj - mov ebx, [ebp+arg_4] - cmp ebx, [edi+TFileNameDatabase.field_214] - jbe loc_1958E85 - push ebx - mov ecx, edi - call sub_1959F50 - or ecx, 0FFFFFFFFh - sub ecx, ebx - add ecx, eax - mov [ebp+arg_4], ecx - jmp loc_1958D84 -sub_1958D70 endp - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -TFileNameDatabase__sub_1959CB0 proc near ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+A1p - ; TFileNameDatabase__sub_1958B00+E8p ... - -pThis = dword ptr -4 -dwKey = dword ptr 8 - - push ebp - mov ebp, esp - push ecx - mov edx, [ebp+dwKey] - mov eax, edx - shr eax, 9 - mov [ebp+pThis], ecx - test edx, 1FFh ; if(dwKey & 0x01FF) - jnz short loc_1959CD3 - mov ecx, [ecx+TFileNameDatabase.Struct68_00.ArrayDwords_38.ItemArray] - mov eax, [ecx+eax*4] ; EAX = pDatabase->NextKeyTable[dwKey >> 0x09] - mov esp, ebp - pop ebp - retn 4 -; --------------------------------------------------------------------------- - -loc_1959CD3: ; CODE XREF: TFileNameDatabase__sub_1959CB0+15j - push ebx - push esi - mov esi, [ecx+TFileNameDatabase.Struct68_00.ArrayDwords_38.ItemArray] - lea esi, [esi+eax*4] - mov eax, [esi] - mov esi, [esi+4] - shr eax, 9 - add esi, 1FFh - push edi - shr esi, 9 - lea edi, [eax+0Ah] - mov [ebp+dwKey], esi - cmp edi, esi - jb short loc_1959D2E - mov edi, [ecx+TFileNameDatabase.Struct68_00.ArrayTriplets_20.ItemArray] - lea esi, [eax+eax*2+3] - lea esi, [edi+esi*4] - mov edi, eax - shl edi, 9 - mov ebx, edi - sub ebx, [esi] - add ebx, 200h - cmp edx, ebx - jb short loc_1959D5F - -loc_1959D14: ; CODE XREF: TFileNameDatabase__sub_1959CB0+7Aj - add edi, 200h - add esi, 0Ch - mov ebx, edi - sub ebx, [esi] - inc eax - add ebx, 200h - cmp edx, ebx - jnb short loc_1959D14 - jmp short loc_1959D5F -; --------------------------------------------------------------------------- - -loc_1959D2E: ; CODE XREF: TFileNameDatabase__sub_1959CB0+45j - lea edi, [eax+1] - cmp edi, esi - jnb short loc_1959D5F - mov ecx, [ecx+TFileNameDatabase.Struct68_00.ArrayTriplets_20.ItemArray] - -loc_1959D38: ; CODE XREF: TFileNameDatabase__sub_1959CB0+AAj - add esi, eax - shr esi, 1 - mov ebx, esi - shl ebx, 9 - lea edi, [esi+esi*2] - sub ebx, [ecx+edi*4] - cmp edx, ebx - jnb short loc_1959D50 - mov [ebp+dwKey], esi - jmp short loc_1959D55 -; --------------------------------------------------------------------------- - -loc_1959D50: ; CODE XREF: TFileNameDatabase__sub_1959CB0+99j - mov eax, esi - mov esi, [ebp+dwKey] - -loc_1959D55: ; CODE XREF: TFileNameDatabase__sub_1959CB0+9Ej - lea edi, [eax+1] - cmp edi, esi - jb short loc_1959D38 - mov ecx, [ebp+pThis] - -loc_1959D5F: ; CODE XREF: TFileNameDatabase__sub_1959CB0+62j - ; TFileNameDatabase__sub_1959CB0+7Cj ... - mov ecx, [ecx+TFileNameDatabase.Struct68_00.ArrayTriplets_20.ItemArray] - lea esi, [eax+eax*2] - mov edi, [ecx+esi*4] ; EDI = Struct68_00.ArrayTriplets_20.ItemArray[eax] - lea esi, [ecx+esi*4] ; ESI = Struct68_00.ArrayTriplets_20.ItemArray + eax - mov ecx, eax - shl ecx, 9 - sub edi, ecx - shl eax, 4 - add edx, edi - mov edi, eax - mov eax, [esi+TRIPLET.NextKey] - mov ecx, eax - shr ecx, 17h - mov ebx, 100h - sub ebx, ecx - cmp edx, ebx - jnb short loc_1959DE8 - mov ecx, eax - shr ecx, 7 - and ecx, 0FFh - mov esi, 80h - sub esi, ecx - cmp edx, esi - jnb short loc_1959DC0 - and eax, 7Fh - mov ecx, 40h - sub ecx, eax - cmp edx, ecx - jb loc_1959E53 - add edi, 2 - lea edx, [edx+eax-40h] - jmp loc_1959E53 -; --------------------------------------------------------------------------- - -loc_1959DC0: ; CODE XREF: TFileNameDatabase__sub_1959CB0+F0j - shr eax, 0Fh - and eax, 0FFh - mov esi, 0C0h - sub esi, eax - cmp edx, esi - jnb short loc_1959DDC - add edi, 4 - lea edx, [edx+ecx-80h] - jmp short loc_1959E53 -; --------------------------------------------------------------------------- - -loc_1959DDC: ; CODE XREF: TFileNameDatabase__sub_1959CB0+121j - add edi, 6 - lea edx, [edx+eax-0C0h] - jmp short loc_1959E53 -; --------------------------------------------------------------------------- - -loc_1959DE8: ; CODE XREF: TFileNameDatabase__sub_1959CB0+DAj - mov esi, [esi+TRIPLET.Distance] - mov eax, esi - shr eax, 9 - and eax, 1FFh - mov ebx, 180h - sub ebx, eax - cmp edx, ebx - jnb short loc_1959E29 - and esi, 1FFh - mov eax, 140h - sub eax, esi - cmp edx, eax - jnb short loc_1959E1D - add edi, 8 - lea edx, [edx+ecx-100h] - jmp short loc_1959E53 -; --------------------------------------------------------------------------- - -loc_1959E1D: ; CODE XREF: TFileNameDatabase__sub_1959CB0+15Fj - add edi, 0Ah - lea edx, [edx+esi-140h] - jmp short loc_1959E53 -; --------------------------------------------------------------------------- - -loc_1959E29: ; CODE XREF: TFileNameDatabase__sub_1959CB0+14Ej - shr esi, 12h - and esi, 1FFh - mov ecx, 1C0h - sub ecx, esi - cmp edx, ecx - jnb short loc_1959E49 - add edi, 0Ch - lea edx, [edx+eax-180h] - jmp short loc_1959E53 -; --------------------------------------------------------------------------- - -loc_1959E49: ; CODE XREF: TFileNameDatabase__sub_1959CB0+18Bj - add edi, 0Eh - lea edx, [edx+esi-1C0h] - -loc_1959E53: ; CODE XREF: TFileNameDatabase__sub_1959CB0+FEj - ; TFileNameDatabase__sub_1959CB0+10Bj ... - mov eax, [ebp+pThis] - mov ebx, [eax+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray] - mov ecx, [ebx+edi*4] - not ecx - mov eax, ecx - shr eax, 1 - and eax, 55555555h - mov esi, ecx - and esi, 55555555h - add eax, esi - mov esi, eax - shr esi, 2 - and eax, 33333333h - and esi, 33333333h - add esi, eax - mov eax, esi - shr eax, 4 - and esi, 0F0F0F0Fh - and eax, 0F0F0F0Fh - add eax, esi - imul eax, 1010101h - mov esi, eax - shr esi, 18h - cmp edx, esi - jb short loc_1959EEA - mov ecx, [ebx+edi*4+4] - inc edi - sub edx, esi - not ecx - mov eax, ecx - shr eax, 1 - and eax, 55555555h - mov esi, ecx - and esi, 55555555h - add eax, esi - mov esi, eax - shr esi, 2 - and eax, 33333333h - and esi, 33333333h - add esi, eax - mov eax, esi - shr eax, 4 - and eax, 0F0F0F0Fh - and esi, 0F0F0F0Fh - add eax, esi - imul eax, 1010101h - -loc_1959EEA: ; CODE XREF: TFileNameDatabase__sub_1959CB0+1F2j - mov esi, eax - shr esi, 8 - and esi, 0FFh - shl edi, 5 - cmp edx, esi - jnb short loc_1959F0D - and eax, 0FFh - cmp edx, eax - jb short loc_1959F2B - add edi, 8 - shr ecx, 8 - jmp short loc_1959F29 -; --------------------------------------------------------------------------- - -loc_1959F0D: ; CODE XREF: TFileNameDatabase__sub_1959CB0+24Aj - shr eax, 10h - and eax, 0FFh - cmp edx, eax - jnb short loc_1959F23 - add edi, 10h - shr ecx, 10h - sub edx, esi - jmp short loc_1959F2B -; --------------------------------------------------------------------------- - -loc_1959F23: ; CODE XREF: TFileNameDatabase__sub_1959CB0+267j - add edi, 18h - shr ecx, 18h - -loc_1959F29: ; CODE XREF: TFileNameDatabase__sub_1959CB0+25Bj - sub edx, eax - -loc_1959F2B: ; CODE XREF: TFileNameDatabase__sub_1959CB0+253j - ; TFileNameDatabase__sub_1959CB0+271j - and ecx, 0FFh - shl edx, 8 - movzx eax, ds:table_1BA1818[ecx+edx] - add eax, edi - pop edi - pop esi - pop ebx - mov esp, ebp - pop ebp - retn 4 -TFileNameDatabase__sub_1959CB0 endp - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -TNameIndexStruct__CheckAndCopyNameFragment proc near ; CODE XREF: TArchiveDatabase__sub_1958B00+74p - ; TArchiveDatabase__sub_1958B00+1E0p ... - -var_C = dword ptr -0Ch -pThis = dword ptr -8 -var_4 = dword ptr -4 -pStruct1C = dword ptr 8 -dwDistance = dword ptr 0Ch - - push ebp - mov ebp, esp - sub esp, 0Ch - mov eax, [ebp+pStruct1C] - push ebx - mov edx, ecx - cmp [edx+TNameIndexStruct.Struct68.TotalItemCount], 0 - push esi - mov esi, [eax+TMndxFindResult.pStruct40] - push edi - mov [ebp+pThis], edx - jnz loc_195A6B7 - mov edi, [edx+TNameIndexStruct.NameFragments.ItemArray] - sub edi, [esi+TStruct40.CharIndex] - add edi, [ebp+dwDistance] - mov [ebp+pThis], edi - lea ebx, [ebx+0] - -loc_195A5A0: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+E6j - mov edx, [esi+TStruct40.CharIndex] - mov ecx, [ebp+pStruct1C] - mov eax, [ecx+TMndxFindResult.szSearchMask] - mov cl, [edx+edi] - mov [ebp+dwDistance], edx - cmp cl, [edx+eax] - jnz loc_195A67D - mov eax, [esi+TStruct40.array_00.ItemCount] - mov ecx, [esi+TStruct40.array_00.MaxItemCount] - mov ebx, 1 - add eax, ebx - cmp eax, ecx - jbe short loc_195A62D - mov ebx, eax - shr eax, 1 - cmp ecx, eax - jbe short loc_195A5E0 - cmp ecx, 7FFFFFFFh - jbe short loc_195A5DD - or ebx, 0FFFFFFFFh - jmp short loc_195A5E0 -; --------------------------------------------------------------------------- - -loc_195A5DD: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+66j - lea ebx, [ecx+ecx] - -loc_195A5E0: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+5Ej - ; TNameIndexStruct__CheckAndCopyNameFragment+6Bj - push offset unk_53ABE00 - push ebx - call j_operator_new_safe - xor ecx, ecx - add esp, 8 - mov edi, eax - cmp [esi+TStruct40.array_00.ItemCount], ecx - jbe short loc_195A60C - -loc_195A5F7: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+9Aj - lea edx, [ecx+edi] - test edx, edx - jz short loc_195A606 - mov eax, [esi+TStruct40.array_00.field_4] - mov al, [ecx+eax] - mov [edx], al - -loc_195A606: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+8Cj - inc ecx - cmp ecx, [esi+TStruct40.array_00.ItemCount] - jb short loc_195A5F7 - -loc_195A60C: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+85j - mov eax, [esi+TStruct40.array_00.DataBuffer] - push eax - mov [esi+TStruct40.array_00.DataBuffer], edi - mov [esi+TStruct40.array_00.field_4], edi - mov [esi+TStruct40.array_00.ItemArray], edi - mov [esi+TStruct40.array_00.MaxItemCount], ebx - call operator_delete - mov edx, [ebp+dwDistance] - mov edi, [ebp+pThis] - add esp, 4 - mov ebx, 1 - -loc_195A62D: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+56j - mov eax, [esi+TStruct40.array_00.field_4] - add eax, [esi+TStruct40.array_00.ItemCount] - jz short loc_195A63A - mov cl, [edx+edi] - mov [eax], cl - -loc_195A63A: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+C3j - add [esi+TStruct40.CharIndex], ebx - add [esi+TStruct40.array_00.ItemCount], ebx - mov ecx, [esi+TStruct40.CharIndex] - cmp byte ptr [ecx+edi], 0 - mov eax, [esi+TStruct40.array_00.ItemCount] - jz loc_195A806 - mov edx, [ebp+pStruct1C] - cmp ecx, [edx+TMndxFindResult.cchSearchMask] - jb loc_195A5A0 - add edi, ecx - mov edi, edi - -loc_195A660: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+13Aj - mov ecx, [esi+TStruct40.array_00.MaxItemCount] - inc eax - cmp eax, ecx - jbe short loc_195A693 - mov edx, eax - shr eax, 1 - cmp ecx, eax - jbe short loc_195A68B - cmp ecx, 7FFFFFFFh - jbe short loc_195A688 - or edx, 0FFFFFFFFh - jmp short loc_195A68B -; --------------------------------------------------------------------------- - -loc_195A67D: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+41j - ; TNameIndexStruct__CheckAndCopyNameFragment+16Bj - pop edi - pop esi - xor al, al - pop ebx - mov esp, ebp - pop ebp - retn 8 -; --------------------------------------------------------------------------- - -loc_195A688: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+106j - lea edx, [ecx+ecx] - -loc_195A68B: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+FEj - ; TNameIndexStruct__CheckAndCopyNameFragment+10Bj - push edx - mov ecx, esi - call TGenericArray__SetMaxItems_BYTE - -loc_195A693: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+F6j - mov eax, [esi+TStruct40.array_00.field_4] - add eax, [esi+TStruct40.array_00.ItemCount] - jz short loc_195A69F - mov cl, [edi] - mov [eax], cl - -loc_195A69F: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+129j - add [esi+TStruct40.array_00.ItemCount], ebx - mov eax, [esi+TStruct40.array_00.ItemCount] - add edi, ebx - cmp byte ptr [edi], 0 - jnz short loc_195A660 - pop edi - pop esi - mov al, 1 - pop ebx - mov esp, ebp - pop ebp - retn 8 -; --------------------------------------------------------------------------- - -loc_195A6B7: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+18j - mov ebx, [ebp+dwDistance] - lea ebx, [ebx+0] - -loc_195A6C0: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+231j - mov edi, [edx+TNameIndexStruct.NameFragments.ItemArray] - mov eax, [ebp+pStruct1C] - mov ecx, [esi+TStruct40.CharIndex] - mov eax, [eax] - add edi, ebx - mov [ebp+var_4], edx - mov dl, [edi] - cmp dl, [ecx+eax] - mov edx, [ebp+var_4] - mov [ebp+var_C], edi - jnz short loc_195A67D - mov eax, [esi+TStruct40.array_00.ItemCount] - mov ecx, [esi+TStruct40.array_00.MaxItemCount] - inc eax - cmp eax, ecx - jbe short loc_195A752 - mov [ebp+var_4], eax - shr eax, 1 - cmp ecx, eax - jbe short loc_195A707 - cmp ecx, 7FFFFFFFh - jbe short loc_195A702 - mov [ebp+var_4], 0FFFFFFFFh - jmp short loc_195A707 -; --------------------------------------------------------------------------- - -loc_195A702: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+187j - add ecx, ecx - mov [ebp+var_4], ecx - -loc_195A707: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+17Fj - ; TNameIndexStruct__CheckAndCopyNameFragment+190j - mov edx, [ebp+var_4] - push offset unk_53ABE00 - push edx - call j_operator_new_safe - xor ecx, ecx - add esp, 8 - mov edi, eax - cmp [esi+TStruct40.array_00.ItemCount], ecx - jbe short loc_195A736 - -loc_195A721: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+1C4j - lea edx, [ecx+edi] - test edx, edx - jz short loc_195A730 - mov eax, [esi+TStruct40.array_00.field_4] - mov al, [ecx+eax] - mov [edx], al - -loc_195A730: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+1B6j - inc ecx - cmp ecx, [esi+TStruct40.array_00.ItemCount] - jb short loc_195A721 - -loc_195A736: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+1AFj - mov eax, [esi+TStruct40.array_00.DataBuffer] - mov ecx, [ebp+var_4] - push eax - mov [esi+TStruct40.array_00.DataBuffer], edi - mov [esi+TStruct40.array_00.field_4], edi - mov [esi+TStruct40.array_00.ItemArray], edi - mov [esi+TStruct40.array_00.MaxItemCount], ecx - call operator_delete - mov edx, [ebp+pThis] - add esp, 4 - -loc_195A752: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+176j - mov edi, [esi+TStruct40.array_00.field_4] - add edi, [esi+TStruct40.array_00.ItemCount] - jz short loc_195A761 - mov eax, [ebp+var_C] - mov cl, [eax] - mov [edi], cl - -loc_195A761: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+1E8j - mov ecx, 1 - add [esi+TStruct40.array_00.ItemCount], ecx - add [esi+TStruct40.CharIndex], ecx - mov edx, [edx+20h] - mov eax, [esi+TStruct40.array_00.ItemCount] - mov ecx, ebx - mov edi, ebx - and ecx, 1Fh - mov ebx, 1 - shl ebx, cl - shr edi, 5 - mov ecx, [edx+edi*4] - and ecx, ebx - mov ebx, [ebp+dwDistance] - inc ebx - mov [ebp+dwDistance], ebx - test ecx, ecx - jnz short loc_195A806 - mov ecx, [esi+TStruct40.CharIndex] - mov edx, [ebp+pStruct1C] - cmp ecx, [edx+4] - jnb short loc_195A7A6 - mov edx, [ebp+pThis] - jmp loc_195A6C0 -; --------------------------------------------------------------------------- - -loc_195A7A6: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+22Cj - ; TNameIndexStruct__CheckAndCopyNameFragment+294j - mov ecx, [ebp+pThis] - mov edi, [ecx+8] - mov ecx, [esi+TStruct40.array_00.MaxItemCount] - inc eax - cmp eax, ecx - jbe short loc_195A7D4 - mov edx, eax - shr eax, 1 - cmp ecx, eax - jbe short loc_195A7CC - cmp ecx, 7FFFFFFFh - jbe short loc_195A7C9 - or edx, 0FFFFFFFFh - jmp short loc_195A7CC -; --------------------------------------------------------------------------- - -loc_195A7C9: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+252j - lea edx, [ecx+ecx] - -loc_195A7CC: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+24Aj - ; TNameIndexStruct__CheckAndCopyNameFragment+257j - push edx - mov ecx, esi - call TGenericArray__SetMaxItems_BYTE - -loc_195A7D4: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+242j - mov eax, [esi+TStruct40.array_00.field_4] - add eax, [esi+TStruct40.array_00.ItemCount] - jz short loc_195A7E1 - mov dl, [edi+ebx] - mov [eax], dl - -loc_195A7E1: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+26Aj - inc [esi+TStruct40.array_00.ItemCount] - mov edi, [ebp+pThis] - mov edi, [edi+20h] - mov eax, [esi+TStruct40.array_00.ItemCount] - mov ecx, ebx - and ecx, 1Fh - mov edx, 1 - shl edx, cl - mov ecx, ebx - shr ecx, 5 - inc ebx - and edx, [edi+ecx*4] - test edx, edx - jz short loc_195A7A6 - -loc_195A806: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+DAj - ; TNameIndexStruct__CheckAndCopyNameFragment+221j - pop edi - pop esi - mov al, 1 - pop ebx - mov esp, ebp - pop ebp - retn 8 -TNameIndexStruct__CheckAndCopyNameFragment endp - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -sub_1959010 proc near ; CODE XREF: TArchiveDatabase__sub_1958B00+67p - ; TArchiveDatabase__sub_1958B00+1CFp ... - -pFragmentInfo = dword ptr -0Ch -var_8 = dword ptr -8 -var_1 = byte ptr -1 -pStruct1C = dword ptr 8 -arg_4 = dword ptr 0Ch - - push ebp - mov ebp, esp - mov eax, [ebp+pStruct1C] - sub esp, 0Ch - push ebx - push esi - mov esi, [eax+TMndxFindResult.pStruct40] - push edi - mov edi, ecx - mov ecx, [ebp+arg_4] - -loc_1959024: ; CODE XREF: sub_1959010+2CEj - mov eax, [edi+TFileNameDatabase.NameFragIndexMask] - and eax, ecx - lea ebx, [eax+eax*2] - mov eax, [edi+TFileNameDatabase.NameFragTable.ItemArray] - add ebx, ebx - add ebx, ebx - add eax, ebx - mov [ebp+pFragmentInfo], ebx - cmp ecx, [eax+NAME_ENTRY.NextHashModifier] - jnz loc_1959147 - mov edx, [eax+NAME_ENTRY.FragmentOffset] - mov ecx, edx - and ecx, 0FFFFFF00h - cmp ecx, 0FFFFFF00h - jz short loc_1959092 - mov ecx, [edi+TFileNameDatabase.NextDB.pDatabase] - push edx - test ecx, ecx - jz short loc_1959070 - mov edx, [ebp+pStruct1C] - push edx - call sub_1959010 - jmp short loc_195907F -; --------------------------------------------------------------------------- - -loc_1959070: ; CODE XREF: sub_1959010+53j - mov eax, [ebp+pStruct1C] - push eax - lea ecx, [edi+TFileNameDatabase.IndexStruct_174] - call TNameIndexStruct__CheckAndCopyNameFragment - -loc_195907F: ; CODE XREF: sub_1959010+5Ej - test al, al - jnz loc_195912E - -loc_1959087: ; CODE XREF: sub_1959010+90j - ; sub_1959010+1F3j ... - pop edi - pop esi - xor al, al - pop ebx - mov esp, ebp - pop ebp - retn 8 -; --------------------------------------------------------------------------- - -loc_1959092: ; CODE XREF: sub_1959010+48j - mov ecx, [ebp+pStruct1C] - mov eax, [ecx+TMndxFindResult.szSearchMask] - mov ecx, [esi+TStruct40.CharIndex] - mov byte ptr [ebp+arg_4+3], dl - cmp dl, [eax+ecx] - jnz short loc_1959087 - mov eax, [esi+TStruct40.array_00.ItemCount] - mov ecx, [esi+TStruct40.array_00.MaxItemCount] - inc eax - cmp eax, ecx - jbe short loc_1959119 - mov [ebp+var_8], eax - shr eax, 1 - cmp ecx, eax - jbe short loc_19590CD - cmp ecx, 7FFFFFFFh - jbe short loc_19590C7 - mov [ebp+var_8], 0FFFFFFFFh - jmp short loc_19590CD -; --------------------------------------------------------------------------- - -loc_19590C7: ; CODE XREF: sub_1959010+ACj - lea edx, [ecx+ecx] - mov [ebp+var_8], edx - -loc_19590CD: ; CODE XREF: sub_1959010+A4j - ; sub_1959010+B5j - mov eax, [ebp+var_8] - push offset unk_53ABE00 - push eax - call j_operator_new_safe - xor ecx, ecx - add esp, 8 - cmp [esi+TStruct40.array_00.ItemCount], ecx - jbe short loc_19590FD - -loc_19590E5: ; CODE XREF: sub_1959010+EBj - lea edx, [ecx+eax] - test edx, edx - jz short loc_19590F7 - mov ebx, [esi+TStruct40.array_00.field_4] - mov bl, [ecx+ebx] - mov [edx], bl - mov ebx, [ebp+pFragmentInfo] - -loc_19590F7: ; CODE XREF: sub_1959010+DAj - inc ecx - cmp ecx, [esi+TStruct40.array_00.ItemCount] - jb short loc_19590E5 - -loc_19590FD: ; CODE XREF: sub_1959010+D3j - mov ecx, [esi+TStruct40.array_00.DataBuffer] - mov edx, [ebp+var_8] - push ecx - mov [esi+TStruct40.array_00.DataBuffer], eax - mov [esi+TStruct40.array_00.field_4], eax - mov [esi+TStruct40.array_00.ItemArray], eax - mov [esi+TStruct40.array_00.MaxItemCount], edx - call operator_delete - mov dl, byte ptr [ebp+arg_4+3] - add esp, 4 - -loc_1959119: ; CODE XREF: sub_1959010+9Bj - mov eax, [esi+TStruct40.array_00.field_4] - add eax, [esi+TStruct40.array_00.ItemCount] - jz short loc_1959123 - mov [eax], dl - -loc_1959123: ; CODE XREF: sub_1959010+10Fj - mov eax, 1 - add [esi+TStruct40.array_00.ItemCount], eax - add [esi+TStruct40.CharIndex], eax - -loc_195912E: ; CODE XREF: sub_1959010+71j - mov eax, [edi+TFileNameDatabase.NameFragTable.ItemArray] - mov ecx, [ebx+eax] - mov [ebp+arg_4], ecx - test ecx, ecx - jz loc_19592ED - jmp loc_19592D5 -; --------------------------------------------------------------------------- - -loc_1959147: ; CODE XREF: sub_1959010+31j - mov eax, [edi+TFileNameDatabase.Struct68_D0.ItemIsPresent.ItemArray] - mov edx, ecx - and ecx, 1Fh - mov ebx, 1 - shl ebx, cl - shr edx, 5 - test [eax+edx*4], ebx - mov eax, [ebp+arg_4] - jz loc_195920E - mov ebx, [edi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] - push eax - lea ecx, [edi+TFileNameDatabase.Struct68_D0] - add ebx, eax - call TSparseArray__GetItemValue - mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry] - imul ecx, eax - mov eax, ecx - and ecx, 1Fh - mov edx, ecx - mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry] - add ecx, edx - shr eax, 5 - cmp ecx, 20h - mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.ItemArray] - ja short loc_19591AB - mov eax, [ecx+eax*4] - mov ecx, edx - shr eax, cl - jmp short loc_19591CE -; --------------------------------------------------------------------------- - -loc_19591AB: ; CODE XREF: sub_1959010+190j - lea eax, [ecx+eax*4] - mov [ebp+pFragmentInfo], eax - mov eax, [eax+4] - mov ecx, 20h - sub ecx, edx - shl eax, cl - mov ecx, [ebp+pFragmentInfo] - mov ecx, [ecx] - mov [ebp+pFragmentInfo], ecx - mov ecx, edx - mov edx, [ebp+pFragmentInfo] - shr edx, cl - or eax, edx - -loc_19591CE: ; CODE XREF: sub_1959010+199j - and eax, [edi+TFileNameDatabase.FrgmDist_HiBits.EntryBitMask] - movzx edx, byte ptr [ebx] - mov ecx, [edi+TFileNameDatabase.NextDB.pDatabase] - shl eax, 8 - or eax, edx - push eax - test ecx, ecx - jz short loc_19591F2 - mov eax, [ebp+pStruct1C] - push eax - call sub_1959010 - jmp short loc_1959201 -; --------------------------------------------------------------------------- - -loc_19591F2: ; CODE XREF: sub_1959010+1D5j - mov ecx, [ebp+pStruct1C] - push ecx - lea ecx, [edi+TFileNameDatabase.IndexStruct_174] - call TNameIndexStruct__CheckAndCopyNameFragment - -loc_1959201: ; CODE XREF: sub_1959010+1E0j - test al, al - jz loc_1959087 - jmp loc_19592B6 -; --------------------------------------------------------------------------- - -loc_195920E: ; CODE XREF: sub_1959010+152j - mov edx, [edi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] - mov dl, [eax+edx] - mov ecx, [ebp+pStruct1C] - mov eax, [ecx+TMndxFindResult.szSearchMask] - mov ecx, [esi+TStruct40.CharIndex] - mov [ebp+var_1], dl - cmp dl, [eax+ecx] - jnz loc_1959087 - mov eax, [esi+TStruct40.array_00.ItemCount] - mov ecx, [esi+TStruct40.array_00.MaxItemCount] - inc eax - cmp eax, ecx - jbe short loc_19592A1 - mov ebx, eax - shr eax, 1 - mov [ebp+var_8], ebx - cmp ecx, eax - jbe short loc_1959254 - cmp ecx, 7FFFFFFFh - jbe short loc_195924E - or ebx, 0FFFFFFFFh - jmp short loc_1959251 -; --------------------------------------------------------------------------- - -loc_195924E: ; CODE XREF: sub_1959010+237j - lea ebx, [ecx+ecx] - -loc_1959251: ; CODE XREF: sub_1959010+23Cj - mov [ebp+var_8], ebx - -loc_1959254: ; CODE XREF: sub_1959010+22Fj - push offset unk_53ABE00 - push ebx - call j_operator_new_safe - xor ecx, ecx - add esp, 8 - cmp [esi+TStruct40.array_00.ItemCount], ecx - jbe short loc_1959288 - lea esp, [esp+0] - -loc_1959270: ; CODE XREF: sub_1959010+273j - lea edx, [ecx+eax] - test edx, edx - jz short loc_195927F - mov ebx, [esi+TStruct40.array_00.field_4] - mov bl, [ecx+ebx] - mov [edx], bl - -loc_195927F: ; CODE XREF: sub_1959010+265j - inc ecx - cmp ecx, [esi+TStruct40.array_00.ItemCount] - jb short loc_1959270 - mov ebx, [ebp+var_8] - -loc_1959288: ; CODE XREF: sub_1959010+257j - mov ecx, [esi+TStruct40.array_00.DataBuffer] - push ecx - mov [esi+TStruct40.array_00.DataBuffer], eax - mov [esi+TStruct40.array_00.field_4], eax - mov [esi+TStruct40.array_00.ItemArray], eax - mov [esi+TStruct40.array_00.MaxItemCount], ebx - call operator_delete - mov dl, [ebp+var_1] - add esp, 4 - -loc_19592A1: ; CODE XREF: sub_1959010+224j - mov eax, [esi+TStruct40.array_00.field_4] - add eax, [esi+TStruct40.array_00.ItemCount] - jz short loc_19592AB - mov [eax], dl - -loc_19592AB: ; CODE XREF: sub_1959010+297j - mov eax, 1 - add [esi+TStruct40.array_00.ItemCount], eax - add [esi+TStruct40.CharIndex], eax - -loc_19592B6: ; CODE XREF: sub_1959010+1F9j - mov ebx, [ebp+arg_4] - cmp ebx, [edi+TFileNameDatabase.field_214] - jbe short loc_19592ED - push ebx - mov ecx, edi - call sub_1959F50 - or edx, 0FFFFFFFFh - sub edx, ebx - add eax, edx - mov ecx, eax - mov [ebp+arg_4], eax - -loc_19592D5: ; CODE XREF: sub_1959010+132j - mov edx, [esi+TStruct40.CharIndex] - mov eax, [ebp+pStruct1C] - cmp edx, [eax+TMndxFindResult.cchSearchMask] - jb loc_1959024 - push ecx - push eax - mov ecx, edi - call sub_1958D70 - -loc_19592ED: ; CODE XREF: sub_1959010+12Cj - ; sub_1959010+2AFj - pop edi - pop esi - mov al, 1 - pop ebx - mov esp, ebp - pop ebp - retn 8 -sub_1959010 endp - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -sub_19582E0 proc near ; CODE XREF: TFileNameDatabase__sub_1958B00+253p - -arg_0 = dword ptr 8 - - push ebp - mov ebp, esp - push esi - mov esi, ecx - mov eax, [esi+0Ch] - mov ecx, [esi+10h] - inc eax - cmp eax, ecx - jbe short loc_1958311 - mov edx, eax - shr eax, 1 - cmp ecx, eax - jbe short loc_1958309 - cmp ecx, 7FFFFFFFh - jbe short loc_1958306 - or edx, 0FFFFFFFFh - jmp short loc_1958309 -; --------------------------------------------------------------------------- - -loc_1958306: ; CODE XREF: sub_19582E0+1Fj - lea edx, [ecx+ecx] - -loc_1958309: ; CODE XREF: sub_19582E0+17j - ; sub_19582E0+24j - push edx - mov ecx, esi - call TGenericArray__SetMaxItems_BYTE - -loc_1958311: ; CODE XREF: sub_19582E0+Fj - mov eax, [esi+4] - add eax, [esi+0Ch] - jz short loc_1958320 - mov ecx, [ebp+arg_0] - mov dl, [ecx] - mov [eax], dl - -loc_1958320: ; CODE XREF: sub_19582E0+37j - inc dword ptr [esi+0Ch] - pop esi - pop ebp - retn 4 -sub_19582E0 endp - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -TFileNameDatabase__sub_1958B00 proc near ; CODE XREF: TFileNameDatabase__sub_1959460+3Bp - -var_C = dword ptr -0Ch -ItemArrayOffset = dword ptr -8 -var_4 = dword ptr -4 -arg_0 = dword ptr 8 - - push ebp - mov ebp, esp - sub esp, 0Ch - mov edx, [ebp+pStruct1C] - push ebx - mov ebx, [edx+TMndxFindResult.szSearchMask] - push esi - push edi - mov edi, [edx+TMndxFindResult.pStruct40] - mov eax, [edi+TStruct40.CharIndex] - movzx eax, byte ptr [eax+ebx] - mov esi, ecx - mov ecx, [edi+TStruct40.HashValue] - mov ebx, ecx - shl ebx, 5 - xor eax, ebx - mov ebx, [esi+TFileNameDatabase.NameFragTable.ItemArray] - xor eax, ecx - and eax, [esi+TFileNameDatabase.NameFragIndexMask] - lea eax, [eax+eax*2] - add eax, eax - add eax, eax - mov [ebp+ItemArrayOffset], eax - cmp ecx, [eax+ebx] - jnz loc_1958BE5 - mov ecx, [eax+ebx+NAME_ENTRY.FragmentOffset] - mov ebx, ecx - and ebx, 0FFFFFF00h - cmp ebx, 0FFFFFF00h - jz short loc_1958B88 - mov eax, [esi+TFileNameDatabase.NextDB.pDatabase] - push ecx - push edx - test eax, eax - jz short loc_1958B6E - mov ecx, eax - call sub_1959010 - jmp short loc_1958B79 -; --------------------------------------------------------------------------- - -loc_1958B6E: ; CODE XREF: TArchiveDatabase__sub_1958B00+63j - lea ecx, [esi+TFileNameDatabase.IndexStruct_174] - call TNameIndexStruct__CheckAndCopyNameFragment - -loc_1958B79: ; CODE XREF: TArchiveDatabase__sub_1958B00+6Cj - test al, al - jnz short loc_1958BCA - -loc_1958B7D: ; CODE XREF: TArchiveDatabase__sub_1958B00+108j - ; TArchiveDatabase__sub_1958B00+1F3j - pop edi - pop esi - xor al, al - pop ebx - mov esp, ebp - pop ebp - retn 4 -; --------------------------------------------------------------------------- - -loc_1958B88: ; CODE XREF: TArchiveDatabase__sub_1958B00+57j - mov eax, [edi+TStruct40.array_00.ItemCount] - mov bl, cl - mov ecx, [edi+TStruct40.array_00.MaxItemCount] - inc eax - cmp eax, ecx - jbe short loc_1958BB5 - mov edx, eax - shr eax, 1 - cmp ecx, eax - jbe short loc_1958BAD - cmp ecx, 7FFFFFFFh - jbe short loc_1958BAA - or edx, 0FFFFFFFFh - jmp short loc_1958BAD -; --------------------------------------------------------------------------- - -loc_1958BAA: ; CODE XREF: TArchiveDatabase__sub_1958B00+A3j - lea edx, [ecx+ecx] - -loc_1958BAD: ; CODE XREF: TArchiveDatabase__sub_1958B00+9Bj - ; TArchiveDatabase__sub_1958B00+A8j - push edx - mov ecx, edi - call TGenericArray__SetMaxItems_BYTE - -loc_1958BB5: ; CODE XREF: TArchiveDatabase__sub_1958B00+93j - mov eax, [edi+TStruct40.array_00.field_4] - add eax, [edi+TStruct40.array_00.ItemCount] - jz short loc_1958BBF - mov [eax], bl - -loc_1958BBF: ; CODE XREF: TArchiveDatabase__sub_1958B00+BBj - mov eax, 1 - add [edi+TStruct40.array_00.ItemCount], eax - add [edi+TStruct40.CharIndex], eax - -loc_1958BCA: ; CODE XREF: TArchiveDatabase__sub_1958B00+7Bj - mov ecx, [esi+TFileNameDatabase.NameFragTable.ItemArray] - mov edx, [ebp+ItemArrayOffset] - mov eax, [ecx+edx+NAME_ENTRY.NextHashModifier] - mov [edi+TStruct40.HashValue], eax - -loc_1958BDA: ; CODE XREF: TArchiveDatabase__sub_1958B00+1E7j - pop edi - pop esi - mov al, 1 - pop ebx - mov esp, ebp - pop ebp - retn 4 -; --------------------------------------------------------------------------- - -loc_1958BE5: ; CODE XREF: TArchiveDatabase__sub_1958B00+3Fj - push ecx - mov ecx, esi - call TArchiveDatabase__sub_1959CB0 - mov ebx, [esi+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray] - inc eax - mov ecx, eax - and ecx, 1Fh - mov edx, 1 - shl edx, cl - mov ecx, eax - shr ecx, 5 - mov [ebp+ItemArrayOffset], eax - test [ebx+ecx*4], edx - jz loc_1958B7D - sub eax, [edi+TStruct40.HashValue] - mov [ebp+var_4], 0FFFFFFFFh - dec eax - mov [edi+TStruct40.HashValue], eax - lea esp, [esp+0] - -loc_1958C20: ; CODE XREF: TArchiveDatabase__sub_1958B00+230j - mov eax, [edi+TStruct40.HashValue] - mov ebx, [esi+TFileNameDatabase.Struct68_D0.ItemIsPresent.ItemArray] - mov ecx, eax - and ecx, 1Fh - mov edx, 1 - shl edx, cl - mov ecx, eax - shr ecx, 5 - test [ebx+ecx*4], edx - jz loc_1958CFB - mov ecx, [ebp+var_4] - cmp ecx, 0FFFFFFFFh - jnz short loc_1958C5E - push eax - lea ecx, [esi+TFileNameDatabase.Struct68_D0] - call TSparseArray__GetItemValue - mov ecx, eax - mov [ebp+var_4], eax - jmp short loc_1958C62 -; --------------------------------------------------------------------------- - -loc_1958C5E: ; CODE XREF: TArchiveDatabase__sub_1958B00+149j - inc ecx - mov [ebp+var_4], ecx - -loc_1958C62: ; CODE XREF: TArchiveDatabase__sub_1958B00+15Cj - mov edx, [edi+TStruct40.CharIndex] - mov [ebp+var_C], edx - mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry] - mov eax, edx - imul eax, ecx - mov ecx, eax - and eax, 1Fh - add edx, eax - shr ecx, 5 - cmp edx, 20h - mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.ItemArray] - ja short loc_1958C91 - mov edx, [edx+ecx*4] - mov ecx, eax - shr edx, cl - jmp short loc_1958CA8 -; --------------------------------------------------------------------------- - -loc_1958C91: ; CODE XREF: TArchiveDatabase__sub_1958B00+186j - lea ebx, [edx+ecx*4] - mov edx, [ebx+4] - mov ebx, [ebx] - mov ecx, 20h - sub ecx, eax - shl edx, cl - mov ecx, eax - shr ebx, cl - or edx, ebx - -loc_1958CA8: ; CODE XREF: TArchiveDatabase__sub_1958B00+18Fj - mov ecx, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] - and edx, [esi+TFileNameDatabase.FrgmDist_HiBits.EntryBitMask] - mov eax, [edi+TStruct40.HashValue] - movzx eax, byte ptr [ecx+eax] - mov ecx, [esi+TFileNameDatabase.NextDB.pDatabase] - shl edx, 8 - or eax, edx - push eax - test ecx, ecx - jz short loc_1958CD6 - mov edx, [ebp+pStruct1C] - push edx - call sub_1959010 - jmp short loc_1958CE5 -; --------------------------------------------------------------------------- - -loc_1958CD6: ; CODE XREF: TArchiveDatabase__sub_1958B00+1C9j - mov eax, [ebp+pStruct1C] - push eax - lea ecx, [esi+TFileNameDatabase.IndexStruct_174] - call TNameIndexStruct__CheckAndCopyNameFragment - -loc_1958CE5: ; CODE XREF: TArchiveDatabase__sub_1958B00+1D4j - test al, al - jnz loc_1958BDA - mov ecx, [ebp+var_C] - cmp [edi+TStruct40.CharIndex], ecx - jnz loc_1958B7D - jmp short loc_1958D11 -; --------------------------------------------------------------------------- - -loc_1958CFB: ; CODE XREF: TArchiveDatabase__sub_1958B00+13Dj - mov edx, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] - mov ebx, [ebp+pStruct1C] - mov ecx, [edi+TStruct40.CharIndex] - mov ebx, [ebx+TMndxFindResult.szSearchMask] - mov dl, [eax+edx] - cmp dl, [ecx+ebx] - jz short loc_1958D41 - -loc_1958D11: ; CODE XREF: TArchiveDatabase__sub_1958B00+1F9j - mov eax, [ebp+ItemArrayOffset] - inc [edi+TStruct40.HashValue] - inc eax - mov ecx, eax - and ecx, 1Fh - mov edx, 1 - shl edx, cl - mov ecx, [esi+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray] - mov [ebp+ItemArrayOffset], eax - shr eax, 5 - test [ecx+eax*4], edx - jnz loc_1958C20 - pop edi - pop esi - xor al, al - pop ebx - mov esp, ebp - pop ebp - retn 4 -; --------------------------------------------------------------------------- - -loc_1958D41: ; CODE XREF: TArchiveDatabase__sub_1958B00+20Fj - mov edx, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] - mov cl, [edx+eax] - lea edx, [ebp+pStruct1C+3] - mov byte ptr [ebp+pStruct1C+3], cl - push edx - mov ecx, edi - call sub_19582E0 - mov eax, 1 - add [edi+TStruct40.CharIndex], eax - pop edi - pop esi - pop ebx - mov esp, ebp - pop ebp - retn 4 -TFileNameDatabase__sub_1958B00 endp - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -TFileNameDatabase__sub_1959460 proc near ; CODE XREF: TFileNameDatabasePtr__sub_1956CE0+2Dp - -Struct14 = dword ptr -20h -var_1C = dword ptr -1Ch -var_18 = dword ptr -18h -var_14 = dword ptr -14h -var_10 = dword ptr -10h -pStruct14 = dword ptr -0Ch -pThis = dword ptr -8 -OneChar = byte ptr -1 -pStruct1C = dword ptr 8 - - push ebp - mov ebp, esp - sub esp, 20h - push ebx - push esi - push edi - mov edi, [ebp+pStruct1C] - mov esi, [edi+TMndxFindResult.pStruct40] - mov eax, [esi+TStruct40.SearchPhase] - mov ebx, ecx - mov [ebp+pThis], ebx - cmp eax, 4 - jz return_false - cmp eax, 2 - jz loc_1959530 - mov ecx, esi - call TStruct40__InitSearchBuffers - mov eax, [esi+TStruct40.CharIndex] - cmp eax, [edi+TMndxFindResult.cchSearchMask] - jnb short loc_19594B0 - -loc_1959498: ; CODE XREF: TFileNameDatabase__sub_1959460+4Ej - push edi - mov ecx, ebx - call TFileNameDatabase__sub_1958B00 - test al, al - jz loc_1959778 - mov ecx, [esi+TStruct40.CharIndex] - cmp ecx, [edi+TMndxFindResult.cchSearchMask] - jb short loc_1959498 - -loc_19594B0: ; CODE XREF: TFileNameDatabase__sub_1959460+36j - mov edx, [esi+TStruct40.HashValue] - or eax, 0FFFFFFFFh - mov [ebp+Struct14], edx - mov [ebp+var_14], eax - mov [ebp+var_10], eax - mov eax, [esi+TStruct40.array_00.ItemCount] - lea edx, [ebp+Struct14] - lea ecx, [esi+TStruct40.array_18] - push edx - mov [ebp+var_1C], 0 - mov [ebp+var_18], eax - call TGenericArray__InsertItem_STRUCT14 - mov ecx, [esi+TStruct40.HashValue] - mov eax, ecx - and ecx, 1Fh - mov edi, 1 - shl edi, cl - mov [esi+TStruct40.ItemCount], 1 - mov edx, [ebx+TFileNameDatabase.FileNameIndexes.ItemIsPresent.ItemArray] - shr eax, 5 - test [edx+eax*4], edi - jz short loc_1959530 - mov ecx, [esi+TStruct40.array_00.field_4] - mov eax, [esi+TStruct40.array_00.ItemCount] - mov edi, [ebp+pStruct1C] - mov [edi+TMndxFindResult.szFoundPath], ecx - mov [edi+TMndxFindResult.cchFoundPath], eax - mov esi, [esi+TStruct40.HashValue] - push esi - lea ecx, [ebx+TFileNameDatabase.FileNameIndexes] - call TSparseArray__GetItemValue - mov [edi+TMndxFindResult.FileNameIndex], eax - pop edi - pop esi - mov al, 1 - pop ebx - mov esp, ebp - pop ebp - retn 4 -; --------------------------------------------------------------------------- - -loc_1959522: ; CODE XREF: TFileNameDatabase__sub_1959460+26Bj - ; TFileNameDatabase__sub_1959460+2D9j ... - mov ebx, [ebp+pThis] - jmp short loc_1959530 -; --------------------------------------------------------------------------- - align 10h - -loc_1959530: ; CODE XREF: TFileNameDatabase__sub_1959460+23j - ; TFileNameDatabase__sub_1959460+97j ... - mov edx, [esi+TStruct40.ItemCount] - cmp edx, [esi+TStruct40.array_18.ItemCount] - jnz loc_19595BD - mov eax, [esi+TStruct40.array_18.ItemCount] - mov ecx, [esi+TStruct40.array_18.field_4] - lea eax, [eax+eax*4] - lea eax, [ecx+eax*4-14h] - mov [ebp+pStruct14], eax - mov eax, [eax+TStruct14.HashValue] - push eax - mov ecx, ebx - call TFileNameDatabase__sub_1959CB0 - mov edx, [ebp+pStruct14] - mov ecx, [esi+TStruct40.array_18.ItemCount] - inc eax - mov ebx, eax - sub ebx, [edx+TStruct14.HashValue] - mov edx, [esi+TStruct40.array_18.MaxItemCount] - inc ecx - dec ebx - mov [ebp+var_1C], eax - cmp ecx, edx - jbe short loc_1959591 - mov eax, ecx - shr ecx, 1 - cmp edx, ecx - jbe short loc_1959585 - mov eax, 0CCCCCCCh - cmp edx, 6666666h - ja short loc_1959585 - lea eax, [edx+edx] - -loc_1959585: ; CODE XREF: TFileNameDatabase__sub_1959460+113j - ; TFileNameDatabase__sub_1959460+120j - push eax - lea ecx, [esi+TStruct40.array_18] - call TGenericArray__SetMaxItems_STRUCT14 - mov eax, [ebp+var_1C] - -loc_1959591: ; CODE XREF: TFileNameDatabase__sub_1959460+10Bj - mov ecx, [esi+TStruct40.array_18.ItemCount] - mov edx, [esi+TStruct40.array_18.field_4] - lea ecx, [ecx+ecx*4] - lea ecx, [edx+ecx*4] - test ecx, ecx - jz short loc_19595B7 - mov [ecx+TStruct14.HashValue], ebx - mov [ecx+TStruct14.field_4], eax - xor eax, eax - mov [ecx+TStruct14.field_8], eax - or eax, 0FFFFFFFFh - mov [ecx+TStruct14.field_C], eax - or eax, 0FFFFFFFFh - mov [ecx+TStruct14.field_10], eax - -loc_19595B7: ; CODE XREF: TFileNameDatabase__sub_1959460+13Fj - inc [esi+TStruct40.array_18.ItemCount] - mov ebx, [ebp+pThis] - -loc_19595BD: ; CODE XREF: TFileNameDatabase__sub_1959460+D6j - mov eax, [esi+TStruct40.ItemCount] - mov ecx, [esi+TStruct40.array_18.field_4] - mov ebx, [ebx+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray] - lea eax, [eax+eax*4] - lea edi, [ecx+eax*4] - mov eax, [edi+TStruct14.field_4] - mov ecx, eax - and ecx, 1Fh - mov edx, 1 - shl edx, cl - mov ecx, eax - shr ecx, 5 - test [ebx+ecx*4], edx - setnz cl - inc eax - mov [edi+TStruct14.field_4], eax - test cl, cl - jz loc_19596E9 - inc [esi+TStruct40.ItemCount] - mov ecx, [edi+TStruct14.HashValue] - mov eax, [ebp+pThis] - mov eax, [eax+TFileNameDatabase.Struct68_D0.ItemIsPresent.ItemArray] - mov edx, ecx - and ecx, 1Fh - mov ebx, 1 - shl ebx, cl - shr edx, 5 - test [eax+edx*4], ebx - mov ebx, [ebp+pThis] - jz short loc_1959665 - mov eax, [edi+TStruct14.field_C] - cmp eax, 0FFFFFFFFh - jnz short loc_195962F - mov eax, [edi+TStruct14.HashValue] - push eax - lea ecx, [ebx+TFileNameDatabase.Struct68_D0] - call TSparseArray__GetItemValue - jmp short loc_1959630 -; --------------------------------------------------------------------------- - -loc_195962F: ; CODE XREF: TFileNameDatabase__sub_1959460+1BDj - inc eax - -loc_1959630: ; CODE XREF: TFileNameDatabase__sub_1959460+1CDj - mov ecx, [edi+TStruct14.HashValue] - push eax - push ecx - mov ecx, ebx - mov [edi+TStruct14.field_C], eax - call sub_19573D0 - mov ecx, [ebx+TFileNameDatabase.NextDB.pDatabase] - push eax - test ecx, ecx - jz short loc_1959654 - mov edx, [ebp+pStruct1C] - push edx - call sub_1958D70 - jmp short loc_19596AE -; --------------------------------------------------------------------------- - -loc_1959654: ; CODE XREF: TFileNameDatabase__sub_1959460+1E7j - mov eax, [ebp+pStruct1C] - push eax - lea ecx, [ebx+TFileNameDatabase.IndexStruct_174] - call CopyNameFragment - jmp short loc_19596AE -; --------------------------------------------------------------------------- - -loc_1959665: ; CODE XREF: TFileNameDatabase__sub_1959460+1B5j - mov ecx, [ebx+TFileNameDatabase.FrgmDist_LoBits.ItemArray] - mov eax, [edi+TStruct14.HashValue] - mov dl, [eax+ecx] - mov eax, [esi+TStruct40.array_00.ItemCount] - mov ecx, [esi+TStruct40.array_00.MaxItemCount] - inc eax - mov [ebp+OneChar], dl - cmp eax, ecx - jbe short loc_195969E - mov edx, eax - shr eax, 1 - cmp ecx, eax - jbe short loc_1959696 - cmp ecx, 7FFFFFFFh - jbe short loc_1959693 - or edx, 0FFFFFFFFh - jmp short loc_1959696 -; --------------------------------------------------------------------------- - -loc_1959693: ; CODE XREF: TFileNameDatabase__sub_1959460+22Cj - lea edx, [ecx+ecx] - -loc_1959696: ; CODE XREF: TFileNameDatabase__sub_1959460+224j - ; TFileNameDatabase__sub_1959460+231j - push edx - mov ecx, esi - call TGenericArray__SetMaxItems_BYTE - -loc_195969E: ; CODE XREF: TFileNameDatabase__sub_1959460+21Cj - mov eax, [esi+TStruct40.array_00.field_4] - add eax, [esi+TStruct40.array_00.ItemCount] - jz short loc_19596AB - mov cl, [ebp+OneChar] - mov [eax], cl - -loc_19596AB: ; CODE XREF: TFileNameDatabase__sub_1959460+244j - inc [esi+TStruct40.array_00.ItemCount] - -loc_19596AE: ; CODE XREF: TFileNameDatabase__sub_1959460+1F2j - ; TFileNameDatabase__sub_1959460+203j - mov edx, [esi+TStruct40.array_00.ItemCount] - mov ecx, [edi+TStruct14.HashValue] - mov [edi+TStruct14.field_8], edx - mov edx, [ebx+TFileNameDatabase.FileNameIndexes.ItemIsPresent.ItemArray] - mov eax, ecx - and ecx, 1Fh - mov ebx, 1 - shl ebx, cl - shr eax, 5 - test [edx+eax*4], ebx - jz loc_1959522 - mov eax, [edi+TStruct14.field_10] - cmp eax, 0FFFFFFFFh - jnz short loc_1959754 - mov eax, [edi+TStruct14.HashValue] - mov ecx, [ebp+pThis] - push eax - add ecx, TFileNameDatabase.FileNameIndexes - call TSparseArray__GetItemValue - jmp short loc_1959755 -; --------------------------------------------------------------------------- - -loc_19596E9: ; CODE XREF: TFileNameDatabase__sub_1959460+18Cj - mov eax, [esi+TStruct40.ItemCount] - cmp eax, 1 - jz loc_1959778 - mov ecx, [esi+TStruct40.array_18.field_4] - lea eax, [eax+eax*4] - inc dword ptr [ecx+eax*4-14h] - lea eax, [ecx+eax*4-14h] - mov eax, [esi+TStruct40.ItemCount] - lea edx, [eax+eax*4] - mov eax, [esi+TStruct40.array_18.field_4] - mov edi, [eax+edx*4-20h] - mov eax, [esi+TStruct40.array_00.MaxItemCount] - cmp edi, eax - jbe short loc_1959749 - mov edx, edi - shr edx, 1 - mov ecx, edi - cmp eax, edx - jbe short loc_1959741 - cmp eax, 7FFFFFFFh - jbe short loc_195973E - or ecx, 0FFFFFFFFh - push ecx - mov ecx, esi - call TGenericArray__SetMaxItems_BYTE - dec [esi+TStruct40.ItemCount] - mov [esi+TStruct40.array_00.ItemCount], edi - jmp loc_1959522 -; --------------------------------------------------------------------------- - -loc_195973E: ; CODE XREF: TFileNameDatabase__sub_1959460+2C6j - lea ecx, [eax+eax] - -loc_1959741: ; CODE XREF: TFileNameDatabase__sub_1959460+2BFj - push ecx - mov ecx, esi - call TGenericArray__SetMaxItems_BYTE - -loc_1959749: ; CODE XREF: TFileNameDatabase__sub_1959460+2B5j - dec [esi+TStruct40.ItemCount] - mov [esi+TStruct40.array_00.ItemCount], edi - jmp loc_1959522 -; --------------------------------------------------------------------------- - -loc_1959754: ; CODE XREF: TFileNameDatabase__sub_1959460+277j - inc eax - -loc_1959755: ; CODE XREF: TFileNameDatabase__sub_1959460+287j - mov [edi+TStruct14.field_10], eax - mov ecx, [esi+TStruct40.array_00.ItemCount] - mov edx, [esi+TStruct40.array_00.field_4] - mov eax, [ebp+pStruct1C] - mov [eax+TMndxFindResult.szFoundPath], edx - mov [eax+TMndxFindResult.cchFoundPath], ecx - mov ecx, [edi+TStruct14.field_10] - pop edi - pop esi - mov [eax+TMndxFindResult.FileNameIndex], ecx - mov al, 1 - pop ebx - mov esp, ebp - pop ebp - retn 4 -; --------------------------------------------------------------------------- - -loc_1959778: ; CODE XREF: TFileNameDatabase__sub_1959460+42j - ; TFileNameDatabase__sub_1959460+28Fj - mov [esi+TStruct40.SearchPhase], 4 - -return_false: ; CODE XREF: TFileNameDatabase__sub_1959460+1Aj - pop edi - pop esi - xor al, al - pop ebx - mov esp, ebp - pop ebp - retn 4 -TFileNameDatabase__sub_1959460 endp - -; --------------------------------------------------------------------------- - -;------------------------------------------------------------------------------ -; Public functions callable from C++ - -; -; DWORD _cdecl sub_19573D0_x86(TFileNameDatabase * pDB, DWORD arg_0, DWORD arg_4); -; - -_sub_19573D0_x86 PROC - - push ebp - mov ebp, esp - mov ecx, [ebp+8] ; pDB - push [ebp+10h] ; arg_4 - push [ebp+0Ch] ; arg_0 - call sub_19573D0 - mov esp, ebp - pop ebp - ret - -_sub_19573D0_x86 ENDP - -; -; DWORD _cdecl sub_1957EF0_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C); -; - -_sub_1957EF0_x86 PROC - - push ebp - mov ebp, esp - mov ecx, [ebp+8] ; pDB - push [ebp+0Ch] ; pStruct1C - call TFileNameDatabase__FindFileInDatabase - mov esp, ebp - pop ebp - ret - -_sub_1957EF0_x86 ENDP - -; -; bool _cdecl _sub_1959460_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C); -; - -_sub_1959460_x86 PROC - - push ebp - mov ebp, esp - mov ecx, [ebp+8] ; pDB - push [ebp+0Ch] ; pStruct1C - call TFileNameDatabase__sub_1959460 - mov esp, ebp - pop ebp - ret - -_sub_1959460_x86 ENDP - -; -; bool _cdecl sub_1958B00_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C); -; - -_sub_1958B00_x86 PROC - - push ebp - mov ebp, esp - mov ecx, [ebp+8] ; pDB - push [ebp+0Ch] ; pStruct1C - call TFileNameDatabase__sub_1959460 - mov esp, ebp - pop ebp - ret - -_sub_1958B00_x86 ENDP - -; -; DWORD _cdecl GetItemValue_x86(TSparseArray * pStruct, DWORD dwKey); -; - -_GetItemValue_x86 PROC - - push ebp - mov ebp, esp - mov ecx, [ebp+8] ; pStruct68 - push [ebp+0Ch] ; dwKey - call TSparseArray__GetItemValue - mov esp, ebp - pop ebp - ret - -_GetItemValue_x86 ENDP - -; -; DWORD _cdecl sub_1959CB0_x86(TFileNameDatabase * pDB, DWORD dwKey); -; - -_sub_1959CB0_x86 PROC - - push ebp - mov ebp, esp - mov ecx, [ebp+8] ; pDB - push [ebp+0Ch] ; dwKey - call TArchiveDatabase__sub_1959CB0 - mov esp, ebp - pop ebp - ret - -_sub_1959CB0_x86 ENDP - -; -; DWORD _cdecl sub_1959F50_x86(TFileNameDatabase * pDB, DWORD arg_0); -; - -_sub_1959F50_x86 PROC - - push ebp - mov ebp, esp - mov ecx, [ebp+8] ; pDB - push [ebp+0Ch] ; dwKey - call sub_1959F50 - mov esp, ebp - pop ebp - ret - -_sub_1959F50_x86 ENDP - -END diff --git a/dep/CascLib/src/CascOpenFile.cpp b/dep/CascLib/src/CascOpenFile.cpp index 2b8c3d3c4ad..c4c27a3f6a6 100644 --- a/dep/CascLib/src/CascOpenFile.cpp +++ b/dep/CascLib/src/CascOpenFile.cpp @@ -11,10 +11,6 @@ #define __CASCLIB_SELF__ #include "CascLib.h" #include "CascCommon.h" -#include "CascMndxRoot.h" - -//----------------------------------------------------------------------------- -// Local structures //----------------------------------------------------------------------------- // Local functions @@ -31,79 +27,19 @@ PCASC_INDEX_ENTRY FindIndexEntry(TCascStorage * hs, PQUERY_KEY pIndexKey) PCASC_INDEX_ENTRY pIndexEntry = NULL; if(hs->pIndexEntryMap != NULL) - pIndexEntry = (PCASC_INDEX_ENTRY)Map_FindObject(hs->pIndexEntryMap, pIndexKey->pbData); + pIndexEntry = (PCASC_INDEX_ENTRY)Map_FindObject(hs->pIndexEntryMap, pIndexKey->pbData, NULL); return pIndexEntry; } -PCASC_ENCODING_ENTRY FindEncodingEntry(TCascStorage * hs, PQUERY_KEY pEncodingKey, size_t * PtrIndex) +PCASC_ENCODING_ENTRY FindEncodingEntry(TCascStorage * hs, PQUERY_KEY pEncodingKey, PDWORD PtrIndex) { - PCASC_ENCODING_ENTRY pEncodingEntry; - size_t StartEntry = 0; - size_t MidlEntry; - size_t EndEntry = hs->nEncodingEntries; - int nResult; - - // Perform binary search - while(StartEntry < EndEntry) - { - // Calculate the middle of the interval - MidlEntry = StartEntry + ((EndEntry - StartEntry) / 2); - pEncodingEntry = hs->ppEncodingEntries[MidlEntry]; - - // Did we find it? - nResult = memcmp(pEncodingKey->pbData, pEncodingEntry->EncodingKey, MD5_HASH_SIZE); - if(nResult == 0) - { - if(PtrIndex != NULL) - PtrIndex[0] = MidlEntry; - return pEncodingEntry; - } - - // Move the interval to the left or right - (nResult < 0) ? EndEntry = MidlEntry : StartEntry = MidlEntry + 1; - } - - // Not found, sorry - return NULL; -} - -// Also used in CascSearchFile -PCASC_ROOT_ENTRY FindRootEntry(TCascStorage * hs, const char * szFileName, DWORD * PtrTableIndex) -{ - PCASC_ROOT_ENTRY pRootEntry; - ULONGLONG FileNameHash; - DWORD TableIndex; - uint32_t dwHashHigh = 0; - uint32_t dwHashLow = 0; - - // Calculate the HASH value of the normalized file name - hashlittle2(szFileName, strlen(szFileName), &dwHashHigh, &dwHashLow); - FileNameHash = ((ULONGLONG)dwHashHigh << 0x20) | dwHashLow; - - // Get the first table index - TableIndex = (DWORD)(FileNameHash & (hs->RootTable.TableSize - 1)); - assert(hs->RootTable.ItemCount < hs->RootTable.TableSize); - - // Search the proper entry - for(;;) - { - // Does the has match? - pRootEntry = hs->RootTable.TablePtr + TableIndex; - if(pRootEntry->FileNameHash == FileNameHash) - { - if(PtrTableIndex != NULL) - PtrTableIndex[0] = TableIndex; - return pRootEntry; - } + PCASC_ENCODING_ENTRY pEncodingEntry = NULL; - // If the entry is free, the file is not there - if(pRootEntry->FileNameHash == 0 && pRootEntry->SumValue == 0) - return NULL; + if(hs->pEncodingMap != NULL) + pEncodingEntry = (PCASC_ENCODING_ENTRY)Map_FindObject(hs->pEncodingMap, pEncodingKey->pbData, PtrIndex); - // Move to the next entry - TableIndex = (DWORD)((TableIndex + 1) & (hs->RootTable.TableSize - 1)); - } + return pEncodingEntry; } static TCascFile * CreateFileHandle(TCascStorage * hs, PCASC_INDEX_ENTRY pIndexEntry) @@ -187,7 +123,7 @@ static bool OpenFileByEncodingKey(TCascStorage * hs, PQUERY_KEY pEncodingKey, DW // Prepare the file index and open the file by index // Note: We don't know what to do if there is more than just one index key // We always take the first file present. Is that correct? - IndexKey.pbData = pEncodingEntry->EncodingKey + MD5_HASH_SIZE; + IndexKey.pbData = GET_INDEX_KEY(pEncodingEntry); IndexKey.cbData = MD5_HASH_SIZE; if(OpenFileByIndexKey(hs, &IndexKey, dwFlags, ppCascFile)) { @@ -259,13 +195,10 @@ bool WINAPI CascOpenFileByEncodingKey(HANDLE hStorage, PQUERY_KEY pEncodingKey, bool WINAPI CascOpenFile(HANDLE hStorage, const char * szFileName, DWORD dwLocale, DWORD dwFlags, HANDLE * phFile) { - PCASC_ROOT_ENTRY_MNDX pRootEntryMndx = NULL; - PCASC_ROOT_ENTRY pRootEntry; - PCASC_PACKAGE pPackage; TCascStorage * hs; QUERY_KEY EncodingKey; - char * szStrippedName; - char szFileName2[MAX_PATH+1]; + LPBYTE pbEncodingKey; + BYTE KeyBuffer[MD5_HASH_SIZE]; int nError = ERROR_SUCCESS; CASCLIB_UNUSED(dwLocale); @@ -285,55 +218,37 @@ bool WINAPI CascOpenFile(HANDLE hStorage, const char * szFileName, DWORD dwLocal return false; } - // If the storage has a MNDX root directory, use it to search the entry - if(hs->pMndxInfo != NULL) + // If the user is opening the file via encoding key, skip the ROOT file processing + if((dwFlags & CASC_OPEN_BY_ENCODING_KEY) == 0) { - // Convert the file name to lowercase + slashes - NormalizeFileName_LowerSlash(szFileName2, szFileName, MAX_PATH); - - // Find the package number - pPackage = FindMndxPackage(hs, szFileName2); - if(pPackage != NULL) + // Let the root directory provider get us the encoding key + pbEncodingKey = RootHandler_GetKey(hs->pRootHandler, szFileName); + if(pbEncodingKey == NULL) { - // Cut the package name off the full path - szStrippedName = szFileName2 + pPackage->nLength; - while(szStrippedName[0] == '/') - szStrippedName++; - - nError = SearchMndxInfo(hs->pMndxInfo, szStrippedName, (DWORD)(pPackage - hs->pPackages->Packages), &pRootEntryMndx); - if(nError == ERROR_SUCCESS) - { - // Prepare the encoding key - EncodingKey.pbData = pRootEntryMndx->EncodingKey; - EncodingKey.cbData = MD5_HASH_SIZE; - } - } - else - { - nError = ERROR_FILE_NOT_FOUND; + SetLastError(ERROR_FILE_NOT_FOUND); + return false; } + + // Setup the encoding key + EncodingKey.pbData = pbEncodingKey; + EncodingKey.cbData = MD5_HASH_SIZE; } else { - // Convert the file name to lowercase + slashes - NormalizeFileName_UpperBkSlash(szFileName2, szFileName, MAX_PATH); - - // Check the root directory for that hash - pRootEntry = FindRootEntry(hs, szFileName2, NULL); - if(pRootEntry != NULL) - { - // Prepare the root key - EncodingKey.pbData = (LPBYTE)pRootEntry->EncodingKey; - EncodingKey.cbData = MD5_HASH_SIZE; - nError = ERROR_SUCCESS; - } - else + // Check the length of the file name + if(strlen(szFileName) < MD5_STRING_SIZE) { - nError = ERROR_FILE_NOT_FOUND; + SetLastError(ERROR_INVALID_PARAMETER); + return false; } + + // Convert the file name to binary blob + EncodingKey.pbData = KeyBuffer; + EncodingKey.cbData = MD5_HASH_SIZE; + nError = ConvertStringToBinary(szFileName, MD5_STRING_SIZE, KeyBuffer); } - // Use the root key to find the file in the encoding table entry + // Use the encoding key to find the file in the encoding table entry if(nError == ERROR_SUCCESS) { if(!OpenFileByEncodingKey(hs, &EncodingKey, dwFlags, (TCascFile **)phFile)) @@ -344,10 +259,10 @@ bool WINAPI CascOpenFile(HANDLE hStorage, const char * szFileName, DWORD dwLocal } #ifdef CASCLIB_TEST - if(phFile[0] != NULL && pRootEntryMndx != NULL) - { - ((TCascFile *)(phFile[0]))->FileSize_RootEntry = pRootEntryMndx->FileSize; - } +// if(phFile[0] != NULL && pRootEntryMndx != NULL) +// { +// ((TCascFile *)(phFile[0]))->FileSize_RootEntry = pRootEntryMndx->FileSize; +// } #endif if(nError != ERROR_SUCCESS) diff --git a/dep/CascLib/src/CascOpenStorage.cpp b/dep/CascLib/src/CascOpenStorage.cpp index 6a8d83ee903..c3d623df9f0 100644 --- a/dep/CascLib/src/CascOpenStorage.cpp +++ b/dep/CascLib/src/CascOpenStorage.cpp @@ -13,19 +13,12 @@ #define __CASCLIB_SELF__ #include "CascLib.h" #include "CascCommon.h" -#include "CascMndxRoot.h" - -//----------------------------------------------------------------------------- -// Dumping options - -#ifdef _DEBUG -#define CASC_DUMP_ROOT_FILE 2 // The root file will be dumped (level 2) -#endif //----------------------------------------------------------------------------- // Local structures -#define CASC_INITIAL_ROOT_TABLE_SIZE 0x00100000 +// Size of one segment in the ENCODING table +// The segment is filled by entries of type #define CASC_ENCODING_SEGMENT_SIZE 0x1000 typedef struct _BLOCK_SIZE_AND_HASH @@ -67,25 +60,10 @@ typedef struct _FILE_INDEX_HEADER_V2 } FILE_INDEX_HEADER_V2, *PFILE_INDEX_HEADER_V2; -typedef struct _FILE_ENCODING_HEADER -{ - BYTE Magic[2]; // "EN" - BYTE field_2; - BYTE field_3; - BYTE field_4; - BYTE field_5[2]; - BYTE field_7[2]; - BYTE NumSegments[4]; // Number of entries (big endian) - BYTE field_D[4]; - BYTE field_11; - BYTE SegmentsPos[4]; // Offset of encoding segments - -} FILE_ENCODING_HEADER, *PFILE_ENCODING_HEADER; - typedef struct _FILE_ENCODING_SEGMENT { - BYTE FirstEncodingKey[MD5_HASH_SIZE]; // The first encoding key in the segment - BYTE SegmentHash[MD5_HASH_SIZE]; // MD5 hash of the entire segment + BYTE FirstEncodingKey[MD5_HASH_SIZE]; // The first encoding key in the segment + BYTE SegmentHash[MD5_HASH_SIZE]; // MD5 hash of the entire segment } FILE_ENCODING_SEGMENT, *PFILE_ENCODING_SEGMENT; @@ -143,28 +121,6 @@ static bool IsIndexFileName_V2(const TCHAR * szFileName) _tcsicmp(szFileName + 0x0A, _T(".idx")) == 0); } -static void QUERY_KEY_Free(PQUERY_KEY pBlob) -{ - if(pBlob != NULL) - { - if(pBlob->pbData != NULL) - CASC_FREE(pBlob->pbData); - - pBlob->pbData = NULL; - pBlob->cbData = 0; - } -} - -static void QUERY_KEY_FreeArray(PQUERY_KEY pBlobArray) -{ - // Free the buffer in the first blob - // (will also free all buffers in the array) - QUERY_KEY_Free(pBlobArray); - - // Free the array itself - CASC_FREE(pBlobArray); -} - static bool IsCascIndexHeader_V1(LPBYTE pbFileData, DWORD cbFileData) { PFILE_INDEX_HEADER_V1 pIndexHeader = (PFILE_INDEX_HEADER_V1)pbFileData; @@ -206,52 +162,99 @@ static bool IsCascIndexHeader_V2(LPBYTE pbFileData, DWORD cbFileData) return (HashHigh == pSizeAndHash->dwBlockHash); } -LPBYTE VerifyLocaleBlock(PROOT_BLOCK_INFO pBlockInfo, LPBYTE pbFilePointer, LPBYTE pbFileEnd) +static bool CutLastPathPart(TCHAR * szWorkPath) { - // Validate the file locale block - pBlockInfo->pLocaleBlockHdr = (PFILE_LOCALE_BLOCK)pbFilePointer; - pbFilePointer = (LPBYTE)(pBlockInfo->pLocaleBlockHdr + 1); - if(pbFilePointer > pbFileEnd) - return NULL; - - // Validate the array of 32-bit integers - pBlockInfo->pInt32Array = (PDWORD)pbFilePointer; - pbFilePointer = (LPBYTE)(pBlockInfo->pInt32Array + pBlockInfo->pLocaleBlockHdr->NumberOfFiles); - if(pbFilePointer > pbFileEnd) - return NULL; - - // Validate the array of root entries - pBlockInfo->pRootEntries = (PFILE_ROOT_ENTRY)pbFilePointer; - pbFilePointer = (LPBYTE)(pBlockInfo->pRootEntries + pBlockInfo->pLocaleBlockHdr->NumberOfFiles); - if(pbFilePointer > pbFileEnd) - return NULL; - - // Return the position of the next block - return pbFilePointer; + size_t nLength = _tcslen(szWorkPath); + + for(nLength = _tcslen(szWorkPath); nLength > 0; nLength--) + { + if(szWorkPath[nLength] == '\\' || szWorkPath[nLength] == '/') + { + szWorkPath[nLength] = 0; + return true; + } + } + + return false; } -static int InitializeCascDirectories(TCascStorage * hs, const TCHAR * szDataPath) +static int InsertExtraFile( + TCascStorage * hs, + const char * szFileName, + PQUERY_KEY pQueryKey) { - TCHAR * szLastPathPart; + // If the given key is not encoding key (aka, it's an index key), + // we need to create a fake encoding entry + if(pQueryKey->cbData == MD5_HASH_SIZE * 2) + { + PCASC_ENCODING_ENTRY pNewEntry; + PCASC_INDEX_ENTRY pIndexEntry; + QUERY_KEY IndexKey; + + // Find the entry in the index table in order to get the file size + IndexKey.pbData = pQueryKey->pbData + MD5_HASH_SIZE; + IndexKey.cbData = MD5_HASH_SIZE; + pIndexEntry = FindIndexEntry(hs, &IndexKey); + if(pIndexEntry == NULL) + return ERROR_FILE_NOT_FOUND; + + // Create a fake entry in the encoding map + pNewEntry = (PCASC_ENCODING_ENTRY)Array_Insert(&hs->ExtraEntries, NULL, 1); + if(pNewEntry == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill the encoding entry + pNewEntry->KeyCount = 1; + pNewEntry->FileSizeBE[0] = pIndexEntry->FileSizeLE[3]; + pNewEntry->FileSizeBE[1] = pIndexEntry->FileSizeLE[2]; + pNewEntry->FileSizeBE[2] = pIndexEntry->FileSizeLE[1]; + pNewEntry->FileSizeBE[3] = pIndexEntry->FileSizeLE[0]; + memcpy(pNewEntry->EncodingKey, pQueryKey->pbData, MD5_HASH_SIZE); + memcpy(pNewEntry + 1, pQueryKey->pbData + MD5_HASH_SIZE, MD5_HASH_SIZE); + + // Insert the entry to the map of encoding keys + Map_InsertObject(hs->pEncodingMap, pNewEntry, pNewEntry->EncodingKey); + } - // Save the game data directory - hs->szDataPath = NewStr(szDataPath, 0); - - // Save the root game directory - hs->szRootPath = NewStr(szDataPath, 0); + // Now we need to insert the entry to the root handler in order + // to be able to translate file name to encoding key + return RootHandler_Insert(hs->pRootHandler, szFileName, pQueryKey->pbData); +} + +static int InitializeCascDirectories(TCascStorage * hs, const TCHAR * szDataPath) +{ + TCHAR * szWorkPath; + int nError = ERROR_NOT_ENOUGH_MEMORY; - // Find the last part - szLastPathPart = hs->szRootPath; - for(size_t i = 0; hs->szRootPath[i] != 0; i++) + // Find the root directory of the storage. The root directory + // is the one where ".build.info" is. + szWorkPath = CascNewStr(szDataPath, 0); + if(szWorkPath != NULL) { - if(hs->szRootPath[i] == '\\' || hs->szRootPath[i] == '/') - szLastPathPart = hs->szRootPath + i; - } - - // Cut the last part - if(szLastPathPart != NULL) - szLastPathPart[0] = 0; - return (hs->szRootPath && hs->szDataPath) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY; + // Get the length and go up until we find the ".build.info" or ".build.db" + for(;;) + { + // Is this a game directory? + nError = CheckGameDirectory(hs, szWorkPath); + if(nError == ERROR_SUCCESS) + { + nError = ERROR_SUCCESS; + break; + } + + // Cut one path part + if(!CutLastPathPart(szWorkPath)) + { + nError = ERROR_FILE_NOT_FOUND; + break; + } + } + + // Free the work path buffer + CASC_FREE(szWorkPath); + } + + return nError; } static bool IndexDirectory_OnFileFound( @@ -566,7 +569,7 @@ static int CreateArrayOfIndexEntries(TCascStorage * hs) // 9e dc a7 8f e2 09 ad d8 b7 (encoding file) // f3 5e bb fb d1 2b 3f ef 8b // c8 69 9f 18 a2 5e df 7e 52 - Map_InsertObject(pMap, pIndexEntry->IndexKey); + Map_InsertObject(pMap, pIndexEntry, pIndexEntry->IndexKey); // Move to the next entry pIndexEntry++; @@ -581,28 +584,28 @@ static int CreateArrayOfIndexEntries(TCascStorage * hs) return nError; } -static int CreateMapOfEncodingKeys(TCascStorage * hs, PFILE_ENCODING_SEGMENT pEncodingSegment, DWORD dwNumberOfSegments) +static int CreateMapOfEncodingKeys(TCascStorage * hs, PFILE_ENCODING_SEGMENT pEncodingSegment, DWORD dwNumSegments) { PCASC_ENCODING_ENTRY pEncodingEntry; - size_t nMaxEntries; - size_t nEntries = 0; + DWORD dwMaxEntries; int nError = ERROR_SUCCESS; // Sanity check - assert(hs->ppEncodingEntries == NULL); assert(hs->pIndexEntryMap != NULL); + assert(hs->pEncodingMap == NULL); - // Calculate the largest eventual number of encodign entries - nMaxEntries = (dwNumberOfSegments * CASC_ENCODING_SEGMENT_SIZE) / (sizeof(CASC_ENCODING_ENTRY) + MD5_HASH_SIZE); + // Calculate the largest eventual number of encoding entries + // Add space for extra entries + dwMaxEntries = (dwNumSegments * CASC_ENCODING_SEGMENT_SIZE) / (sizeof(CASC_ENCODING_ENTRY) + MD5_HASH_SIZE); - // Allocate the array of pointers to encoding entries - hs->ppEncodingEntries = CASC_ALLOC(PCASC_ENCODING_ENTRY, nMaxEntries); - if(hs->ppEncodingEntries != NULL) + // Create the map of the encoding entries + hs->pEncodingMap = Map_Create(dwMaxEntries + CASC_EXTRA_FILES, MD5_HASH_SIZE, FIELD_OFFSET(CASC_ENCODING_ENTRY, EncodingKey)); + if(hs->pEncodingMap != NULL) { - LPBYTE pbStartOfSegment = (LPBYTE)(pEncodingSegment + dwNumberOfSegments); + LPBYTE pbStartOfSegment = (LPBYTE)(pEncodingSegment + dwNumSegments); // Parse all segments - for(DWORD i = 0; i < dwNumberOfSegments; i++) + for(DWORD i = 0; i < dwNumSegments; i++) { LPBYTE pbEncodingEntry = pbStartOfSegment; LPBYTE pbEndOfSegment = pbStartOfSegment + CASC_ENCODING_SEGMENT_SIZE - sizeof(CASC_ENCODING_ENTRY) - MD5_HASH_SIZE; @@ -616,7 +619,7 @@ static int CreateMapOfEncodingKeys(TCascStorage * hs, PFILE_ENCODING_SEGMENT pEn break; // Insert the pointer the array - hs->ppEncodingEntries[nEntries++] = pEncodingEntry; + Map_InsertObject(hs->pEncodingMap, pEncodingEntry, pEncodingEntry->EncodingKey); // Move to the next encoding entry pbEncodingEntry += sizeof(CASC_ENCODING_ENTRY) + (pEncodingEntry->KeyCount * MD5_HASH_SIZE); @@ -625,9 +628,6 @@ static int CreateMapOfEncodingKeys(TCascStorage * hs, PFILE_ENCODING_SEGMENT pEn // Move to the next segment pbStartOfSegment += CASC_ENCODING_SEGMENT_SIZE; } - - // Remember the total number of encoding entries - hs->nEncodingEntries = nEntries; } else nError = ERROR_NOT_ENOUGH_MEMORY; @@ -684,8 +684,16 @@ static LPBYTE LoadEncodingFileToMemory(HANDLE hFile, DWORD * pcbEncodingFile) CascReadFile(hFile, &EncodingHeader, sizeof(CASC_ENCODING_HEADER), &dwBytesRead); if(dwBytesRead == sizeof(CASC_ENCODING_HEADER)) { - dwNumSegments = ConvertBytesToInteger_4(EncodingHeader.NumSegments); - dwSegmentPos = ConvertBytesToInteger_4(EncodingHeader.SegmentsPos); + // Check the version and sizes + if(EncodingHeader.Version != 0x01 || EncodingHeader.ChecksumSizeA != MD5_HASH_SIZE || EncodingHeader.ChecksumSizeB != MD5_HASH_SIZE) + { + assert(false); + return NULL; + } + + // Get the number of segments + dwNumSegments = ConvertBytesToInteger_4(EncodingHeader.Entries_TableA); + dwSegmentPos = ConvertBytesToInteger_4(EncodingHeader.Size_StringTable1); if(EncodingHeader.Magic[0] == 'E' && EncodingHeader.Magic[1] == 'N' && dwSegmentPos != 0 && dwNumSegments != 0) nError = ERROR_SUCCESS; } @@ -721,36 +729,16 @@ static LPBYTE LoadEncodingFileToMemory(HANDLE hFile, DWORD * pcbEncodingFile) static LPBYTE LoadRootFileToMemory(HANDLE hFile, DWORD * pcbRootFile) { - TCascFile * hf; LPBYTE pbRootFile = NULL; DWORD cbRootFile = 0; DWORD dwBytesRead = 0; - BYTE StartOfFile[0x10]; int nError = ERROR_SUCCESS; - // Dummy read the first 16 bytes - CascReadFile(hFile, &StartOfFile, sizeof(StartOfFile), &dwBytesRead); - if(dwBytesRead != sizeof(StartOfFile)) + // Retrieve the size of the ROOT file + cbRootFile = CascGetFileSize(hFile, NULL); + if(cbRootFile == 0) nError = ERROR_BAD_FORMAT; - // Calculate and allocate space for the entire file - if(nError == ERROR_SUCCESS) - { - // Convert the file handle to pointer to TCascFile - hf = IsValidFileHandle(hFile); - if(hf != NULL) - { - // Parse the frames to get the file size - for(DWORD i = 0; i < hf->FrameCount; i++) - { - cbRootFile += hf->pFrames[i].FrameSize; - } - } - - // Evaluate the error - nError = (cbRootFile != 0) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT; - } - // Allocate space for the entire file if(nError == ERROR_SUCCESS) { @@ -762,12 +750,9 @@ static LPBYTE LoadRootFileToMemory(HANDLE hFile, DWORD * pcbRootFile) // If all went OK, we load the entire file to memory if(nError == ERROR_SUCCESS) { - // Copy the header itself - memcpy(pbRootFile, StartOfFile, sizeof(StartOfFile)); - - // Read the rest of the data - CascReadFile(hFile, pbRootFile + sizeof(StartOfFile), cbRootFile - sizeof(StartOfFile), &dwBytesRead); - if(dwBytesRead != (cbRootFile - sizeof(StartOfFile))) + // Read the entire file to memory + CascReadFile(hFile, pbRootFile, cbRootFile, &dwBytesRead); + if(dwBytesRead != cbRootFile) nError = ERROR_FILE_CORRUPT; } @@ -780,17 +765,19 @@ static LPBYTE LoadRootFileToMemory(HANDLE hFile, DWORD * pcbRootFile) static int LoadEncodingFile(TCascStorage * hs) { PFILE_ENCODING_SEGMENT pEncodingSegment; - PCASC_ENCODING_ENTRY pEncodingEntry; + QUERY_KEY EncodingKey; LPBYTE pbStartOfSegment; LPBYTE pbEncodingFile = NULL; HANDLE hFile = NULL; DWORD cbEncodingFile = 0; - DWORD dwNumberOfSegments = 0; + DWORD dwNumSegments = 0; DWORD dwSegmentsPos = 0; int nError = ERROR_SUCCESS; // Open the encoding file - if(!CascOpenFileByIndexKey((HANDLE)hs, &hs->EncodingEKey, 0, &hFile)) + EncodingKey.pbData = hs->EncodingKey.pbData + MD5_HASH_SIZE; + EncodingKey.cbData = MD5_HASH_SIZE; + if(!CascOpenFileByIndexKey((HANDLE)hs, &EncodingKey, 0, &hFile)) nError = GetLastError(); // Load the entire ENCODING file to memory @@ -808,20 +795,25 @@ static int LoadEncodingFile(TCascStorage * hs) // Verify all encoding segments if(nError == ERROR_SUCCESS) { - // Save the encoding header - hs->pEncodingHeader = (PCASC_ENCODING_HEADER)pbEncodingFile; + PCASC_ENCODING_HEADER pEncodingHeader = (PCASC_ENCODING_HEADER)pbEncodingFile; // Convert size and offset - dwNumberOfSegments = ConvertBytesToInteger_4(hs->pEncodingHeader->NumSegments); - dwSegmentsPos = ConvertBytesToInteger_4(hs->pEncodingHeader->SegmentsPos); + dwNumSegments = ConvertBytesToInteger_4(pEncodingHeader->Entries_TableA); + dwSegmentsPos = ConvertBytesToInteger_4(pEncodingHeader->Size_StringTable1); + + // Store the encoding file to the CASC storage + hs->EncodingFile.pbData = pbEncodingFile; + hs->EncodingFile.cbData = cbEncodingFile; // Allocate the array of encoding segments pEncodingSegment = (PFILE_ENCODING_SEGMENT)(pbEncodingFile + sizeof(CASC_ENCODING_HEADER) + dwSegmentsPos); - pbStartOfSegment = (LPBYTE)(pEncodingSegment + dwNumberOfSegments); + pbStartOfSegment = (LPBYTE)(pEncodingSegment + dwNumSegments); // Go through all encoding segments and verify them - for(DWORD i = 0; i < dwNumberOfSegments; i++) + for(DWORD i = 0; i < dwNumSegments; i++) { + PCASC_ENCODING_ENTRY pEncodingEntry = (PCASC_ENCODING_ENTRY)pbStartOfSegment; + // Check if there is enough space in the buffer if((pbStartOfSegment + CASC_ENCODING_SEGMENT_SIZE) > (pbEncodingFile + cbEncodingFile)) { @@ -837,8 +829,7 @@ static int LoadEncodingFile(TCascStorage * hs) // break; // } - // Check if the encoding key matches - pEncodingEntry = (PCASC_ENCODING_ENTRY)pbStartOfSegment; + // Check if the encoding key matches with the expected first value if(memcmp(pEncodingEntry->EncodingKey, pEncodingSegment->FirstEncodingKey, MD5_HASH_SIZE)) { nError = ERROR_FILE_CORRUPT; @@ -856,239 +847,10 @@ static int LoadEncodingFile(TCascStorage * hs) if(nError == ERROR_SUCCESS) { pEncodingSegment = (PFILE_ENCODING_SEGMENT)(pbEncodingFile + sizeof(CASC_ENCODING_HEADER) + dwSegmentsPos); - nError = CreateMapOfEncodingKeys(hs, pEncodingSegment, dwNumberOfSegments); - } - return nError; -} - -typedef struct _CHECK_ROOT_ENTRY_INPUT -{ - ULONGLONG FileNameHash; - DWORD SumValue; - DWORD EncodingKey[4]; - -} CHECK_ROOT_ENTRY_INPUT, *PCHECK_ROOT_ENTRY_INPUT; - -typedef struct _CHECK_ROOT_ENTRY_OUTPUT -{ - DWORD field_0; - DWORD field_4; - DWORD field_8; - bool field_C; - -} CHECK_ROOT_ENTRY_OUTPUT, *PCHECK_ROOT_ENTRY_OUTPUT; - - -// WoW6: 00413F61 -static bool EnlargeHashTableIfMoreThan75PercentUsed(PCASC_ROOT_HASH_TABLE pRootTable, DWORD NewItemCount) -{ - // Don't relocate anything, just check - assert((double)NewItemCount / (double)pRootTable->TableSize < .75); - return true; -} - -// WOW6: 00414402 -// Finds an existing root table entry or a free one -PCASC_ROOT_ENTRY CascRootTable_FindFreeEntryWithEnlarge( - PCASC_ROOT_HASH_TABLE pRootTable, - PCASC_ROOT_ENTRY pNewEntry) -{ - PCASC_ROOT_ENTRY pEntry; - DWORD TableIndex; - - // The table size must be a power of two - assert((pRootTable->TableSize & (pRootTable->TableSize - 1)) == 0); - - // Make sure that number of occupied items is never bigger - // than 75% of the table size - if(!EnlargeHashTableIfMoreThan75PercentUsed(pRootTable, pRootTable->ItemCount + 1)) - return NULL; - - // Get the start index of the table - TableIndex = (DWORD)(pNewEntry->FileNameHash) & (pRootTable->TableSize - 1); - - // If that entry is already occupied, move to a next entry - for(;;) - { - // Check that entry if it's free or not - pEntry = pRootTable->TablePtr + TableIndex; - if(pEntry->SumValue == 0) - break; - - // Is the found entry equal to the existing one? - if(pEntry->FileNameHash == pNewEntry->FileNameHash) - break; - - // Move to the next entry - TableIndex = (TableIndex + 1) & (pRootTable->TableSize - 1); - } - - // Either return a free entry or an existing one - return pEntry; -} - -// WOW6: 004145D1 -static void CascRootTable_InsertTableEntry( - PCASC_ROOT_HASH_TABLE pRootTable, - PCASC_ROOT_ENTRY pNewEntry) -{ - PCASC_ROOT_ENTRY pEntry; - - // Find an existing entry or an empty one - pEntry = CascRootTable_FindFreeEntryWithEnlarge(pRootTable, pNewEntry); - assert(pEntry != NULL); - - // If that entry is not used yet, fill it in - if(pEntry->FileNameHash == 0) - { - *pEntry = *pNewEntry; - pRootTable->ItemCount++; + nError = CreateMapOfEncodingKeys(hs, pEncodingSegment, dwNumSegments); } -} - -static int LoadWowRootFileLocales( - TCascStorage * hs, - LPBYTE pbRootFile, - DWORD cbRootFile, - DWORD dwLocaleMask, - bool bLoadBlocksWithFlags80, - BYTE HighestBitValue) -{ - CASC_ROOT_ENTRY NewRootEntry; - ROOT_BLOCK_INFO BlockInfo; - LPBYTE pbRootFileEnd = pbRootFile + cbRootFile; - LPBYTE pbFilePointer; - - // Now parse the root file - for(pbFilePointer = pbRootFile; pbFilePointer <= pbRootFileEnd; ) - { - // Validate the file locale block - pbFilePointer = VerifyLocaleBlock(&BlockInfo, pbFilePointer, pbRootFileEnd); - if(pbFilePointer == NULL) - break; - - // WoW.exe (build 19116): Entries with flag 0x100 set are skipped - if(BlockInfo.pLocaleBlockHdr->Flags & 0x100) - continue; - - // WoW.exe (build 19116): Entries with flag 0x80 set are skipped if arg_4 is set to FALSE (which is by default) - if(bLoadBlocksWithFlags80 == 0 && (BlockInfo.pLocaleBlockHdr->Flags & 0x80)) - continue; - // WoW.exe (build 19116): Entries with (flags >> 0x1F) not equal to arg_8 are skipped - if((BYTE)(BlockInfo.pLocaleBlockHdr->Flags >> 0x1F) != HighestBitValue) - continue; - - // WoW.exe (build 19116): Locales other than defined mask are skipped too - if((BlockInfo.pLocaleBlockHdr->Locales & dwLocaleMask) == 0) - continue; - - // Reset the sum value - NewRootEntry.SumValue = 0; - - // WoW.exe (build 19116): Blocks with zero files are skipped - for(DWORD i = 0; i < BlockInfo.pLocaleBlockHdr->NumberOfFiles; i++) - { - // (004147A3) Prepare the CASC_ROOT_ENTRY structure - NewRootEntry.FileNameHash = BlockInfo.pRootEntries[i].FileNameHash; - NewRootEntry.SumValue = NewRootEntry.SumValue + BlockInfo.pInt32Array[i]; - NewRootEntry.Locales = BlockInfo.pLocaleBlockHdr->Locales; - NewRootEntry.EncodingKey[0] = BlockInfo.pRootEntries[i].EncodingKey[0]; - NewRootEntry.EncodingKey[1] = BlockInfo.pRootEntries[i].EncodingKey[1]; - NewRootEntry.EncodingKey[2] = BlockInfo.pRootEntries[i].EncodingKey[2]; - NewRootEntry.EncodingKey[3] = BlockInfo.pRootEntries[i].EncodingKey[3]; - - // Insert the root table item to the hash table - CascRootTable_InsertTableEntry(&hs->RootTable, &NewRootEntry); - NewRootEntry.SumValue++; - } - } - - return 1; -} - -// WoW.exe: 004146C7 (BuildManifest::Load) -static int LoadWowRootFileWithParams( - TCascStorage * hs, - LPBYTE pbRootFile, - DWORD cbRootFile, - DWORD dwLocaleBits, - BYTE HighestBitValue) -{ - // Load the locale as-is - LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, dwLocaleBits, false, HighestBitValue); - - // If we wanted enGB, we also load enUS for the missing files - if(dwLocaleBits == CASC_LOCALE_ENGB) - LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_ENUS, false, HighestBitValue); - - if(dwLocaleBits == CASC_LOCALE_PTPT) - LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_PTBR, false, HighestBitValue); - - return ERROR_SUCCESS; -} - -/* - // Code from WoW.exe - if(dwLocaleBits == CASC_LOCALE_DUAL_LANG) - { - // Is this english version of WoW? - if(arg_4 == CASC_LOCALE_BIT_ENUS) - { - LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_ENGB, false, HighestBitValue); - LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_ENUS, false, HighestBitValue); - return ERROR_SUCCESS; - } - - // Is this portuguese version of WoW? - if(arg_4 == CASC_LOCALE_BIT_PTBR) - { - LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_PTPT, false, HighestBitValue); - LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_PTBR, false, HighestBitValue); - } - } - - LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, (1 << arg_4), false, HighestBitValue); -*/ - -static int LoadWowRootFile( - TCascStorage * hs, - LPBYTE pbRootFile, - DWORD cbRootFile, - DWORD dwLocaleMask) -{ - int nError; - - // Dump the root file, if needed -#ifdef CASC_DUMP_ROOT_FILE - //CascDumpRootFile(hs, - // pbRootFile, - // cbRootFile, - // "\\casc_root_%build%.txt", - // _T("\\Ladik\\Appdir\\CascLib\\listfile\\listfile-wow6.txt"), - // CASC_DUMP_ROOT_FILE); -#endif - - // Allocate root table entries. Note that the initial size - // of the root table is set to 0x00200000 by World of Warcraft 6.x - hs->RootTable.TablePtr = CASC_ALLOC(CASC_ROOT_ENTRY, CASC_INITIAL_ROOT_TABLE_SIZE); - hs->RootTable.TableSize = CASC_INITIAL_ROOT_TABLE_SIZE; - if(hs->RootTable.TablePtr == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - // Clear the entire table - memset(hs->RootTable.TablePtr, 0, CASC_INITIAL_ROOT_TABLE_SIZE * sizeof(CASC_ROOT_ENTRY)); - - // Load the root file - nError = LoadWowRootFileWithParams(hs, pbRootFile, cbRootFile, dwLocaleMask, 0); - if(nError != ERROR_SUCCESS) - return nError; - - nError = LoadWowRootFileWithParams(hs, pbRootFile, cbRootFile, dwLocaleMask, 1); - if(nError != ERROR_SUCCESS) - return nError; - - return ERROR_SUCCESS; + return nError; } static int LoadRootFile(TCascStorage * hs, DWORD dwLocaleMask) @@ -1100,49 +862,70 @@ static int LoadRootFile(TCascStorage * hs, DWORD dwLocaleMask) int nError = ERROR_SUCCESS; // Sanity checks - assert(hs->RootTable.TablePtr == NULL); - assert(hs->RootTable.ItemCount == 0); - assert(hs->ppEncodingEntries != NULL); + assert(hs->pEncodingMap != NULL); + assert(hs->pRootHandler == NULL); // Locale: The default parameter is 0 - in that case, // we assign the default locale, loaded from the .build.info file if(dwLocaleMask == 0) dwLocaleMask = hs->dwDefaultLocale; - // The root file is either MNDX file (Heroes of the Storm) - // or a file containing an array of root entries (World of Warcraft 6.0+) - // Note: The "root" key file's MD5 hash is equal to its name - // in the configuration + // Load the entire ROOT file to memory if(!CascOpenFileByEncodingKey((HANDLE)hs, &hs->RootKey, 0, &hFile)) nError = GetLastError(); - // Load the entire ROOT file to memory + // Load the entire file to memory if(nError == ERROR_SUCCESS) { - // Load the necessary part of the ENCODING file to memory pbRootFile = LoadRootFileToMemory(hFile, &cbRootFile); - if(pbRootFile == NULL || cbRootFile <= sizeof(PFILE_LOCALE_BLOCK)) - nError = ERROR_FILE_CORRUPT; - - // Close the encoding file CascCloseFile(hFile); } - // Check if the file is a MNDX file - if(nError == ERROR_SUCCESS) + // Check if the version of the ROOT file + if(nError == ERROR_SUCCESS && pbRootFile != NULL) { FileSignature = (PDWORD)pbRootFile; - if(FileSignature[0] == CASC_MNDX_SIGNATURE) + switch(FileSignature[0]) { - nError = LoadMndxRootFile(hs, pbRootFile, cbRootFile); - } - else - { - // WOW6: 00415000 - nError = LoadWowRootFile(hs, pbRootFile, cbRootFile, dwLocaleMask); + case CASC_MNDX_ROOT_SIGNATURE: + nError = RootHandler_CreateMNDX(hs, pbRootFile, cbRootFile); + break; + + case CASC_DIABLO3_ROOT_SIGNATURE: + nError = RootHandler_CreateDiablo3(hs, pbRootFile, cbRootFile); + break; + + case CASC_OVERWATCH_ROOT_SIGNATURE: + nError = RootHandler_CreateOverwatch(hs, pbRootFile, cbRootFile); + break; + + default: + nError = RootHandler_CreateWoW6(hs, pbRootFile, cbRootFile, dwLocaleMask); + break; } } + // Insert entry for the + if(nError == ERROR_SUCCESS) + { + InsertExtraFile(hs, "ENCODING", &hs->EncodingKey); + InsertExtraFile(hs, "ROOT", &hs->RootKey); + InsertExtraFile(hs, "DOWNLOAD", &hs->DownloadKey); + InsertExtraFile(hs, "INSTALL", &hs->InstallKey); + } + +#ifdef _DEBUG + if(nError == ERROR_SUCCESS) + { + //RootFile_Dump(hs, + // pbRootFile, + // cbRootFile, + // _T("\\casc_root_%build%.txt"), + // _T("\\Ladik\\Appdir\\CascLib\\listfile\\listfile-wow6.txt"), + // DUMP_LEVEL_INDEX_ENTRIES); + } +#endif + // Free the root file CASC_FREE(pbRootFile); return nError; @@ -1154,19 +937,19 @@ static TCascStorage * FreeCascStorage(TCascStorage * hs) if(hs != NULL) { - // Free the MNDX info - if(hs->pPackages != NULL) - CASC_FREE(hs->pPackages); - if(hs->pMndxInfo != NULL) - FreeMndxInfo(hs->pMndxInfo); + // Free the root handler + if(hs->pRootHandler != NULL) + RootHandler_Close(hs->pRootHandler); + hs->pRootHandler = NULL; + + // Free the extra encoding entries + Array_Free(&hs->ExtraEntries); // Free the pointers to file entries - if(hs->RootTable.TablePtr != NULL) - CASC_FREE(hs->RootTable.TablePtr); - if(hs->ppEncodingEntries != NULL) - CASC_FREE(hs->ppEncodingEntries); - if(hs->pEncodingHeader != NULL) - CASC_FREE(hs->pEncodingHeader); + if(hs->pEncodingMap != NULL) + Map_Free(hs->pEncodingMap); + if(hs->EncodingFile.pbData != NULL) + CASC_FREE(hs->EncodingFile.pbData); if(hs->pIndexEntryMap != NULL) Map_Free(hs->pIndexEntryMap); @@ -1195,25 +978,24 @@ static TCascStorage * FreeCascStorage(TCascStorage * hs) CASC_FREE(hs->szRootPath); if(hs->szDataPath != NULL) CASC_FREE(hs->szDataPath); + if(hs->szBuildFile != NULL) + CASC_FREE(hs->szBuildFile); if(hs->szIndexPath != NULL) CASC_FREE(hs->szIndexPath); if(hs->szUrlPath != NULL) CASC_FREE(hs->szUrlPath); - // Fre the blob arrays - QUERY_KEY_FreeArray(hs->pArchiveArray); - QUERY_KEY_FreeArray(hs->pPatchArchiveArray); - QUERY_KEY_FreeArray(hs->pEncodingKeys); - // Free the blobs - QUERY_KEY_Free(&hs->CdnConfigKey); - QUERY_KEY_Free(&hs->CdnBuildKey); - QUERY_KEY_Free(&hs->ArchiveGroup); - QUERY_KEY_Free(&hs->PatchArchiveGroup); - QUERY_KEY_Free(&hs->RootKey); - QUERY_KEY_Free(&hs->PatchKey); - QUERY_KEY_Free(&hs->DownloadKey); - QUERY_KEY_Free(&hs->InstallKey); + FreeCascBlob(&hs->CdnConfigKey); + FreeCascBlob(&hs->CdnBuildKey); + FreeCascBlob(&hs->ArchivesGroup); + FreeCascBlob(&hs->ArchivesKey); + FreeCascBlob(&hs->PatchArchivesKey); + FreeCascBlob(&hs->RootKey); + FreeCascBlob(&hs->PatchKey); + FreeCascBlob(&hs->DownloadKey); + FreeCascBlob(&hs->InstallKey); + FreeCascBlob(&hs->EncodingKey); // Free the storage structure hs->szClassName = NULL; @@ -1266,6 +1048,13 @@ bool WINAPI CascOpenStorage(const TCHAR * szDataPath, DWORD dwLocaleMask, HANDLE nError = LoadEncodingFile(hs); } + // Initialize the dynamic array for extra files + // Reserve space for 0x20 encoding entries + if(nError == ERROR_SUCCESS) + { + nError = Array_Create(&hs->ExtraEntries, CASC_ENCODING_ENTRY_1, CASC_EXTRA_FILES); + } + // Load the index files if(nError == ERROR_SUCCESS) { @@ -1309,8 +1098,7 @@ bool WINAPI CascGetStorageInfo( break; case CascStorageFeatures: - if(hs->pMndxInfo != NULL) - dwInfoValue |= CASC_FEATURE_LISTFILE; + dwInfoValue |= (hs->pRootHandler->dwRootFlags & ROOT_FLAG_HAS_NAMES) ? CASC_FEATURE_LISTFILE : 0; break; case CascStorageGameInfo: @@ -1342,8 +1130,6 @@ bool WINAPI CascGetStorageInfo( return true; } - - bool WINAPI CascCloseStorage(HANDLE hStorage) { TCascStorage * hs; diff --git a/dep/CascLib/src/CascPort.h b/dep/CascLib/src/CascPort.h index 3bf1efde4b8..5d0190e07cc 100644 --- a/dep/CascLib/src/CascPort.h +++ b/dep/CascLib/src/CascPort.h @@ -176,6 +176,7 @@ #define _tcsrchr strrchr #define _tcsstr strstr #define _tcsspn strspn + #define _tcsncmp strncmp #define _tprintf printf #define _stprintf sprintf #define _tremove remove diff --git a/dep/CascLib/src/CascReadFile.cpp b/dep/CascLib/src/CascReadFile.cpp index 83fdd0d2096..72eb2c4b647 100644 --- a/dep/CascLib/src/CascReadFile.cpp +++ b/dep/CascLib/src/CascReadFile.cpp @@ -98,9 +98,10 @@ static int LoadFileFrames(TCascFile * hf) else nError = GetLastError(); - // Note: Do not take the FileSize from the sum of frames. - // This value is invalid when loading the ENCODING file. -// hf->FileSize = FileSize; + // Note: on ENCODING file, this value is almost always bigger + // then the real size of ENCODING. We handle this problem + // by calculating size of the ENCODIG file from its header. + hf->FileSize = FileSize; #ifdef CASCLIB_TEST hf->FileSize_FrameSum = FileSize; @@ -264,6 +265,85 @@ static PCASC_FILE_FRAME FindFileFrame(TCascFile * hf, DWORD FilePointer) return NULL; } +static int ProcessFileFrame( + LPBYTE pbOutBuffer, + DWORD cbOutBuffer, + LPBYTE pbInBuffer, + DWORD cbInBuffer, + DWORD dwFrameIndex) +{ + LPBYTE pbTempBuffer; + LPBYTE pbWorkBuffer; + DWORD cbTempBuffer = CASCLIB_MAX(cbInBuffer, cbOutBuffer); + DWORD cbWorkBuffer = cbOutBuffer + 1; + DWORD dwStepCount = 0; + bool bWorkComplete = false; + int nError = ERROR_SUCCESS; + + // Allocate the temporary buffer that will serve as output + pbWorkBuffer = pbTempBuffer = CASC_ALLOC(BYTE, cbTempBuffer); + if(pbWorkBuffer == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Perform the loop + for(;;) + { + // Set the output buffer. + // Even operations: extract to temporary buffer + // Odd operations: extract to output buffer + pbWorkBuffer = (dwStepCount & 0x01) ? pbOutBuffer : pbTempBuffer; + cbWorkBuffer = (dwStepCount & 0x01) ? cbOutBuffer : cbTempBuffer; + + // Perform the operation specific to the operation ID + switch(pbInBuffer[0]) + { + case 'E': // Encrypted files + nError = CascDecrypt(pbWorkBuffer, &cbWorkBuffer, pbInBuffer + 1, cbInBuffer - 1, dwFrameIndex); + bWorkComplete = (nError != ERROR_SUCCESS); + break; + + case 'Z': // ZLIB compressed files + nError = CascDecompress(pbWorkBuffer, &cbWorkBuffer, pbInBuffer + 1, cbInBuffer - 1); + bWorkComplete = true; + break; + + case 'N': // Normal stored files + nError = CascDirectCopy(pbWorkBuffer, &cbWorkBuffer, pbInBuffer + 1, cbInBuffer - 1); + bWorkComplete = true; + break; + + case 'F': // Recursive frames - not supported + default: // Unrecognized - if we unpacked something, we consider it done + nError = ERROR_NOT_SUPPORTED; + bWorkComplete = true; + assert(false); + break; + } + + // Are we done? + if(bWorkComplete) + break; + + // Set the input buffer to the work buffer + pbInBuffer = pbWorkBuffer; + cbInBuffer = cbWorkBuffer; + dwStepCount++; + } + + // If the data are currently in the temporary buffer, + // we need to copy them to output buffer + if(nError == ERROR_SUCCESS && pbWorkBuffer != pbOutBuffer) + { + if(cbWorkBuffer != cbOutBuffer) + nError = ERROR_INSUFFICIENT_BUFFER; + memcpy(pbOutBuffer, pbWorkBuffer, cbOutBuffer); + } + + // Free the temporary buffer + CASC_FREE(pbTempBuffer); + return nError; +} + //----------------------------------------------------------------------------- // Public functions @@ -299,7 +379,7 @@ DWORD WINAPI CascGetFileSize(HANDLE hFile, PDWORD pdwFileSizeHigh) } // Make sure that the file header area is loaded - nError = EnsureHeaderAreaIsLoaded(hf); + nError = EnsureFrameHeadersLoaded(hf); if(nError != ERROR_SUCCESS) { SetLastError(nError); @@ -387,7 +467,6 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW DWORD dwFilePointer = 0; DWORD dwEndPointer = 0; DWORD dwFrameSize; - DWORD cbOutBuffer; bool bReadResult; int nError = ERROR_SUCCESS; @@ -423,7 +502,7 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW { // Get the frame pFrame = FindFileFrame(hf, hf->FilePointer); - if(pFrame == NULL) + if(pFrame == NULL || pFrame->CompressedSize < 1) nError = ERROR_FILE_CORRUPT; } @@ -439,7 +518,7 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW // Perform block read from each file frame while(dwFilePointer < dwEndPointer) { - LPBYTE pbRawData = NULL; + LPBYTE pbFrameData = NULL; DWORD dwFrameStart = pFrame->FrameFileOffset; DWORD dwFrameEnd = pFrame->FrameFileOffset + pFrame->FrameSize; @@ -457,8 +536,8 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW } // We also need to allocate buffer for the raw data - pbRawData = CASC_ALLOC(BYTE, pFrame->CompressedSize); - if(pbRawData == NULL) + pbFrameData = CASC_ALLOC(BYTE, pFrame->CompressedSize); + if(pbFrameData == NULL) { nError = ERROR_NOT_ENOUGH_MEMORY; break; @@ -466,7 +545,7 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW // Load the raw file data to memory FileOffset = pFrame->FrameArchiveOffset; - bReadResult = FileStream_Read(hf->pStream, &FileOffset, pbRawData, pFrame->CompressedSize); + bReadResult = FileStream_Read(hf->pStream, &FileOffset, pbFrameData, pFrame->CompressedSize); // Note: The raw file data size could be less than expected // Happened in WoW build 19342 with the ROOT file. MD5 in the frame header @@ -484,43 +563,34 @@ bool WINAPI CascReadFile(HANDLE hFile, void * pvBuffer, DWORD dwBytesToRead, PDW // If the frame offset is before EOF and frame end is beyond EOF, correct it if(FileOffset < StreamSize && dwFrameSize < pFrame->CompressedSize) { - memset(pbRawData + dwFrameSize, 0, (pFrame->CompressedSize - dwFrameSize)); + memset(pbFrameData + dwFrameSize, 0, (pFrame->CompressedSize - dwFrameSize)); bReadResult = true; } } // If the read result failed, we cannot finish reading it - if(bReadResult == false) - { - CASC_FREE(pbRawData); - nError = GetLastError(); - break; - } - - // Verify the block MD5 - if(!VerifyDataBlockHash(pbRawData, pFrame->CompressedSize, pFrame->md5)) + if(bReadResult && VerifyDataBlockHash(pbFrameData, pFrame->CompressedSize, pFrame->md5)) { - CASC_FREE(pbRawData); - nError = ERROR_FILE_CORRUPT; - break; + // Convert the source frame to the file cache + nError = ProcessFileFrame(hf->pbFileCache, + pFrame->FrameSize, + pbFrameData, + pFrame->CompressedSize, + (DWORD)(pFrame - hf->pFrames)); + if(nError == ERROR_SUCCESS) + { + // Set the start and end of the cache + hf->CacheStart = dwFrameStart; + hf->CacheEnd = dwFrameEnd; + } } - - // Decompress the file frame - cbOutBuffer = pFrame->FrameSize; - nError = CascDecompress(hf->pbFileCache, &cbOutBuffer, pbRawData, pFrame->CompressedSize); - if(nError != ERROR_SUCCESS || cbOutBuffer != pFrame->FrameSize) + else { - CASC_FREE(pbRawData); nError = ERROR_FILE_CORRUPT; - break; } - // Set the start and end of the cache - hf->CacheStart = dwFrameStart; - hf->CacheEnd = dwFrameEnd; - - // Free the decompress buffer, if needed - CASC_FREE(pbRawData); + // Free the raw frame data + CASC_FREE(pbFrameData); } // Copy the decompressed data diff --git a/dep/CascLib/src/CascRootFile_Diablo3.cpp b/dep/CascLib/src/CascRootFile_Diablo3.cpp new file mode 100644 index 00000000000..98a42cc3226 --- /dev/null +++ b/dep/CascLib/src/CascRootFile_Diablo3.cpp @@ -0,0 +1,1189 @@ +/*****************************************************************************/ +/* CascRootFile_Diablo3.cpp Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Support for loading Diablo 3 ROOT file */ +/* Note: D3 offsets refer to Diablo III.exe 2.2.0.30013 (32-bit) */ +/* SHA1: e4f17eca8aad8dde70870bf932ac3f5b85f17a1f */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 04.03.15 1.00 Lad The first version of CascRootFile_Diablo3.cpp */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "CascLib.h" +#include "CascCommon.h" + +//----------------------------------------------------------------------------- +// Local structures + +#define DIABLO3_SUBDIR_SIGNATURE 0xEAF1FE87 +#define DIABLO3_PACKAGES_SIGNATURE 0xAABB0002 +#define DIABLO3_MAX_SUBDIRS 0x20 + +#define DIABLO3_INVALID_INDEX 0xFFFFFFFF +#define DIABLO3_INVALID_FILE 0xFFFFFFFF +#define DIABLO3_MAX_ASSETS 70 // Maximum possible number of assets +#define DIABLO3_MAX_LEVEL0_LENGTH 0x10 // Maximum length of the level-0 directory name + +#define INVALID_FILE_INDEX 0xFFFFFFFF +#define INVALID_ASSET_INDEX 0xFF + +#define ENTRY_FLAG_DIRECTORY_ENTRY 0x80 // The file is actually a directory entry +#define ENTRY_FLAG_PLAIN_NAME 0x01 // If set, the file entry contains offset of the plain file name +#define ENTRY_FLAG_FULL_NAME 0x02 // If set, the file entry contains offset of the full name +#define ENTRY_FLAG_FLAGS_MASK 0xF0 // Mask for the entry flags +#define ENTRY_FLAG_NAME_MASK 0x0F // Mask for the entry file name type + +// Values for CASC_FILE_ENTRY::dwFlags +#define CASC_ENTRY_SHORT_NAME 0x000000001 // If set, the name is in format XXYYplain-name[\sub-index].ext +#define CASC_ENTRY_HAS_SUBINDEX 0x000000002 // If set, the subitem is present in the file name (i.e. XXYYplain-name\sub-index.ext) + +#define SEARCH_PHASE_NAMES 0 // Searching named entry +#define SEARCH_PHASE_FILE_IDS 1 // Searching filed by ID + +// Macro for constructing 64-bit integer from root-index, file-index and sub-index +// The result value is RRAAAAAAAASSSSSS +#define MAKE_INDEX64(ri, fi, si) (((ULONGLONG)ri << 0x38) | ((ULONGLONG)fi << 0x18) | ((ULONGLONG)si)) +#define INDEX64_ROOT_INDEX(hash) (DWORD)((hash >> 0x38) & 0x000000FF) +#define INDEX64_FILE_INDEX(hash) (DWORD)((hash >> 0x18) & 0xFFFFFFFF) +#define INDEX64_SUB_INDEX(hash) (DWORD)((hash >> 0x00) & 0x00FFFFFF) + +// On-disk structure for a file given by file number +typedef struct _DIABLO3_FILEID1_ENTRY +{ + ENCODING_KEY EncodingKey; // Encoding key for the file + DWORD FileIndex; // File index +} DIABLO3_FILEID1_ENTRY, *PDIABLO3_FILEID1_ENTRY; + +// On-disk structure for a file given by file number and suffix +typedef struct _DIABLO3_FILEID2_ENTRY +{ + ENCODING_KEY EncodingKey; // Encoding key for the file + DWORD FileIndex; // File index + DWORD SubIndex; // File subindex, like "SoundBank\3D Ambience\0000.smp" +} DIABLO3_FILEID2_ENTRY, *PDIABLO3_FILEID2_ENTRY; + +// On-disk structure of the named entry +typedef struct _DIABLO3_NAMED_ENTRY +{ + ENCODING_KEY EncodingKey; // Encoding key for the file + BYTE szFileName[1]; // ASCIIZ file name (variable length) +} DIABLO3_NAMED_ENTRY, *PDIABLO3_NAMED_ENTRY; + +// On-disk structure of CoreToc.dat header +typedef struct _DIABLO3_CORE_TOC_HEADER +{ + DWORD EntryCounts[DIABLO3_MAX_ASSETS]; // Array of number of entries (files) for each asset (level-1 directory) + DWORD EntryOffsets[DIABLO3_MAX_ASSETS]; // Array of offsets of each DIABLO3_CORE_TOC_ENTRY, relative to data after header + DWORD Unknowns[DIABLO3_MAX_ASSETS]; // Unknown + DWORD Alignment; +} DIABLO3_CORE_TOC_HEADER, *PDIABLO3_CORE_TOC_HEADER; + +// On-disk structure of the entry in CoreToc.dat +typedef struct _DIABLO3_CORE_TOC_ENTRY +{ + DWORD AssetIndex; // Index of the Diablo3 asset (aka directory) + DWORD FileIndex; // File index + DWORD NameOffset; // Offset of the plain file name + +} DIABLO3_CORE_TOC_ENTRY, *PDIABLO3_CORE_TOC_ENTRY; + +// In-memory structure of parsed directory header +typedef struct _DIABLO3_DIR_HEADER +{ + LPBYTE pbEntries1; + LPBYTE pbEntries2; + LPBYTE pbEntries3; + DWORD dwEntries1; + DWORD dwEntries2; + DWORD dwEntries3; +} DIABLO3_DIR_HEADER, *PDIABLO3_DIR_HEADER; + +// In-memory structure of loaded CoreTOC.dat +typedef struct _DIABLO3_CORE_TOC +{ + DIABLO3_CORE_TOC_HEADER Hdr; // Header of CoreTOC.dat + + LPBYTE pbCoreToc; // Content of the CoreTOC.dat file + DIABLO3_CORE_TOC_ENTRY Entries[1]; // Buffer for storing the entries (variable length) + +} DIABLO3_CORE_TOC, *PDIABLO3_CORE_TOC; + +// On-disk structure of Packages.dat header +typedef struct _DIABLO3_PACKAGES_DAT_HEADER +{ + DWORD Signature; + DWORD NumberOfNames; +} DIABLO3_PACKAGES_DAT_HEADER, *PDIABLO3_PACKAGES_DAT_HEADER; + +// Structure for conversion DirectoryID -> Directory name +typedef struct _DIABLO3_ASSET_INFO +{ + const char * szDirectoryName; // Directory name + const char * szExtension; + +} DIABLO3_ASSET_INFO; +typedef const DIABLO3_ASSET_INFO * PDIABLO3_ASSET_INFO; + +// In-memory structure of a file entry in the linear file list +typedef struct _CASC_FILE_ENTRY +{ + ENCODING_KEY EncodingKey; // Encoding key + ULONGLONG FileNameHash; // Hash of the full file name + DWORD dwFileName; // Offset of the name (in name's dynamic array) + DWORD dwFlags; // Entry flags (see CASC_ENTRY_XXXX) + + DWORD NameOffset; // Offset of the name (in name's dynamic array) + USHORT SubIndex; // File\SubFile index + BYTE AssetIndex; // Asset index (aka directory index) + BYTE EntryFlags; // Entry flags +} CASC_FILE_ENTRY, *PCASC_FILE_ENTRY; + +//----------------------------------------------------------------------------- +// Structure definitions for Diablo3 root file + +struct TRootHandler_Diablo3 : public TRootHandler +{ + // Linear global list of all files + DYNAMIC_ARRAY FileTable; + + // Linear global list of names + DYNAMIC_ARRAY FileNames; + + // Global map of FileName -> FileEntry + PCASC_MAP pRootMap; +}; + +//----------------------------------------------------------------------------- +// Local variables + +static const DIABLO3_ASSET_INFO Assets[] = +{ +// DIR-NAME EXTENSION +// ========== ========= + {NULL, NULL}, // 0x00 + {"Actor", "acr"}, // 0x01 + {"Adventure", "adv"}, // 0x02 + {NULL, NULL}, // 0x03 + {NULL, NULL}, // 0x04 + {"AmbientSound", "ams"}, // 0x05 + {"Anim", "ani"}, // 0x06 + {"Anim2D", "an2"}, // 0x07 + {"AnimSet", "ans"}, // 0x08 + {"Appearance", "app"}, // 0x09 + {NULL, NULL}, // 0x0A + {"Cloth", "clt"}, // 0x0B + {"Conversation", "cnv"}, // 0x0C + {NULL, NULL}, // 0x0D + {"EffectGroup", "efg"}, // 0x0E + {"Encounter", "enc"}, // 0x0F + {NULL, NULL}, // 0x10 + {"Explosion", "xpl"}, // 0x11 + {NULL, NULL}, // 0x12 + {"Font", "fnt"}, // 0x13 + {"GameBalance", "gam"}, // 0x14 + {"Globals", "glo"}, // 0x15 + {"LevelArea", "lvl"}, // 0x16 + {"Light", "lit"}, // 0x17 + {"MarkerSet", "mrk"}, // 0x18 + {"Monster", "mon"}, // 0x19 + {"Observer", "obs"}, // 0x1A + {"Particle", "prt"}, // 0x1B + {"Physics", "phy"}, // 0x1C + {"Power", "pow"}, // 0x1D + {NULL, NULL}, // 0x1E + {"Quest", "qst"}, // 0x1F + {"Rope", "rop"}, // 0x20 + {"Scene", "scn"}, // 0x21 + {"SceneGroup", "scg"}, // 0x22 + {NULL, NULL}, // 0x23 + {"ShaderMap", "shm"}, // 0x24 + {"Shaders", "shd"}, // 0x25 + {"Shakes", "shk"}, // 0x26 + {"SkillKit", "skl"}, // 0x27 + {"Sound", "snd"}, // 0x28 + {"SoundBank", "sbk"}, // 0x29 + {"StringList", "stl"}, // 0x2A + {"Surface", "srf"}, // 0x2B + {"Textures", "tex"}, // 0x2C + {"Trail", "trl"}, // 0x2D + {"UI", "ui"}, // 0x2E + {"Weather", "wth"}, // 0x2F + {"Worlds", "wrl"}, // 0x30 + {"Recipe", "rcp"}, // 0x31 + {NULL, NULL}, // 0x32 + {"Condition", "cnd"}, // 0x33 + {NULL, NULL}, // 0x34 + {NULL, NULL}, // 0x35 + {NULL, NULL}, // 0x36 + {NULL, NULL}, // 0x37 + {"Act", "act"}, // 0x38 + {"Material", "mat"}, // 0x39 + {"QuestRange", "qsr"}, // 0x3A + {"Lore", "lor"}, // 0x3B + {"Reverb", "rev"}, // 0x3C + {"PhysMesh", "phm"}, // 0x3D + {"Music", "mus"}, // 0x3E + {"Tutorial", "tut"}, // 0x3F + {"BossEncounter", "bos"}, // 0x40 + {NULL, NULL}, // 0x41 + {"Accolade", "aco"}, // 0x42 +}; + +static const DIABLO3_ASSET_INFO UnknownAsset = {"Unknown", "xxx"}; + +#define DIABLO3_ASSET_COUNT (sizeof(Assets) / sizeof(Assets[0])) + +//----------------------------------------------------------------------------- +// Local functions + +static PDIABLO3_ASSET_INFO GetAssetInfo(DWORD dwAssetIndex) +{ + if(dwAssetIndex < DIABLO3_ASSET_COUNT && Assets[dwAssetIndex].szDirectoryName != NULL) + return &Assets[dwAssetIndex]; + return &UnknownAsset; +} + +static DWORD VerifyNamedFileEntry(LPBYTE pbNamedEntry, LPBYTE pbFileEnd) +{ + LPBYTE pbFileName = ((PDIABLO3_NAMED_ENTRY)pbNamedEntry)->szFileName; + + // Find the end of the name + while(pbFileName < pbFileEnd && pbFileName[0] != 0) + pbFileName++; + + // Did we get past the end of the root file? + if(pbFileName >= pbFileEnd) + return 0; + pbFileName++; + + // Return the length of the structure + return (DWORD)(pbFileName - pbNamedEntry); +} + +static char * FindPackageName( + PCASC_MAP pPackageMap, + const char * szAssetName, + const char * szPlainName) +{ + char szFileName[MAX_PATH+1]; + size_t nLength; + + // Construct the name without extension and find it in the map + nLength = sprintf(szFileName, "%s\\%s", szAssetName, szPlainName); + return (char *)Map_FindString(pPackageMap, szFileName, szFileName + nLength); +} + +static size_t CreateShortName( + PCASC_MAP pPackageMap, + DWORD dwRootIndex, // Level-0-dir: Index of the root subdirectory + DWORD dwAssetIndex, // Level-1-dir: Index of the asset name + const char * szPlainName, // Plain name of the file, without extension + DWORD dwSubIndex, + char * szBuffer) +{ + PDIABLO3_ASSET_INFO pAssetInfo = GetAssetInfo(dwAssetIndex); + const char * szPackageName = NULL; + const char * szFormat; + size_t nLength; + + // Write the level-0 directory index as 2-digit hexa number + assert(dwRootIndex < 0x100); + *szBuffer++ = IntToHexChar[dwRootIndex >> 0x04]; + *szBuffer++ = IntToHexChar[dwRootIndex & 0x0F]; + + // Write the level-1 directory index as 2-digit hexa number + assert(dwAssetIndex < 0x100); + *szBuffer++ = IntToHexChar[dwAssetIndex >> 0x04]; + *szBuffer++ = IntToHexChar[dwAssetIndex & 0x0F]; + + // Construct the file name with ending "." for extension + szFormat = (dwSubIndex != DIABLO3_INVALID_INDEX) ? "%s\\%04u." : "%s."; + nLength = sprintf(szBuffer, szFormat, szPlainName, dwSubIndex); + + // Try to fixup the file extension from the package name. + // File extensions are not predictable because for subitems, + // they are not always equal to the main items: + // + // SoundBank\3D Ambience.sbk + // SoundBank\3D Ambience\0000.smp + // SoundBank\3D Ambience\0002.smp + // ... + // SoundBank\Angel.sbk + // SoundBank\Angel\0000.fsb + // SoundBank\Angel\0002.fsb + // + // We use the Base\Data_D3\PC\Misc\Packages.dat for real file extensions, where possible + // + if(pPackageMap != NULL) + { + // Retrieve the asset name + szPackageName = FindPackageName(pPackageMap, pAssetInfo->szDirectoryName, szBuffer); + if(szPackageName != NULL) + { + strcpy(szBuffer, szPackageName + strlen(pAssetInfo->szDirectoryName) + 1); + nLength = strlen(szBuffer); + } + } + + // If we havent't found the package, we either use the default asset extension or "xxx" + if(szPackageName == NULL) + { + if(dwSubIndex == DIABLO3_INVALID_INDEX) + { + strcpy(szBuffer + nLength, pAssetInfo->szExtension); + nLength += strlen(pAssetInfo->szExtension); + } + else + { + strcpy(szBuffer + nLength, "xxx"); + nLength += 3; + } + } + + // Return the length of the short file name + return nLength + 4; +} + +static size_t CreateFileName( + TRootHandler_Diablo3 * pRootHandler, + const char * szShortName, // Short file name of the file + char * szBuffer) +{ + PCASC_FILE_ENTRY pRootEntry; + const char * szNameLevel0; + const char * szNameLevel1 = NULL; + DWORD dwRootIndex0 = 0; + DWORD dwAssetIndex = 0; + + // Retrieve the level-0 and level-1 directory indexes + ConvertStringToInt08(szShortName+0, &dwRootIndex0); + ConvertStringToInt08(szShortName+2, &dwAssetIndex); + + // Retrieve the name of the level-0 directory (aka root subdirectory) + pRootEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, dwRootIndex0); + szNameLevel0 = (char *)Array_ItemAt(&pRootHandler->FileNames, pRootEntry->dwFileName); + + // Retrieve the name of the level-1 directory (aka asset name) + if(dwAssetIndex < DIABLO3_ASSET_COUNT) + szNameLevel1 = Assets[dwAssetIndex].szDirectoryName; + if(szNameLevel1 == NULL) + szNameLevel1 = UnknownAsset.szDirectoryName; + + // Copy the rest of the name as-is + return sprintf(szBuffer, "%s\\%s\\%s", szNameLevel0, szNameLevel1, szShortName + 4); +} + + +// Creates a map of String -> Pointer +static PCASC_MAP CreatePackageMap( + LPBYTE pbPackagesDat, + LPBYTE pbPackagesEnd) +{ + PDIABLO3_PACKAGES_DAT_HEADER pDatHeader = (PDIABLO3_PACKAGES_DAT_HEADER)pbPackagesDat; + PCASC_MAP pPackageMap; + + // Get the header + if((pbPackagesDat + sizeof(DIABLO3_PACKAGES_DAT_HEADER)) >= pbPackagesEnd) + return NULL; + pbPackagesDat += sizeof(DIABLO3_PACKAGES_DAT_HEADER); + + // Check the signature and name count + if(pDatHeader->Signature != DIABLO3_PACKAGES_SIGNATURE) + return NULL; + + // Create the map for fast search of the file name + pPackageMap = Map_Create(pDatHeader->NumberOfNames, KEY_LENGTH_STRING, 0); + if(pPackageMap != NULL) + { + char * szFileName = (char *)pbPackagesDat; + + // Go as long as there is something + for(DWORD i = 0; i < pDatHeader->NumberOfNames; i++) + { + // Get the file extension + if((LPBYTE)szFileName >= pbPackagesEnd) + break; + + // Insert the file name to the map. The file extension is not included + Map_InsertString(pPackageMap, szFileName, true); + szFileName = szFileName + strlen(szFileName) + 1; + } + } + + return pPackageMap; +} + +// Insert an entry with file name as-is +static int InsertFileEntry( + TRootHandler_Diablo3 * pRootHandler, + ENCODING_KEY & EncodingKey, + const char * szFileName, + size_t cchFileName) +{ + PCASC_FILE_ENTRY pFileEntry; + + // We must not allow the file name array to be reallocated. + // Reallocating the array would cause pointers in TRootHandler_Diablo3::pRootMap + // become invalid + if(pRootHandler->FileTable.ItemCount >= pRootHandler->FileTable.ItemCountMax) + { + assert(false); + return ERROR_NOT_ENOUGH_MEMORY; + } + + // Insert the plain name to the root handler's global name list + szFileName = (const char *)Array_Insert(&pRootHandler->FileNames, szFileName, cchFileName); + if(szFileName == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Make sure that we don't exceed the file limit at this phase + pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1); + assert(pFileEntry != NULL); + + // Store the info into the file entry + pFileEntry->EncodingKey = EncodingKey; + pFileEntry->FileNameHash = CalcFileNameHash(szFileName); + pFileEntry->dwFileName = (DWORD)Array_IndexOf(&pRootHandler->FileNames, szFileName); + pFileEntry->dwFlags = 0; + + // Verify collisions (debug version only) + assert(Map_FindObject(pRootHandler->pRootMap, &pFileEntry->FileNameHash, NULL) == NULL); + + // Calculate the file name hash + Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash); + + // Success + return ERROR_SUCCESS; +} + +static int ParseDirEntries_FileId1( + TRootHandler_Diablo3 * pRootHandler, + LPBYTE pbFileEntries, + DWORD dwFileEntries, + DWORD dwRootDirIndex) +{ + PDIABLO3_FILEID1_ENTRY pEntry = (PDIABLO3_FILEID1_ENTRY)pbFileEntries; + PCASC_FILE_ENTRY pFileEntry; + + // Overflow test + if((pRootHandler->FileTable.ItemCount + dwFileEntries) >= pRootHandler->FileTable.ItemCountMax) + { + assert(false); + return ERROR_NOT_ENOUGH_MEMORY; + } + + // Parse the all ID1 entries in the file + for(DWORD i = 0; i < dwFileEntries; i++, pEntry++) + { + // Insert the file entry to the global list + pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1); + assert(pFileEntry != NULL); + + // Fill the index entry + pFileEntry->EncodingKey = pEntry->EncodingKey; + pFileEntry->FileNameHash = MAKE_INDEX64(dwRootDirIndex, pEntry->FileIndex, 0); + pFileEntry->dwFlags = CASC_ENTRY_SHORT_NAME; + } + + return ERROR_SUCCESS; +} + +static int ParseDirEntries_FileId2( + TRootHandler_Diablo3 * pRootHandler, + LPBYTE pbFileEntries, + DWORD dwFileEntries, + DWORD dwRootDirIndex) +{ + PDIABLO3_FILEID2_ENTRY pEntry = (PDIABLO3_FILEID2_ENTRY)pbFileEntries; + PCASC_FILE_ENTRY pFileEntry; + + // Overflow test + if((pRootHandler->FileTable.ItemCount + dwFileEntries) >= pRootHandler->FileTable.ItemCountMax) + { + assert(false); + return ERROR_NOT_ENOUGH_MEMORY; + } + + // Parse the all ID1 entries in the file + for(DWORD i = 0; i < dwFileEntries; i++, pEntry++) + { + // Insert the file entry to the global list + pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1); + assert(pFileEntry != NULL); + + // Fill the index entry + pFileEntry->EncodingKey = pEntry->EncodingKey; + pFileEntry->FileNameHash = MAKE_INDEX64(dwRootDirIndex, pEntry->FileIndex, pEntry->SubIndex); + pFileEntry->dwFlags = CASC_ENTRY_SHORT_NAME | CASC_ENTRY_HAS_SUBINDEX; + } + + return ERROR_SUCCESS; +} + +static int ParseDirEntries_Named( + TRootHandler_Diablo3 * pRootHandler, + LPBYTE pbFileEntries, + LPBYTE pbFileEnd, + DWORD dwFileEntries, + DWORD dwRootDirIndex) +{ + char szFileName[MAX_PATH+1]; + char * szNamePtr = szFileName; + DWORD cbFileEntry; + int nError = ERROR_SUCCESS; + + // Overflow test + if((pRootHandler->FileTable.ItemCount + dwFileEntries) >= pRootHandler->FileTable.ItemCountMax) + { + assert(false); + return ERROR_NOT_ENOUGH_MEMORY; + } + + // If we the file is not in the root directory itself, + // prepare the prefix for the root directory. + if(dwRootDirIndex != DIABLO3_INVALID_INDEX) + { + PCASC_FILE_ENTRY pRootEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, dwRootDirIndex); + const char * szRootName = (const char *)Array_ItemAt(&pRootHandler->FileNames, pRootEntry->dwFileName); + + // Copy the root directory name + while(szRootName[0] != 0) + *szNamePtr++ = *szRootName++; + + // Append the backslash + *szNamePtr++ = '\\'; + } + + // Parse the file entry + while(pbFileEntries < pbFileEnd) + { + PDIABLO3_NAMED_ENTRY pNamedEntry = (PDIABLO3_NAMED_ENTRY)pbFileEntries; + DWORD cchFileName; + + // Verify the named entry whether it does not go beyond the EOF + cbFileEntry = VerifyNamedFileEntry(pbFileEntries, pbFileEnd); + if(cbFileEntry == 0) + return ERROR_FILE_CORRUPT; + + // Append the file name to the prepared file name + // This way we obtain the full name and the name lookup + // will be fully operational + memcpy(szNamePtr, pNamedEntry->szFileName, (cbFileEntry - sizeof(ENCODING_KEY))); + cchFileName = (DWORD)((szNamePtr - szFileName) + (cbFileEntry - sizeof(ENCODING_KEY))); + + // Insert the named entry to the global file table + nError = InsertFileEntry(pRootHandler, + pNamedEntry->EncodingKey, + szFileName, + cchFileName); + if(nError != ERROR_SUCCESS) + return nError; + + // Move the pointer to the next entry + pbFileEntries += cbFileEntry; + } + + return ERROR_SUCCESS; +} + +static void ResolveFullFileNames( + TRootHandler_Diablo3 * pRootHandler, + PDIABLO3_CORE_TOC_ENTRY pCoreTocEntries, + PCASC_MAP pPackageMap, + LPBYTE pbCoreTocFile, + DWORD dwFileIndexes) +{ + PCASC_FILE_ENTRY pFileEntry; + char * szPlainName; + char * szNamePtr; + size_t nLength; + DWORD dwRootIndex; + DWORD dwFileIndex; + DWORD dwSubIndex; + char szShortName[MAX_PATH+1]; + char szFullName[MAX_PATH+1]; + + // Parse the entire file table + for(size_t i = 0; i < pRootHandler->FileTable.ItemCount; i++) + { + // Retrieve the file entry at n-th position + pFileEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, i); + + // Skip the items that already have full name + if(pFileEntry->dwFlags & CASC_ENTRY_SHORT_NAME) + { + // Retrieve the file index of that file + dwRootIndex = INDEX64_ROOT_INDEX(pFileEntry->FileNameHash); + dwFileIndex = INDEX64_FILE_INDEX(pFileEntry->FileNameHash); + dwSubIndex = (pFileEntry->dwFlags & CASC_ENTRY_HAS_SUBINDEX) ? INDEX64_SUB_INDEX(pFileEntry->FileNameHash) : DIABLO3_INVALID_INDEX; + assert(dwFileIndex < dwFileIndexes); + + // Get the plain name of the file + szPlainName = (char *)(pbCoreTocFile + pCoreTocEntries[dwFileIndex].NameOffset); + + // Create the short file name + nLength = CreateShortName(pPackageMap, + dwRootIndex, + pCoreTocEntries[dwFileIndex].AssetIndex, + szPlainName, + dwSubIndex, + szShortName); + + // Insert the short name to the list of the names + szNamePtr = (char *)Array_Insert(&pRootHandler->FileNames, szShortName, nLength + 1); + pFileEntry->dwFileName = (DWORD)Array_IndexOf(&pRootHandler->FileNames, szNamePtr); + + // Create the full file name + nLength = CreateFileName(pRootHandler, szShortName, szFullName); + pFileEntry->FileNameHash = CalcFileNameHash(szFullName); + + // Insert the entry to the name map. Use the mapping of FullName -> FileHash + Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash); + } + } +} + +static LPBYTE LoadFileToMemory(TCascStorage * hs, LPBYTE pbEncodingKey, DWORD * pcbFileData) +{ + QUERY_KEY EncodingKey; + LPBYTE pbFileData = NULL; + HANDLE hFile; + DWORD cbBytesRead = 0; + DWORD cbFileData = 0; + + // Open the file by encoding key + EncodingKey.pbData = pbEncodingKey; + EncodingKey.cbData = MD5_HASH_SIZE; + if(CascOpenFileByEncodingKey((HANDLE)hs, &EncodingKey, 0, &hFile)) + { + // Retrieve the file size + cbFileData = CascGetFileSize(hFile, NULL); + if(cbFileData > 0) + { + pbFileData = CASC_ALLOC(BYTE, cbFileData); + if(pbFileData != NULL) + { + CascReadFile(hFile, pbFileData, cbFileData, &cbBytesRead); + } + } + + // Close the file + CascCloseFile(hFile); + } + + // Give the file to the caller + if(pcbFileData != NULL) + pcbFileData[0] = cbBytesRead; + return pbFileData; +} + +static LPBYTE LoadFileToMemory(TCascStorage * hs, const char * szFileName, DWORD * pcbFileData) +{ + LPBYTE pbEncodingKey = NULL; + LPBYTE pbFileData = NULL; + + // Try to find encoding key for the file + pbEncodingKey = RootHandler_GetKey(hs->pRootHandler, szFileName); + if(pbEncodingKey != NULL) + pbFileData = LoadFileToMemory(hs, pbEncodingKey, pcbFileData); + + return pbFileData; +} + +static int ParseDirectoryHeader( + PDIABLO3_DIR_HEADER pDirHeader, + LPBYTE pbDirFile, + LPBYTE pbFileEnd) +{ + DWORD dwSignature = 0; + + // + // Structure of a Diablo3 directory file + // 1) Signature (4 bytes) + // 2) Number of DIABLO3_FILEID1_ENTRY entries (4 bytes) + // 3) Array of DIABLO3_FILEID1_ENTRY entries + // 4) Number of DIABLO3_FILEID2_ENTRY entries (4 bytes) + // 5) Array of DIABLO3_FILEID2_ENTRY entries + // 6) Number of DIABLO3_NAMED_ENTRY entries (4 bytes) + // 7) Array of DIABLO3_NAMED_ENTRY entries + // + + // Prepare the header signature + memset(pDirHeader, 0, sizeof(DIABLO3_DIR_HEADER)); + + // Get the signature + if((pbDirFile + sizeof(DWORD)) >= pbFileEnd) + return ERROR_BAD_FORMAT; + dwSignature = *(PDWORD)pbDirFile; + + // Check the signature + if(dwSignature != CASC_DIABLO3_ROOT_SIGNATURE && dwSignature != DIABLO3_SUBDIR_SIGNATURE) + return ERROR_BAD_FORMAT; + pbDirFile += sizeof(DWORD); + + // Subdirectories have extra two arrays + if(dwSignature == DIABLO3_SUBDIR_SIGNATURE) + { + // Get the number of DIABLO3_FILEID1_ENTRY items + if((pbDirFile + sizeof(DWORD)) >= pbFileEnd) + return ERROR_BAD_FORMAT; + pDirHeader->dwEntries1 = *(PDWORD)pbDirFile; + + // Get the array of DIABLO3_FILEID1_ENTRY + pDirHeader->pbEntries1 = (pbDirFile + sizeof(DWORD)); + pbDirFile = pbDirFile + sizeof(DWORD) + pDirHeader->dwEntries1 * sizeof(DIABLO3_FILEID1_ENTRY); + + // Get the number of DIABLO3_FILEID2_ENTRY items + if((pbDirFile + sizeof(DWORD)) >= pbFileEnd) + return ERROR_BAD_FORMAT; + pDirHeader->dwEntries2 = *(PDWORD)pbDirFile; + + // Get the array of DIABLO3_FILEID2_ENTRY + pDirHeader->pbEntries2 = (pbDirFile + sizeof(DWORD)); + pbDirFile = pbDirFile + sizeof(DWORD) + pDirHeader->dwEntries2 * sizeof(DIABLO3_FILEID2_ENTRY); + } + + // Get the pointer and length DIABLO3_NAMED_ENTRY array + if((pbDirFile + sizeof(DWORD)) >= pbFileEnd) + return ERROR_BAD_FORMAT; + pDirHeader->dwEntries3 = *(PDWORD)pbDirFile; + pDirHeader->pbEntries3 = (pbDirFile + sizeof(DWORD)); + return ERROR_SUCCESS; +} + +static DWORD ScanDirectoryFile( + TCascStorage * hs, + LPBYTE pbRootFile, + LPBYTE pbFileEnd) +{ + PDIABLO3_NAMED_ENTRY pNamedEntry; + DIABLO3_DIR_HEADER RootHeader; + DIABLO3_DIR_HEADER DirHeader; + LPBYTE pbSubDir; + DWORD dwTotalFileCount; + DWORD cbNamedEntry; + DWORD cbSubDir; + int nError; + + // Parse the directory header in order to retrieve the items + nError = ParseDirectoryHeader(&RootHeader, pbRootFile, pbFileEnd); + if(nError != ERROR_SUCCESS) + return 0; + + // Add the root directory's entries + dwTotalFileCount = RootHeader.dwEntries1 + RootHeader.dwEntries2 + RootHeader.dwEntries3; + + // Parse the named entries + for(DWORD i = 0; i < RootHeader.dwEntries3; i++) + { + // Get the this named entry + if((cbNamedEntry = VerifyNamedFileEntry(RootHeader.pbEntries3, pbFileEnd)) == 0) + return 0; + pNamedEntry = (PDIABLO3_NAMED_ENTRY)RootHeader.pbEntries3; + RootHeader.pbEntries3 += cbNamedEntry; + + // Load the subdirectory to memory + pbSubDir = LoadFileToMemory(hs, pNamedEntry->EncodingKey.Value, &cbSubDir); + if(pbSubDir != NULL) + { + // Count the files in the subdirectory + if(ParseDirectoryHeader(&DirHeader, pbSubDir, pbSubDir + cbSubDir) == ERROR_SUCCESS) + { + dwTotalFileCount += DirHeader.dwEntries1 + DirHeader.dwEntries2 + DirHeader.dwEntries3; + } + + // Free the subdirectory + CASC_FREE(pbSubDir); + } + } + + // Return the total number of entries + return dwTotalFileCount; +} + +static int ParseDirectoryFile( + TRootHandler_Diablo3 * pRootHandler, + LPBYTE pbDirFile, + LPBYTE pbFileEnd, + DWORD dwRootDirIndex) +{ + DIABLO3_DIR_HEADER DirHeader; + int nError; + + // Sanity checks + assert(pRootHandler->FileTable.ItemArray != NULL); + assert(pRootHandler->FileTable.ItemCount < pRootHandler->FileTable.ItemCountMax); + + // Parse the directory header in order to retrieve the items + nError = ParseDirectoryHeader(&DirHeader, pbDirFile, pbFileEnd); + if(nError != ERROR_SUCCESS) + return nError; + + // Process all DIABLO3_FILEID1_ENTRY entries. These are for files + // belonging to an asset group, without subitem number. + // Example: "SoundBank\SoundFile.smp" + // We skip inserting them to the name map, because the names are not known yet + if(DirHeader.pbEntries1 && DirHeader.dwEntries1) + { + assert(dwRootDirIndex != DIABLO3_INVALID_INDEX); + nError = ParseDirEntries_FileId1(pRootHandler, DirHeader.pbEntries1, DirHeader.dwEntries1, dwRootDirIndex); + if(nError != ERROR_SUCCESS) + return nError; + } + + // Parse all DIABLO3_FILEID2_ENTRY entries. These are for files + // belonging to an asset group, with a subitem number. + // Example: "SoundBank\SoundFile\0001.smp" + // We skip inserting them to the name map, because the names are not known yet + if(DirHeader.pbEntries2 && DirHeader.dwEntries2) + { + assert(dwRootDirIndex != DIABLO3_INVALID_INDEX); + nError = ParseDirEntries_FileId2(pRootHandler, DirHeader.pbEntries2, DirHeader.dwEntries2, dwRootDirIndex); + if(nError != ERROR_SUCCESS) + return nError; + } + + + // Parse all named entries. These are for files with arbitrary names, + // and they do not belong to an asset. + if(DirHeader.pbEntries3 && DirHeader.dwEntries3) + { + nError = ParseDirEntries_Named(pRootHandler, DirHeader.pbEntries3, pbFileEnd, DirHeader.dwEntries3, dwRootDirIndex); + if(nError != ERROR_SUCCESS) + return nError; + } + + // Give the directory to the caller + return nError; +} + +static int ParseCoreTOC( + TRootHandler_Diablo3 * pRootHandler, + PCASC_MAP pPackageMap, + LPBYTE pbCoreTocFile, + LPBYTE pbCoreTocEnd) +{ + PDIABLO3_CORE_TOC_HEADER pTocHeader; + PDIABLO3_CORE_TOC_ENTRY pSortedEntries; + PDIABLO3_CORE_TOC_ENTRY pTocEntry; + LPBYTE pbCoreTocNames; + DWORD dwFileIndexes = 0; + DWORD i; + + // Check the space for header + if((pbCoreTocFile + sizeof(DIABLO3_CORE_TOC_HEADER)) > pbCoreTocEnd) + return ERROR_FILE_CORRUPT; + pTocHeader = (PDIABLO3_CORE_TOC_HEADER)pbCoreTocFile; + pbCoreTocFile += sizeof(DIABLO3_CORE_TOC_HEADER); + + // Calculate space needed for allocation + for(i = 0; i < DIABLO3_MAX_ASSETS; i++) + { + // Get the first entry + pTocEntry = (PDIABLO3_CORE_TOC_ENTRY)(pbCoreTocFile + pTocHeader->EntryOffsets[i]); + + // Find out the entry with the maximum index + for(DWORD n = 0; n < pTocHeader->EntryCounts[i]; n++) + { + if(pTocEntry->FileIndex > dwFileIndexes) + dwFileIndexes = pTocEntry->FileIndex + 1; + pTocEntry++; + } + } + + // Allocate and populate the array of DIABLO3_CORE_TOC_ENTRYs + pSortedEntries = CASC_ALLOC(DIABLO3_CORE_TOC_ENTRY, dwFileIndexes); + if(pSortedEntries != NULL) + { + // Initialize all entries to invalid + memset(pSortedEntries, 0xFF, dwFileIndexes * sizeof(DIABLO3_CORE_TOC_ENTRY)); + + // Populate the linear array with the entries + for(i = 0; i < DIABLO3_MAX_ASSETS; i++) + { + // Set the pointers + pTocEntry = (PDIABLO3_CORE_TOC_ENTRY)(pbCoreTocFile + pTocHeader->EntryOffsets[i]); + pbCoreTocNames = (LPBYTE)(pTocEntry + pTocHeader->EntryCounts[i]); + + // Setup the entries + for(DWORD n = 0; n < pTocHeader->EntryCounts[i]; n++) + { + pSortedEntries[pTocEntry->FileIndex].AssetIndex = pTocEntry->AssetIndex; + pSortedEntries[pTocEntry->FileIndex].FileIndex = pTocEntry->FileIndex; + pSortedEntries[pTocEntry->FileIndex].NameOffset = (DWORD)(pbCoreTocNames - pbCoreTocFile) + pTocEntry->NameOffset; + pTocEntry++; + } + } + + // Now use the linear array to resolve the asset indexes and plain names + ResolveFullFileNames(pRootHandler, pSortedEntries, pPackageMap, pbCoreTocFile, dwFileIndexes); + CASC_FREE(pSortedEntries); + } + + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// Implementation of Diablo III root file + +static int D3Handler_Insert(TRootHandler_Diablo3 * pRootHandler, const char * szFileName, LPBYTE pbEncodingKey) +{ + ENCODING_KEY EncodingKey; + DWORD dwFileIndex; + + // Don't let the number of items to overflow + if(pRootHandler->FileTable.ItemCount >= pRootHandler->FileTable.ItemCountMax) + return ERROR_NOT_ENOUGH_MEMORY; + + // Insert the item + EncodingKey = *(PENCODING_KEY)pbEncodingKey; + dwFileIndex = InsertFileEntry(pRootHandler, + EncodingKey, + szFileName, + strlen(szFileName) + 1); + return (dwFileIndex != INVALID_FILE_INDEX) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY; +} + +static LPBYTE D3Handler_Search(TRootHandler_Diablo3 * pRootHandler, TCascSearch * pSearch, PDWORD /* PtrFileSize */, PDWORD /* PtrLocaleFlags */) +{ + PCASC_FILE_ENTRY pFileEntry; + const char * szSrcName = NULL; + + // Are we still inside the root directory range? + while(pSearch->IndexLevel1 < pRootHandler->FileTable.ItemCount) + { + // Get the n-th directory and the file name + pFileEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, pSearch->IndexLevel1); + szSrcName = (char *)Array_ItemAt(&pRootHandler->FileNames, pFileEntry->dwFileName); + + // This is either a full file name or an abbreviated name + if(pFileEntry->dwFlags & CASC_ENTRY_SHORT_NAME) + { + CreateFileName(pRootHandler, szSrcName, pSearch->szFileName); + } + else + { + strcpy(pSearch->szFileName, szSrcName); + } + + // Prepare for the next search + pSearch->IndexLevel1++; + return pFileEntry->EncodingKey.Value; + } + + // No more entries + return NULL; +} + +static void D3Handler_EndSearch(TRootHandler_Diablo3 * /* pRootHandler */, TCascSearch * /* pSearch */) +{ + // Do nothing +} + +static LPBYTE D3Handler_GetKey(TRootHandler_Diablo3 * pRootHandler, const char * szFileName) +{ + PCASC_FILE_ENTRY pFileEntry; + ULONGLONG FileNameHash = CalcFileNameHash(szFileName); + + // Find the file in the name table + pFileEntry = (PCASC_FILE_ENTRY)Map_FindObject(pRootHandler->pRootMap, &FileNameHash, NULL); + return (pFileEntry != NULL) ? pFileEntry->EncodingKey.Value : NULL; +} + +static void D3Handler_Close(TRootHandler_Diablo3 * pRootHandler) +{ + if(pRootHandler != NULL) + { + // Free the file map + Map_Free(pRootHandler->pRootMap); + + // Free the array of the file entries and file names + Array_Free(&pRootHandler->FileTable); + Array_Free(&pRootHandler->FileNames); + + // Free the root file itself + CASC_FREE(pRootHandler); + } +} + +/* +static void DumpRootFile(TDumpContext * dc, LPBYTE pbFileData, LPBYTE pbFileDataEnd) +{ + char szMD5Buffer[MD5_STRING_SIZE+1]; + DWORD dwSignature; + DWORD dwItemCount; + DWORD i; + + dwSignature = *(PDWORD)pbFileData; + if(dwSignature != CASC_DIABLO3_SUBDIR_SIGNATURE) + return; + pbFileData += sizeof(DWORD); + + // Dump items that contain EncodingKey + AssetId + dwItemCount = *(PDWORD)pbFileData; + pbFileData += sizeof(DWORD); + for(i = 0; i < dwItemCount; i++) + { + PCASC_DIABLO3_ASSET_ENTRY pEntry = (PCASC_DIABLO3_ASSET_ENTRY)pbFileData; + + if((pbFileData + sizeof(*pEntry)) > pbFileDataEnd) + return; + pbFileData += sizeof(*pEntry); + + dump_print(dc, "%s %08X\n", StringFromMD5(pEntry->EncodingKey, szMD5Buffer), pEntry->AssetId); + } + + // Terminate with two newlines + dump_print(dc, "\n"); + + // Dump items that contain EncodingKey + AssetId + FileNumber + dwItemCount = *(PDWORD)pbFileData; + pbFileData += sizeof(DWORD); + for(i = 0; i < dwItemCount; i++) + { + PCASC_DIABLO3_ASSET_ENTRY2 pEntry = (PCASC_DIABLO3_ASSET_ENTRY2)pbFileData; + + if((pbFileData + sizeof(*pEntry)) > pbFileDataEnd) + return; + pbFileData += sizeof(*pEntry); + + dump_print(dc, "%s %08X %08X\n", StringFromMD5((LPBYTE)pEntry->EncodingKey, szMD5Buffer), pEntry->AssetId, pEntry->FileNumber); + } + + // Terminate with two newlines + dump_print(dc, "\n"); + + // Dump items that contain EncodingKey + FileName + dwItemCount = *(PDWORD)pbFileData; + pbFileData += sizeof(DWORD); + for(i = 0; i < dwItemCount; i++) + { + PDIABLO3_NAMED_ENTRY pEntry = (PDIABLO3_NAMED_ENTRY)pbFileData; + DWORD dwEntrySize = VerifyNamedFileEntry(pbFileData, pbFileDataEnd); + + if((pbFileData + dwEntrySize) > pbFileDataEnd) + return; + pbFileData += dwEntrySize; + + dump_print(dc, "%s %s\n", StringFromMD5((LPBYTE)pEntry->EncodingKey, szMD5Buffer), pEntry->szFileName); + } + + dump_print(dc, "\n\n"); +} +*/ +//----------------------------------------------------------------------------- +// Public functions + +int RootHandler_CreateDiablo3(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile) +{ + TRootHandler_Diablo3 * pRootHandler; + PCASC_MAP pPackageMap = NULL; + LPBYTE pbRootFileEnd = pbRootFile + cbRootFile; + LPBYTE pbPackagesDat = NULL; + DWORD dwTotalFileCount; + DWORD cbPackagesDat = 0; + int nError; + + // Allocate the root handler object + hs->pRootHandler = pRootHandler = CASC_ALLOC(TRootHandler_Diablo3, 1); + if(pRootHandler == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill-in the handler functions + memset(pRootHandler, 0, sizeof(TRootHandler_Diablo3)); + pRootHandler->Insert = (ROOT_INSERT)D3Handler_Insert; + pRootHandler->Search = (ROOT_SEARCH)D3Handler_Search; + pRootHandler->EndSearch = (ROOT_ENDSEARCH)D3Handler_EndSearch; + pRootHandler->GetKey = (ROOT_GETKEY)D3Handler_GetKey; + pRootHandler->Close = (ROOT_CLOSE)D3Handler_Close; + + // Fill-in the flags + pRootHandler->dwRootFlags |= ROOT_FLAG_HAS_NAMES; + + // Scan the total number of files in the root directories + // Reserve space for extra files + dwTotalFileCount = ScanDirectoryFile(hs, pbRootFile, pbRootFileEnd); + if(dwTotalFileCount == 0) + return ERROR_FILE_CORRUPT; + dwTotalFileCount += CASC_EXTRA_FILES; + + // Allocate the global linear file table + // Note: This is about 18 MB of memory for Diablo III PTR build 30013 + nError = Array_Create(&pRootHandler->FileTable, CASC_FILE_ENTRY, dwTotalFileCount); + if(nError != ERROR_SUCCESS) + return nError; + + // Allocate global buffer for file names. + // The size of the buffer was taken from Diablo III build 30013 + nError = Array_Create(&pRootHandler->FileNames, char, 0x01000000); + if(nError != ERROR_SUCCESS) + return nError; + + // Create map of ROOT_ENTRY -> FileEntry + pRootHandler->pRootMap = Map_Create(dwTotalFileCount, sizeof(ULONGLONG), FIELD_OFFSET(CASC_FILE_ENTRY, FileNameHash)); + if(pRootHandler->pRootMap == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Parse the ROOT file and insert all entries in the file table + nError = ParseDirectoryFile(pRootHandler, pbRootFile, pbRootFileEnd, DIABLO3_INVALID_INDEX); + if(nError == ERROR_SUCCESS) + { + size_t dwRootEntries = pRootHandler->FileTable.ItemCount; + + // We expect the number of level-0 to be less than maximum + assert(dwRootEntries < DIABLO3_MAX_SUBDIRS); + + // Now parse the all root items and load them + for(size_t i = 0; i < dwRootEntries; i++) + { + PCASC_FILE_ENTRY pRootEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, i); + + // Load the entire file to memory + pbRootFile = LoadFileToMemory(hs, pRootEntry->EncodingKey.Value, &cbRootFile); + if(pbRootFile != NULL) + { + nError = ParseDirectoryFile(pRootHandler, pbRootFile, pbRootFile + cbRootFile, i); + CASC_FREE(pbRootFile); + } + } + } + + // Note: The file "Base\Data_D3\PC\Misc\Packages.dat" contains the names + // of the files (without level-0 and level-1 directory). We can use these + // names for supplying the missing extensions + if(nError == ERROR_SUCCESS) + { + // Load the entire file to memory + pbPackagesDat = LoadFileToMemory(hs, "Base\\Data_D3\\PC\\Misc\\Packages.dat", &cbPackagesDat); + if(pbPackagesDat != NULL) + { + pPackageMap = CreatePackageMap(pbPackagesDat, pbPackagesDat + cbPackagesDat); + } + } + + // Vast majorify of files at this moment don't have names. + // We can load the Base\CoreTOC.dat file in order + // to get directory asset indexes, file names and extensions + if(nError == ERROR_SUCCESS) + { + LPBYTE pbCoreTOC; + DWORD cbCoreTOC = 0; + + // Load the entire file to memory + pbCoreTOC = LoadFileToMemory(hs, "Base\\CoreTOC.dat", &cbCoreTOC); + if(pbCoreTOC != NULL) + { + ParseCoreTOC(pRootHandler, pPackageMap, pbCoreTOC, pbCoreTOC + cbCoreTOC); + CASC_FREE(pbCoreTOC); + } + } + + // Free the packages map + if(pPackageMap != NULL) + Map_Free(pPackageMap); + if(pbPackagesDat != NULL) + CASC_FREE(pbPackagesDat); + return nError; +} diff --git a/dep/CascLib/src/CascRootFile_Mndx.cpp b/dep/CascLib/src/CascRootFile_Mndx.cpp new file mode 100644 index 00000000000..bf17290a0af --- /dev/null +++ b/dep/CascLib/src/CascRootFile_Mndx.cpp @@ -0,0 +1,3602 @@ +/*****************************************************************************/ +/* CascMndxRoot.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 CascMndxRoot.cpp */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "CascLib.h" +#include "CascCommon.h" +#include "CascMndx.h" + +//----------------------------------------------------------------------------- +// Local defines + +#define CASC_MAR_SIGNATURE 0x0052414d // 'MAR\0' + +//----------------------------------------------------------------------------- +// Local structures + +typedef struct _FILE_MNDX_HEADER +{ + DWORD Signature; // 'MNDX' + DWORD HeaderVersion; // Must be <= 2 + DWORD FormatVersion; + +} FILE_MNDX_HEADER, *PFILE_MNDX_HEADER; + +typedef struct _FILE_MAR_INFO +{ + DWORD MarIndex; + DWORD MarDataSize; + DWORD MarDataSizeHi; + DWORD MarDataOffset; + DWORD MarDataOffsetHi; +} FILE_MAR_INFO, *PFILE_MAR_INFO; + +typedef struct _CASC_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 MndxEntriesOffset; + DWORD MndxEntriesTotal; // Total number of MNDX root entries + DWORD MndxEntriesValid; // Number of valid MNDX root entries + DWORD MndxEntrySize; // Size of one MNDX root entry + struct _MAR_FILE * pMarFile1; // File name list for the packages + struct _MAR_FILE * pMarFile2; // File name list for names stripped of package names + struct _MAR_FILE * pMarFile3; // File name list for complete names +// PCASC_ROOT_ENTRY_MNDX pMndxEntries; +// PCASC_ROOT_ENTRY_MNDX * ppValidEntries; + bool bRootFileLoaded; // true if the root info file was properly loaded + +} CASC_MNDX_INFO, *PCASC_MNDX_INFO; + +typedef struct _CASC_MNDX_PACKAGE +{ + char * szFileName; // Pointer to file name + size_t nLength; // Length of the file name + +} CASC_MNDX_PACKAGE, *PCASC_MNDX_PACKAGE; + +typedef struct _CASC_MNDX_PACKAGES +{ + char * szNameBuffer; // Pointer to the buffer for file names + size_t NameEntries; // Number of name entries in Names + size_t NameBufferUsed; // Number of bytes used in the name buffer + size_t NameBufferMax; // Total size of the name buffer + + CASC_MNDX_PACKAGE Packages[1]; // List of packages + +} CASC_MNDX_PACKAGES, *PCASC_MNDX_PACKAGES; + +// Root file entry for CASC storages with MNDX root file (Heroes of the Storm) +// Corresponds to the in-file structure +typedef struct _CASC_ROOT_ENTRY_MNDX +{ + DWORD Flags; // High 8 bits: Flags, low 24 bits: package index + BYTE EncodingKey[MD5_HASH_SIZE]; // Encoding key for the file + DWORD FileSize; // Uncompressed file size, in bytes + +} CASC_ROOT_ENTRY_MNDX, *PCASC_ROOT_ENTRY_MNDX; + +//----------------------------------------------------------------------------- +// Testing functions prototypes + +#if defined(_DEBUG) && defined(_X86_) && defined(CASCLIB_TEST) +extern "C" bool _cdecl sub_1958B00_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C); +void TestMndxRootFile(PCASC_MNDX_INFO pMndxInfo); +#endif + +//----------------------------------------------------------------------------- +// 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 +DWORD GetNumberOfSetBits(DWORD Value32) +{ + Value32 = ((Value32 >> 1) & 0x55555555) + (Value32 & 0x55555555); + Value32 = ((Value32 >> 2) & 0x33333333) + (Value32 & 0x33333333); + Value32 = ((Value32 >> 4) & 0x0F0F0F0F) + (Value32 & 0x0F0F0F0F); + + return (Value32 * 0x01010101); +} + +#define GetNumbrOfSetBits32(x) (GetNumberOfSetBits(x) >> 0x18) + +//----------------------------------------------------------------------------- +// Local functions - common + +static bool RootFileRead(LPBYTE pbFilePointer, LPBYTE pbFileEnd, void * pvBuffer, size_t dwBytesToRead) +{ + // False if the file pointer is beyond the end + if(pbFilePointer > pbFileEnd) + return false; + + // False if there is not enough bytes available + if((size_t)(pbFileEnd - pbFilePointer) < dwBytesToRead) + return false; + + memcpy(pvBuffer, pbFilePointer, dwBytesToRead); + return true; +} + +//----------------------------------------------------------------------------- +// Local functions - TMndxFindResult + +// HOTS: 01956EE0 +TMndxFindResult::TMndxFindResult() +{ + szSearchMask = NULL; + cchSearchMask = 0; + field_8 = 0; + szFoundPath = NULL; + cchFoundPath = 0; + FileNameIndex = 0; + pStruct40 = NULL; +} + +// HOTS: 01956F00 +TMndxFindResult::~TMndxFindResult() +{ + FreeStruct40(); +} + +// HOTS: 01956F30 +int TMndxFindResult::CreateStruct40() +{ + if(pStruct40 != NULL) + return ERROR_INVALID_PARAMETER; + + pStruct40 = new TStruct40(); + return (pStruct40 != NULL) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY; +} + +void TMndxFindResult::FreeStruct40() +{ + if(pStruct40 != NULL) + delete pStruct40; + pStruct40 = NULL; +} + +// HOTS: 01956E70 +int TMndxFindResult::SetSearchPath( + const char * szNewSearchMask, + size_t cchNewSearchMask) +{ + if(szSearchMask == NULL && cchSearchMask != 0) + return ERROR_INVALID_PARAMETER; + + if(pStruct40 != NULL) + pStruct40->SearchPhase = CASC_SEARCH_INITIALIZING; + + szSearchMask = szNewSearchMask; + cchSearchMask = cchNewSearchMask; + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// TByteStream functions + +// HOTS: 01959990 +TByteStream::TByteStream() +{ + pbByteData = NULL; + pvMappedFile = NULL; + cbByteData = 0; + field_C = 0; + hFile = 0; + hMap = 0; +} + +// HOTS: 19599F0 +void TByteStream::ExchangeWith(TByteStream & Target) +{ + TByteStream WorkBuff; + + WorkBuff = *this; + *this = Target; + Target = WorkBuff; +} + +// HOTS: 19599F0 +int TByteStream::GetBytes(DWORD cbByteCount, PARRAY_POINTER PtrArray) +{ + if(cbByteData < cbByteCount) + return ERROR_BAD_FORMAT; + + // Give the buffer to the caller + PtrArray->Bytes = pbByteData; + + // Move pointers + pbByteData += cbByteCount; + cbByteData -= cbByteCount; + return ERROR_SUCCESS; +} + +// HOTS: 1957190 +int TByteStream::GetArray_DWORDs(PARRAY_POINTER PtrArray, DWORD ItemCount) +{ + if(PtrArray == NULL && ItemCount != 0) + return ERROR_INVALID_PARAMETER; + if(ItemCount > CASC_MAX_ENTRIES(DWORD)) + return ERROR_NOT_ENOUGH_MEMORY; + + return GetBytes(ItemCount * 4, PtrArray); +} + +// HOTS: 19571E0 +int TByteStream::GetArray_Triplets(PARRAY_POINTER PtrArray, DWORD ItemCount) +{ + if(PtrArray == NULL && ItemCount != 0) + return ERROR_INVALID_PARAMETER; + if(ItemCount > CASC_MAX_ENTRIES(TRIPLET)) + return ERROR_NOT_ENOUGH_MEMORY; + + return GetBytes(ItemCount * sizeof(TRIPLET), PtrArray); +} + +// HOTS: 1957230 +int TByteStream::GetArray_BYTES(PARRAY_POINTER PtrArray, DWORD ItemCount) +{ + if(PtrArray == NULL && ItemCount != 0) + return ERROR_INVALID_PARAMETER; + if(ItemCount > CASC_MAX_ENTRIES(BYTE)) + return ERROR_NOT_ENOUGH_MEMORY; + + return GetBytes(ItemCount, PtrArray); +} + +// HOTS: 1957280 +int TByteStream::GetArray_NameTable(PARRAY_POINTER PtrArray, DWORD ItemCount) +{ + if(PtrArray == NULL && ItemCount != 0) + return ERROR_INVALID_PARAMETER; + if(ItemCount > CASC_MAX_ENTRIES(NAME_FRAG)) + return ERROR_NOT_ENOUGH_MEMORY; + + return GetBytes(ItemCount * sizeof(NAME_FRAG), PtrArray); +} + +// HOTS: 1959A60 +int TByteStream::SkipBytes(DWORD cbByteCount) +{ + ARRAY_POINTER Dummy; + + return GetBytes(cbByteCount, &Dummy); +} + +// HOTS: 1959AF0 +int TByteStream::SetByteBuffer(LPBYTE pbNewByteData, DWORD cbNewByteData) +{ + if(pbNewByteData != NULL || cbNewByteData == 0) + { + pbByteData = pbNewByteData; + cbByteData = cbNewByteData; + return ERROR_SUCCESS; + } + + return ERROR_INVALID_PARAMETER; +} + + +// HOTS: 1957160 +int TByteStream::GetValue_DWORD(DWORD & Value) +{ + ARRAY_POINTER Pointer; + int nError; + + nError = GetBytes(sizeof(DWORD), &Pointer); + if(nError != ERROR_SUCCESS) + return nError; + + Value = Pointer.Uint32s[0]; + return ERROR_SUCCESS; +} + +int TByteStream::GetValue_ItemCount(DWORD & NumberOfBytes, DWORD & ItemCount, DWORD ItemSize) +{ + ARRAY_POINTER Pointer; + ULONGLONG ByteCount; + int nError; + + // Verify if there is at least - 8 bytes + nError = GetBytes(sizeof(ULONGLONG), &Pointer); + if(nError != ERROR_SUCCESS) + return nError; + + // Extract the number of bytes + ByteCount = Pointer.Int64Ptr[0]; + if(ByteCount > 0xFFFFFFFF || (ByteCount % ItemSize) != 0) + return ERROR_BAD_FORMAT; + + // Give the result to the caller + NumberOfBytes = (DWORD)ByteCount; + ItemCount = (DWORD)(ByteCount / ItemSize); + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// TGenericArray functions + +TGenericArray::TGenericArray() +{ + DataBuffer.Bytes = NULL; + FirstValid.Bytes = NULL; + ArrayPointer.Bytes = NULL; + ItemCount = 0; + MaxItemCount = 0; + bIsValidArray = false; +} + +TGenericArray::~TGenericArray() +{ + if(DataBuffer.Bytes != NULL) + CASC_FREE(DataBuffer.Bytes); +} + +// HOTS: inlined +void TGenericArray::ExchangeWith(TGenericArray & Target) +{ + TGenericArray WorkBuff; + + WorkBuff = *this; + *this = Target; + Target = WorkBuff; +} + +// HOTS: Inlined +void TGenericArray::CopyFrom(TGenericArray & Source) +{ + if(DataBuffer.Bytes != NULL) + CASC_FREE(DataBuffer.Bytes); + *this = Source; +} + +// HOTS: 1957090 (SetDwordsValid) +// HOTS: 19570B0 (SetTripletsValid) +// HOTS: 19570D0 (? SetBitsValid ?) +// HOTS: 19570F0 (SetNameFragmentsValid) +int TGenericArray::SetArrayValid() +{ + if(bIsValidArray != 0) + return 1; + + bIsValidArray = true; + return ERROR_SUCCESS; +} + + +// HOTS: 19575A0 +void TGenericArray::SetMaxItems_CHARS(DWORD NewMaxItemCount) +{ + ARRAY_POINTER OldDataBuffer = DataBuffer; + ARRAY_POINTER NewDataBuffer; + + // Allocate new data buffer + NewDataBuffer.Chars = CASC_ALLOC(char, NewMaxItemCount); + if(NewDataBuffer.Chars != NULL) + { + // Copy the old items to the buffer + for(DWORD i = 0; i < ItemCount; i++) + { + NewDataBuffer.Chars[i] = FirstValid.Chars[i]; + } + } + + DataBuffer = NewDataBuffer; + FirstValid = NewDataBuffer; + ArrayPointer = NewDataBuffer; + MaxItemCount = NewMaxItemCount; + CASC_FREE(OldDataBuffer.Chars); +} + +// HOTS: 1957600 +void TGenericArray::SetMaxItems_PATH_STOP(DWORD NewMaxItemCount) +{ + ARRAY_POINTER OldDataBuffer = DataBuffer; + ARRAY_POINTER NewDataBuffer; + + // Allocate new data buffer + NewDataBuffer.PathStopPtr = CASC_ALLOC(PATH_STOP, NewMaxItemCount); + if(NewDataBuffer.PathStopPtr != NULL) + { + // Copy the old items to the buffer + for(DWORD i = 0; i < ItemCount; i++) + { + NewDataBuffer.PathStopPtr[i] = FirstValid.PathStopPtr[i]; + } + } + + DataBuffer = NewDataBuffer; + FirstValid = NewDataBuffer; + ArrayPointer = NewDataBuffer; + MaxItemCount = NewMaxItemCount; + CASC_FREE(OldDataBuffer.PathStopPtr); +} + +// HOTS: inline +void TGenericArray::InsertOneItem_CHAR(char NewItem) +{ + DWORD NewMaxItemCount; + DWORD NewItemCount; + + NewItemCount = ItemCount + 1; + if(NewItemCount > MaxItemCount) + { + NewMaxItemCount = NewItemCount; + + if(MaxItemCount > (NewItemCount / 2)) + { + if(MaxItemCount <= (CASC_MAX_ENTRIES(BYTE) / 2)) + NewMaxItemCount = MaxItemCount + MaxItemCount; + else + NewMaxItemCount = CASC_MAX_ENTRIES(BYTE); + } + + SetMaxItems_CHARS(NewMaxItemCount); + } + + // Put the character to the slot that has been reserved + FirstValid.Chars[ItemCount++] = NewItem; +} + +// HOTS: 1958330, inline +void TGenericArray::InsertOneItem_PATH_STOP(PATH_STOP & NewItem) +{ + DWORD NewMaxItemCount; + DWORD NewItemCount; + + NewItemCount = ItemCount + 1; + if(NewItemCount > MaxItemCount) + { + NewMaxItemCount = NewItemCount; + + if(MaxItemCount > (NewItemCount / 2)) + { + if(MaxItemCount <= (CASC_MAX_ENTRIES(PATH_STOP) / 2)) + NewMaxItemCount = MaxItemCount + MaxItemCount; + else + NewMaxItemCount = CASC_MAX_ENTRIES(PATH_STOP); + } + + SetMaxItems_PATH_STOP(NewMaxItemCount); + } + + // Put the structure to the slot that has been reserved + FirstValid.PathStopPtr[ItemCount++] = NewItem; +} + +// HOTS: 19583A0 +void TGenericArray::sub_19583A0(DWORD NewItemCount) +{ + DWORD OldMaxItemCount = MaxItemCount; + + if(NewItemCount > MaxItemCount) + { + DWORD NewMaxItemCount = NewItemCount; + + if(MaxItemCount > (NewItemCount / 2)) + { + if(MaxItemCount <= (CASC_MAX_ENTRIES(PATH_STOP) / 2)) + NewMaxItemCount = MaxItemCount + MaxItemCount; + else + NewMaxItemCount = CASC_MAX_ENTRIES(PATH_STOP); + } + + SetMaxItems_PATH_STOP(NewMaxItemCount); + } + + // Initialize the newly inserted items + for(DWORD i = OldMaxItemCount; i < NewItemCount; i++) + { + FirstValid.PathStopPtr[i].ItemIndex = 0; + FirstValid.PathStopPtr[i].field_4 = 0; + FirstValid.PathStopPtr[i].field_8 = 0; + FirstValid.PathStopPtr[i].field_C = 0xFFFFFFFF; + FirstValid.PathStopPtr[i].field_10 = 0xFFFFFFFF; + } + + ItemCount = NewItemCount; +} + +// HOTS: 1957440 +int TGenericArray::LoadDwordsArray(TByteStream & InStream) +{ + DWORD NumberOfBytes; + int nError; + + // Get and verify the number of items + nError = InStream.GetValue_ItemCount(NumberOfBytes, ItemCount, sizeof(DWORD)); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.GetArray_DWORDs(&ArrayPointer, ItemCount); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07); + if(nError != ERROR_SUCCESS) + return nError; + + return SetArrayValid(); +} + +// HOTS: 19574E0 +int TGenericArray::LoadTripletsArray(TByteStream & InStream) +{ + DWORD NumberOfBytes; + int nError; + + // Get and verify the number of items + nError = InStream.GetValue_ItemCount(NumberOfBytes, ItemCount, sizeof(TRIPLET)); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.GetArray_Triplets(&ArrayPointer, ItemCount); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07); + if(nError != ERROR_SUCCESS) + return nError; + + return SetArrayValid(); +} + +// HOTS: 1957690 +int TGenericArray::LoadByteArray(TByteStream & InStream) +{ + DWORD NumberOfBytes; + int nError; + + // Get and verify the number of items + nError = InStream.GetValue_ItemCount(NumberOfBytes, ItemCount, sizeof(BYTE)); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.GetArray_BYTES(&ArrayPointer, ItemCount); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07); + if(nError != ERROR_SUCCESS) + return nError; + + return SetArrayValid(); +} + +// HOTS: 1957700 +int TGenericArray::LoadFragmentInfos(TByteStream & InStream) +{ + DWORD NumberOfBytes; + int nError; + + // Get and verify the number of items + nError = InStream.GetValue_ItemCount(NumberOfBytes, ItemCount, sizeof(NAME_FRAG)); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.GetArray_NameTable(&ArrayPointer, ItemCount); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07); + if(nError != ERROR_SUCCESS) + return nError; + + return SetArrayValid(); +} + +// HOTS: 195A220 +int TGenericArray::LoadStrings(TByteStream & InStream) +{ + DWORD NumberOfBytes; + int nError; + + // Get and verify the number of items + nError = InStream.GetValue_ItemCount(NumberOfBytes, ItemCount, sizeof(char)); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.GetArray_BYTES(&ArrayPointer, ItemCount); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.SkipBytes((0 - (DWORD)NumberOfBytes) & 0x07); + if(nError != ERROR_SUCCESS) + return nError; + + return SetArrayValid(); +} + +// HOTS: 19581C0 +int TGenericArray::LoadDwordsArray_Copy(TByteStream & InStream) +{ + TGenericArray TempArray; + int nError; + + nError = TempArray.LoadDwordsArray(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + CopyFrom(TempArray); + return ERROR_SUCCESS; +} + +// HOTS: 1958250 +int TGenericArray::LoadTripletsArray_Copy(TByteStream & InStream) +{ + TGenericArray TempArray; + int nError; + + nError = TempArray.LoadTripletsArray(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + CopyFrom(TempArray); + return ERROR_SUCCESS; +} + +// HOTS: 1958420 +int TGenericArray::LoadBytes_Copy(TByteStream & InStream) +{ + TGenericArray TempArray; + int nError; + + nError = TempArray.LoadByteArray(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + CopyFrom(TempArray); + return 0; +} + +// HOTS: 19584F0 +int TGenericArray::LoadFragmentInfos_Copy(TByteStream & InStream) +{ + TGenericArray TempArray; + int nError; + + nError = TempArray.LoadFragmentInfos(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + CopyFrom(TempArray); + return ERROR_SUCCESS; +} + +// HOTS: 195A360 +int TGenericArray::LoadStringsWithCopy(TByteStream & InStream) +{ + TGenericArray TempArray; + int nError; + + nError = TempArray.LoadStrings(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + CopyFrom(TempArray); + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// TBitEntryArray functions + +TBitEntryArray::TBitEntryArray() +{ + BitsPerEntry = 0; + EntryBitMask = 0; + TotalEntries = 0; +} + +TBitEntryArray::~TBitEntryArray() +{} + +// HOTS: 01957D20 +void TBitEntryArray::ExchangeWith(TBitEntryArray & Target) +{ + TBitEntryArray WorkBuff; + + WorkBuff = *this; + *this = Target; + Target = WorkBuff; +} + +// HOTS: 1958580 +int TBitEntryArray::LoadFromStream(TByteStream & InStream) +{ + ARRAY_POINTER Pointer; + ULONGLONG Value = 0; + int nError; + + nError = LoadDwordsArray_Copy(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.GetBytes(sizeof(DWORD), &Pointer); + if(nError != ERROR_SUCCESS) + return nError; + + BitsPerEntry = Pointer.Uint32s[0]; + if(BitsPerEntry > 0x20) + return ERROR_BAD_FORMAT; + + nError = InStream.GetBytes(sizeof(DWORD), &Pointer); + if(nError != ERROR_SUCCESS) + return nError; + EntryBitMask = Pointer.Uint32s[0]; + + nError = InStream.GetBytes(sizeof(ULONGLONG), &Pointer); + if(nError == ERROR_SUCCESS) + Value = Pointer.Int64Ptr[0]; + if(Value > 0xFFFFFFFF) + return ERROR_BAD_FORMAT; + TotalEntries = (DWORD)Value; + + assert((BitsPerEntry * TotalEntries) / 32 <= ItemCount); + return ERROR_SUCCESS; +} + +// HOTS: 1959300 +int TBitEntryArray::LoadFromStream_Exchange(TByteStream & InStream) +{ + TBitEntryArray TempArray; + int nError; + + nError = TempArray.LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + ExchangeWith(TempArray); + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// TStruct40 functions + +TStruct40::TStruct40() +{ + ItemIndex = 0; + CharIndex = 0; + ItemCount = 0; + SearchPhase = CASC_SEARCH_INITIALIZING; +} + +// HOTS: 19586B0 +void TStruct40::InitSearchBuffers() +{ + DWORD NewMaxItemCount; + + array_00.ItemCount = 0; + + // HOTS: 19586BD + if(array_00.MaxItemCount < 0x40) + { + // HOTS: 19586C2 + NewMaxItemCount = 0x40; + + if(array_00.MaxItemCount > 0x20) + { + if(array_00.MaxItemCount <= 0x7FFFFFFF) + NewMaxItemCount = array_00.MaxItemCount + array_00.MaxItemCount; + else + NewMaxItemCount = CASC_MAX_ENTRIES(BYTE); + } + + array_00.SetMaxItems_CHARS(NewMaxItemCount); + } + + // HOTS: 19586E1 + // Set the new item count + PathStops.sub_19583A0(0); + + if(PathStops.MaxItemCount < 4) + { + // HOTS: 19586F2 + NewMaxItemCount = 4; + + // HOTS: 19586EA + if(PathStops.MaxItemCount > 2) + { + if(PathStops.MaxItemCount <= 0x6666666) + NewMaxItemCount = PathStops.MaxItemCount + PathStops.MaxItemCount; + else + NewMaxItemCount = CASC_MAX_ENTRIES(PATH_STOP); + } + + // HOTS: 195870B + PathStops.SetMaxItems_PATH_STOP(NewMaxItemCount); + } + + ItemIndex = 0; + CharIndex = 0; + ItemCount = 0; + SearchPhase = CASC_SEARCH_SEARCHING; +} + +//----------------------------------------------------------------------------- +// TSparseArray functions + +TSparseArray::TSparseArray() +{ + TotalItemCount = 0; + ValidItemCount = 0; +} + +// HOTS: 1957DA0 +void TSparseArray::ExchangeWith(TSparseArray & Target) +{ + TSparseArray WorkBuff; + + WorkBuff = *this; + *this = Target; + Target = WorkBuff; +} + +// HOTS: 1958630 +int TSparseArray::LoadFromStream(TByteStream & InStream) +{ + ARRAY_POINTER Pointer; + int nError; + + nError = ItemBits.LoadDwordsArray_Copy(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.GetBytes(sizeof(DWORD), &Pointer); + if(nError != ERROR_SUCCESS) + return nError; + TotalItemCount = Pointer.Uint32s[0]; + + nError = InStream.GetBytes(sizeof(DWORD), &Pointer); + if(nError != ERROR_SUCCESS) + return nError; + ValidItemCount = Pointer.Uint32s[0]; + + if(ValidItemCount > TotalItemCount) + return ERROR_FILE_CORRUPT; + + nError = BaseValues.LoadTripletsArray_Copy(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + nError = ArrayDwords_38.LoadDwordsArray_Copy(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + nError = ArrayDwords_50.LoadDwordsArray_Copy(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + return ERROR_SUCCESS; +} + +// HOTS: 1959380 +int TSparseArray::LoadFromStream_Exchange(TByteStream & InStream) +{ + TSparseArray NewStruct68; + int nError; + + nError = NewStruct68.LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + ExchangeWith(NewStruct68); + return ERROR_SUCCESS; +} + +// HOTS: 1959B60 +DWORD TSparseArray::GetItemValue(DWORD ItemIndex) +{ + PTRIPLET pTriplet; + DWORD DwordIndex; + DWORD BaseValue; + DWORD BitMask; + + // + // Divide the low-8-bits index to four parts: + // + // |-----------------------|---|------------| + // | A (23 bits) | B | C | + // |-----------------------|---|------------| + // + // A (23-bits): Index to the table (60 bits per entry) + // + // Layout of the table entry: + // |--------------------------------|-------|--------|--------|---------|---------|---------|---------|-----| + // | Base Value | val[0]| val[1] | val[2] | val[3] | val[4] | val[5] | val[6] | - | + // | 32 bits | 7 bits| 8 bits | 8 bits | 9 bits | 9 bits | 9 bits | 9 bits |5bits| + // |--------------------------------|-------|--------|--------|---------|---------|---------|---------|-----| + // + // B (3 bits) : Index of the variable-bit value in the array (val[#], see above) + // + // C (32 bits): Number of bits to be checked (up to 0x3F bits). + // Number of set bits is then added to the values obtained from A and B + + // Upper 23 bits contain index to the table + pTriplet = BaseValues.TripletArray + (ItemIndex >> 0x09); + BaseValue = pTriplet->BaseValue; + + // Next 3 bits contain the index to the VBR + switch(((ItemIndex >> 0x06) & 0x07) - 1) + { + case 0: // Add the 1st value (7 bits) + BaseValue += (pTriplet->Value2 & 0x7F); + break; + + case 1: // Add the 2nd value (8 bits) + BaseValue += (pTriplet->Value2 >> 0x07) & 0xFF; + break; + + case 2: // Add the 3rd value (8 bits) + BaseValue += (pTriplet->Value2 >> 0x0F) & 0xFF; + break; + + case 3: // Add the 4th value (9 bits) + BaseValue += (pTriplet->Value2 >> 0x17); + break; + + case 4: // Add the 5th value (9 bits) + BaseValue += (pTriplet->Value3 & 0x1FF); + break; + + case 5: // Add the 6th value (9 bits) + BaseValue += (pTriplet->Value3 >> 0x09) & 0x1FF; + break; + + case 6: // Add the 7th value (9 bits) + BaseValue += (pTriplet->Value3 >> 0x12) & 0x1FF; + break; + } + + // + // Take the upper 27 bits as an index to DWORD array, take lower 5 bits + // as number of bits to mask. Then calculate number of set bits in the value + // masked value. + // + + // Get the index into the array of DWORDs + DwordIndex = (ItemIndex >> 0x05); + + // Add number of set bits in the masked value up to 0x3F bits + if(ItemIndex & 0x20) + BaseValue += GetNumbrOfSetBits32(ItemBits.Uint32Array[DwordIndex - 1]); + + BitMask = (1 << (ItemIndex & 0x1F)) - 1; + return BaseValue + GetNumbrOfSetBits32(ItemBits.Uint32Array[DwordIndex] & BitMask); +} + +//----------------------------------------------------------------------------- +// TNameIndexStruct functions + +// HOTS: 0195A290 +TNameIndexStruct::TNameIndexStruct() +{} + +// HOTS: inlined +TNameIndexStruct::~TNameIndexStruct() +{} + +// HOTS: 195A180 +bool TNameIndexStruct::CheckNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs) +{ + TStruct40 * pStruct40 = pStruct1C->pStruct40; + const char * szPathFragment; + const char * szSearchMask; + + if(!Struct68.TotalItemCount) + { + // Get the offset of the fragment to compare. For convenience with pStruct40->CharIndex, + // subtract the CharIndex from the fragment offset + szPathFragment = (NameFragments.CharArray + dwFragOffs - pStruct40->CharIndex); + szSearchMask = pStruct1C->szSearchMask; + + // Keep searching as long as the name matches with the fragment + while(szPathFragment[pStruct40->CharIndex] == szSearchMask[pStruct40->CharIndex]) + { + // Move to the next character + pStruct40->CharIndex++; + + // Is it the end of the fragment or end of the path? + if(szPathFragment[pStruct40->CharIndex] == 0) + return true; + if(pStruct40->CharIndex >= pStruct1C->cchSearchMask) + return false; + } + + return false; + } + else + { + // Get the offset of the fragment to compare. + szPathFragment = (const char *)(NameFragments.CharArray); + szSearchMask = pStruct1C->szSearchMask; + + // Keep searching as long as the name matches with the fragment + while(szPathFragment[dwFragOffs] == szSearchMask[pStruct40->CharIndex]) + { + // Move to the next character + pStruct40->CharIndex++; + + // Is it the end of the fragment or end of the path? + if(Struct68.IsItemPresent(dwFragOffs++)) + return true; + if(dwFragOffs >= pStruct1C->cchSearchMask) + return false; + } + + return false; + } +} + +// HOTS: 195A570 +bool TNameIndexStruct::CheckAndCopyNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs) +{ + TStruct40 * pStruct40 = pStruct1C->pStruct40; + const char * szPathFragment; + const char * szSearchMask; + + if(!Struct68.TotalItemCount) + { + // Get the offset of the fragment to compare. For convenience with pStruct40->CharIndex, + // subtract the CharIndex from the fragment offset + szPathFragment = (const char *)(NameFragments.CharArray + dwFragOffs - pStruct40->CharIndex); + szSearchMask = pStruct1C->szSearchMask; + + // Keep copying as long as we don't reach the end of the search mask + while(pStruct40->CharIndex < pStruct1C->cchSearchMask) + { + // HOTS: 195A5A0 + if(szPathFragment[pStruct40->CharIndex] != szSearchMask[pStruct40->CharIndex]) + return false; + + // HOTS: 195A5B7 + pStruct40->array_00.InsertOneItem_CHAR(szPathFragment[pStruct40->CharIndex]); + pStruct40->CharIndex++; + + if(szPathFragment[pStruct40->CharIndex] == 0) + return true; + } + + // Fixup the address of the fragment + szPathFragment += pStruct40->CharIndex; + + // HOTS: 195A660 + // Now we need to copy the rest of the fragment + while(szPathFragment[0] != 0) + { + pStruct40->array_00.InsertOneItem_CHAR(szPathFragment[0]); + szPathFragment++; + } + } + else + { + // Get the offset of the fragment to compare + // HOTS: 195A6B7 + szPathFragment = NameFragments.CharArray; + szSearchMask = pStruct1C->szSearchMask; + + // Keep copying as long as we don't reach the end of the search mask + while(dwFragOffs < pStruct1C->cchSearchMask) + { + if(szPathFragment[dwFragOffs] != szSearchMask[pStruct40->CharIndex]) + return false; + + pStruct40->array_00.InsertOneItem_CHAR(szPathFragment[dwFragOffs]); + pStruct40->CharIndex++; + + // Keep going as long as the given bit is not set + if(Struct68.IsItemPresent(dwFragOffs++)) + return true; + } + + // Fixup the address of the fragment + szPathFragment += dwFragOffs; + + // Now we need to copy the rest of the fragment + while(Struct68.IsItemPresent(dwFragOffs++) == 0) + { + // HOTS: 195A7A6 + pStruct40->array_00.InsertOneItem_CHAR(szPathFragment[0]); + szPathFragment++; + } + } + + return true; +} + +// HOTS: 195A3F0 +void TNameIndexStruct::CopyNameFragment(TMndxFindResult * pStruct1C, DWORD dwFragOffs) +{ + TStruct40 * pStruct40 = pStruct1C->pStruct40; + const char * szPathFragment; + + // HOTS: 195A3FA + if(!Struct68.TotalItemCount) + { + // HOTS: 195A40C + szPathFragment = NameFragments.CharArray + dwFragOffs; + while(szPathFragment[0] != 0) + { + // Insert the character to the path being built + pStruct40->array_00.InsertOneItem_CHAR(*szPathFragment++); + } + } + else + { + // HOTS: 195A4B3 + for(;;) + { + // Insert the character to the path being built + pStruct40->array_00.InsertOneItem_CHAR(NameFragments.CharArray[dwFragOffs]); + + // Keep going as long as the given bit is not set + if(Struct68.IsItemPresent(dwFragOffs++)) + break; + } + } +} + +// HOTS: 0195A300 +void TNameIndexStruct::ExchangeWith(TNameIndexStruct & Target) +{ + TNameIndexStruct WorkBuff; + + WorkBuff = *this; + *this = Target; + Target = WorkBuff; +} + +// HOTS: 0195A820 +int TNameIndexStruct::LoadFromStream(TByteStream & InStream) +{ + int nError; + + nError = NameFragments.LoadStringsWithCopy(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + return Struct68.LoadFromStream_Exchange(InStream); +} + +// HOTS: 195A850 +int TNameIndexStruct::LoadFromStream_Exchange(TByteStream & InStream) +{ + TNameIndexStruct TempIndexStruct; + int nError; + + nError = TempIndexStruct.LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + ExchangeWith(TempIndexStruct); + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// TStruct10 functions + +TStruct10::TStruct10() +{ + field_0 = 0x03; + field_4 = 0x200; + field_8 = 0x1000; + field_C = 0x20000; +} + +// HOTS: inline +void TStruct10::CopyFrom(TStruct10 & Target) +{ + field_0 = Target.field_0; + field_4 = Target.field_4; + field_8 = Target.field_8; + field_C = Target.field_C; +} + +// HOTS: 1956FD0 +int TStruct10::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 TStruct10::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 TStruct10::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 TStruct10::sub_1957800(DWORD dwBitMask) +{ + TStruct10 TempStruct; + int nError; + + nError = TempStruct.sub_19572E0(dwBitMask); + if(nError != ERROR_SUCCESS) + return nError; + + CopyFrom(TempStruct); + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// TFileNameDatabase functions + +// HOTS: 01958730 +TFileNameDatabase::TFileNameDatabase() +{ + NameFragIndexMask = 0; + field_214 = 0; +} + +// HOTS: inlined +void TFileNameDatabase::ExchangeWith(TFileNameDatabase & Target) +{ + TFileNameDatabasePtr TempPtr; + DWORD dwTemp; + + Struct68_00.ExchangeWith(Target.Struct68_00); + FileNameIndexes.ExchangeWith(Target.FileNameIndexes); + Struct68_D0.ExchangeWith(Target.Struct68_D0); + + FrgmDist_LoBits.ExchangeWith(Target.FrgmDist_LoBits); + FrgmDist_HiBits.ExchangeWith(Target.FrgmDist_HiBits); + + IndexStruct_174.ExchangeWith(Target.IndexStruct_174); + + TempPtr = NextDB; + NextDB = Target.NextDB; + Target.NextDB = TempPtr; + + NameFragTable.ExchangeWith(Target.NameFragTable); + + dwTemp = NameFragIndexMask; + NameFragIndexMask = Target.NameFragIndexMask; + Target.NameFragIndexMask = dwTemp; + + dwTemp = field_214; + field_214 = Target.field_214; + Target.field_214 = dwTemp; + + Struct10.CopyFrom(Target.Struct10); +} + +// HOTS: 1959CB0 +DWORD TFileNameDatabase::sub_1959CB0(DWORD dwItemIndex) +{ + PTRIPLET pTriplet; + DWORD dwKeyShifted = (dwItemIndex >> 9); + DWORD eax, ebx, ecx, edx, esi, edi; + + // If lower 9 is zero + edx = dwItemIndex; + if((edx & 0x1FF) == 0) + return Struct68_00.ArrayDwords_38.Uint32Array[dwKeyShifted]; + + eax = Struct68_00.ArrayDwords_38.Uint32Array[dwKeyShifted] >> 9; + esi = (Struct68_00.ArrayDwords_38.Uint32Array[dwKeyShifted + 1] + 0x1FF) >> 9; + dwItemIndex = esi; + + if((eax + 0x0A) >= esi) + { + // HOTS: 1959CF7 + pTriplet = Struct68_00.BaseValues.TripletArray + eax + 1; + edi = (eax << 0x09); + ebx = edi - pTriplet->BaseValue + 0x200; + while(edx >= ebx) + { + // HOTS: 1959D14 + edi += 0x200; + pTriplet++; + + ebx = edi - pTriplet->BaseValue + 0x200; + eax++; + } + } + else + { + // HOTS: 1959D2E + while((eax + 1) < esi) + { + // HOTS: 1959D38 + // ecx = Struct68_00.BaseValues.TripletArray; + esi = (esi + eax) >> 1; + ebx = (esi << 0x09) - Struct68_00.BaseValues.TripletArray[esi].BaseValue; + if(edx < ebx) + { + // HOTS: 01959D4B + dwItemIndex = esi; + } + else + { + // HOTS: 1959D50 + eax = esi; + esi = dwItemIndex; + } + } + } + + // HOTS: 1959D5F + pTriplet = Struct68_00.BaseValues.TripletArray + eax; + edx += pTriplet->BaseValue - (eax << 0x09); + edi = (eax << 4); + + eax = pTriplet->Value2; + ecx = (eax >> 0x17); + ebx = 0x100 - ecx; + if(edx < ebx) + { + // HOTS: 1959D8C + ecx = ((eax >> 0x07) & 0xFF); + esi = 0x80 - ecx; + if(edx < esi) + { + // HOTS: 01959DA2 + eax = eax & 0x7F; + ecx = 0x40 - eax; + if(edx >= ecx) + { + // HOTS: 01959DB7 + edi += 2; + edx = edx + eax - 0x40; + } + } + else + { + // HOTS: 1959DC0 + eax = (eax >> 0x0F) & 0xFF; + esi = 0xC0 - eax; + if(edx < esi) + { + // HOTS: 1959DD3 + edi += 4; + edx = edx + ecx - 0x80; + } + else + { + // HOTS: 1959DD3 + edi += 6; + edx = edx + eax - 0xC0; + } + } + } + else + { + // HOTS: 1959DE8 + esi = pTriplet->Value3; + eax = ((esi >> 0x09) & 0x1FF); + ebx = 0x180 - eax; + if(edx < ebx) + { + // HOTS: 01959E00 + esi = esi & 0x1FF; + eax = (0x140 - esi); + if(edx < eax) + { + // HOTS: 1959E11 + edi = edi + 8; + edx = edx + ecx - 0x100; + } + else + { + // HOTS: 1959E1D + edi = edi + 0x0A; + edx = edx + esi - 0x140; + } + } + else + { + // HOTS: 1959E29 + esi = (esi >> 0x12) & 0x1FF; + ecx = (0x1C0 - esi); + if(edx < ecx) + { + // HOTS: 1959E3D + edi = edi + 0x0C; + edx = edx + eax - 0x180; + } + else + { + // HOTS: 1959E49 + edi = edi + 0x0E; + edx = edx + esi - 0x1C0; + } + } + } + + // HOTS: 1959E53: + // Calculate the number of bits set in the value of "ecx" + ecx = ~Struct68_00.ItemBits.Uint32Array[edi]; + eax = GetNumberOfSetBits(ecx); + esi = eax >> 0x18; + + if(edx >= esi) + { + // HOTS: 1959ea4 + ecx = ~Struct68_00.ItemBits.Uint32Array[++edi]; + edx = edx - esi; + eax = GetNumberOfSetBits(ecx); + } + + // HOTS: 1959eea + // ESI gets the number of set bits in the lower 16 bits of ECX + esi = (eax >> 0x08) & 0xFF; + edi = edi << 0x05; + if(edx < esi) + { + // HOTS: 1959EFC + eax = eax & 0xFF; + if(edx >= eax) + { + // HOTS: 1959F05 + ecx >>= 0x08; + edi += 0x08; + edx -= eax; + } + } + else + { + // HOTS: 1959F0D + eax = (eax >> 0x10) & 0xFF; + if(edx < eax) + { + // HOTS: 1959F19 + ecx >>= 0x10; + edi += 0x10; + edx -= esi; + } + else + { + // HOTS: 1959F23 + ecx >>= 0x18; + edi += 0x18; + edx -= eax; + } + } + + // HOTS: 1959f2b + edx = edx << 0x08; + ecx = ecx & 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((ecx + edx) < sizeof(table_1BA1818)); + return table_1BA1818[ecx + edx] + edi; +} + +DWORD TFileNameDatabase::sub_1959F50(DWORD arg_0) +{ + PTRIPLET pTriplet; + PDWORD ItemArray; + DWORD eax, ebx, ecx, edx, esi, edi; + + edx = arg_0; + eax = arg_0 >> 0x09; + if((arg_0 & 0x1FF) == 0) + return Struct68_00.ArrayDwords_50.Uint32Array[eax]; + + ItemArray = Struct68_00.ArrayDwords_50.Uint32Array + eax; + eax = (ItemArray[0] >> 0x09); + edi = (ItemArray[1] + 0x1FF) >> 0x09; + + if((eax + 0x0A) > edi) + { + // HOTS: 01959F94 + pTriplet = Struct68_00.BaseValues.TripletArray + eax + 1; + while(edx >= pTriplet->BaseValue) + { + // HOTS: 1959FA3 + pTriplet++; + eax++; + } + } + else + { + // Binary search + // HOTS: 1959FAD + if((eax + 1) < edi) + { + // HOTS: 1959FB4 + esi = (edi + eax) >> 1; + if(edx < Struct68_00.BaseValues.TripletArray[esi].BaseValue) + { + // HOTS: 1959FC4 + edi = esi; + } + else + { + // HOTS: 1959FC8 + eax = esi; + } + } + } + + // HOTS: 1959FD4 + pTriplet = Struct68_00.BaseValues.TripletArray + eax; + edx = edx - pTriplet->BaseValue; + edi = eax << 0x04; + eax = pTriplet->Value2; + ebx = (eax >> 0x17); + if(edx < ebx) + { + // HOTS: 1959FF1 + esi = (eax >> 0x07) & 0xFF; + if(edx < esi) + { + // HOTS: 0195A000 + eax = eax & 0x7F; + if(edx >= eax) + { + // HOTS: 195A007 + edi = edi + 2; + edx = edx - eax; + } + } + else + { + // HOTS: 195A00E + eax = (eax >> 0x0F) & 0xFF; + if(edx < eax) + { + // HOTS: 195A01A + edi += 4; + edx = edx - esi; + } + else + { + // HOTS: 195A01F + edi += 6; + edx = edx - eax; + } + } + } + else + { + // HOTS: 195A026 + esi = pTriplet->Value3; + eax = (pTriplet->Value3 >> 0x09) & 0x1FF; + if(edx < eax) + { + // HOTS: 195A037 + esi = esi & 0x1FF; + if(edx < esi) + { + // HOTS: 195A041 + edi = edi + 8; + edx = edx - ebx; + } + else + { + // HOTS: 195A048 + edi = edi + 0x0A; + edx = edx - esi; + } + } + else + { + // HOTS: 195A04D + esi = (esi >> 0x12) & 0x1FF; + if(edx < esi) + { + // HOTS: 195A05A + edi = edi + 0x0C; + edx = edx - eax; + } + else + { + // HOTS: 195A061 + edi = edi + 0x0E; + edx = edx - esi; + } + } + } + + // HOTS: 195A066 + esi = Struct68_00.ItemBits.Uint32Array[edi]; + eax = GetNumberOfSetBits(esi); + ecx = eax >> 0x18; + + if(edx >= ecx) + { + // HOTS: 195A0B2 + esi = Struct68_00.ItemBits.Uint32Array[++edi]; + edx = edx - ecx; + eax = GetNumberOfSetBits(esi); + } + + // HOTS: 195A0F6 + ecx = (eax >> 0x08) & 0xFF; + + edi = (edi << 0x05); + if(edx < ecx) + { + // HOTS: 195A111 + eax = eax & 0xFF; + if(edx >= eax) + { + // HOTS: 195A111 + edi = edi + 0x08; + esi = esi >> 0x08; + edx = edx - eax; + } + } + else + { + // HOTS: 195A119 + eax = (eax >> 0x10) & 0xFF; + if(edx < eax) + { + // HOTS: 195A125 + esi = esi >> 0x10; + edi = edi + 0x10; + edx = edx - ecx; + } + else + { + // HOTS: 195A12F + esi = esi >> 0x18; + edi = edi + 0x18; + edx = edx - eax; + } + } + + esi = esi & 0xFF; + edx = edx << 0x08; + + // BUGBUG: Potential buffer overflow + // Happens in Heroes of the Storm when arg_0 == 0x5B + assert((esi + edx) < sizeof(table_1BA1818)); + return table_1BA1818[esi + edx] + edi; +} + +// HOTS: 1957970 +bool TFileNameDatabase::CheckNextPathFragment(TMndxFindResult * pStruct1C) +{ + TStruct40 * pStruct40 = pStruct1C->pStruct40; + LPBYTE pbPathName = (LPBYTE)pStruct1C->szSearchMask; + DWORD CollisionIndex; + DWORD NameFragIndex; + DWORD SaveCharIndex; + DWORD HiBitsIndex; + DWORD FragOffs; + + // Calculate index of the next name fragment in the name fragment table + NameFragIndex = ((pStruct40->ItemIndex << 0x05) ^ pStruct40->ItemIndex ^ pbPathName[pStruct40->CharIndex]) & NameFragIndexMask; + + // Does the hash value match? + if(NameFragTable.NameFragArray[NameFragIndex].ItemIndex == pStruct40->ItemIndex) + { + // Check if there is single character match + if(IS_SINGLE_CHAR_MATCH(NameFragTable, NameFragIndex)) + { + pStruct40->ItemIndex = NameFragTable.NameFragArray[NameFragIndex].NextIndex; + pStruct40->CharIndex++; + return true; + } + + // Check if there is a name fragment match + if(NextDB.pDB != NULL) + { + if(!NextDB.pDB->sub_1957B80(pStruct1C, NameFragTable.NameFragArray[NameFragIndex].FragOffs)) + return false; + } + else + { + if(!IndexStruct_174.CheckNameFragment(pStruct1C, NameFragTable.NameFragArray[NameFragIndex].FragOffs)) + return false; + } + + pStruct40->ItemIndex = NameFragTable.NameFragArray[NameFragIndex].NextIndex; + return true; + } + + // + // Conflict: Multiple hashes give the same table index + // + + // HOTS: 1957A0E + CollisionIndex = sub_1959CB0(pStruct40->ItemIndex) + 1; + if(!Struct68_00.IsItemPresent(CollisionIndex)) + return false; + + pStruct40->ItemIndex = (CollisionIndex - pStruct40->ItemIndex - 1); + HiBitsIndex = 0xFFFFFFFF; + +// CascDumpSparseArray("E:\\casc-array-68.txt", &FileNameIndexes); +// CascDumpSparseArray("E:\\casc-array-D0.txt", &Struct68_D0); + + // HOTS: 1957A41: + do + { + // HOTS: 1957A41 + // Check if the low 8 bits if the fragment offset contain a single character + // or an offset to a name fragment + if(Struct68_D0.IsItemPresent(pStruct40->ItemIndex)) + { + if(HiBitsIndex == 0xFFFFFFFF) + { + // HOTS: 1957A6C + HiBitsIndex = Struct68_D0.GetItemValue(pStruct40->ItemIndex); + } + else + { + // HOTS: 1957A7F + HiBitsIndex++; + } + + // HOTS: 1957A83 + SaveCharIndex = pStruct40->CharIndex; + + // Get the name fragment offset as combined value from lower 8 bits and upper bits + FragOffs = GetNameFragmentOffsetEx(pStruct40->ItemIndex, HiBitsIndex); + + // Compare the string with the fragment name database + if(NextDB.pDB != NULL) + { + // HOTS: 1957AEC + if(NextDB.pDB->sub_1957B80(pStruct1C, FragOffs)) + return true; + } + else + { + // HOTS: 1957AF7 + if(IndexStruct_174.CheckNameFragment(pStruct1C, FragOffs)) + return true; + } + + // HOTS: 1957B0E + // If there was partial match with the fragment, end the search + if(pStruct40->CharIndex != SaveCharIndex) + return false; + } + else + { + // HOTS: 1957B1C + if(FrgmDist_LoBits.ByteArray[pStruct40->ItemIndex] == pStruct1C->szSearchMask[pStruct40->CharIndex]) + { + pStruct40->CharIndex++; + return true; + } + } + + // HOTS: 1957B32 + pStruct40->ItemIndex++; + CollisionIndex++; + } + while(Struct68_00.IsItemPresent(CollisionIndex)); + return false; +} + +// HOTS: 1957B80 +bool TFileNameDatabase::sub_1957B80(TMndxFindResult * pStruct1C, DWORD arg_4) +{ + TStruct40 * pStruct40 = pStruct1C->pStruct40; + PNAME_FRAG pNameEntry; + DWORD FragOffs; + DWORD eax, edi; + + edi = arg_4; + + // HOTS: 1957B95 + for(;;) + { + pNameEntry = NameFragTable.NameFragArray + (edi & NameFragIndexMask); + if(edi == pNameEntry->NextIndex) + { + // HOTS: 01957BB4 + if((pNameEntry->FragOffs & 0xFFFFFF00) != 0xFFFFFF00) + { + // HOTS: 1957BC7 + if(NextDB.pDB != NULL) + { + // HOTS: 1957BD3 + if(!NextDB.pDB->sub_1957B80(pStruct1C, pNameEntry->FragOffs)) + return false; + } + else + { + // HOTS: 1957BE0 + if(!IndexStruct_174.CheckNameFragment(pStruct1C, pNameEntry->FragOffs)) + return false; + } + } + else + { + // HOTS: 1957BEE + if(pStruct1C->szSearchMask[pStruct40->CharIndex] != (char)pNameEntry->FragOffs) + return false; + pStruct40->CharIndex++; + } + + // HOTS: 1957C05 + edi = pNameEntry->ItemIndex; + if(edi == 0) + return true; + + if(pStruct40->CharIndex >= pStruct1C->cchSearchMask) + return false; + } + else + { + // HOTS: 1957C30 + if(Struct68_D0.IsItemPresent(edi)) + { + // HOTS: 1957C4C + if(NextDB.pDB != NULL) + { + // HOTS: 1957C58 + FragOffs = GetNameFragmentOffset(edi); + if(!NextDB.pDB->sub_1957B80(pStruct1C, FragOffs)) + return false; + } + else + { + // HOTS: 1957350 + FragOffs = GetNameFragmentOffset(edi); + if(!IndexStruct_174.CheckNameFragment(pStruct1C, FragOffs)) + return false; + } + } + else + { + // HOTS: 1957C8E + if(FrgmDist_LoBits.ByteArray[edi] != pStruct1C->szSearchMask[pStruct40->CharIndex]) + return false; + + pStruct40->CharIndex++; + } + + // HOTS: 1957CB2 + if(edi <= field_214) + return true; + + if(pStruct40->CharIndex >= pStruct1C->cchSearchMask) + return false; + + eax = sub_1959F50(edi); + edi = (eax - edi - 1); + } + } +} + +// HOTS: 1958D70 +void TFileNameDatabase::sub_1958D70(TMndxFindResult * pStruct1C, DWORD arg_4) +{ + TStruct40 * pStruct40 = pStruct1C->pStruct40; + PNAME_FRAG pNameEntry; + + // HOTS: 1958D84 + for(;;) + { + pNameEntry = NameFragTable.NameFragArray + (arg_4 & NameFragIndexMask); + if(arg_4 == pNameEntry->NextIndex) + { + // HOTS: 1958DA6 + if((pNameEntry->FragOffs & 0xFFFFFF00) != 0xFFFFFF00) + { + // HOTS: 1958DBA + if(NextDB.pDB != NULL) + { + NextDB.pDB->sub_1958D70(pStruct1C, pNameEntry->FragOffs); + } + else + { + IndexStruct_174.CopyNameFragment(pStruct1C, pNameEntry->FragOffs); + } + } + else + { + // HOTS: 1958DE7 + // Insert the low 8 bits to the path being built + pStruct40->array_00.InsertOneItem_CHAR((char)(pNameEntry->FragOffs & 0xFF)); + } + + // HOTS: 1958E71 + arg_4 = pNameEntry->ItemIndex; + if(arg_4 == 0) + return; + } + else + { + // HOTS: 1958E8E + if(Struct68_D0.IsItemPresent(arg_4)) + { + DWORD FragOffs; + + // HOTS: 1958EAF + FragOffs = GetNameFragmentOffset(arg_4); + if(NextDB.pDB != NULL) + { + NextDB.pDB->sub_1958D70(pStruct1C, FragOffs); + } + else + { + IndexStruct_174.CopyNameFragment(pStruct1C, FragOffs); + } + } + else + { + // HOTS: 1958F50 + // Insert one character to the path being built + pStruct40->array_00.InsertOneItem_CHAR(FrgmDist_LoBits.CharArray[arg_4]); + } + + // HOTS: 1958FDE + if(arg_4 <= field_214) + return; + + arg_4 = 0xFFFFFFFF - arg_4 + sub_1959F50(arg_4); + } + } +} + +// HOTS: 1959010 +bool TFileNameDatabase::sub_1959010(TMndxFindResult * pStruct1C, DWORD arg_4) +{ + TStruct40 * pStruct40 = pStruct1C->pStruct40; + PNAME_FRAG pNameEntry; + + // HOTS: 1959024 + for(;;) + { + pNameEntry = NameFragTable.NameFragArray + (arg_4 & NameFragIndexMask); + if(arg_4 == pNameEntry->NextIndex) + { + // HOTS: 1959047 + if((pNameEntry->FragOffs & 0xFFFFFF00) != 0xFFFFFF00) + { + // HOTS: 195905A + if(NextDB.pDB != NULL) + { + if(!NextDB.pDB->sub_1959010(pStruct1C, pNameEntry->FragOffs)) + return false; + } + else + { + if(!IndexStruct_174.CheckAndCopyNameFragment(pStruct1C, pNameEntry->FragOffs)) + return false; + } + } + else + { + // HOTS: 1959092 + if((char)(pNameEntry->FragOffs & 0xFF) != pStruct1C->szSearchMask[pStruct40->CharIndex]) + return false; + + // Insert the low 8 bits to the path being built + pStruct40->array_00.InsertOneItem_CHAR((char)(pNameEntry->FragOffs & 0xFF)); + pStruct40->CharIndex++; + } + + // HOTS: 195912E + arg_4 = pNameEntry->ItemIndex; + if(arg_4 == 0) + return true; + } + else + { + // HOTS: 1959147 + if(Struct68_D0.IsItemPresent(arg_4)) + { + DWORD FragOffs; + + // HOTS: 195917C + FragOffs = GetNameFragmentOffset(arg_4); + if(NextDB.pDB != NULL) + { + if(!NextDB.pDB->sub_1959010(pStruct1C, FragOffs)) + return false; + } + else + { + if(!IndexStruct_174.CheckAndCopyNameFragment(pStruct1C, FragOffs)) + return false; + } + } + else + { + // HOTS: 195920E + if(FrgmDist_LoBits.CharArray[arg_4] != pStruct1C->szSearchMask[pStruct40->CharIndex]) + return false; + + // Insert one character to the path being built + pStruct40->array_00.InsertOneItem_CHAR(FrgmDist_LoBits.CharArray[arg_4]); + pStruct40->CharIndex++; + } + + // HOTS: 19592B6 + if(arg_4 <= field_214) + return true; + + arg_4 = 0xFFFFFFFF - arg_4 + sub_1959F50(arg_4); + } + + // HOTS: 19592D5 + if(pStruct40->CharIndex >= pStruct1C->cchSearchMask) + break; + } + + sub_1958D70(pStruct1C, arg_4); + return true; +} + +// HOTS: 1959460 +bool TFileNameDatabase::sub_1959460(TMndxFindResult * pStruct1C) +{ + TStruct40 * pStruct40 = pStruct1C->pStruct40; + PPATH_STOP pPathStop; + PATH_STOP PathStop; + DWORD NewMaxItemCount; + DWORD FragOffs; + DWORD edi; + + if(pStruct40->SearchPhase == CASC_SEARCH_FINISHED) + return false; + + if(pStruct40->SearchPhase != CASC_SEARCH_SEARCHING) + { + // HOTS: 1959489 + pStruct40->InitSearchBuffers(); + + // If the caller passed a part of the search path, we need to find that one + while(pStruct40->CharIndex < pStruct1C->cchSearchMask) + { + if(!sub_1958B00(pStruct1C)) + { + pStruct40->SearchPhase = CASC_SEARCH_FINISHED; + return false; + } + } + + // HOTS: 19594b0 + PathStop.ItemIndex = pStruct40->ItemIndex; + PathStop.field_4 = 0; + PathStop.field_8 = pStruct40->array_00.ItemCount; + PathStop.field_C = 0xFFFFFFFF; + PathStop.field_10 = 0xFFFFFFFF; + pStruct40->PathStops.InsertOneItem_PATH_STOP(PathStop); + pStruct40->ItemCount = 1; + + if(FileNameIndexes.IsItemPresent(pStruct40->ItemIndex)) + { + pStruct1C->szFoundPath = pStruct40->array_00.FirstValid.Chars; + pStruct1C->cchFoundPath = pStruct40->array_00.ItemCount; + pStruct1C->FileNameIndex = FileNameIndexes.GetItemValue(pStruct40->ItemIndex); + return true; + } + } + + // HOTS: 1959522 + for(;;) + { + // HOTS: 1959530 + if(pStruct40->ItemCount == pStruct40->PathStops.ItemCount) + { + PPATH_STOP pLastStop; + DWORD CollisionIndex; + + pLastStop = pStruct40->PathStops.FirstValid.PathStopPtr + pStruct40->PathStops.ItemCount - 1; + CollisionIndex = sub_1959CB0(pLastStop->ItemIndex) + 1; + + // Insert a new structure + PathStop.ItemIndex = CollisionIndex - pLastStop->ItemIndex - 1;; + PathStop.field_4 = CollisionIndex; + PathStop.field_8 = 0; + PathStop.field_C = 0xFFFFFFFF; + PathStop.field_10 = 0xFFFFFFFF; + pStruct40->PathStops.InsertOneItem_PATH_STOP(PathStop); + } + + // HOTS: 19595BD + pPathStop = pStruct40->PathStops.FirstValid.PathStopPtr + pStruct40->ItemCount; + + // HOTS: 19595CC + if(Struct68_00.IsItemPresent(pPathStop->field_4++)) + { + // HOTS: 19595F2 + pStruct40->ItemCount++; + + if(Struct68_D0.IsItemPresent(pPathStop->ItemIndex)) + { + // HOTS: 1959617 + if(pPathStop->field_C == 0xFFFFFFFF) + pPathStop->field_C = Struct68_D0.GetItemValue(pPathStop->ItemIndex); + else + pPathStop->field_C++; + + // HOTS: 1959630 + FragOffs = GetNameFragmentOffsetEx(pPathStop->ItemIndex, pPathStop->field_C); + if(NextDB.pDB != NULL) + { + // HOTS: 1959649 + NextDB.pDB->sub_1958D70(pStruct1C, FragOffs); + } + else + { + // HOTS: 1959654 + IndexStruct_174.CopyNameFragment(pStruct1C, FragOffs); + } + } + else + { + // HOTS: 1959665 + // Insert one character to the path being built + pStruct40->array_00.InsertOneItem_CHAR(FrgmDist_LoBits.CharArray[pPathStop->ItemIndex]); + } + + // HOTS: 19596AE + pPathStop->field_8 = pStruct40->array_00.ItemCount; + + // HOTS: 19596b6 + if(FileNameIndexes.IsItemPresent(pPathStop->ItemIndex)) + { + // HOTS: 19596D1 + if(pPathStop->field_10 == 0xFFFFFFFF) + { + // HOTS: 19596D9 + pPathStop->field_10 = FileNameIndexes.GetItemValue(pPathStop->ItemIndex); + } + else + { + pPathStop->field_10++; + } + + // HOTS: 1959755 + pStruct1C->szFoundPath = pStruct40->array_00.FirstValid.Chars; + pStruct1C->cchFoundPath = pStruct40->array_00.ItemCount; + pStruct1C->FileNameIndex = pPathStop->field_10; + return true; + } + } + else + { + // HOTS: 19596E9 + if(pStruct40->ItemCount == 1) + { + pStruct40->SearchPhase = CASC_SEARCH_FINISHED; + return false; + } + + // HOTS: 19596F5 + pPathStop = pStruct40->PathStops.FirstValid.PathStopPtr + pStruct40->ItemCount - 1; + pPathStop->ItemIndex++; + + pPathStop = pStruct40->PathStops.FirstValid.PathStopPtr + pStruct40->ItemCount - 2; + edi = pPathStop->field_8; + + if(edi > pStruct40->array_00.MaxItemCount) + { + // HOTS: 1959717 + NewMaxItemCount = edi; + + if(pStruct40->array_00.MaxItemCount > (edi / 2)) + { + if(pStruct40->array_00.MaxItemCount > 0x7FFFFFFF) + { + NewMaxItemCount = 0xFFFFFFFF; + } + else + { + NewMaxItemCount = pStruct40->array_00.MaxItemCount + pStruct40->array_00.MaxItemCount; + } + } + + pStruct40->array_00.SetMaxItems_CHARS(NewMaxItemCount); + } + + // HOTS: 1959749 + pStruct40->array_00.ItemCount = edi; + pStruct40->ItemCount--; + } + } +} + +// HOTS: 1958B00 +bool TFileNameDatabase::sub_1958B00(TMndxFindResult * pStruct1C) +{ + TStruct40 * pStruct40 = pStruct1C->pStruct40; + LPBYTE pbPathName = (LPBYTE)pStruct1C->szSearchMask; + DWORD CollisionIndex; + DWORD FragmentOffset; + DWORD SaveCharIndex; + DWORD ItemIndex; + DWORD FragOffs; + DWORD var_4; + + ItemIndex = pbPathName[pStruct40->CharIndex] ^ (pStruct40->ItemIndex << 0x05) ^ pStruct40->ItemIndex; + ItemIndex = ItemIndex & NameFragIndexMask; + if(pStruct40->ItemIndex == NameFragTable.NameFragArray[ItemIndex].ItemIndex) + { + // HOTS: 1958B45 + FragmentOffset = NameFragTable.NameFragArray[ItemIndex].FragOffs; + if((FragmentOffset & 0xFFFFFF00) == 0xFFFFFF00) + { + // HOTS: 1958B88 + pStruct40->array_00.InsertOneItem_CHAR((char)FragmentOffset); + pStruct40->ItemIndex = NameFragTable.NameFragArray[ItemIndex].NextIndex; + pStruct40->CharIndex++; + return true; + } + + // HOTS: 1958B59 + if(NextDB.pDB != NULL) + { + if(!NextDB.pDB->sub_1959010(pStruct1C, FragmentOffset)) + return false; + } + else + { + if(!IndexStruct_174.CheckAndCopyNameFragment(pStruct1C, FragmentOffset)) + return false; + } + + // HOTS: 1958BCA + pStruct40->ItemIndex = NameFragTable.NameFragArray[ItemIndex].NextIndex; + return true; + } + + // HOTS: 1958BE5 + CollisionIndex = sub_1959CB0(pStruct40->ItemIndex) + 1; + if(!Struct68_00.IsItemPresent(CollisionIndex)) + return false; + + pStruct40->ItemIndex = (CollisionIndex - pStruct40->ItemIndex - 1); + var_4 = 0xFFFFFFFF; + + // HOTS: 1958C20 + for(;;) + { + if(Struct68_D0.IsItemPresent(pStruct40->ItemIndex)) + { + // HOTS: 1958C0E + if(var_4 == 0xFFFFFFFF) + { + // HOTS: 1958C4B + var_4 = Struct68_D0.GetItemValue(pStruct40->ItemIndex); + } + else + { + var_4++; + } + + // HOTS: 1958C62 + SaveCharIndex = pStruct40->CharIndex; + + FragOffs = GetNameFragmentOffsetEx(pStruct40->ItemIndex, var_4); + if(NextDB.pDB != NULL) + { + // HOTS: 1958CCB + if(NextDB.pDB->sub_1959010(pStruct1C, FragOffs)) + return true; + } + else + { + // HOTS: 1958CD6 + if(IndexStruct_174.CheckAndCopyNameFragment(pStruct1C, FragOffs)) + return true; + } + + // HOTS: 1958CED + if(SaveCharIndex != pStruct40->CharIndex) + return false; + } + else + { + // HOTS: 1958CFB + if(FrgmDist_LoBits.ByteArray[pStruct40->ItemIndex] == pStruct1C->szSearchMask[pStruct40->CharIndex]) + { + // HOTS: 1958D11 + pStruct40->array_00.InsertOneItem_CHAR(FrgmDist_LoBits.ByteArray[pStruct40->ItemIndex]); + pStruct40->CharIndex++; + return true; + } + } + + // HOTS: 1958D11 + pStruct40->ItemIndex++; + CollisionIndex++; + + if(!Struct68_00.IsItemPresent(CollisionIndex)) + break; + } + + return false; +} + +// HOTS: 1957EF0 +bool TFileNameDatabase::FindFileInDatabase(TMndxFindResult * pStruct1C) +{ + TStruct40 * pStruct40 = pStruct1C->pStruct40; + + pStruct40->ItemIndex = 0; + pStruct40->CharIndex = 0; + pStruct40->SearchPhase = CASC_SEARCH_INITIALIZING; + + if(pStruct1C->cchSearchMask > 0) + { + while(pStruct40->CharIndex < pStruct1C->cchSearchMask) + { + // HOTS: 01957F12 + if(!CheckNextPathFragment(pStruct1C)) + return false; + } + } + + // HOTS: 1957F26 + if(!FileNameIndexes.IsItemPresent(pStruct40->ItemIndex)) + return false; + + pStruct1C->szFoundPath = pStruct1C->szSearchMask; + pStruct1C->cchFoundPath = pStruct1C->cchSearchMask; + pStruct1C->FileNameIndex = FileNameIndexes.GetItemValue(pStruct40->ItemIndex); + return true; +} + +// HOTS: 1959790 +int TFileNameDatabase::LoadFromStream(TByteStream & InStream) +{ + DWORD dwBitMask; + int nError; + + nError = Struct68_00.LoadFromStream_Exchange(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + nError = FileNameIndexes.LoadFromStream_Exchange(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + nError = Struct68_D0.LoadFromStream_Exchange(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + // HOTS: 019597CD + nError = FrgmDist_LoBits.LoadBytes_Copy(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + nError = FrgmDist_HiBits.LoadFromStream_Exchange(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + // HOTS: 019597F5 + nError = IndexStruct_174.LoadFromStream_Exchange(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + // HOTS: 0195980A + if(Struct68_D0.ValidItemCount != 0 && IndexStruct_174.NameFragments.ItemCount == 0) + { + TFileNameDatabase * pNextDB = new TFileNameDatabase; + + nError = NextDB.SetDatabase(pNextDB); + if(nError != ERROR_SUCCESS) + return nError; + + if(NextDB.pDB == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + nError = NextDB.pDB->LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + } + + // HOTS: 0195986B + nError = NameFragTable.LoadFragmentInfos_Copy(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + NameFragIndexMask = NameFragTable.ItemCount - 1; + + nError = InStream.GetValue_DWORD(field_214); + if(nError != ERROR_SUCCESS) + return nError; + + nError = InStream.GetValue_DWORD(dwBitMask); + if(nError != ERROR_SUCCESS) + return nError; + + return Struct10.sub_1957800(dwBitMask); +} + +// HOTS: 19598D0 +int TFileNameDatabase::LoadFromStream_Exchange(TByteStream & InStream) +{ + TFileNameDatabase TempDatabase; + ARRAY_POINTER Pointer; + DWORD dwSignature; + int nError; + + // Get pointer to MAR signature + nError = InStream.GetBytes(sizeof(DWORD), &Pointer); + if(nError != ERROR_SUCCESS) + return nError; + + // Verify the signature + dwSignature = Pointer.Uint32s[0]; + if(dwSignature != CASC_MAR_SIGNATURE) + return ERROR_BAD_FORMAT; + + nError = TempDatabase.LoadFromStream(InStream); + if(nError != ERROR_SUCCESS) + return nError; + + MarStream.ExchangeWith(InStream); + ExchangeWith(TempDatabase); + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// TFileNameDatabasePtr functions + +// HOTS: 01956D70 +TFileNameDatabasePtr::TFileNameDatabasePtr() +{ + pDB = NULL; +} + +TFileNameDatabasePtr::~TFileNameDatabasePtr() +{ + delete pDB; +} + +// HOTS: 1956C60 +int TFileNameDatabasePtr::FindFileInDatabase(TMndxFindResult * pStruct1C) +{ + int nError = ERROR_SUCCESS; + + if(pDB == NULL) + return ERROR_INVALID_PARAMETER; + + nError = pStruct1C->CreateStruct40(); + if(nError != ERROR_SUCCESS) + return nError; + + if(!pDB->FindFileInDatabase(pStruct1C)) + nError = ERROR_FILE_NOT_FOUND; + + pStruct1C->FreeStruct40(); + return nError; +} + +// HOTS: 1956CE0 +int TFileNameDatabasePtr::sub_1956CE0(TMndxFindResult * pStruct1C, bool * pbFindResult) +{ + int nError = ERROR_SUCCESS; + + if(pDB == NULL) + return ERROR_INVALID_PARAMETER; + + // Create the pStruct40, if not initialized yet + if(pStruct1C->pStruct40 == NULL) + { + nError = pStruct1C->CreateStruct40(); + if(nError != ERROR_SUCCESS) + return nError; + } + + *pbFindResult = pDB->sub_1959460(pStruct1C); + return nError; +} + +// HOTS: 1956D20 +int TFileNameDatabasePtr::GetFileNameCount(PDWORD PtrFileNameCount) +{ + if(pDB == NULL) + return ERROR_INVALID_PARAMETER; + + PtrFileNameCount[0] = pDB->FileNameIndexes.ValidItemCount; + return ERROR_SUCCESS; +} + +// HOTS: 1956DA0 +int TFileNameDatabasePtr::CreateDatabase(LPBYTE pbMarData, DWORD cbMarData) +{ + TFileNameDatabase * pDatabase; + TByteStream ByteStream; + int nError; + + if(pbMarData == NULL && cbMarData != 0) + return ERROR_INVALID_PARAMETER; + + pDatabase = new TFileNameDatabase; + if(pDatabase == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + nError = ByteStream.SetByteBuffer(pbMarData, cbMarData); + if(nError != ERROR_SUCCESS) + return nError; + + // HOTS: 1956E11 + nError = pDatabase->LoadFromStream_Exchange(ByteStream); + if(nError != ERROR_SUCCESS) + return nError; + + pDB = pDatabase; + return ERROR_SUCCESS; +} + +// HOTS: 19584B0 +int TFileNameDatabasePtr::SetDatabase(TFileNameDatabase * pNewDB) +{ + if(pNewDB != NULL && pDB == pNewDB) + return ERROR_INVALID_PARAMETER; + + if(pDB != NULL) + delete pDB; + pDB = pNewDB; + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// Local functions - MAR file + +// HOTS: 00E94180 +static void MAR_FILE_CreateDatabase(PMAR_FILE pMarFile) +{ + pMarFile->pDatabasePtr = new TFileNameDatabasePtr; + if(pMarFile->pDatabasePtr != NULL) + pMarFile->pDatabasePtr->CreateDatabase(pMarFile->pbMarData, pMarFile->cbMarData); +} + +static int MAR_FILE_SearchFile(PMAR_FILE pMarFile, TMndxFindResult * pStruct1C) +{ + return pMarFile->pDatabasePtr->FindFileInDatabase(pStruct1C); +} + +static void MAR_FILE_Destructor(PMAR_FILE pMarFile) +{ + if(pMarFile != NULL) + { + if(pMarFile->pDatabasePtr != NULL) + delete pMarFile->pDatabasePtr; + if(pMarFile->pbMarData != NULL) + CASC_FREE(pMarFile->pbMarData); + + CASC_FREE(pMarFile); + } +} + +//----------------------------------------------------------------------------- +// Package functions + +// TODO: When working, increment these values to lower number of (re)allocations +#define CASC_PACKAGES_INIT 0x10 +#define CASC_PACKAGES_DELTA 0x10 + +static PCASC_MNDX_PACKAGES AllocatePackages(size_t nNameEntries, size_t nNameBufferMax) +{ + PCASC_MNDX_PACKAGES pPackages; + size_t cbToAllocate; + + // Allocate space + cbToAllocate = sizeof(CASC_MNDX_PACKAGES) + (nNameEntries * sizeof(CASC_MNDX_PACKAGE)) + nNameBufferMax; + pPackages = (PCASC_MNDX_PACKAGES)CASC_ALLOC(BYTE, cbToAllocate); + if(pPackages != NULL) + { + // Fill the structure + memset(pPackages, 0, cbToAllocate); + + // Init the list entries + pPackages->szNameBuffer = (char *)(&pPackages->Packages[nNameEntries]); + pPackages->NameEntries = nNameEntries; + pPackages->NameBufferUsed = 0; + pPackages->NameBufferMax = nNameBufferMax; + } + + return pPackages; +} + +static PCASC_MNDX_PACKAGES InsertToPackageList( + PCASC_MNDX_PACKAGES pPackages, + const char * szFileName, + size_t cchFileName, + size_t nPackageIndex) +{ + size_t nNewNameEntries = pPackages->NameEntries; + size_t nNewNameBufferMax = pPackages->NameBufferMax; + size_t cbToAllocate; + char * szNameBuffer; + + // Need to reallocate? + while(nPackageIndex >= nNewNameEntries) + nNewNameEntries = nNewNameEntries + CASC_PACKAGES_DELTA; + if((pPackages->NameBufferUsed + cchFileName + 1) > nNewNameBufferMax) + nNewNameBufferMax = nNewNameBufferMax + 0x1000; + + // If any of the two variables overflowed, we need to reallocate the name list + if(nNewNameEntries > pPackages->NameEntries || nNewNameBufferMax > pPackages->NameBufferMax) + { + PCASC_MNDX_PACKAGES pOldPackages = pPackages; + + // Allocate new name list + cbToAllocate = sizeof(CASC_MNDX_PACKAGES) + (nNewNameEntries * sizeof(CASC_MNDX_PACKAGE)) + nNewNameBufferMax; + pPackages = (PCASC_MNDX_PACKAGES)CASC_ALLOC(BYTE, cbToAllocate); + if(pPackages == NULL) + return NULL; + + // Copy the old entries + memset(pPackages, 0, cbToAllocate); + pPackages->szNameBuffer = szNameBuffer = (char *)(&pPackages->Packages[nNewNameEntries]); + memcpy(pPackages->szNameBuffer, pOldPackages->szNameBuffer, pOldPackages->NameBufferUsed); + + // Copy the old entries + for(size_t i = 0; i < pOldPackages->NameEntries; i++) + { + if(pOldPackages->Packages[i].szFileName != NULL) + { + pPackages->Packages[i].szFileName = pPackages->szNameBuffer + (pOldPackages->Packages[i].szFileName - pOldPackages->szNameBuffer); + pPackages->Packages[i].nLength = pOldPackages->Packages[i].nLength; + } + } + + // Fill the limits + pPackages->NameEntries = nNewNameEntries; + pPackages->NameBufferUsed = pOldPackages->NameBufferUsed; + pPackages->NameBufferMax = nNewNameBufferMax; + + // Switch the name lists + CASC_FREE(pOldPackages); + } + + // The slot is expected to be empty at the moment + assert(pPackages->Packages[nPackageIndex].szFileName == NULL); + assert(pPackages->Packages[nPackageIndex].nLength == 0); + + // Set the file name entry + szNameBuffer = pPackages->szNameBuffer + pPackages->NameBufferUsed; + pPackages->Packages[nPackageIndex].szFileName = szNameBuffer; + pPackages->Packages[nPackageIndex].nLength = cchFileName; + memcpy(szNameBuffer, szFileName, cchFileName); + pPackages->NameBufferUsed += (cchFileName + 1); + return pPackages; +} + +static int LoadPackageNames(PCASC_MNDX_INFO pMndxInfo, PCASC_MNDX_PACKAGES * ppPackages) +{ + TMndxFindResult Struct1C; + PCASC_MNDX_PACKAGES pPackages = NULL; + PMAR_FILE pMarFile; + + // Sanity checks + assert(pMndxInfo != NULL); + + // Prepare the file name search in the top level directory + pMarFile = pMndxInfo->pMarFile1; + Struct1C.SetSearchPath("", 0); + + // Allocate initial name list structure + pPackages = AllocatePackages(CASC_PACKAGES_INIT, 0x1000); + if(pPackages == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Keep searching as long as we find something + for(;;) + { + bool bFindResult = false; + + // Search the next file name + pMarFile->pDatabasePtr->sub_1956CE0(&Struct1C, &bFindResult); + if(bFindResult == false) + break; + + // Insert the found name to the top level directory list + pPackages = InsertToPackageList(pPackages, Struct1C.szFoundPath, Struct1C.cchFoundPath, Struct1C.FileNameIndex); + if(pPackages == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + } + + // Give the packages to the caller + if(ppPackages != NULL) + ppPackages[0] = pPackages; + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// Implementation of root file functions + +struct TRootHandler_MNDX : public TRootHandler +{ + CASC_MNDX_INFO MndxInfo; + + PCASC_ROOT_ENTRY_MNDX * ppValidEntries; + PCASC_ROOT_ENTRY_MNDX pMndxEntries; + PCASC_MNDX_PACKAGES pPackages; // Linear list of present packages +}; + +PCASC_MNDX_PACKAGE FindMndxPackage(TRootHandler_MNDX * pRootHandler, const char * szFileName) +{ + PCASC_MNDX_PACKAGE pMatching = NULL; + PCASC_MNDX_PACKAGE pPackage; + size_t nMaxLength = 0; + size_t nLength = strlen(szFileName); + + // Packages must be loaded + assert(pRootHandler->pPackages != NULL); + pPackage = pRootHandler->pPackages->Packages; + + //FILE * fp = fopen("E:\\packages.txt", "wt"); + //for(size_t i = 0; i < hs->pPackages->NameEntries; i++, pPackage++) + //{ + // if(pPackage->szFileName != NULL) + // fprintf(fp, "%s\n", pPackage->szFileName); + //} + //fclose(fp); + + // Find the longest matching name + for(size_t i = 0; i < pRootHandler->pPackages->NameEntries; i++, pPackage++) + { + if(pPackage->szFileName != NULL && pPackage->nLength < nLength && pPackage->nLength > nMaxLength) + { + // Compare the package name + if(!strncmp(szFileName, pPackage->szFileName, pPackage->nLength)) + { + pMatching = pPackage; + nMaxLength = pPackage->nLength; + } + } + } + + // Give the package pointer or NULL if not found + return pMatching; +} + +int SearchMndxInfo(TRootHandler_MNDX * pRootHandler, const char * szFileName, DWORD dwPackage, PCASC_ROOT_ENTRY_MNDX * ppRootEntry) +{ + PCASC_ROOT_ENTRY_MNDX pRootEntry; + PCASC_MNDX_INFO pMndxInfo = &pRootHandler->MndxInfo; + TMndxFindResult Struct1C; + + // Search the database for the file name + if(pMndxInfo->bRootFileLoaded) + { + Struct1C.SetSearchPath(szFileName, strlen(szFileName)); + + // Search the file name in the second MAR info (the one with stripped package names) + if(MAR_FILE_SearchFile(pMndxInfo->pMarFile2, &Struct1C) != ERROR_SUCCESS) + return ERROR_FILE_NOT_FOUND; + + // The found MNDX index must fall into range of valid MNDX entries + if(Struct1C.FileNameIndex < pMndxInfo->MndxEntriesValid) + { + // HOTS: E945F4 + pRootEntry = pRootHandler->ppValidEntries[Struct1C.FileNameIndex]; + while((pRootEntry->Flags & 0x00FFFFFF) != dwPackage) + { + // The highest bit serves as a terminator if set + if(pRootEntry->Flags & 0x80000000) + return ERROR_FILE_NOT_FOUND; + + pRootEntry++; + } + + // Give the root entry pointer to the caller + if(ppRootEntry != NULL) + ppRootEntry[0] = pRootEntry; + return ERROR_SUCCESS; + } + } + + return ERROR_FILE_NOT_FOUND; +} + +static LPBYTE FillFindData(TRootHandler_MNDX * pRootHandler, TCascSearch * pSearch, TMndxFindResult * pStruct1C, PDWORD PtrFileSize) +{ + PCASC_ROOT_ENTRY_MNDX pRootEntry = NULL; + PCASC_MNDX_PACKAGE pPackage; + char * szStrippedPtr; + char szStrippedName[MAX_PATH+1]; + int nError; + + // Sanity check + assert(pStruct1C->cchFoundPath < MAX_PATH); + + // Fill the file name + memcpy(pSearch->szFileName, pStruct1C->szFoundPath, pStruct1C->cchFoundPath); + pSearch->szFileName[pStruct1C->cchFoundPath] = 0; + + // Fill the file size + pPackage = FindMndxPackage(pRootHandler, pSearch->szFileName); + if(pPackage == NULL) + return NULL; + + // Cut the package name off the full path + szStrippedPtr = pSearch->szFileName + pPackage->nLength; + while(szStrippedPtr[0] == '/') + szStrippedPtr++; + + // We need to convert the stripped name to lowercase, replacing backslashes with slashes + NormalizeFileName_LowerSlash(szStrippedName, szStrippedPtr, MAX_PATH); + + // Search the package + nError = SearchMndxInfo(pRootHandler, szStrippedName, (DWORD)(pPackage - pRootHandler->pPackages->Packages), &pRootEntry); + if(nError != ERROR_SUCCESS) + return NULL; + + // Give the file size + if(PtrFileSize != NULL) + PtrFileSize[0] = pRootEntry->FileSize; + return pRootEntry->EncodingKey; +} + +static int MndxHandler_Insert(TRootHandler_MNDX *, const char *, LPBYTE) +{ + return ERROR_NOT_SUPPORTED; +} + +static LPBYTE MndxHandler_Search(TRootHandler_MNDX * pRootHandler, TCascSearch * pSearch, PDWORD PtrFileSize, PDWORD /* PtrLocaleFlags */) +{ + TMndxFindResult * pStruct1C = NULL; + PCASC_MNDX_INFO pMndxInfo = &pRootHandler->MndxInfo; + PMAR_FILE pMarFile = pMndxInfo->pMarFile3; + bool bFindResult = false; + + // If the first time, allocate the structure for the search result + if(pSearch->pRootContext == NULL) + { + // Create the new search structure + pStruct1C = new TMndxFindResult; + if(pStruct1C == NULL) + return NULL; + + // Setup the search mask + pStruct1C->SetSearchPath("", 0); + pSearch->pRootContext = pStruct1C; + } + + // Make shortcut for the search structure + assert(pSearch->pRootContext != NULL); + pStruct1C = (TMndxFindResult *)pSearch->pRootContext; + + // Search the next file name (our code) + pMarFile->pDatabasePtr->sub_1956CE0(pStruct1C, &bFindResult); + if(bFindResult == false) + return NULL; + + // Give the file size and encoding key + return FillFindData(pRootHandler, pSearch, pStruct1C, PtrFileSize); +} + +static void MndxHandler_EndSearch(TRootHandler_MNDX * /* pRootHandler */, TCascSearch * pSearch) +{ + if(pSearch != NULL) + delete (TMndxFindResult *)pSearch->pRootContext; + pSearch->pRootContext = NULL; +} + +static LPBYTE MndxHandler_GetKey(TRootHandler_MNDX * pRootHandler, const char * szFileName) +{ + PCASC_ROOT_ENTRY_MNDX pRootEntry = NULL; + PCASC_MNDX_PACKAGE pPackage; + char * szStrippedName; + char szNormName[MAX_PATH+1]; + int nError; + + // Convert the file name to lowercase + slashes + NormalizeFileName_LowerSlash(szNormName, szFileName, MAX_PATH); + + // Find the package number + pPackage = FindMndxPackage(pRootHandler, szNormName); + if(pPackage == NULL) + return NULL; + + // Cut the package name off the full path + szStrippedName = szNormName + pPackage->nLength; + while(szStrippedName[0] == '/') + szStrippedName++; + + // Find the root entry + nError = SearchMndxInfo(pRootHandler, szStrippedName, (DWORD)(pPackage - pRootHandler->pPackages->Packages), &pRootEntry); + if(nError != ERROR_SUCCESS || pRootEntry == NULL) + return NULL; + + // Return the encoding key + return pRootEntry->EncodingKey; +} + +static void MndxHandler_Close(TRootHandler_MNDX * pRootHandler) +{ + if(pRootHandler->MndxInfo.pMarFile1 != NULL) + MAR_FILE_Destructor(pRootHandler->MndxInfo.pMarFile1); + if(pRootHandler->MndxInfo.pMarFile2 != NULL) + MAR_FILE_Destructor(pRootHandler->MndxInfo.pMarFile2); + if(pRootHandler->MndxInfo.pMarFile3 != NULL) + MAR_FILE_Destructor(pRootHandler->MndxInfo.pMarFile3); + if(pRootHandler->ppValidEntries != NULL) + CASC_FREE(pRootHandler->ppValidEntries); + if(pRootHandler->pMndxEntries != NULL) + CASC_FREE(pRootHandler->pMndxEntries); + if(pRootHandler->pPackages != NULL) + CASC_FREE(pRootHandler->pPackages); + + CASC_FREE(pRootHandler); +} + +//----------------------------------------------------------------------------- +// Public functions - MNDX info + +int RootHandler_CreateMNDX(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile) +{ + PFILE_MNDX_HEADER pMndxHeader = (PFILE_MNDX_HEADER)pbRootFile; + PCASC_MNDX_INFO pMndxInfo; + TRootHandler_MNDX * pRootHandler; + FILE_MAR_INFO MarInfo; + PMAR_FILE pMarFile; + LPBYTE pbRootFileEnd = pbRootFile + cbRootFile; + DWORD cbToAllocate; + DWORD dwFilePointer = 0; + DWORD i; + int nError = ERROR_SUCCESS; + + // Check signature and the other variables + if(pMndxHeader->Signature != CASC_MNDX_SIGNATURE || pMndxHeader->FormatVersion > 2 || pMndxHeader->FormatVersion < 1) + return ERROR_BAD_FORMAT; + + // Allocate the structure for the MNDX root file + hs->pRootHandler = pRootHandler = CASC_ALLOC(TRootHandler_MNDX, 1); + if(pRootHandler == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill-in the handler functions + memset(pRootHandler, 0, sizeof(TRootHandler_MNDX)); + pRootHandler->Insert = (ROOT_INSERT)MndxHandler_Insert; + pRootHandler->Search = (ROOT_SEARCH)MndxHandler_Search; + pRootHandler->EndSearch = (ROOT_ENDSEARCH)MndxHandler_EndSearch; + pRootHandler->GetKey = (ROOT_GETKEY)MndxHandler_GetKey; + pRootHandler->Close = (ROOT_CLOSE) MndxHandler_Close; + pMndxInfo = &pRootHandler->MndxInfo; + + // Fill-in the flags + pRootHandler->dwRootFlags |= ROOT_FLAG_HAS_NAMES; + + // Copy the header into the MNDX info + pMndxInfo->HeaderVersion = pMndxHeader->HeaderVersion; + pMndxInfo->FormatVersion = pMndxHeader->FormatVersion; + dwFilePointer += sizeof(FILE_MNDX_HEADER); + + // Header version 2 has 2 extra fields that we need to load + if(pMndxInfo->HeaderVersion == 2) + { + if(!RootFileRead(pbRootFile + dwFilePointer, pbRootFileEnd, &pMndxInfo->field_1C, sizeof(DWORD) + sizeof(DWORD))) + return ERROR_FILE_CORRUPT; + dwFilePointer += sizeof(DWORD) + sizeof(DWORD); + } + + // Load the rest of the file header + if(!RootFileRead(pbRootFile + dwFilePointer, pbRootFileEnd, &pMndxInfo->MarInfoOffset, 0x1C)) + return ERROR_FILE_CORRUPT; + + // Verify the structure + if(pMndxInfo->MarInfoCount > CASC_MAX_MAR_FILES || pMndxInfo->MarInfoSize != sizeof(FILE_MAR_INFO)) + return ERROR_FILE_CORRUPT; + + // Load all MAR infos + for(i = 0; i < pMndxInfo->MarInfoCount; i++) + { + // Load the n-th MAR info + dwFilePointer = pMndxInfo->MarInfoOffset + (pMndxInfo->MarInfoSize * i); + if(!RootFileRead(pbRootFile + dwFilePointer, pbRootFileEnd, &MarInfo, sizeof(FILE_MAR_INFO))) + return ERROR_FILE_CORRUPT; + + // Allocate MAR_FILE structure + pMarFile = CASC_ALLOC(MAR_FILE, 1); + if(pMarFile == NULL) + { + nError = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // Allocate space for the MAR data + pMarFile->pDatabasePtr = NULL; + pMarFile->pbMarData = CASC_ALLOC(BYTE, MarInfo.MarDataSize); + pMarFile->cbMarData = MarInfo.MarDataSize; + if(pMarFile->pbMarData == NULL) + { + nError = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + // Read the MAR data + if(!RootFileRead(pbRootFile + MarInfo.MarDataOffset, pbRootFileEnd, pMarFile->pbMarData, pMarFile->cbMarData)) + { + nError = ERROR_FILE_CORRUPT; + break; + } + + // HOTS: 00E94FF1 + MAR_FILE_CreateDatabase(pMarFile); + if(i == 0) + pMndxInfo->pMarFile1 = pMarFile; + if(i == 1) + pMndxInfo->pMarFile2 = pMarFile; + if(i == 2) + pMndxInfo->pMarFile3 = pMarFile; + } + + // All three MAR files must be loaded + // HOTS: 00E9503B + if(nError == ERROR_SUCCESS) + { + if(pMndxInfo->pMarFile1 == NULL || pMndxInfo->pMarFile2 == NULL || pMndxInfo->pMarFile3 == NULL) + nError = ERROR_BAD_FORMAT; + if(pMndxInfo->MndxEntrySize != sizeof(CASC_ROOT_ENTRY_MNDX)) + nError = ERROR_BAD_FORMAT; + } + + // Load the complete array of MNDX entries + if(nError == ERROR_SUCCESS) + { + TFileNameDatabasePtr * pDbPtr = pMndxInfo->pMarFile2->pDatabasePtr; + DWORD FileNameCount; + + nError = pDbPtr->GetFileNameCount(&FileNameCount); + if(nError == ERROR_SUCCESS && FileNameCount == pMndxInfo->MndxEntriesValid) + { + cbToAllocate = pMndxInfo->MndxEntriesTotal * pMndxInfo->MndxEntrySize; + pRootHandler->pMndxEntries = (PCASC_ROOT_ENTRY_MNDX)CASC_ALLOC(BYTE, cbToAllocate); + if(pRootHandler->pMndxEntries != NULL) + { + if(!RootFileRead(pbRootFile + pMndxInfo->MndxEntriesOffset, pbRootFileEnd, pRootHandler->pMndxEntries, cbToAllocate)) + nError = ERROR_FILE_CORRUPT; + } + else + nError = ERROR_NOT_ENOUGH_MEMORY; + } + else + nError = ERROR_FILE_CORRUPT; + } + + // Pick the valid MNDX entries and put them to a separate array + if(nError == ERROR_SUCCESS) + { + assert(pMndxInfo->MndxEntriesValid <= pMndxInfo->MndxEntriesTotal); + pRootHandler->ppValidEntries = CASC_ALLOC(PCASC_ROOT_ENTRY_MNDX, pMndxInfo->MndxEntriesValid + 1); + if(pRootHandler->ppValidEntries != NULL) + { + PCASC_ROOT_ENTRY_MNDX pRootEntry = pRootHandler->pMndxEntries; + DWORD ValidEntryCount = 1; // edx + DWORD nIndex1 = 0; + + // The first entry is always valid + pRootHandler->ppValidEntries[nIndex1++] = pRootHandler->pMndxEntries; + + // Put the remaining entries + for(i = 0; i < pMndxInfo->MndxEntriesTotal; i++, pRootEntry++) + { + if(ValidEntryCount > pMndxInfo->MndxEntriesValid) + break; + + if(pRootEntry->Flags & 0x80000000) + { + pRootHandler->ppValidEntries[nIndex1++] = pRootEntry + 1; + ValidEntryCount++; + } + } + + // Verify the final number of valid entries + if((ValidEntryCount - 1) != pMndxInfo->MndxEntriesValid) + nError = ERROR_BAD_FORMAT; + } + else + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Load the MNDX packages + if(nError == ERROR_SUCCESS) + { + nError = LoadPackageNames(pMndxInfo, &pRootHandler->pPackages); + pMndxInfo->bRootFileLoaded = (nError == ERROR_SUCCESS); + } + +#if defined(_DEBUG) && defined(_X86_) && defined(CASCLIB_TEST) +// CascDumpNameFragTable("E:\\casc-name-fragment-table.txt", pMndxInfo->pMarFile1); +// CascDumpFileNames("E:\\casc-listfile.txt", pMndxInfo->pMarFile1); +// TestMndxRootFile(pRootHandler); +#endif + + // Return the result + return nError; +} + +//---------------------------------------------------------------------------- +// Unit tests + +#if defined(_DEBUG) && defined(_X86_) && defined(CASCLIB_TEST) + +extern "C" { + DWORD _cdecl sub_19573D0_x86(TFileNameDatabase * pDB, DWORD arg_0, DWORD arg_4); + DWORD _cdecl sub_1957EF0_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C); + bool _cdecl sub_1959460_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C); + DWORD _cdecl GetItemValue_x86(TSparseArray * pStruct, DWORD dwKey); + DWORD _cdecl sub_1959CB0_x86(TFileNameDatabase * pDB, DWORD dwKey); + DWORD _cdecl sub_1959F50_x86(TFileNameDatabase * pDB, DWORD arg_0); +} + +extern "C" void * allocate_zeroed_memory_x86(size_t bytes) +{ + void * ptr = CASC_ALLOC(BYTE, bytes); + + if(ptr != NULL) + memset(ptr, 0, bytes); + return ptr; +} + +extern "C" void free_memory_x86(void * ptr) +{ + if(ptr != NULL) + { + CASC_FREE(ptr); + } +} + +static int sub_1956CE0_x86(TFileNameDatabasePtr * pDatabasePtr, TMndxFindResult * pStruct1C, bool * pbFindResult) +{ + int nError = ERROR_SUCCESS; + + if(pDatabasePtr->pDB == NULL) + return ERROR_INVALID_PARAMETER; + + // Create the pStruct40, if not initialized yet + if(pStruct1C->pStruct40 == NULL) + { + nError = pStruct1C->CreateStruct40(); + if(nError != ERROR_SUCCESS) + return nError; + } + + *pbFindResult = sub_1959460_x86(pDatabasePtr->pDB, pStruct1C); + return nError; +} +/* +static void TestFileSearch_SubStrings(PMAR_FILE pMarFile, char * szFileName, size_t nLength) +{ + TMndxFindResult Struct1C_1; + TMndxFindResult Struct1C_2; + +// if(strcmp(szFileName, "mods/heroes.stormmod/base.stormassets/assets/textures/storm_temp_war3_btnstatup.dds")) +// return; + + // Perform search on anything, that is longer than 4 chars + while(nLength >= 4) + { + // Set a substring as search name + Struct1C_1.SetSearchPath(szFileName, nLength); + Struct1C_2.SetSearchPath(szFileName, nLength); + szFileName[nLength] = 0; + + // Keep searching + for(;;) + { + bool bFindResult1 = false; + bool bFindResult2 = false; + + // Search the next file name (orig HOTS code) + sub_1956CE0_x86(pMarFile->pDatabasePtr, &Struct1C_1, &bFindResult1); + + // Search the next file name (our code) + pMarFile->pDatabasePtr->sub_1956CE0(&Struct1C_2, &bFindResult2); + + // Check the result + assert(bFindResult1 == bFindResult2); + assert(Struct1C_1.cchFoundPath == Struct1C_1.cchFoundPath); + assert(Struct1C_1.FileNameIndex == Struct1C_2.FileNameIndex); + assert(strncmp(Struct1C_1.szFoundPath, Struct1C_2.szFoundPath, Struct1C_1.cchFoundPath) == 0); + assert(Struct1C_1.cchFoundPath < MAX_PATH); + + // Stop the search in case of failure + if(bFindResult1 == false || bFindResult2 == false) + break; + } + + // Free the search structures + Struct1C_1.FreeStruct40(); + Struct1C_2.FreeStruct40(); + nLength--; + } +} +*/ + +static void TestFindPackage(PMAR_FILE pMarFile, const char * szPackageName) +{ + TMndxFindResult Struct1C; + + // Search the database for the file name + Struct1C.SetSearchPath(szPackageName, strlen(szPackageName)); + + // Search the file name in the second MAR info (the one with stripped package names) + MAR_FILE_SearchFile(pMarFile, &Struct1C); +} + +static void TestFileSearch(PMAR_FILE pMarFile, const char * szFileName) +{ + TMndxFindResult Struct1C_1; + TMndxFindResult Struct1C_2; + size_t nLength = strlen(szFileName); + char szNameBuff[MAX_PATH + 1]; + + // Set an empty path as search mask (?) + Struct1C_1.SetSearchPath(szFileName, nLength); + Struct1C_2.SetSearchPath(szFileName, nLength); + + // Keep searching + for(;;) + { + bool bFindResult1 = false; + bool bFindResult2 = false; + + // Search the next file name (orig HOTS code) + sub_1956CE0_x86(pMarFile->pDatabasePtr, &Struct1C_1, &bFindResult1); + + // Search the next file name (our code) + pMarFile->pDatabasePtr->sub_1956CE0(&Struct1C_2, &bFindResult2); + + assert(bFindResult1 == bFindResult2); + assert(Struct1C_1.cchFoundPath == Struct1C_1.cchFoundPath); + assert(Struct1C_1.FileNameIndex == Struct1C_2.FileNameIndex); + assert(strncmp(Struct1C_1.szFoundPath, Struct1C_2.szFoundPath, Struct1C_1.cchFoundPath) == 0); + assert(Struct1C_1.cchFoundPath < MAX_PATH); + + // Stop the search in case of failure + if(bFindResult1 == false || bFindResult2 == false) + break; + + // Printf the found file name + memcpy(szNameBuff, Struct1C_2.szFoundPath, Struct1C_2.cchFoundPath); + szNameBuff[Struct1C_2.cchFoundPath] = 0; +// printf("%s \r", szNameBuff); + + // Perform sub-searches on this string and its substrings that are longer than 4 chars +// TestFileSearch_SubStrings(pMarFile, szNameBuff, Struct1C_2.cchFoundPath); + } + + // Free the search structures + Struct1C_1.FreeStruct40(); + Struct1C_2.FreeStruct40(); +} + +static void TestMarFile(PMAR_FILE pMarFile, const char * szFileName, size_t nLength) +{ + TFileNameDatabase * pDB = pMarFile->pDatabasePtr->pDB; + DWORD dwFileNameIndex1 = 0xFFFFFFFF; + DWORD dwFileNameIndex2 = 0xFFFFFFFF; + + // Perform the search using original HOTS code + { + TMndxFindResult Struct1C; + + Struct1C.CreateStruct40(); + Struct1C.SetSearchPath(szFileName, nLength); + + // Call the original HOTS function + sub_1957EF0_x86(pDB, &Struct1C); + dwFileNameIndex1 = Struct1C.FileNameIndex; + } + + // Perform the search using our code + { + TMndxFindResult Struct1C; + + Struct1C.CreateStruct40(); + Struct1C.SetSearchPath(szFileName, nLength); + + // Call our function + pDB->FindFileInDatabase(&Struct1C); + dwFileNameIndex2 = Struct1C.FileNameIndex; + } + + // Compare both + assert(dwFileNameIndex1 == dwFileNameIndex2); +} + +static void TestMndxFunctions(PMAR_FILE pMarFile) +{ + TFileNameDatabase * pDB = pMarFile->pDatabasePtr->pDB; + + // Exercise function sub_19573D0 + for(DWORD arg_0 = 0; arg_0 < 0x100; arg_0++) + { + for(DWORD arg_4 = 0; arg_4 < 0x100; arg_4++) + { + DWORD dwResult1 = sub_19573D0_x86(pDB, arg_0, arg_4); + DWORD dwResult2 = pDB->GetNameFragmentOffsetEx(arg_0, arg_4); + + assert(dwResult1 == dwResult2); + } + } + + // Exercise function GetItemValue + for(DWORD i = 0; i < 0x10000; i++) + { + DWORD dwResult1 = GetItemValue_x86(&pDB->Struct68_D0, i); + DWORD dwResult2 = pDB->Struct68_D0.GetItemValue(i); + + assert(dwResult1 == dwResult2); + } + + // Exercise function sub_1959CB0 + for(DWORD i = 0; i < 0x9C; i++) + { + DWORD dwResult1 = sub_1959CB0_x86(pDB, i); + DWORD dwResult2 = pDB->sub_1959CB0(i); + + assert(dwResult1 == dwResult2); + } + + // Exercise function sub_1959F50 + for(DWORD i = 0; i < 0x40; i++) + { + DWORD dwResult1 = sub_1959F50_x86(pDB, i); + DWORD dwResult2 = pDB->sub_1959F50(i); + + assert(dwResult1 == dwResult2); + } +} + +void TestMndxRootFile(PCASC_MNDX_INFO pMndxInfo) +{ + size_t nLength; + char szFileName[MAX_PATH+1]; + void * pvListFile; + + // Exercise low level functions and compare their results + // with original code from Heroes of the Storm + TestMndxFunctions(pMndxInfo->pMarFile1); + TestMndxFunctions(pMndxInfo->pMarFile2); + TestMndxFunctions(pMndxInfo->pMarFile3); + + // Find a "mods" in the package array + TestFindPackage(pMndxInfo->pMarFile3, "mods/heroes.stormmod/base.stormassets/assets/textures/glow_green2.dds"); + TestMarFile(pMndxInfo->pMarFile3, "mods/heroes.stormmod/base.stormassets/assets/textures/glow_green2.dds", 69); + + // Search the package MAR file aith a path shorter than a fragment + TestFileSearch(pMndxInfo->pMarFile1, "mods/heroes.s"); + + // Test the file search + TestFileSearch(pMndxInfo->pMarFile1, ""); + TestFileSearch(pMndxInfo->pMarFile2, ""); + TestFileSearch(pMndxInfo->pMarFile3, ""); + + // False file search + TestFileSearch(pMndxInfo->pMarFile2, "assets/textures/storm_temp_hrhu"); + + // Open the listfile stream and initialize the listfile cache + pvListFile = ListFile_OpenExternal(_T("e:\\Ladik\\Appdir\\CascLib\\listfile\\listfile-hots-29049.txt")); + if(pvListFile != NULL) + { + // Check every file in the database + while((nLength = ListFile_GetNext(pvListFile, "*", szFileName, MAX_PATH)) != 0) + { + // Normalize the file name: ToLower + BackSlashToSlash + NormalizeFileName_LowerSlash(szFileName, szFileName, MAX_PATH); + + // Check the file with all three MAR files + TestMarFile(pMndxInfo->pMarFile1, szFileName, nLength); + TestMarFile(pMndxInfo->pMarFile2, szFileName, nLength); + TestMarFile(pMndxInfo->pMarFile3, szFileName, nLength); + } + + ListFile_Free(pvListFile); + } +} +#endif // defined(_DEBUG) && defined(_X86_) && defined(CASCLIB_TEST) diff --git a/dep/CascLib/src/CascRootFile_Mndx_x86.asm b/dep/CascLib/src/CascRootFile_Mndx_x86.asm new file mode 100644 index 00000000000..bf6d6d0b489 --- /dev/null +++ b/dep/CascLib/src/CascRootFile_Mndx_x86.asm @@ -0,0 +1,4369 @@ +.686P +.MODEL FLAT +ASSUME FS: NOTHING + +; --------------------------------------------------------------------------- + +TMndxFindResult struc ; (sizeof=0x1C) ; XREF: GAME_OBJECT_03F7E848::sub_E94500_r +szSearchMask dd ? ; XREF: TMndxFindResult__SetPath+2D_w + ; TMndxFindResult__Constructor+4_w +cchSearchMask dd ? ; XREF: TMndxFindResult__SetPath:loc_1956E9A_w + ; TMndxFindResult__Constructor+6_w +field_8 dd ? ; XREF: TMndxFindResult__Constructor+9_w +szFoundPath dd ? ; XREF: TMndxFindResult__Constructor+C_w + ; TFileNameDatabase__FindFileInDatabase+55_w +cchFoundPath dd ? ; XREF: TMndxFindResult__Constructor+F_w + ; TFileNameDatabase__FindFileInDatabase+5B_w +FileNameIndex dd ? ; XREF: TMndxFindResult__Constructor+12_w + ; TFileNameDatabase__FindFileInDatabase+6B_w +pStruct40 dd ? ; XREF: MAR_FILE__FindFileInDatabase+19_r + ; TMndxFindResult__SetPath:loc_1956E8C_r +TMndxFindResult ends + +; --------------------------------------------------------------------------- + +TRIPLET struc ; (sizeof=0xC) +BitIndex dd ? ; XREF: TFileNameDatabase__CheckNextPathFragment+39_r +NextKey dd ? ; XREF: TFileNameDatabase__CheckNextPathFragment+8C_r + ; TSparseArray__GetItemValue:loc_1959B8F_r +Distance dd ? ; XREF: TFileNameDatabase__CheckNextPathFragment+3E_r + ; TSparseArray__GetItemValue:loc_1959BBE_r +TRIPLET ends + +; --------------------------------------------------------------------------- + +NAME_ENTRY struc ; (sizeof=0xC) +ExpectedHashModifier dd ? +NextHashModifier dd ? ; XREF: TArchiveDatabase__sub_1958B00+D3r + ; sub_1958D70+2Cr +FragmentOffset dd ? ; XREF: TArchiveDatabase__sub_1958B00+45r + ; sub_1958D70+36r +NAME_ENTRY ends + +; --------------------------------------------------------------------------- + +TStruct14 struc ; (sizeof=0x14) ; XREF: TFileNameDatabase::sub_1959460r +HashValue dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+44r + ; TGenericArray__InsertItem_STRUCT14+46w +field_4 dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+48r + ; TGenericArray__InsertItem_STRUCT14+4Bw +field_8 dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+4Er + ; TGenericArray__InsertItem_STRUCT14+51w +field_C dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+54r + ; TGenericArray__InsertItem_STRUCT14+57w +field_10 dd ? ; XREF: TGenericArray__InsertItem_STRUCT14+5Ar + ; TGenericArray__InsertItem_STRUCT14+5Dw +TStruct14 ends + +; --------------------------------------------------------------------------- + +TGenericArray struc ; (sizeof=0x15) ; XREF: TGenericArray::LoadDwordsArrayWithCopyr + ; TFileNameDatabase::LoadBytesr +DataBuffer dd ? ; XREF: TMndxFindResult__CreateStruct40+24w + ; TMndxFindResult__CreateStruct40+35w +field_4 dd ? ; XREF: TMndxFindResult__CreateStruct40+26w + ; TMndxFindResult__CreateStruct40+38w +ItemArray dd ? ; XREF: TMndxFindResult__CreateStruct40+29w + ; TMndxFindResult__CreateStruct40+3Bw +ItemCount dd ? ; XREF: TMndxFindResult__CreateStruct40+2Cw + ; TMndxFindResult__CreateStruct40+3Ew +MaxItemCount dd ? ; XREF: TFileNameDatabasePtr__CreateDatabase+27o + ; TMndxFindResult__CreateStruct40+2Fw +bIsValidArray db ? ; XREF: LoadAndVerifyIndexFileHeader+31w + ; TMndxFindResult__CreateStruct40+32w +TGenericArray ends + +; --------------------------------------------------------------------------- + +TBitEntryArray struc ; (sizeof=0x24) ; XREF: TGenericArrayEx::LoadFromStream_Exchanger + ; TFileNameDatabaser +DataBuffer dd ? ; XREF: TArchiveDatabase__Destructor+64r + ; TArchiveDatabase__Constructor+1A3w +field_4 dd ? ; XREF: TArchiveDatabase__Constructor+1A9w +ItemArray dd ? ; XREF: sub_1957350+31r + ; sub_19573D0+1Fr +ItemCount dd ? ; XREF: TArchiveDatabase__Constructor+1B5w +MaxItemCount dd ? ; XREF: TArchiveDatabase__Constructor+1BBw +bIsValidArray db ? ; XREF: TArchiveDatabase__Constructor+1C1w + db ? ; undefined + db ? ; undefined + db ? ; undefined +BitsPerEntry dd ? ; XREF: sub_1957350+1Fr + ; sub_19573D0+6r +EntryBitMask dd ? ; XREF: sub_1957350:loc_19573B1r + ; sub_19573D0:loc_1957419r +TotalEntries dd ? ; XREF: TGenericArrayEx__LoadFromStream:loc_195861Bw + ; TArchiveDatabase__Constructor+1D3w +TBitEntryArray ends + ; TFileNameDatabase__Constructor+1D3_w +; --------------------------------------------------------------------------- + +TStruct40 struc ; (sizeof=0x40) +array_00 TGenericArray <> ; XREF: TMndxFindResult__CreateStruct40+24w + ; TMndxFindResult__CreateStruct40+26w + db ? ; undefined + db ? ; undefined + db ? ; undefined +array_18 TGenericArray <> ; XREF: TMndxFindResult__CreateStruct40+35w + ; TMndxFindResult__CreateStruct40+38w + db ? ; undefined + db ? ; undefined + db ? ; undefined +HashValue dd ? ; XREF: TMndxFindResult__CreateStruct40+47w + ; TFileNameDatabase__CheckNextPathFragment+1Ar +CharIndex dd ? ; XREF: TMndxFindResult__CreateStruct40+4Aw + ; TFileNameDatabase__CheckNextPathFragment+11r +ItemCount dd ? ; XREF: TMndxFindResult__CreateStruct40+4Dw + ; TStruct40__InitSearchBuffers+6Bw +SearchPhase dd ? ; XREF: TMndxFindResult__CreateStruct40+50w + ; TFileNameDatabase__FindFileInDatabase+17w +TStruct40 ends + +; --------------------------------------------------------------------------- + +TSparseArray struc ; (sizeof=0x65) ; XREF: TSparseArray::LoadFromStream_Exchange_r + ; TNameIndexStruct_r +ItemIsPresent TGenericArray <> ; XREF: LoadAndVerifyIndexFileHeader+31_w + ; TFileNameDatabase__Destructor+4C_r + db ? ; undefined + db ? ; undefined + db ? ; undefined +TotalItemCount dd ? ; XREF: TSparseArray__ExchangeWith+4D_r + ; TSparseArray__ExchangeWith+56_w +ValidItemCount dd ? ; XREF: TFileNameDatabasePtr__GetFileNameCount:loc_1956D32_r + ; TSparseArray__ExchangeWith+59_r +ArrayTriplets_20 TGenericArray <> ; XREF: TFileNameDatabase__Destructor+40_r + ; TFileNameDatabase__Destructor+94_r + db ? ; undefined + db ? ; undefined + db ? ; undefined +ArrayDwords_38 TGenericArray <> ; XREF: TFileNameDatabasePtr__CreateDatabase+27_o + ; TFileNameDatabase__Destructor+34_r + db ? ; undefined + db ? ; undefined + db ? ; undefined +ArrayDwords_50 TGenericArray <> ; XREF: TFileNameDatabase__Destructor+28_r + ; TFileNameDatabase__Destructor+7C_r +TSparseArray ends + +; --------------------------------------------------------------------------- + +TNameIndexStruct struc ; (sizeof=0x7D) ; XREF: TNameIndexStruct::LoadFromStream_Exchange_r + ; TFileNameDatabaser +NameFragments TGenericArray <> ; XREF: TFileNameDatabase__Destructor+58_r + ; TFileNameDatabase__LoadFromStream+82_r + db ? ; undefined + db ? ; undefined + db ? ; undefined +Struct68 TSparseArray <> ; XREF: LoadAndVerifyIndexFileHeader+31_w + ; TFileNameDatabase__Destructor+28_r +TNameIndexStruct ends + +; --------------------------------------------------------------------------- + +TByteStream struc ; (sizeof=0x18) ; XREF: TFileNameDatabasePtr::CreateDatabase_r + ; TFileNameDatabase_r +pbData dd ? ; XREF: TByteStream__Constructor+4_w + ; TByteStream__IsMarDataValid+2_r +pvMappedFile dd ? ; XREF: TByteStream__Constructor+6_w + ; TByteStream__Destructor+3_r +cbData dd ? ; XREF: TByteStream__Constructor+9_w + ; TByteStream__GetBytes:loc_1959A05_r +field_C dd ? ; XREF: TByteStream__Constructor+C_w +hFile dd ? ; XREF: TByteStream__Constructor+F_w + ; TByteStream__Destructor:loc_19599D2_r +hMap dd ? ; XREF: TByteStream__Constructor+12_w + ; TByteStream__Destructor:loc_19599C2_r +TByteStream ends + +; --------------------------------------------------------------------------- + +TStruct10 struc ; (sizeof=0x10) ; XREF: TStruct10::sub_1957800_r + ; TFileNameDatabase_r +field_0 dd ? ; XREF: sub_19572E0+24_w + ; TFileNameDatabase__Constructor+21A_w +field_4 dd ? ; XREF: sub_1956FD0+28_w + ; sub_1956FD0:loc_1957001_w +field_8 dd ? ; XREF: sub_19572E0+4A_w + ; sub_19572E0+5B_w +field_C dd ? ; XREF: sub_1957050:loc_1957074_w + ; sub_1957050:loc_1957081_w +TStruct10 ends + +; --------------------------------------------------------------------------- + +TFileNameDatabasePtr struc ; (sizeof=0x4) ; XREF: TFileNameDatabase_r + ; MAR_FILE_r +pDatabase dd ? ; XREF: MAR_FILE__Constructor+1D_w + ; MAR_FILE__CreateDatabase+22_w +TFileNameDatabasePtr ends + +; --------------------------------------------------------------------------- + +TFileNameDatabase struc ; (sizeof=0x240) ; XREF: TFileNameDatabase::LoadFromStream_Exchange_r +Struct68_00 TSparseArray <> ; XREF: TFileNameDatabasePtr__CreateDatabase+27_o + ; TFileNameDatabase__Destructor+D9_r + db ? ; undefined + db ? ; undefined + db ? ; undefined +FileNameIndexes TSparseArray <> ; XREF: TFileNameDatabasePtr__GetFileNameCount:loc_1956D32_r + ; TFileNameDatabase__Destructor+AC_r + db ? ; undefined + db ? ; undefined + db ? ; undefined +Struct68_D0 TSparseArray <> ; XREF: TFileNameDatabase__Destructor+7C_r + ; TFileNameDatabase__Destructor+88_r + db ? ; undefined + db ? ; undefined + db ? ; undefined +FrgmDist_LoBits TGenericArray <> ; XREF: TFileNameDatabase__Destructor+70_r + ; TFileNameDatabase__CheckNextPathFragment:loc_1957AC9_r + db ? ; undefined + db ? ; undefined + db ? ; undefined +FrgmDist_HiBits TBitEntryArray <> ; XREF: TFileNameDatabase__Destructor+64_r + ; TFileNameDatabase__CheckNextPathFragment+119_r +IndexStruct_174 TNameIndexStruct <> ; XREF: TFileNameDatabase__Destructor+28_r + ; TFileNameDatabase__Destructor+34_r + db ? ; undefined + db ? ; undefined + db ? ; undefined +NextDB TFileNameDatabasePtr <> ; XREF: TFileNameDatabase__Destructor+1D_o + ; TFileNameDatabase__CheckNextPathFragment+52_r +NameFragTable TGenericArray <> ; XREF: TFileNameDatabase__Destructor+E_r + ; TFileNameDatabase__CheckNextPathFragment+2F_r + db ? ; undefined + db ? ; undefined + db ? ; undefined +NameFragIndexMask dd ? ; XREF: TFileNameDatabase__CheckNextPathFragment+26_r + ; sub_1957B80:loc_1957B95_r +field_214 dd ? ; XREF: TFileNameDatabase__Constructor+20E_w + ; TFileNameDatabase__LoadFromStream+110_w +Struct10 TStruct10 <> ; XREF: TFileNameDatabase__Constructor+21A_w + ; TFileNameDatabase__Constructor+224_w +MarStream TByteStream <> ; XREF: TFileNameDatabase__Destructor+3_o + ; TFileNameDatabase__Constructor+214_o +TFileNameDatabase ends + +; --------------------------------------------------------------------------- + +MAR_FILE struc ; (sizeof=0xC) +pDatabasePtr TFileNameDatabasePtr <> ; XREF: MAR_FILE__Constructor+1D_w + ; MAR_FILE__CreateDatabase+22_w +pbMarFileData dd ? ; XREF: MAR_FILE__Constructor+1A_w + ; MAR_FILE__CreateDatabase+1B_r +cbMarFileData dd ? ; XREF: MAR_FILE__Constructor+12_w + ; MAR_FILE__CreateDatabase+18_r +MAR_FILE ends + +.DATA +table_1BA1818 db 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0 + db 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0 + db 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0 + db 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0 + db 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0 + db 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0 + db 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0 + db 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 + db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0 + db 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0 + db 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0 + db 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0 + db 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0 + db 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0 + db 2, 0, 1, 0, 3 dup(7), 1, 7, 2 dup(2), 1, 7, 2 dup(3) + db 1, 3, 2 dup(2), 1, 7, 2 dup(4), 1, 4, 2 dup(2), 1, 4 + db 2 dup(3), 1, 3, 2 dup(2), 1, 7, 2 dup(5), 1, 5, 2 dup(2) + db 1, 5, 2 dup(3), 1, 3, 2 dup(2), 1, 5, 2 dup(4), 1, 4 + db 2 dup(2), 1, 4, 2 dup(3), 1, 3, 2 dup(2), 1, 7, 2 dup(6) + db 1, 6, 2 dup(2), 1, 6, 2 dup(3), 1, 3, 2 dup(2), 1, 6 + db 2 dup(4), 1, 4, 2 dup(2), 1, 4, 2 dup(3), 1, 3, 2 dup(2) + db 1, 6, 2 dup(5), 1, 5, 2 dup(2), 1, 5, 2 dup(3), 1, 3 + db 2 dup(2), 1, 5, 2 dup(4), 1, 4, 2 dup(2), 1, 4, 2 dup(3) + db 1, 3, 2 dup(2), 1, 3 dup(7), 1, 7, 2 dup(2), 1, 7, 2 dup(3) + db 1, 3, 2 dup(2), 1, 7, 2 dup(4), 1, 4, 2 dup(2), 1, 4 + db 2 dup(3), 1, 3, 2 dup(2), 1, 7, 2 dup(5), 1, 5, 2 dup(2) + db 1, 5, 2 dup(3), 1, 3, 2 dup(2), 1, 5, 2 dup(4), 1, 4 + db 2 dup(2), 1, 4, 2 dup(3), 1, 3, 2 dup(2), 1, 7, 2 dup(6) + db 1, 6, 2 dup(2), 1, 6, 2 dup(3), 1, 3, 2 dup(2), 1, 6 + db 2 dup(4), 1, 4, 2 dup(2), 1, 4, 2 dup(3), 1, 3, 2 dup(2) + db 1, 6, 2 dup(5), 1, 5, 2 dup(2), 1, 5, 2 dup(3), 1, 3 + db 2 dup(2), 1, 5, 2 dup(4), 1, 4, 2 dup(2), 1, 4, 2 dup(3) + db 1, 3, 2 dup(2), 1, 7 dup(7), 2, 3 dup(7), 3, 7, 2 dup(3) + db 2, 3 dup(7), 4, 7, 2 dup(4), 2, 7, 2 dup(4), 3, 4, 2 dup(3) + db 2, 3 dup(7), 5, 7, 2 dup(5), 2, 7, 2 dup(5), 3, 5, 2 dup(3) + db 2, 7, 2 dup(5), 4, 5, 2 dup(4), 2, 5, 2 dup(4), 3, 4 + db 2 dup(3), 2, 3 dup(7), 6, 7, 2 dup(6), 2, 7, 2 dup(6) + db 3, 6, 2 dup(3), 2, 7, 2 dup(6), 4, 6, 2 dup(4), 2, 6 + db 2 dup(4), 3, 4, 2 dup(3), 2, 7, 2 dup(6), 5, 6, 2 dup(5) + db 2, 6, 2 dup(5), 3, 5, 2 dup(3), 2, 6, 2 dup(5), 4, 5 + db 2 dup(4), 2, 5, 2 dup(4), 3, 4, 2 dup(3), 2, 7 dup(7) + db 2, 3 dup(7), 3, 7, 2 dup(3), 2, 3 dup(7), 4, 7, 2 dup(4) + db 2, 7, 2 dup(4), 3, 4, 2 dup(3), 2, 3 dup(7), 5, 7, 2 dup(5) + db 2, 7, 2 dup(5), 3, 5, 2 dup(3), 2, 7, 2 dup(5), 4, 5 + db 2 dup(4), 2, 5, 2 dup(4), 3, 4, 2 dup(3), 2, 3 dup(7) + db 6, 7, 2 dup(6), 2, 7, 2 dup(6), 3, 6, 2 dup(3), 2, 7 + db 2 dup(6), 4, 6, 2 dup(4), 2, 6, 2 dup(4), 3, 4, 2 dup(3) + db 2, 7, 2 dup(6), 5, 6, 2 dup(5), 2, 6, 2 dup(5), 3, 5 + db 2 dup(3), 2, 6, 2 dup(5), 4, 5, 2 dup(4), 2, 5, 2 dup(4) + db 3, 4, 2 dup(3), 2, 0Fh dup(7), 3, 7 dup(7), 4, 3 dup(7) + db 4, 7, 2 dup(4), 3, 7 dup(7), 5, 3 dup(7), 5, 7, 2 dup(5) + db 3, 3 dup(7), 5, 7, 2 dup(5), 4, 7, 2 dup(5), 4, 5, 2 dup(4) + db 3, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6), 3, 3 dup(7) + db 6, 7, 2 dup(6), 4, 7, 2 dup(6), 4, 6, 2 dup(4), 3, 3 dup(7) + db 6, 7, 2 dup(6), 5, 7, 2 dup(6), 5, 6, 2 dup(5), 3, 7 + db 2 dup(6), 5, 6, 2 dup(5), 4, 6, 2 dup(5), 4, 5, 2 dup(4) + db 3, 0Fh dup(7), 3, 7 dup(7), 4, 3 dup(7), 4, 7, 2 dup(4) + db 3, 7 dup(7), 5, 3 dup(7), 5, 7, 2 dup(5), 3, 3 dup(7) + db 5, 7, 2 dup(5), 4, 7, 2 dup(5), 4, 5, 2 dup(4), 3, 7 dup(7) + db 6, 3 dup(7), 6, 7, 2 dup(6), 3, 3 dup(7), 6, 7, 2 dup(6) + db 4, 7, 2 dup(6), 4, 6, 2 dup(4), 3, 3 dup(7), 6, 7, 2 dup(6) + db 5, 7, 2 dup(6), 5, 6, 2 dup(5), 3, 7, 2 dup(6), 5, 6 + db 2 dup(5), 4, 6, 2 dup(5), 4, 5, 2 dup(4), 3, 1Fh dup(7) + db 4, 0Fh dup(7), 5, 7 dup(7), 5, 3 dup(7), 5, 7, 2 dup(5) + db 4, 0Fh dup(7), 6, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6) + db 4, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6), 5, 3 dup(7) + db 6, 7, 2 dup(6), 5, 7, 2 dup(6), 5, 6, 2 dup(5), 4, 1Fh dup(7) + db 4, 0Fh dup(7), 5, 7 dup(7), 5, 3 dup(7), 5, 7, 2 dup(5) + db 4, 0Fh dup(7), 6, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6) + db 4, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6), 5, 3 dup(7) + db 6, 7, 2 dup(6), 5, 7, 2 dup(6), 5, 6, 2 dup(5), 4, 3Fh dup(7) + db 5, 1Fh dup(7), 6, 0Fh dup(7), 6, 7 dup(7), 6, 3 dup(7) + db 6, 7, 2 dup(6), 5, 3Fh dup(7), 5, 1Fh dup(7), 6, 0Fh dup(7) + db 6, 7 dup(7), 6, 3 dup(7), 6, 7, 2 dup(6), 5, 7Fh dup(7) + db 6, 7Fh dup(7), 6, 100h dup(7) + +unk_53ABE00 db 0 + +.CODE + +; +; void * operator_new_safe(size_t ByteCount, void * unk_53ABE00); +; + +EXTERN _allocate_zeroed_memory_x86:PROC +EXTERN _free_memory_x86:PROC + +j_operator_new_safe PROC + push ebp + mov ebp, esp + push [ebp+08] + call _allocate_zeroed_memory_x86 + add esp, 4 + mov esp, ebp + pop ebp + ret +j_operator_new_safe ENDP + +operator_delete PROC + push ebp + mov ebp, esp + push [ebp+08] + call _free_memory_x86 + add esp, 4 + mov esp, ebp + pop ebp + ret +operator_delete ENDP + + +TSparseArray__GetItemValue proc near ; CODE XREF: sub_1957350+1A_p + ; TFileNameDatabase__CheckNextPathFragment+103_p + +arg_0 = dword ptr 8 + + push ebp + mov ebp, esp + mov edx, [ecx+28h] + push ebx + push esi + push edi + mov edi, [ebp+arg_0] + mov eax, edi + shr eax, 9 + lea eax, [eax+eax*2] + mov esi, [edx+eax*4] + lea eax, [edx+eax*4] + mov edx, edi + shr edx, 6 + and edx, 7 + dec edx + cmp edx, 6 ; switch 7 cases + ja short loc_1959BE0 ; jumptable 01959B88 default case + jmp ds:off_1959C90[edx*4] ; switch jump + +loc_1959B8F: ; DATA XREF: .text:off_1959C90o + mov eax, [eax+4] ; jumptable 01959B88 case 0 + and eax, 7Fh + jmp short loc_1959BDE +; --------------------------------------------------------------------------- + +loc_1959B97: ; CODE XREF: TSparseArray__GetItemValue+28_j + ; DATA XREF: .text:off_1959C90o + mov edx, [eax+4] ; jumptable 01959B88 case 1 + shr edx, 7 + and edx, 0FFh + add esi, edx + jmp short loc_1959BE0 ; jumptable 01959B88 default case +; --------------------------------------------------------------------------- + +loc_1959BA7: ; CODE XREF: TSparseArray__GetItemValue+28_j + ; DATA XREF: .text:off_1959C90o + mov eax, [eax+4] ; jumptable 01959B88 case 2 + shr eax, 0Fh + and eax, 0FFh + jmp short loc_1959BDE +; --------------------------------------------------------------------------- + +loc_1959BB4: ; CODE XREF: TSparseArray__GetItemValue+28_j + ; DATA XREF: .text:off_1959C90o + mov edx, [eax+4] ; jumptable 01959B88 case 3 + shr edx, 17h + add esi, edx + jmp short loc_1959BE0 ; jumptable 01959B88 default case +; --------------------------------------------------------------------------- + +loc_1959BBE: ; CODE XREF: TSparseArray__GetItemValue+28_j + ; DATA XREF: .text:off_1959C90o + mov eax, [eax+8] ; jumptable 01959B88 case 4 + jmp short loc_1959BD9 +; --------------------------------------------------------------------------- + +loc_1959BC3: ; CODE XREF: TSparseArray__GetItemValue+28_j + ; DATA XREF: .text:off_1959C90o + mov edx, [eax+8] ; jumptable 01959B88 case 5 + shr edx, 9 + and edx, 1FFh + add esi, edx + jmp short loc_1959BE0 ; jumptable 01959B88 default case +; --------------------------------------------------------------------------- + +loc_1959BD3: ; CODE XREF: TSparseArray__GetItemValue+28_j + ; DATA XREF: .text:off_1959C90o + mov eax, [eax+8] ; jumptable 01959B88 case 6 + shr eax, 12h + +loc_1959BD9: ; CODE XREF: TSparseArray__GetItemValue+61_j + and eax, 1FFh + +loc_1959BDE: ; CODE XREF: TSparseArray__GetItemValue+35_j + ; TSparseArray__GetItemValue+52_j + add esi, eax + +loc_1959BE0: ; CODE XREF: TSparseArray__GetItemValue+26_j + ; TSparseArray__GetItemValue+45_j + mov ebx, edi ; jumptable 01959B88 default case + shr ebx, 5 + test bl, 1 + jz short loc_1959C31 + mov edx, [ecx+8] + mov edx, [edx+ebx*4-4] + mov eax, edx + shr eax, 1 + and eax, 55555555h + and edx, 55555555h + add eax, edx + mov edx, eax + and eax, 33333333h + shr edx, 2 + and edx, 33333333h + add edx, eax + mov eax, edx + shr eax, 4 + and eax, 0F0F0F0Fh + and edx, 0F0F0F0Fh + add eax, edx + imul eax, 1010101h + shr eax, 18h + add esi, eax + +loc_1959C31: ; CODE XREF: TSparseArray__GetItemValue+88_j + mov edx, [ecx+8] + mov ecx, edi + and ecx, 1Fh + mov eax, 1 + shl eax, cl + mov ecx, [edx+ebx*4] + pop edi + dec eax + and ecx, eax + mov eax, ecx + shr eax, 1 + and eax, 55555555h + and ecx, 55555555h + add eax, ecx + mov ecx, eax + and eax, 33333333h + shr ecx, 2 + and ecx, 33333333h + add ecx, eax + mov eax, ecx + shr eax, 4 + and eax, 0F0F0F0Fh + and ecx, 0F0F0F0Fh + add eax, ecx + imul eax, 1010101h + shr eax, 18h + add eax, esi + pop esi + pop ebx + pop ebp + retn 4 + +off_1959C90 dd offset loc_1959B8F ; DATA XREF: TSparseArray__GetItemValue+28_r + dd offset loc_1959B97 ; jump table for switch statement + dd offset loc_1959BA7 + dd offset loc_1959BB4 + dd offset loc_1959BBE + dd offset loc_1959BC3 + dd offset loc_1959BD3 + +TSparseArray__GetItemValue endp + +;------------------------------------------------------------------------------ +; TArchiveDatabase__sub_1959CB0 + +TArchiveDatabase__sub_1959CB0 proc near + ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+A1_p + ; sub_1958B00+E8_p + +pThis = dword ptr -4 +dwKey = dword ptr 8 + + push ebp + mov ebp, esp + push ecx + mov edx, [ebp+dwKey] + mov eax, edx + shr eax, 9 + mov [ebp+pThis], ecx + test edx, 1FFh ; if(dwKey & 0x01FF) + jnz short loc_1959CD3 + mov ecx, [ecx+40h] + mov eax, [ecx+eax*4] ; EAX = pDatabase->NextKeyTable[dwKey >> 0x09] + mov esp, ebp + pop ebp + retn 4 +; --------------------------------------------------------------------------- + +loc_1959CD3: ; CODE XREF: TFileNameDatabase__FindNextMatch+15_j + push ebx + push esi + mov esi, [ecx+40h] + lea esi, [esi+eax*4] + mov eax, [esi] + mov esi, [esi+4] + shr eax, 9 + add esi, 1FFh + push edi + shr esi, 9 + lea edi, [eax+0Ah] + mov [ebp+dwKey], esi + cmp edi, esi + jb short loc_1959D2E + mov edi, [ecx+28h] + lea esi, [eax+eax*2+3] + lea esi, [edi+esi*4] + mov edi, eax + shl edi, 9 + mov ebx, edi + sub ebx, [esi] + add ebx, 200h + cmp edx, ebx + jb short loc_1959D5F + +loc_1959D14: ; CODE XREF: TFileNameDatabase__FindNextMatch+7Aj + add edi, 200h + add esi, 0Ch + mov ebx, edi + sub ebx, [esi] + inc eax + add ebx, 200h + cmp edx, ebx + jnb short loc_1959D14 + jmp short loc_1959D5F +; --------------------------------------------------------------------------- + +loc_1959D2E: ; CODE XREF: TFileNameDatabase__FindNextMatch+45_j + lea edi, [eax+1] + cmp edi, esi + jnb short loc_1959D5F + mov ecx, [ecx+28h] + +loc_1959D38: ; CODE XREF: TFileNameDatabase__FindNextMatch+AAj + add esi, eax + shr esi, 1 + mov ebx, esi + shl ebx, 9 + lea edi, [esi+esi*2] + sub ebx, [ecx+edi*4] + cmp edx, ebx + jnb short loc_1959D50 + mov [ebp+dwKey], esi + jmp short loc_1959D55 +; --------------------------------------------------------------------------- + +loc_1959D50: ; CODE XREF: TFileNameDatabase__FindNextMatch+99_j + mov eax, esi + mov esi, [ebp+dwKey] + +loc_1959D55: ; CODE XREF: TFileNameDatabase__FindNextMatch+9E_j + lea edi, [eax+1] + cmp edi, esi + jb short loc_1959D38 + mov ecx, [ebp+pThis] + +loc_1959D5F: ; CODE XREF: TFileNameDatabase__FindNextMatch+62_j + ; TFileNameDatabase__FindNextMatch+7C_j + mov ecx, [ecx+28h] + lea esi, [eax+eax*2] + mov edi, [ecx+esi*4] ; EDI = Struct68_00.ArrayTriplets_20.ItemArray[eax] + lea esi, [ecx+esi*4] ; ESI = Struct68_00.ArrayTriplets_20.ItemArray + eax + mov ecx, eax + shl ecx, 9 + sub edi, ecx + shl eax, 4 + add edx, edi + mov edi, eax + mov eax, [esi+4] + mov ecx, eax + shr ecx, 17h + mov ebx, 100h + sub ebx, ecx + cmp edx, ebx + jnb short loc_1959DE8 + mov ecx, eax + shr ecx, 7 + and ecx, 0FFh + mov esi, 80h + sub esi, ecx + cmp edx, esi + jnb short loc_1959DC0 + and eax, 7Fh + mov ecx, 40h + sub ecx, eax + cmp edx, ecx + jb loc_1959E53 + add edi, 2 + lea edx, [edx+eax-40h] + jmp loc_1959E53 +; --------------------------------------------------------------------------- + +loc_1959DC0: ; CODE XREF: TFileNameDatabase__FindNextMatch+F0_j + shr eax, 0Fh + and eax, 0FFh + mov esi, 0C0h + sub esi, eax + cmp edx, esi + jnb short loc_1959DDC + add edi, 4 + lea edx, [edx+ecx-80h] + jmp short loc_1959E53 +; --------------------------------------------------------------------------- + +loc_1959DDC: ; CODE XREF: TFileNameDatabase__FindNextMatch+121_j + add edi, 6 + lea edx, [edx+eax-0C0h] + jmp short loc_1959E53 +; --------------------------------------------------------------------------- + +loc_1959DE8: ; CODE XREF: TFileNameDatabase__FindNextMatch+DA_j + mov esi, [esi+8] + mov eax, esi + shr eax, 9 + and eax, 1FFh + mov ebx, 180h + sub ebx, eax + cmp edx, ebx + jnb short loc_1959E29 + and esi, 1FFh + mov eax, 140h + sub eax, esi + cmp edx, eax + jnb short loc_1959E1D + add edi, 8 + lea edx, [edx+ecx-100h] + jmp short loc_1959E53 +; --------------------------------------------------------------------------- + +loc_1959E1D: ; CODE XREF: TFileNameDatabase__FindNextMatch+15F_j + add edi, 0Ah + lea edx, [edx+esi-140h] + jmp short loc_1959E53 +; --------------------------------------------------------------------------- + +loc_1959E29: ; CODE XREF: TFileNameDatabase__FindNextMatch+14E_j + shr esi, 12h + and esi, 1FFh + mov ecx, 1C0h + sub ecx, esi + cmp edx, ecx + jnb short loc_1959E49 + add edi, 0Ch + lea edx, [edx+eax-180h] + jmp short loc_1959E53 +; --------------------------------------------------------------------------- + +loc_1959E49: ; CODE XREF: TFileNameDatabase__FindNextMatch+18B_j + add edi, 0Eh + lea edx, [edx+esi-1C0h] + +loc_1959E53: ; CODE XREF: TFileNameDatabase__FindNextMatch+FE_j + ; TFileNameDatabase__FindNextMatch+10B_j + mov eax, [ebp+pThis] + mov ebx, [eax+8] + mov ecx, [ebx+edi*4] + not ecx + mov eax, ecx + shr eax, 1 + and eax, 55555555h + mov esi, ecx + and esi, 55555555h + add eax, esi + mov esi, eax + shr esi, 2 + and eax, 33333333h + and esi, 33333333h + add esi, eax + mov eax, esi + shr eax, 4 + and esi, 0F0F0F0Fh + and eax, 0F0F0F0Fh + add eax, esi + imul eax, 1010101h + mov esi, eax + shr esi, 18h + cmp edx, esi + jb short loc_1959EEA + mov ecx, [ebx+edi*4+4] + inc edi + sub edx, esi + not ecx + mov eax, ecx + shr eax, 1 + and eax, 55555555h + mov esi, ecx + and esi, 55555555h + add eax, esi + mov esi, eax + shr esi, 2 + and eax, 33333333h + and esi, 33333333h + add esi, eax + mov eax, esi + shr eax, 4 + and eax, 0F0F0F0Fh + and esi, 0F0F0F0Fh + add eax, esi + imul eax, 1010101h + +loc_1959EEA: ; CODE XREF: TFileNameDatabase__FindNextMatch+1F2_j + mov esi, eax + shr esi, 8 + and esi, 0FFh + shl edi, 5 + cmp edx, esi + jnb short loc_1959F0D + and eax, 0FFh + cmp edx, eax + jb short loc_1959F2B + add edi, 8 + shr ecx, 8 + jmp short loc_1959F29 +; --------------------------------------------------------------------------- + +loc_1959F0D: ; CODE XREF: TFileNameDatabase__FindNextMatch+24A_j + shr eax, 10h + and eax, 0FFh + cmp edx, eax + jnb short loc_1959F23 + add edi, 10h + shr ecx, 10h + sub edx, esi + jmp short loc_1959F2B +; --------------------------------------------------------------------------- + +loc_1959F23: ; CODE XREF: TFileNameDatabase__FindNextMatch+267_j + add edi, 18h + shr ecx, 18h + +loc_1959F29: ; CODE XREF: TFileNameDatabase__FindNextMatch+25B_j + sub edx, eax + +loc_1959F2B: ; CODE XREF: TFileNameDatabase__FindNextMatch+253_j + ; TFileNameDatabase__FindNextMatch+271_j + and ecx, 0FFh + shl edx, 8 + movzx eax, byte ptr ds:table_1BA1818[ecx+edx] + add eax, edi + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + retn 4 +TArchiveDatabase__sub_1959CB0 endp + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +TNameIndexStruct__CheckNameFragment proc near ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+6B_p + ; TFileNameDatabase__CheckNextPathFragment+191_p + +pThis = dword ptr -4 +pUnknownStruct1C= dword ptr 8 +dwDistance = dword ptr 0Ch + + push ebp + mov ebp, esp + push ecx + push ebx + push esi + push edi + mov edi, ecx + cmp [edi+TNameIndexStruct.Struct68.TotalItemCount], 0 + mov ecx, [ebp+pUnknownStruct1C] + mov edx, [ecx+TMndxFindResult.pStruct40] + mov [ebp+pThis], edi + jnz short loc_195A1C8 + mov edi, [edi+TNameIndexStruct.NameFragments.ItemArray] ; Pointer to name table + sub edi, [edx+TStruct40.CharIndex] + add edi, [ebp+dwDistance] ; EDI = szPathFragment + +loc_195A1A1: ; CODE XREF: TNameIndexStruct__CheckNameFragment+3Bj + mov eax, [edx+TStruct40.CharIndex] + mov esi, [ecx+TMndxFindResult.szSearchMask] + mov bl, [eax+edi] + cmp bl, [eax+esi] + jnz short loc_195A1BD + inc eax + mov [edx+TStruct40.CharIndex], eax + cmp byte ptr [eax+edi], 0 + jz short loc_195A215 + cmp eax, [ecx+TMndxFindResult.cchSearchMask] + jb short loc_195A1A1 + +loc_195A1BD: ; CODE XREF: TNameIndexStruct__CheckNameFragment+2C_j + ; TNameIndexStruct__CheckNameFragment+5Ej + pop edi + pop esi + xor al, al + pop ebx + mov esp, ebp + pop ebp + retn 8 +; --------------------------------------------------------------------------- + +loc_195A1C8: ; CODE XREF: TNameIndexStruct__CheckNameFragment+16_j + mov eax, [ebp+dwDistance] + jmp short loc_195A1D0 +; --------------------------------------------------------------------------- + align 10h + +loc_195A1D0: ; CODE XREF: TNameIndexStruct__CheckNameFragment+4B_j + ; TNameIndexStruct__CheckNameFragment+93j + mov ebx, [edi+TNameIndexStruct.NameFragments.ItemArray] + mov esi, [edx+TStruct40.CharIndex] + mov ecx, [ecx+TMndxFindResult.szSearchMask] + mov bl, [eax+ebx] ; pNameList[dwNameOffset] == szPathName[nCharIndex] + cmp bl, [esi+ecx] + jnz short loc_195A1BD + lea ecx, [esi+1] + mov [edx+TStruct40.CharIndex], ecx + mov edi, [edi+TNameIndexStruct.Struct68.ItemIsPresent.ItemArray] + mov [ebp+dwDistance], ecx + mov ecx, eax + and ecx, 1Fh ; ecx = (dwNameOffset & 0x1F) + mov esi, eax + mov ebx, 1 + shl ebx, cl ; ebx = 1 << (dwNameOffset & 0x1F); + shr esi, 5 ; esi = (dwNameOffset >> 0x05) + mov ecx, [edi+esi*4] + inc eax + and ecx, ebx + jnz short loc_195A215 + mov esi, [ebp+dwDistance] + mov ecx, [ebp+pUnknownStruct1C] + cmp esi, [ecx+4] + jnb short loc_195A1BD + mov edi, [ebp+pThis] + jmp short loc_195A1D0 +; --------------------------------------------------------------------------- + +loc_195A215: ; CODE XREF: TNameIndexStruct__CheckNameFragment+36_j + ; TNameIndexStruct__CheckNameFragment+83_j + pop edi + pop esi + mov al, 1 + pop ebx + mov esp, ebp + pop ebp + retn 8 +TNameIndexStruct__CheckNameFragment endp + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +sub_1957350 proc near ; CODE XREF: sub_1957B80+D8p + ; sub_1957B80:loc_1957C73p + +arg_0 = dword ptr 8 + + push ebp + mov ebp, esp + mov eax, [ebp+arg_0] + push ebx + push esi + mov esi, ecx + mov ebx, [esi+140h] + push edi + push eax + lea ecx, [esi+0D0h] + add ebx, eax + call TSparseArray__GetItemValue + mov edi, [esi+168h] + mov ecx, edi + imul ecx, eax + mov eax, ecx + and ecx, 1Fh + mov edx, ecx + mov ecx, [esi+158h] + add edi, edx + shr eax, 5 + cmp edi, 20h + ja short loc_195739A + mov eax, [ecx+eax*4] + mov ecx, edx + shr eax, cl + jmp short loc_19573B1 +; --------------------------------------------------------------------------- + +loc_195739A: ; CODE XREF: sub_1957350+3F_j + lea edi, [ecx+eax*4] + mov eax, [edi+4] + mov edi, [edi] + mov ecx, 20h + sub ecx, edx + shl eax, cl + mov ecx, edx + shr edi, cl + or eax, edi + +loc_19573B1: ; CODE XREF: sub_1957350+48_j + and eax, [esi+16Ch] + movzx edx, byte ptr [ebx] + pop edi + shl eax, 8 + pop esi + or eax, edx + pop ebx + pop ebp + retn 4 +sub_1957350 endp + +; --------------------------------------------------------------------------- + + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +sub_1959F50 proc near ; CODE XREF: sub_1957B80+14C_p + ; sub_1958980+62_p + +var_4 = dword ptr -4 +arg_0 = dword ptr 8 + + push ebp + mov ebp, esp + push ecx + mov edx, [ebp+arg_0] + mov eax, edx + shr eax, 9 + mov [ebp+var_4], ecx + test edx, 1FFh + jnz short loc_1959F73 + mov ecx, [ecx+58h] + mov eax, [ecx+eax*4] + mov esp, ebp + pop ebp + retn 4 +; --------------------------------------------------------------------------- + +loc_1959F73: ; CODE XREF: sub_1959F50+15_j + push ebx + push esi + mov esi, [ecx+58h] + lea esi, [esi+eax*4] + mov eax, [esi] + push edi + mov edi, [esi+4] + shr eax, 9 + add edi, 1FFh + shr edi, 9 + lea esi, [eax+0Ah] + cmp esi, edi + jb short loc_1959FAD + mov edi, [ecx+28h] + lea esi, [eax+eax*2+3] + cmp edx, [edi+esi*4] + lea esi, [edi+esi*4] + jb short loc_1959FD4 + +loc_1959FA3: ; CODE XREF: sub_1959F50+59j + add esi, 0Ch + inc eax + cmp edx, [esi] + jnb short loc_1959FA3 + jmp short loc_1959FD4 +; --------------------------------------------------------------------------- + +loc_1959FAD: ; CODE XREF: sub_1959F50+42_j + lea esi, [eax+1] + cmp esi, edi + jnb short loc_1959FD4 + mov ecx, [ecx+28h] + +loc_1959FB7: ; CODE XREF: sub_1959F50+7Fj + lea esi, [edi+eax] + shr esi, 1 + lea ebx, [esi+esi*2] + cmp edx, [ecx+ebx*4] + jnb short loc_1959FC8 + mov edi, esi + jmp short loc_1959FCA +; --------------------------------------------------------------------------- + +loc_1959FC8: ; CODE XREF: sub_1959F50+72_j + mov eax, esi + +loc_1959FCA: ; CODE XREF: sub_1959F50+76_j + lea esi, [eax+1] + cmp esi, edi + jb short loc_1959FB7 + mov ecx, [ebp+var_4] + +loc_1959FD4: ; CODE XREF: sub_1959F50+51_j + ; sub_1959F50+5B_j + mov edi, [ecx+28h] + lea esi, [eax+eax*2] + sub edx, [edi+esi*4] + shl eax, 4 + lea esi, [edi+esi*4] + mov edi, eax + mov eax, [esi+4] + mov ebx, eax + shr ebx, 17h + cmp edx, ebx + jnb short loc_195A026 + mov esi, eax + shr esi, 7 + and esi, 0FFh + cmp edx, esi + jnb short loc_195A00E + and eax, 7Fh + cmp edx, eax + jb short loc_195A066 + add edi, 2 + sub edx, eax + jmp short loc_195A066 +; --------------------------------------------------------------------------- + +loc_195A00E: ; CODE XREF: sub_1959F50+AE_j + shr eax, 0Fh + and eax, 0FFh + cmp edx, eax + jnb short loc_195A01F + add edi, 4 + jmp short loc_195A064 +; --------------------------------------------------------------------------- + +loc_195A01F: ; CODE XREF: sub_1959F50+C8_j + add edi, 6 + sub edx, eax + jmp short loc_195A066 +; --------------------------------------------------------------------------- + +loc_195A026: ; CODE XREF: sub_1959F50+9F_j + mov esi, [esi+8] + mov eax, esi + shr eax, 9 + and eax, 1FFh + cmp edx, eax + jnb short loc_195A04D + and esi, 1FFh + cmp edx, esi + jnb short loc_195A048 + add edi, 8 + sub edx, ebx + jmp short loc_195A066 +; --------------------------------------------------------------------------- + +loc_195A048: ; CODE XREF: sub_1959F50+EF_j + add edi, 0Ah + jmp short loc_195A064 +; --------------------------------------------------------------------------- + +loc_195A04D: ; CODE XREF: sub_1959F50+E5_j + shr esi, 12h + and esi, 1FFh + cmp edx, esi + jnb short loc_195A061 + add edi, 0Ch + sub edx, eax + jmp short loc_195A066 +; --------------------------------------------------------------------------- + +loc_195A061: ; CODE XREF: sub_1959F50+108_j + add edi, 0Eh + +loc_195A064: ; CODE XREF: sub_1959F50+CD_j + ; sub_1959F50+FB_j + sub edx, esi + +loc_195A066: ; CODE XREF: sub_1959F50+B5_j + ; sub_1959F50+BC_j + mov ebx, [ecx+8] + mov esi, [ebx+edi*4] + mov eax, esi + shr eax, 1 + and eax, 55555555h + mov ecx, esi + and ecx, 55555555h + add eax, ecx + mov ecx, eax + shr ecx, 2 + and eax, 33333333h + and ecx, 33333333h + add ecx, eax + mov eax, ecx + shr eax, 4 + and ecx, 0F0F0F0Fh + and eax, 0F0F0F0Fh + add eax, ecx + imul eax, 1010101h + mov ecx, eax + shr ecx, 18h + cmp edx, ecx + jb short loc_195A0F6 + mov esi, [ebx+edi*4+4] + sub edx, ecx + inc edi + mov eax, esi + shr eax, 1 + and eax, 55555555h + mov ecx, esi + and ecx, 55555555h + add eax, ecx + mov ecx, eax + shr ecx, 2 + and eax, 33333333h + and ecx, 33333333h + add ecx, eax + mov eax, ecx + shr eax, 4 + and eax, 0F0F0F0Fh + and ecx, 0F0F0F0Fh + add eax, ecx + imul eax, 1010101h + +loc_195A0F6: ; CODE XREF: sub_1959F50+160_j + mov ecx, eax + shr ecx, 8 + and ecx, 0FFh + shl edi, 5 + cmp edx, ecx + jnb short loc_195A119 + and eax, 0FFh + cmp edx, eax + jb short loc_195A137 + add edi, 8 + shr esi, 8 + jmp short loc_195A135 +; --------------------------------------------------------------------------- + +loc_195A119: ; CODE XREF: sub_1959F50+1B6_j + shr eax, 10h + and eax, 0FFh + cmp edx, eax + jnb short loc_195A12F + add edi, 10h + shr esi, 10h + sub edx, ecx + jmp short loc_195A137 +; --------------------------------------------------------------------------- + +loc_195A12F: ; CODE XREF: sub_1959F50+1D3_j + add edi, 18h + shr esi, 18h + +loc_195A135: ; CODE XREF: sub_1959F50+1C7_j + sub edx, eax + +loc_195A137: ; CODE XREF: sub_1959F50+1BF_j + ; sub_1959F50+1DD_j + and esi, 0FFh + shl edx, 8 + movzx eax, ds:table_1BA1818[esi+edx] + add eax, edi + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + retn 4 +sub_1959F50 endp + +; --------------------------------------------------------------------------- + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +sub_1957B80 proc near ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+5E_p + ; TFileNameDatabase__CheckNextPathFragment+180_p + +pStruct40 = dword ptr -4 +arg_0 = dword ptr 8 +arg_4 = dword ptr 0Ch + + push ebp + mov ebp, esp + push ecx + push ebx + mov ebx, [ebp+arg_0] + mov eax, [ebx+18h] + push esi + push edi + mov edi, [ebp+arg_4] + mov esi, ecx + mov [ebp+pStruct40], eax + +loc_1957B95: ; CODE XREF: sub_1957B80+9Fj + ; sub_1957B80+156j + mov eax, [esi+TFileNameDatabase.NameFragIndexMask] + and eax, edi + lea ecx, [eax+eax*2] + mov eax, [esi+TFileNameDatabase.NameFragTable.ItemArray] + add ecx, ecx + add ecx, ecx + add eax, ecx + mov [ebp+arg_4], ecx + cmp edi, [eax+4] + jnz short loc_1957C30 + mov edx, [eax+8] + mov edi, edx + and edi, 0FFFFFF00h + cmp edi, 0FFFFFF00h + jz short loc_1957BEE + mov ecx, [esi+TFileNameDatabase.NextDB.pDatabase] + push edx + push ebx + test ecx, ecx + jz short loc_1957BDA + call sub_1957B80 + jmp short loc_1957BE5 +; --------------------------------------------------------------------------- + +loc_1957BDA: ; CODE XREF: sub_1957B80+51_j + lea ecx, [esi+TFileNameDatabase.IndexStruct_174] + call TNameIndexStruct__CheckNameFragment + +loc_1957BE5: ; CODE XREF: sub_1957B80+58_j + test al, al + jz short loc_1957C25 + mov ecx, [ebp+arg_4] + jmp short loc_1957C05 +; --------------------------------------------------------------------------- + +loc_1957BEE: ; CODE XREF: sub_1957B80+45_j + mov edx, [ebp+pStruct40] + mov edi, [edx+34h] + mov edx, [ebx] + mov al, [eax+8] + cmp al, [edi+edx] + jnz short loc_1957C25 + mov edx, [ebp+pStruct40] + inc edi + mov [edx+34h], edi + +loc_1957C05: ; CODE XREF: sub_1957B80+6C_j + mov eax, [esi+200h] + mov edi, [ecx+eax] + test edi, edi + jz loc_1957CDB + mov ecx, [ebp+pStruct40] + mov edx, [ecx+34h] + cmp edx, [ebx+4] + jb loc_1957B95 + +loc_1957C25: ; CODE XREF: sub_1957B80+67_j + ; sub_1957B80+7C_j + pop edi + pop esi + xor al, al + pop ebx + mov esp, ebp + pop ebp + retn 8 +; --------------------------------------------------------------------------- + +loc_1957C30: ; CODE XREF: sub_1957B80+32_j + mov edx, [esi+0D8h] + mov ecx, edi + and ecx, 1Fh + mov ebx, 1 + shl ebx, cl + mov eax, edi + shr eax, 5 + test [edx+eax*4], ebx + jz short loc_1957C8E + cmp dword ptr [esi+1F4h], 0 + push edi + mov ecx, esi + jz short loc_1957C73 + call sub_1957350 + mov ecx, [esi+1F4h] + mov ebx, [ebp+arg_0] + push eax + push ebx + test ecx, ecx + jz short loc_1957C7D + call sub_1957B80 + jmp short loc_1957C88 +; --------------------------------------------------------------------------- + +loc_1957C73: ; CODE XREF: sub_1957B80+D6_j + call sub_1957350 + mov ebx, [ebp+arg_0] + push eax + push ebx + +loc_1957C7D: ; CODE XREF: sub_1957B80+EA_j + lea ecx, [esi+174h] + call TNameIndexStruct__CheckNameFragment + +loc_1957C88: ; CODE XREF: sub_1957B80+F1_j + test al, al + jz short loc_1957C25 + jmp short loc_1957CB2 +; --------------------------------------------------------------------------- + +loc_1957C8E: ; CODE XREF: sub_1957B80+CA_j + mov eax, [ebp+pStruct40] + mov ecx, [esi+140h] + mov ebx, [ebp+arg_0] + mov eax, [eax+34h] + mov edx, [ebx] + mov cl, [edi+ecx] + cmp cl, [eax+edx] + jnz loc_1957C25 + mov edx, [ebp+pStruct40] + inc eax + mov [edx+34h], eax + +loc_1957CB2: ; CODE XREF: sub_1957B80+10C_j + cmp edi, [esi+214h] + jbe short loc_1957CDB + mov eax, [ebp+pStruct40] + mov ecx, [eax+34h] + cmp ecx, [ebx+4] + jnb loc_1957C25 + push edi + mov ecx, esi + call sub_1959F50 + sub eax, edi + lea edi, [eax-1] + jmp loc_1957B95 +; --------------------------------------------------------------------------- + +loc_1957CDB: ; CODE XREF: sub_1957B80+90_j + ; sub_1957B80+138_j + pop edi + pop esi + mov al, 1 + pop ebx + mov esp, ebp + pop ebp + retn 8 +sub_1957B80 endp + + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +sub_19573D0 proc near ; CODE XREF: TFileNameDatabase__sub_1959460+1D9p + +arg_0 = dword ptr 8 +arg_4 = dword ptr 0Ch + + push ebp + mov ebp, esp + push esi + mov esi, ecx + mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry] + mov eax, edx + imul eax, [ebp+arg_4] + mov ecx, eax + and eax, 1Fh + add edx, eax + shr ecx, 5 + cmp edx, 20h + mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.ItemArray] + ja short loc_1957400 + mov edx, [edx+ecx*4] + mov ecx, eax + shr edx, cl + jmp short loc_1957419 +; --------------------------------------------------------------------------- + +loc_1957400: ; CODE XREF: sub_19573D0+25j + push edi + lea edi, [edx+ecx*4] + mov edx, [edi+4] + mov edi, [edi] + mov ecx, 20h + sub ecx, eax + shl edx, cl + mov ecx, eax + shr edi, cl + or edx, edi + pop edi + +loc_1957419: ; CODE XREF: sub_19573D0+2Ej + and edx, [esi+TFileNameDatabase.FrgmDist_HiBits.EntryBitMask] + mov eax, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] + mov ecx, [ebp+arg_0] + movzx eax, byte ptr [eax+ecx] + shl edx, 8 + or eax, edx + pop esi + pop ebp + retn 8 +sub_19573D0 endp + +; --------------------------------------------------------------------------- + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +TFileNameDatabase__CheckNextPathFragment proc near ; CODE XREF: TFileNameDatabase__FindFileInDatabase+25p + +var_C = dword ptr -0Ch +CollisionIndex = dword ptr -8 +var_4 = dword ptr -4 +pStruct1C = dword ptr 8 + + push ebp + mov ebp, esp + mov edx, [ebp+pStruct1C] + sub esp, 0Ch + push ebx + mov ebx, [edx+TMndxFindResult.szSearchMask] + push esi + push edi + mov edi, [edx+TMndxFindResult.pStruct40] + mov eax, [edi+TStruct40.CharIndex] + movzx eax, byte ptr [eax+ebx] ; EAX = szPathName[nCharIndex] + mov esi, ecx + mov ecx, [edi+TStruct40.HashValue] + mov ebx, ecx + shl ebx, 5 + xor eax, ebx + xor eax, ecx + and eax, [esi+TFileNameDatabase.NameFragIndexMask] ; (000000ff) - Mask value + lea ebx, [eax+eax*2] + mov eax, [esi+TFileNameDatabase.NameFragTable.ItemArray] ; (7f3ae128) - Array of 256 triplets + add ebx, ebx + add ebx, ebx ; EBX = Offset of the triplet we want to know + cmp ecx, [eax+ebx+TRIPLET.BitIndex] + jnz short loc_1957A0E + mov eax, [eax+ebx+TRIPLET.Distance] + mov ecx, eax + and ecx, 0FFFFFF00h + cmp ecx, 0FFFFFF00h + jz short loc_19579EF + mov ecx, [esi+TFileNameDatabase.NextDB.pDatabase] + push eax + push edx + test ecx, ecx + jz short loc_19579D5 + call sub_1957B80 + jmp short loc_19579E0 +; --------------------------------------------------------------------------- + +loc_19579D5: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+5C_j + lea ecx, [esi+TFileNameDatabase.IndexStruct_174] + call TNameIndexStruct__CheckNameFragment + +loc_19579E0: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+63_j + test al, al + jnz short loc_19579F6 + +loc_19579E4: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+C1j + ; TFileNameDatabase__CheckNextPathFragment+1A4j + pop edi + pop esi + xor al, al + pop ebx + mov esp, ebp + pop ebp + retn 4 +; --------------------------------------------------------------------------- + +loc_19579EF: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+50_j + mov eax, [edi+TStruct40.CharIndex] ; nCharIndex = nCharIndex + 1 + inc eax + mov [edi+TStruct40.CharIndex], eax + +loc_19579F6: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+72_j + mov edx, [esi+TFileNameDatabase.NameFragTable.ItemArray] ; EDX = pTripletArray + mov eax, [edx+ebx+TRIPLET.NextKey] + mov [edi+TStruct40.HashValue], eax + +loc_1957A03: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+198j + pop edi + pop esi + mov al, 1 + pop ebx + mov esp, ebp + pop ebp + retn 4 +; --------------------------------------------------------------------------- + +loc_1957A0E: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+3C_j + push ecx ; dwKey + mov ecx, esi ; pDatabase + call TArchiveDatabase__sub_1959CB0 + mov ebx, [esi+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray] + inc eax + mov ecx, eax + and ecx, 1Fh + mov edx, 1 + shl edx, cl + mov ecx, eax + shr ecx, 5 + mov [ebp+CollisionIndex], eax + test [ebx+ecx*4], edx + jz short loc_19579E4 + sub eax, [edi+TStruct40.HashValue] + mov [ebp+var_4], 0FFFFFFFFh + dec eax + mov [edi+TStruct40.HashValue], eax + +loc_1957A41: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+1E1j + mov eax, [edi+TStruct40.HashValue] + mov ebx, [esi+TFileNameDatabase.Struct68_D0.ItemIsPresent.ItemArray] + mov ecx, eax + and ecx, 1Fh + mov edx, 1 + shl edx, cl + mov ecx, eax + shr ecx, 5 + test [ebx+ecx*4], edx + jz loc_1957B1C + mov ecx, [ebp+var_4] + cmp ecx, 0FFFFFFFFh + jnz short loc_1957A7F + push eax + lea ecx, [esi+TFileNameDatabase.Struct68_D0] + call TSparseArray__GetItemValue + mov ecx, eax + mov [ebp+var_4], eax + jmp short loc_1957A83 +; --------------------------------------------------------------------------- + +loc_1957A7F: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+FA_j + inc ecx + mov [ebp+var_4], ecx + +loc_1957A83: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+10D_j + mov edx, [edi+TStruct40.CharIndex] + mov [ebp+var_C], edx + mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry] + mov eax, edx + imul eax, ecx + mov ecx, eax + and eax, 1Fh + add edx, eax + shr ecx, 5 + cmp edx, 20h + mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.ItemArray] + ja short loc_1957AB2 + mov edx, [edx+ecx*4] + mov ecx, eax + shr edx, cl + jmp short loc_1957AC9 +; --------------------------------------------------------------------------- + +loc_1957AB2: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+137_j + lea ebx, [edx+ecx*4] + mov edx, [ebx+4] + mov ebx, [ebx] + mov ecx, 20h + sub ecx, eax + shl edx, cl + mov ecx, eax + shr ebx, cl + or edx, ebx + +loc_1957AC9: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+140_j + mov ecx, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] + and edx, [esi+TFileNameDatabase.FrgmDist_HiBits.EntryBitMask] + mov eax, [edi+TStruct40.HashValue] + movzx eax, byte ptr [ecx+eax] + mov ecx, [esi+TFileNameDatabase.NextDB.pDatabase] + shl edx, 8 + or eax, edx + push eax + test ecx, ecx + jz short loc_1957AF7 + mov edx, [ebp+pStruct1C] + push edx + call sub_1957B80 + jmp short loc_1957B06 +; --------------------------------------------------------------------------- + +loc_1957AF7: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+17A_j + mov eax, [ebp+pStruct1C] + push eax + lea ecx, [esi+TFileNameDatabase.IndexStruct_174] + call TNameIndexStruct__CheckNameFragment + +loc_1957B06: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+185_j + test al, al + jnz loc_1957A03 + mov ecx, [ebp+var_C] + cmp [edi+TStruct40.CharIndex], ecx + jnz loc_19579E4 + jmp short loc_1957B32 +; --------------------------------------------------------------------------- + +loc_1957B1C: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+EE_j + mov edx, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] + mov ebx, [ebp+pStruct1C] + mov ecx, [edi+TStruct40.CharIndex] + mov ebx, [ebx+TMndxFindResult.szSearchMask] + mov dl, [eax+edx] + cmp dl, [ecx+ebx] + jz short loc_1957B62 + +loc_1957B32: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+1AA_j + mov eax, [ebp+CollisionIndex] + inc [edi+TStruct40.HashValue] + inc eax + mov ecx, eax + and ecx, 1Fh + mov edx, 1 + shl edx, cl + mov ecx, [esi+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray] + mov [ebp+CollisionIndex], eax + shr eax, 5 + test [ecx+eax*4], edx + jnz loc_1957A41 + pop edi + pop esi + xor al, al + pop ebx + mov esp, ebp + pop ebp + retn 4 +; --------------------------------------------------------------------------- + +loc_1957B62: ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+1C0_j + mov eax, 1 + add [edi+TStruct40.CharIndex], eax + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + retn 4 +TFileNameDatabase__CheckNextPathFragment endp + + +TFileNameDatabase__FindFileInDatabase proc near + ; CODE XREF: MAR_FILE__FindFileInDatabase+2D_p + +pThis = dword ptr -4 +pStruct1C = dword ptr 8 + + push ebp ; ecx = Pointer to ARCHIVE_DATABASE + mov ebp, esp + push ecx + push ebx + push esi + mov esi, [ebp+pStruct1C] + xor eax, eax + push edi + mov edi, [esi+TMndxFindResult.pStruct40] + mov ebx, ecx + mov [edi+TStruct40.HashValue], eax + mov [edi+TStruct40.CharIndex], eax + mov [edi+TStruct40.SearchPhase], eax + mov [ebp+pThis], ebx + cmp [esi+TMndxFindResult.cchSearchMask], eax + jbe short loc_1957F26 + +label_process_all_characters: ; CODE XREF: TFileNameDatabase__FindFileInDatabase+34j + push esi + mov ecx, ebx + call TFileNameDatabase__CheckNextPathFragment + test al, al + jz short label_return_false + mov eax, [edi+TStruct40.CharIndex] + cmp eax, [esi+TMndxFindResult.cchSearchMask] + jb short label_process_all_characters + +loc_1957F26: ; CODE XREF: TFileNameDatabase__FindFileInDatabase+20_j + mov ecx, [edi+TStruct40.HashValue] + mov eax, [ebx+TFileNameDatabase.FileNameIndexes.ItemIsPresent.ItemArray] + mov edx, ecx + and ecx, 1Fh + mov ebx, 1 + shl ebx, cl + shr edx, 5 + test [eax+edx*4], ebx + jz short label_return_false + mov ecx, [esi+TMndxFindResult.szSearchMask] + mov eax, [esi+TMndxFindResult.cchSearchMask] + mov [esi+TMndxFindResult.szFoundPath], ecx + mov ecx, [ebp+pThis] + mov [esi+TMndxFindResult.cchFoundPath], eax + mov edi, [edi+TStruct40.HashValue] + push edi + add ecx, TFileNameDatabase.FileNameIndexes + call TSparseArray__GetItemValue + pop edi + mov [esi+TMndxFindResult.FileNameIndex], eax + pop esi + mov al, 1 + pop ebx + mov esp, ebp + pop ebp + retn 4 +; --------------------------------------------------------------------------- + +label_return_false: ; CODE XREF: TFileNameDatabase__FindFileInDatabase+2C_j + ; TFileNameDatabase__FindFileInDatabase+4E_j + pop edi + pop esi + xor al, al + pop ebx + mov esp, ebp + pop ebp + retn 4 +TFileNameDatabase__FindFileInDatabase endp + + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +TGenericArray__SetMaxItems_BYTE proc near ; CODE XREF: sub_19582E0+2Cp + ; TStruct40__InitSearchBuffers+2Cp + +ByteCount = dword ptr 8 + + push ebp + mov ebp, esp + push ebx + mov ebx, [ebp+ByteCount] + push esi + push edi + push offset unk_53ABE00 + push ebx + mov esi, ecx + call j_operator_new_safe + xor ecx, ecx + add esp, 8 + mov edi, eax + cmp [esi+TGenericArray.ItemCount], ecx + jbe short loc_19575D7 + +loc_19575C2: ; CODE XREF: TGenericArray__SetMaxItems_BYTE+35j + lea edx, [ecx+edi] + test edx, edx + jz short loc_19575D1 + mov eax, [esi+TGenericArray.field_4] + mov al, [ecx+eax] + mov [edx], al + +loc_19575D1: ; CODE XREF: TGenericArray__SetMaxItems_BYTE+27j + inc ecx + cmp ecx, [esi+TGenericArray.ItemCount] + jb short loc_19575C2 + +loc_19575D7: ; CODE XREF: TGenericArray__SetMaxItems_BYTE+20j + mov eax, [esi+TGenericArray.DataBuffer] + push eax + mov [esi+TGenericArray.DataBuffer], edi + mov [esi+TGenericArray.field_4], edi + mov [esi+TGenericArray.ItemArray], edi + mov [esi+TGenericArray.MaxItemCount], ebx + call operator_delete + add esp, 4 + pop edi + pop esi + pop ebx + pop ebp + retn 4 +TGenericArray__SetMaxItems_BYTE endp + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +TGenericArray__SetMaxItems_STRUCT14 proc near + ; CODE XREF: TGenericArray__InsertItem_STRUCT14+2Cp + ; TGenericArray__sub_19583A0+2Dp + +var_4 = dword ptr -4 +ItemCount = dword ptr 8 + + push ebp + mov ebp, esp + push ecx + push esi + push edi + mov edi, [ebp+ItemCount] + lea eax, [edi+edi*4] ; EAX = (ItemCount * 5) + add eax, eax ; EAX = (ItemCount * 10) + add eax, eax ; EAX = (ItemCount * 20) + push offset unk_53ABE00 + push eax + mov esi, ecx + call j_operator_new_safe + mov ecx, eax + xor eax, eax + add esp, 8 + mov [ebp+var_4], ecx + cmp [esi+0Ch], eax + jbe short loc_195766A + xor edi, edi + mov edx, ecx + push ebx + +loc_1957631: ; CODE XREF: TGenericArray__SetMaxItems_STRUCT14+64j + test edx, edx + jz short loc_195765A + mov ecx, [esi+4] + mov ebx, [ecx+edi] + add ecx, edi + mov [edx], ebx + mov ebx, [ecx+4] + mov [edx+4], ebx + mov ebx, [ecx+8] + mov [edx+8], ebx + mov ebx, [ecx+0Ch] + mov [edx+0Ch], ebx + mov ecx, [ecx+10h] + mov [edx+10h], ecx + mov ecx, [ebp+var_4] + +loc_195765A: ; CODE XREF: TGenericArray__SetMaxItems_STRUCT14+33j + inc eax + add edi, 14h + add edx, 14h + cmp eax, [esi+0Ch] + jb short loc_1957631 + mov edi, [ebp+ItemCount] + pop ebx + +loc_195766A: ; CODE XREF: TGenericArray__SetMaxItems_STRUCT14+2Aj + mov eax, [esi+TGenericArray.DataBuffer] + push eax + mov [esi+TGenericArray.DataBuffer], ecx + mov [esi+TGenericArray.field_4], ecx + mov [esi+TGenericArray.ItemArray], ecx + mov [esi+TGenericArray.MaxItemCount], edi + call operator_delete + add esp, 4 + pop edi + pop esi + mov esp, ebp + pop ebp + retn 4 +TGenericArray__SetMaxItems_STRUCT14 endp + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +TGenericArray__sub_19583A0 proc near ; CODE XREF: TStruct40__InitSearchBuffers+35p + +NewItemCount = dword ptr 8 + + push ebp + mov ebp, esp + push esi + mov esi, ecx + mov eax, [esi+TGenericArray.MaxItemCount] + push edi + mov edi, [ebp+NewItemCount] + cmp edi, eax + jbe short loc_19583D2 + mov edx, edi + shr edx, 1 + mov ecx, edi + cmp eax, edx + jbe short loc_19583CA + mov ecx, 0CCCCCCCh + cmp eax, 6666666h + ja short loc_19583CA + lea ecx, [eax+eax] + +loc_19583CA: ; CODE XREF: TGenericArray__sub_19583A0+19j + ; TGenericArray__sub_19583A0+25j + push ecx + mov ecx, esi + call TGenericArray__SetMaxItems_STRUCT14 + +loc_19583D2: ; CODE XREF: TGenericArray__sub_19583A0+Fj + mov eax, [esi+TGenericArray.ItemCount] + cmp eax, edi + jnb short loc_1958410 + lea ecx, [eax+eax*4] + add ecx, ecx + mov edx, edi + push ebx + add ecx, ecx + sub edx, eax + or ebx, 0FFFFFFFFh + +loc_19583E8: ; CODE XREF: TGenericArray__sub_19583A0+6Dj + mov eax, [esi+TGenericArray.field_4] + add eax, ecx + jz short loc_1958409 + mov dword ptr [eax], 0 + mov dword ptr [eax+4], 0 + mov dword ptr [eax+8], 0 + mov [eax+0Ch], ebx + mov [eax+10h], ebx + +loc_1958409: ; CODE XREF: TGenericArray__sub_19583A0+4Dj + add ecx, 14h + dec edx + jnz short loc_19583E8 + pop ebx + +loc_1958410: ; CODE XREF: TGenericArray__sub_19583A0+37j + mov [esi+TGenericArray.ItemCount], edi + pop edi + pop esi + pop ebp + retn 4 +TGenericArray__sub_19583A0 endp + +; =============== S U B R O U T I N E ======================================= + + +TStruct40__InitSearchBuffers proc near ; CODE XREF: TFileNameDatabase__sub_1959460+2Bp + push ebx + push esi + mov esi, ecx + mov eax, [esi+TStruct40.array_00.MaxItemCount] + xor ebx, ebx + push edi + mov [esi+TStruct40.array_00.ItemCount], ebx + cmp eax, 40h + jnb short loc_19586E1 + lea ecx, [ebx+40h] ; ECX = 0x40 + cmp eax, 20h + jbe short loc_19586D9 + cmp eax, 7FFFFFFFh + jbe short loc_19586D6 + or ecx, 0FFFFFFFFh + jmp short loc_19586D9 +; --------------------------------------------------------------------------- + +loc_19586D6: ; CODE XREF: TStruct40__InitSearchBuffers+1Fj + lea ecx, [eax+eax] + +loc_19586D9: ; CODE XREF: TStruct40__InitSearchBuffers+18j + ; TStruct40__InitSearchBuffers+24j + push ecx + mov ecx, esi + call TGenericArray__SetMaxItems_BYTE + +loc_19586E1: ; CODE XREF: TStruct40__InitSearchBuffers+10j + push ebx + lea ecx, [esi+TStruct40.array_18] + call TGenericArray__sub_19583A0 + mov eax, [esi+TStruct40.array_18.MaxItemCount] + cmp eax, 4 + jnb short loc_1958714 + mov ecx, 4 + cmp eax, 2 + jbe short loc_195870B + mov ecx, 0CCCCCCCh + cmp eax, 6666666h + ja short loc_195870B + lea ecx, [eax+eax] + +loc_195870B: ; CODE XREF: TStruct40__InitSearchBuffers+4Aj + ; TStruct40__InitSearchBuffers+56j + push ecx + lea ecx, [esi+TStruct40.array_18] + call TGenericArray__SetMaxItems_STRUCT14 + +loc_1958714: ; CODE XREF: TStruct40__InitSearchBuffers+40j + pop edi + mov [esi+TStruct40.HashValue], ebx + mov [esi+TStruct40.CharIndex], ebx + mov [esi+TStruct40.ItemCount], ebx + mov [esi+TStruct40.SearchPhase], 2 + pop esi + pop ebx + retn +TStruct40__InitSearchBuffers endp + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +TGenericArray__InsertItem_STRUCT14 proc near + ; CODE XREF: TFileNameDatabase__sub_1959460+73p + +pStruct14 = dword ptr 8 + + push ebp + mov ebp, esp + push esi + mov esi, ecx + mov eax, [esi+TGenericArray.ItemCount] + mov ecx, [esi+TGenericArray.MaxItemCount] + inc eax + cmp eax, ecx + jbe short loc_1958361 + mov edx, eax + shr eax, 1 + cmp ecx, eax + jbe short loc_1958359 + mov edx, 0CCCCCCCh + cmp ecx, 6666666h + ja short loc_1958359 + lea edx, [ecx+ecx] + +loc_1958359: ; CODE XREF: TGenericArray__InsertItem_STRUCT14+17j + ; TGenericArray__InsertItem_STRUCT14+24j + push edx + mov ecx, esi + call TGenericArray__SetMaxItems_STRUCT14 + +loc_1958361: ; CODE XREF: TGenericArray__InsertItem_STRUCT14+Fj + mov eax, [esi+TGenericArray.ItemCount] + mov ecx, [esi+TGenericArray.field_4] + lea eax, [eax+eax*4] + lea eax, [ecx+eax*4] + test eax, eax + jz short loc_1958390 + mov ecx, [ebp+pStruct14] + mov edx, [ecx+TStruct14.HashValue] + mov [eax+TStruct14.HashValue], edx + mov edx, [ecx+TStruct14.field_4] + mov [eax+TStruct14.field_4], edx + mov edx, [ecx+TStruct14.field_8] + mov [eax+TStruct14.field_8], edx + mov edx, [ecx+TStruct14.field_C] + mov [eax+TStruct14.field_C], edx + mov ecx, [ecx+TStruct14.field_10] + mov [eax+TStruct14.field_10], ecx + +loc_1958390: ; CODE XREF: TGenericArray__InsertItem_STRUCT14+3Fj + inc [esi+TGenericArray.ItemCount] + pop esi + pop ebp + retn 4 +TGenericArray__InsertItem_STRUCT14 endp + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +CopyNameFragment proc near ; CODE XREF: sub_1958980+DAp + ; sub_1958D70+6Dp + +pThis = dword ptr -4 +pStruct1C = dword ptr 8 +dwDistance = dword ptr 0Ch + + push ebp + mov ebp, esp + push ecx + mov eax, [ebp+pStruct1C] + push ebx + mov ebx, ecx + cmp [ebx+TNameIndexStruct.Struct68.TotalItemCount], 0 + push esi + mov esi, [eax+TMndxFindResult.pStruct40] + push edi + mov [ebp+pThis], ebx + jnz loc_195A4B3 + mov ebx, [ebx+TNameIndexStruct.NameFragments.ItemArray] + add ebx, [ebp+dwDistance] + cmp byte ptr [ebx], 0 + mov [ebp+dwDistance], ebx + jz loc_195A55E + mov edi, edi + +loc_195A420: ; CODE XREF: CopyNameFragment+B4j + mov eax, [esi+TStruct40.array_00.ItemCount] + mov ecx, [esi+TStruct40.array_00.MaxItemCount] + inc eax + cmp eax, ecx + jbe short loc_195A48E + mov ebx, eax + shr eax, 1 + cmp ecx, eax + jbe short loc_195A443 + cmp ecx, 7FFFFFFFh + jbe short loc_195A440 + or ebx, 0FFFFFFFFh + jmp short loc_195A443 +; --------------------------------------------------------------------------- + +loc_195A440: ; CODE XREF: CopyNameFragment+49j + lea ebx, [ecx+ecx] + +loc_195A443: ; CODE XREF: CopyNameFragment+41j + ; CopyNameFragment+4Ej + push offset unk_53ABE00 + push ebx + call j_operator_new_safe + xor ecx, ecx + add esp, 8 + mov edi, eax + cmp [esi+TStruct40.array_00.ItemCount], ecx + jbe short loc_195A475 + lea ebx, [ebx+0] + +loc_195A460: ; CODE XREF: CopyNameFragment+83j + lea edx, [ecx+edi] + test edx, edx + jz short loc_195A46F + mov eax, [esi+TStruct40.array_00.field_4] + mov al, [ecx+eax] + mov [edx], al + +loc_195A46F: ; CODE XREF: CopyNameFragment+75j + inc ecx + cmp ecx, [esi+TStruct40.array_00.ItemCount] + jb short loc_195A460 + +loc_195A475: ; CODE XREF: CopyNameFragment+68j + mov eax, [esi+TStruct40.array_00.DataBuffer] + push eax + mov [esi+TStruct40.array_00.DataBuffer], edi + mov [esi+TStruct40.array_00.field_4], edi + mov [esi+TStruct40.array_00.ItemArray], edi + mov [esi+TStruct40.array_00.MaxItemCount], ebx + call operator_delete + mov ebx, [ebp+dwDistance] + add esp, 4 + +loc_195A48E: ; CODE XREF: CopyNameFragment+39j + mov eax, [esi+TStruct40.array_00.ItemCount] + add eax, [esi+TStruct40.array_00.field_4] + jz short loc_195A49A + mov cl, [ebx] + mov [eax], cl + +loc_195A49A: ; CODE XREF: CopyNameFragment+A4j + inc [esi+TStruct40.array_00.ItemCount] + inc ebx + cmp byte ptr [ebx], 0 + mov [ebp+dwDistance], ebx + jnz loc_195A420 + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + retn 8 +; --------------------------------------------------------------------------- + +loc_195A4B3: ; CODE XREF: CopyNameFragment+16j + ; CopyNameFragment+168j + mov eax, [esi+TStruct40.array_00.ItemCount] + mov edx, [ebx+TNameIndexStruct.NameFragments.ItemArray] + mov edi, [ebp+dwDistance] + mov ecx, [esi+TStruct40.array_00.MaxItemCount] + add edx, edi + inc eax + mov [ebp+pStruct1C], edx + cmp eax, ecx + jbe short loc_195A52C + mov ebx, eax + shr eax, 1 + cmp ecx, eax + jbe short loc_195A4E1 + cmp ecx, 7FFFFFFFh + jbe short loc_195A4DE + or ebx, 0FFFFFFFFh + jmp short loc_195A4E1 +; --------------------------------------------------------------------------- + +loc_195A4DE: ; CODE XREF: CopyNameFragment+E7j + lea ebx, [ecx+ecx] + +loc_195A4E1: ; CODE XREF: CopyNameFragment+DFj + ; CopyNameFragment+ECj + push offset unk_53ABE00 + push ebx + call j_operator_new_safe + xor ecx, ecx + add esp, 8 + mov edi, eax + cmp [esi+TStruct40.array_00.ItemCount], ecx + jbe short loc_195A50D + +loc_195A4F8: ; CODE XREF: CopyNameFragment+11Bj + lea edx, [ecx+edi] + test edx, edx + jz short loc_195A507 + mov eax, [esi+TStruct40.array_00.field_4] + mov al, [ecx+eax] + mov [edx], al + +loc_195A507: ; CODE XREF: CopyNameFragment+10Dj + inc ecx + cmp ecx, [esi+TStruct40.array_00.ItemCount] + jb short loc_195A4F8 + +loc_195A50D: ; CODE XREF: CopyNameFragment+106j + mov eax, [esi+TStruct40.array_00.DataBuffer] + push eax + mov [esi+TStruct40.array_00.DataBuffer], edi + mov [esi+TStruct40.array_00.field_4], edi + mov [esi+TStruct40.array_00.ItemArray], edi + mov [esi+TStruct40.array_00.MaxItemCount], ebx + call operator_delete + mov edx, [ebp+pStruct1C] + mov edi, [ebp+dwDistance] + mov ebx, [ebp+pThis] + add esp, 4 + +loc_195A52C: ; CODE XREF: CopyNameFragment+D7j + mov eax, [esi+TStruct40.array_00.ItemCount] + add eax, [esi+TStruct40.array_00.field_4] + jz short loc_195A538 + mov cl, [edx] + mov [eax], cl + +loc_195A538: ; CODE XREF: CopyNameFragment+142j + inc [esi+TStruct40.array_00.ItemCount] + mov ecx, edi + and ecx, 1Fh + mov edx, 1 + shl edx, cl + mov ecx, [ebx+TNameIndexStruct.Struct68.ItemIsPresent.ItemArray] + mov eax, edi + shr eax, 5 + and edx, [ecx+eax*4] + inc edi + mov [ebp+dwDistance], edi + test edx, edx + jz loc_195A4B3 + +loc_195A55E: ; CODE XREF: CopyNameFragment+28j + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + retn 8 +CopyNameFragment endp + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +sub_1958D70 proc near ; CODE XREF: sub_1958980+C9p + ; sub_1958D70+59p + +var_C = dword ptr -0Ch +var_8 = dword ptr -8 +var_1 = byte ptr -1 +pStruct1C = dword ptr 8 +arg_4 = dword ptr 0Ch + + push ebp + mov ebp, esp + mov eax, [ebp+pStruct1C] + sub esp, 0Ch + push ebx + push esi + mov esi, [eax+TMndxFindResult.pStruct40] + push edi + mov edi, ecx + mov ecx, [ebp+arg_4] + +loc_1958D84: ; CODE XREF: sub_1958D70+10Fj + ; sub_1958D70+28Fj + mov eax, [edi+TFileNameDatabase.NameFragIndexMask] + and eax, ecx + lea ebx, [eax+eax*2] + mov eax, [edi+TFileNameDatabase.NameFragTable.ItemArray] + add ebx, ebx + add ebx, ebx + mov [ebp+var_C], ebx + cmp ecx, [eax+ebx+4] + jnz loc_1958E8E + mov edx, [eax+ebx+8] + mov ecx, edx + and ecx, 0FFFFFF00h + cmp ecx, 0FFFFFF00h + jz short loc_1958DE7 + mov ecx, [edi+TFileNameDatabase.NextDB.pDatabase] + push edx + test ecx, ecx + jz short loc_1958DD3 + mov edx, [ebp+pStruct1C] + push edx + call sub_1958D70 + jmp loc_1958E71 +; --------------------------------------------------------------------------- + +loc_1958DD3: ; CODE XREF: sub_1958D70+53j + mov eax, [ebp+pStruct1C] + push eax + lea ecx, [edi+TFileNameDatabase.IndexStruct_174] + call CopyNameFragment + jmp loc_1958E71 +; --------------------------------------------------------------------------- + +loc_1958DE7: ; CODE XREF: sub_1958D70+48j + mov eax, [esi+TStruct40.array_00.ItemCount] + mov ecx, [esi+TStruct40.array_00.MaxItemCount] + inc eax + mov byte ptr [ebp+arg_4+3], dl + cmp eax, ecx + jbe short loc_1958E61 + mov [ebp+var_8], eax + shr eax, 1 + cmp ecx, eax + jbe short loc_1958E15 + cmp ecx, 7FFFFFFFh + jbe short loc_1958E0F + mov [ebp+var_8], 0FFFFFFFFh + jmp short loc_1958E15 +; --------------------------------------------------------------------------- + +loc_1958E0F: ; CODE XREF: sub_1958D70+94j + lea edx, [ecx+ecx] + mov [ebp+var_8], edx + +loc_1958E15: ; CODE XREF: sub_1958D70+8Cj + ; sub_1958D70+9Dj + mov eax, [ebp+var_8] + push offset unk_53ABE00 + push eax + call j_operator_new_safe + xor ecx, ecx + add esp, 8 + cmp [esi+TStruct40.array_00.ItemCount], ecx + jbe short loc_1958E48 + lea ecx, [ecx+0] + +loc_1958E30: ; CODE XREF: sub_1958D70+D6j + lea edx, [ecx+eax] + test edx, edx + jz short loc_1958E42 + mov ebx, [esi+4] + mov bl, [ecx+ebx] + mov [edx], bl + mov ebx, [ebp+var_C] + +loc_1958E42: ; CODE XREF: sub_1958D70+C5j + inc ecx + cmp ecx, [esi+TStruct40.array_00.ItemCount] + jb short loc_1958E30 + +loc_1958E48: ; CODE XREF: sub_1958D70+BBj + mov ecx, [esi] + mov edx, [ebp+var_8] + push ecx + mov [esi+TStruct40.array_00.DataBuffer], eax + mov [esi+TStruct40.array_00.field_4], eax + mov [esi+TStruct40.array_00.ItemArray], eax + mov [esi+TStruct40.array_00.MaxItemCount], edx + call operator_delete + add esp, 4 + +loc_1958E61: ; CODE XREF: sub_1958D70+83j + mov eax, [esi+TStruct40.array_00.field_4] + add eax, [esi+TStruct40.array_00.ItemCount] + jz short loc_1958E6E + mov cl, byte ptr [ebp+arg_4+3] + mov [eax], cl + +loc_1958E6E: ; CODE XREF: sub_1958D70+F7j + inc [esi+TStruct40.array_00.ItemCount] + +loc_1958E71: ; CODE XREF: sub_1958D70+5Ej + ; sub_1958D70+72j + mov edx, [edi+TFileNameDatabase.NameFragTable.ItemArray] + mov ecx, [ebx+edx] + mov [ebp+arg_4], ecx + test ecx, ecx + jnz loc_1958D84 + +loc_1958E85: ; CODE XREF: sub_1958D70+277j + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + retn 8 +; --------------------------------------------------------------------------- + +loc_1958E8E: ; CODE XREF: sub_1958D70+30j + mov edx, [edi+TFileNameDatabase.Struct68_D0.ItemIsPresent.ItemArray] + mov eax, ecx + and ecx, 1Fh + mov ebx, 1 + shl ebx, cl + shr eax, 5 + test [edx+eax*4], ebx + mov eax, [ebp+arg_4] + jz loc_1958F50 + mov ebx, [edi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] + push eax + lea ecx, [edi+TFileNameDatabase.Struct68_D0] + add ebx, eax + call TSparseArray__GetItemValue + mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry] + imul ecx, eax + mov eax, ecx + and ecx, 1Fh + mov edx, ecx + mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry] + add ecx, edx + shr eax, 5 + cmp ecx, 20h + mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.ItemArray] + ja short loc_1958EF2 + mov eax, [ecx+eax*4] + mov ecx, edx + shr eax, cl + jmp short loc_1958F15 +; --------------------------------------------------------------------------- + +loc_1958EF2: ; CODE XREF: sub_1958D70+177j + lea eax, [ecx+eax*4] + mov [ebp+var_C], eax + mov eax, [eax+4] + mov ecx, 20h + sub ecx, edx + shl eax, cl + mov ecx, [ebp+var_C] + mov ecx, [ecx] + mov [ebp+var_C], ecx + mov ecx, edx + mov edx, [ebp+var_C] + shr edx, cl + or eax, edx + +loc_1958F15: ; CODE XREF: sub_1958D70+180j + and eax, [edi+TFileNameDatabase.FrgmDist_HiBits.EntryBitMask] + movzx edx, byte ptr [ebx] + mov ecx, [edi+TFileNameDatabase.NextDB.pDatabase] + shl eax, 8 + or eax, edx + push eax + test ecx, ecx + jz short loc_1958F3C + mov eax, [ebp+pStruct1C] + push eax + call sub_1958D70 + jmp loc_1958FDE +; --------------------------------------------------------------------------- + +loc_1958F3C: ; CODE XREF: sub_1958D70+1BCj + mov ecx, [ebp+pStruct1C] + push ecx + lea ecx, [edi+TFileNameDatabase.IndexStruct_174] + call CopyNameFragment + jmp loc_1958FDE +; --------------------------------------------------------------------------- + +loc_1958F50: ; CODE XREF: sub_1958D70+139j + mov edx, [edi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] + mov cl, [eax+edx] + mov eax, [esi+TStruct40.array_00.ItemCount] + mov [ebp+var_1], cl + mov ecx, [esi+TStruct40.array_00.MaxItemCount] + inc eax + cmp eax, ecx + jbe short loc_1958FCE + mov ebx, eax + shr eax, 1 + mov [ebp+var_8], ebx + cmp ecx, eax + jbe short loc_1958F85 + cmp ecx, 7FFFFFFFh + jbe short loc_1958F7F + or ebx, 0FFFFFFFFh + jmp short loc_1958F82 +; --------------------------------------------------------------------------- + +loc_1958F7F: ; CODE XREF: sub_1958D70+208j + lea ebx, [ecx+ecx] + +loc_1958F82: ; CODE XREF: sub_1958D70+20Dj + mov [ebp+var_8], ebx + +loc_1958F85: ; CODE XREF: sub_1958D70+200j + push offset unk_53ABE00 + push ebx + call j_operator_new_safe + xor ecx, ecx + add esp, 8 + cmp [esi+TStruct40.array_00.ItemCount], ecx + jbe short loc_1958FB8 + lea ebx, [ebx+0] + +loc_1958FA0: ; CODE XREF: sub_1958D70+243j + lea edx, [ecx+eax] + test edx, edx + jz short loc_1958FAF + mov ebx, [esi+TStruct40.array_00.field_4] + mov bl, [ecx+ebx] + mov [edx], bl + +loc_1958FAF: ; CODE XREF: sub_1958D70+235j + inc ecx + cmp ecx, [esi+TStruct40.array_00.ItemCount] + jb short loc_1958FA0 + mov ebx, [ebp+var_8] + +loc_1958FB8: ; CODE XREF: sub_1958D70+228j + mov ecx, [esi+TStruct40.array_00.DataBuffer] + push ecx + mov [esi+TStruct40.array_00.DataBuffer], eax + mov [esi+TStruct40.array_00.field_4], eax + mov [esi+TStruct40.array_00.ItemArray], eax + mov [esi+TStruct40.array_00.MaxItemCount], ebx + call operator_delete + add esp, 4 + +loc_1958FCE: ; CODE XREF: sub_1958D70+1F5j + mov eax, [esi+TStruct40.array_00.field_4] + add eax, [esi+TStruct40.array_00.ItemCount] + jz short loc_1958FDB + mov dl, [ebp+var_1] + mov [eax], dl + +loc_1958FDB: ; CODE XREF: sub_1958D70+264j + inc [esi+TStruct40.array_00.ItemCount] + +loc_1958FDE: ; CODE XREF: sub_1958D70+1C7j + ; sub_1958D70+1DBj + mov ebx, [ebp+arg_4] + cmp ebx, [edi+TFileNameDatabase.field_214] + jbe loc_1958E85 + push ebx + mov ecx, edi + call sub_1959F50 + or ecx, 0FFFFFFFFh + sub ecx, ebx + add ecx, eax + mov [ebp+arg_4], ecx + jmp loc_1958D84 +sub_1958D70 endp + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +TFileNameDatabase__sub_1959CB0 proc near ; CODE XREF: TFileNameDatabase__CheckNextPathFragment+A1p + ; TFileNameDatabase__sub_1958B00+E8p + +pThis = dword ptr -4 +dwKey = dword ptr 8 + + push ebp + mov ebp, esp + push ecx + mov edx, [ebp+dwKey] + mov eax, edx + shr eax, 9 + mov [ebp+pThis], ecx + test edx, 1FFh ; if(dwKey & 0x01FF) + jnz short loc_1959CD3 + mov ecx, [ecx+TFileNameDatabase.Struct68_00.ArrayDwords_38.ItemArray] + mov eax, [ecx+eax*4] ; EAX = pDatabase->NextKeyTable[dwKey >> 0x09] + mov esp, ebp + pop ebp + retn 4 +; --------------------------------------------------------------------------- + +loc_1959CD3: ; CODE XREF: TFileNameDatabase__sub_1959CB0+15j + push ebx + push esi + mov esi, [ecx+TFileNameDatabase.Struct68_00.ArrayDwords_38.ItemArray] + lea esi, [esi+eax*4] + mov eax, [esi] + mov esi, [esi+4] + shr eax, 9 + add esi, 1FFh + push edi + shr esi, 9 + lea edi, [eax+0Ah] + mov [ebp+dwKey], esi + cmp edi, esi + jb short loc_1959D2E + mov edi, [ecx+TFileNameDatabase.Struct68_00.ArrayTriplets_20.ItemArray] + lea esi, [eax+eax*2+3] + lea esi, [edi+esi*4] + mov edi, eax + shl edi, 9 + mov ebx, edi + sub ebx, [esi] + add ebx, 200h + cmp edx, ebx + jb short loc_1959D5F + +loc_1959D14: ; CODE XREF: TFileNameDatabase__sub_1959CB0+7Aj + add edi, 200h + add esi, 0Ch + mov ebx, edi + sub ebx, [esi] + inc eax + add ebx, 200h + cmp edx, ebx + jnb short loc_1959D14 + jmp short loc_1959D5F +; --------------------------------------------------------------------------- + +loc_1959D2E: ; CODE XREF: TFileNameDatabase__sub_1959CB0+45j + lea edi, [eax+1] + cmp edi, esi + jnb short loc_1959D5F + mov ecx, [ecx+TFileNameDatabase.Struct68_00.ArrayTriplets_20.ItemArray] + +loc_1959D38: ; CODE XREF: TFileNameDatabase__sub_1959CB0+AAj + add esi, eax + shr esi, 1 + mov ebx, esi + shl ebx, 9 + lea edi, [esi+esi*2] + sub ebx, [ecx+edi*4] + cmp edx, ebx + jnb short loc_1959D50 + mov [ebp+dwKey], esi + jmp short loc_1959D55 +; --------------------------------------------------------------------------- + +loc_1959D50: ; CODE XREF: TFileNameDatabase__sub_1959CB0+99j + mov eax, esi + mov esi, [ebp+dwKey] + +loc_1959D55: ; CODE XREF: TFileNameDatabase__sub_1959CB0+9Ej + lea edi, [eax+1] + cmp edi, esi + jb short loc_1959D38 + mov ecx, [ebp+pThis] + +loc_1959D5F: ; CODE XREF: TFileNameDatabase__sub_1959CB0+62j + ; TFileNameDatabase__sub_1959CB0+7Cj + mov ecx, [ecx+TFileNameDatabase.Struct68_00.ArrayTriplets_20.ItemArray] + lea esi, [eax+eax*2] + mov edi, [ecx+esi*4] ; EDI = Struct68_00.ArrayTriplets_20.ItemArray[eax] + lea esi, [ecx+esi*4] ; ESI = Struct68_00.ArrayTriplets_20.ItemArray + eax + mov ecx, eax + shl ecx, 9 + sub edi, ecx + shl eax, 4 + add edx, edi + mov edi, eax + mov eax, [esi+TRIPLET.NextKey] + mov ecx, eax + shr ecx, 17h + mov ebx, 100h + sub ebx, ecx + cmp edx, ebx + jnb short loc_1959DE8 + mov ecx, eax + shr ecx, 7 + and ecx, 0FFh + mov esi, 80h + sub esi, ecx + cmp edx, esi + jnb short loc_1959DC0 + and eax, 7Fh + mov ecx, 40h + sub ecx, eax + cmp edx, ecx + jb loc_1959E53 + add edi, 2 + lea edx, [edx+eax-40h] + jmp loc_1959E53 +; --------------------------------------------------------------------------- + +loc_1959DC0: ; CODE XREF: TFileNameDatabase__sub_1959CB0+F0j + shr eax, 0Fh + and eax, 0FFh + mov esi, 0C0h + sub esi, eax + cmp edx, esi + jnb short loc_1959DDC + add edi, 4 + lea edx, [edx+ecx-80h] + jmp short loc_1959E53 +; --------------------------------------------------------------------------- + +loc_1959DDC: ; CODE XREF: TFileNameDatabase__sub_1959CB0+121j + add edi, 6 + lea edx, [edx+eax-0C0h] + jmp short loc_1959E53 +; --------------------------------------------------------------------------- + +loc_1959DE8: ; CODE XREF: TFileNameDatabase__sub_1959CB0+DAj + mov esi, [esi+TRIPLET.Distance] + mov eax, esi + shr eax, 9 + and eax, 1FFh + mov ebx, 180h + sub ebx, eax + cmp edx, ebx + jnb short loc_1959E29 + and esi, 1FFh + mov eax, 140h + sub eax, esi + cmp edx, eax + jnb short loc_1959E1D + add edi, 8 + lea edx, [edx+ecx-100h] + jmp short loc_1959E53 +; --------------------------------------------------------------------------- + +loc_1959E1D: ; CODE XREF: TFileNameDatabase__sub_1959CB0+15Fj + add edi, 0Ah + lea edx, [edx+esi-140h] + jmp short loc_1959E53 +; --------------------------------------------------------------------------- + +loc_1959E29: ; CODE XREF: TFileNameDatabase__sub_1959CB0+14Ej + shr esi, 12h + and esi, 1FFh + mov ecx, 1C0h + sub ecx, esi + cmp edx, ecx + jnb short loc_1959E49 + add edi, 0Ch + lea edx, [edx+eax-180h] + jmp short loc_1959E53 +; --------------------------------------------------------------------------- + +loc_1959E49: ; CODE XREF: TFileNameDatabase__sub_1959CB0+18Bj + add edi, 0Eh + lea edx, [edx+esi-1C0h] + +loc_1959E53: ; CODE XREF: TFileNameDatabase__sub_1959CB0+FEj + ; TFileNameDatabase__sub_1959CB0+10Bj + mov eax, [ebp+pThis] + mov ebx, [eax+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray] + mov ecx, [ebx+edi*4] + not ecx + mov eax, ecx + shr eax, 1 + and eax, 55555555h + mov esi, ecx + and esi, 55555555h + add eax, esi + mov esi, eax + shr esi, 2 + and eax, 33333333h + and esi, 33333333h + add esi, eax + mov eax, esi + shr eax, 4 + and esi, 0F0F0F0Fh + and eax, 0F0F0F0Fh + add eax, esi + imul eax, 1010101h + mov esi, eax + shr esi, 18h + cmp edx, esi + jb short loc_1959EEA + mov ecx, [ebx+edi*4+4] + inc edi + sub edx, esi + not ecx + mov eax, ecx + shr eax, 1 + and eax, 55555555h + mov esi, ecx + and esi, 55555555h + add eax, esi + mov esi, eax + shr esi, 2 + and eax, 33333333h + and esi, 33333333h + add esi, eax + mov eax, esi + shr eax, 4 + and eax, 0F0F0F0Fh + and esi, 0F0F0F0Fh + add eax, esi + imul eax, 1010101h + +loc_1959EEA: ; CODE XREF: TFileNameDatabase__sub_1959CB0+1F2j + mov esi, eax + shr esi, 8 + and esi, 0FFh + shl edi, 5 + cmp edx, esi + jnb short loc_1959F0D + and eax, 0FFh + cmp edx, eax + jb short loc_1959F2B + add edi, 8 + shr ecx, 8 + jmp short loc_1959F29 +; --------------------------------------------------------------------------- + +loc_1959F0D: ; CODE XREF: TFileNameDatabase__sub_1959CB0+24Aj + shr eax, 10h + and eax, 0FFh + cmp edx, eax + jnb short loc_1959F23 + add edi, 10h + shr ecx, 10h + sub edx, esi + jmp short loc_1959F2B +; --------------------------------------------------------------------------- + +loc_1959F23: ; CODE XREF: TFileNameDatabase__sub_1959CB0+267j + add edi, 18h + shr ecx, 18h + +loc_1959F29: ; CODE XREF: TFileNameDatabase__sub_1959CB0+25Bj + sub edx, eax + +loc_1959F2B: ; CODE XREF: TFileNameDatabase__sub_1959CB0+253j + ; TFileNameDatabase__sub_1959CB0+271j + and ecx, 0FFh + shl edx, 8 + movzx eax, ds:table_1BA1818[ecx+edx] + add eax, edi + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + retn 4 +TFileNameDatabase__sub_1959CB0 endp + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +TNameIndexStruct__CheckAndCopyNameFragment proc near ; CODE XREF: TArchiveDatabase__sub_1958B00+74p + ; TArchiveDatabase__sub_1958B00+1E0p + +var_C = dword ptr -0Ch +pThis = dword ptr -8 +var_4 = dword ptr -4 +pStruct1C = dword ptr 8 +dwDistance = dword ptr 0Ch + + push ebp + mov ebp, esp + sub esp, 0Ch + mov eax, [ebp+pStruct1C] + push ebx + mov edx, ecx + cmp [edx+TNameIndexStruct.Struct68.TotalItemCount], 0 + push esi + mov esi, [eax+TMndxFindResult.pStruct40] + push edi + mov [ebp+pThis], edx + jnz loc_195A6B7 + mov edi, [edx+TNameIndexStruct.NameFragments.ItemArray] + sub edi, [esi+TStruct40.CharIndex] + add edi, [ebp+dwDistance] + mov [ebp+pThis], edi + lea ebx, [ebx+0] + +loc_195A5A0: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+E6j + mov edx, [esi+TStruct40.CharIndex] + mov ecx, [ebp+pStruct1C] + mov eax, [ecx+TMndxFindResult.szSearchMask] + mov cl, [edx+edi] + mov [ebp+dwDistance], edx + cmp cl, [edx+eax] + jnz loc_195A67D + mov eax, [esi+TStruct40.array_00.ItemCount] + mov ecx, [esi+TStruct40.array_00.MaxItemCount] + mov ebx, 1 + add eax, ebx + cmp eax, ecx + jbe short loc_195A62D + mov ebx, eax + shr eax, 1 + cmp ecx, eax + jbe short loc_195A5E0 + cmp ecx, 7FFFFFFFh + jbe short loc_195A5DD + or ebx, 0FFFFFFFFh + jmp short loc_195A5E0 +; --------------------------------------------------------------------------- + +loc_195A5DD: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+66j + lea ebx, [ecx+ecx] + +loc_195A5E0: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+5Ej + ; TNameIndexStruct__CheckAndCopyNameFragment+6Bj + push offset unk_53ABE00 + push ebx + call j_operator_new_safe + xor ecx, ecx + add esp, 8 + mov edi, eax + cmp [esi+TStruct40.array_00.ItemCount], ecx + jbe short loc_195A60C + +loc_195A5F7: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+9Aj + lea edx, [ecx+edi] + test edx, edx + jz short loc_195A606 + mov eax, [esi+TStruct40.array_00.field_4] + mov al, [ecx+eax] + mov [edx], al + +loc_195A606: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+8Cj + inc ecx + cmp ecx, [esi+TStruct40.array_00.ItemCount] + jb short loc_195A5F7 + +loc_195A60C: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+85j + mov eax, [esi+TStruct40.array_00.DataBuffer] + push eax + mov [esi+TStruct40.array_00.DataBuffer], edi + mov [esi+TStruct40.array_00.field_4], edi + mov [esi+TStruct40.array_00.ItemArray], edi + mov [esi+TStruct40.array_00.MaxItemCount], ebx + call operator_delete + mov edx, [ebp+dwDistance] + mov edi, [ebp+pThis] + add esp, 4 + mov ebx, 1 + +loc_195A62D: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+56j + mov eax, [esi+TStruct40.array_00.field_4] + add eax, [esi+TStruct40.array_00.ItemCount] + jz short loc_195A63A + mov cl, [edx+edi] + mov [eax], cl + +loc_195A63A: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+C3j + add [esi+TStruct40.CharIndex], ebx + add [esi+TStruct40.array_00.ItemCount], ebx + mov ecx, [esi+TStruct40.CharIndex] + cmp byte ptr [ecx+edi], 0 + mov eax, [esi+TStruct40.array_00.ItemCount] + jz loc_195A806 + mov edx, [ebp+pStruct1C] + cmp ecx, [edx+TMndxFindResult.cchSearchMask] + jb loc_195A5A0 + add edi, ecx + mov edi, edi + +loc_195A660: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+13Aj + mov ecx, [esi+TStruct40.array_00.MaxItemCount] + inc eax + cmp eax, ecx + jbe short loc_195A693 + mov edx, eax + shr eax, 1 + cmp ecx, eax + jbe short loc_195A68B + cmp ecx, 7FFFFFFFh + jbe short loc_195A688 + or edx, 0FFFFFFFFh + jmp short loc_195A68B +; --------------------------------------------------------------------------- + +loc_195A67D: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+41j + ; TNameIndexStruct__CheckAndCopyNameFragment+16Bj + pop edi + pop esi + xor al, al + pop ebx + mov esp, ebp + pop ebp + retn 8 +; --------------------------------------------------------------------------- + +loc_195A688: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+106j + lea edx, [ecx+ecx] + +loc_195A68B: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+FEj + ; TNameIndexStruct__CheckAndCopyNameFragment+10Bj + push edx + mov ecx, esi + call TGenericArray__SetMaxItems_BYTE + +loc_195A693: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+F6j + mov eax, [esi+TStruct40.array_00.field_4] + add eax, [esi+TStruct40.array_00.ItemCount] + jz short loc_195A69F + mov cl, [edi] + mov [eax], cl + +loc_195A69F: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+129j + add [esi+TStruct40.array_00.ItemCount], ebx + mov eax, [esi+TStruct40.array_00.ItemCount] + add edi, ebx + cmp byte ptr [edi], 0 + jnz short loc_195A660 + pop edi + pop esi + mov al, 1 + pop ebx + mov esp, ebp + pop ebp + retn 8 +; --------------------------------------------------------------------------- + +loc_195A6B7: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+18j + mov ebx, [ebp+dwDistance] + lea ebx, [ebx+0] + +loc_195A6C0: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+231j + mov edi, [edx+TNameIndexStruct.NameFragments.ItemArray] + mov eax, [ebp+pStruct1C] + mov ecx, [esi+TStruct40.CharIndex] + mov eax, [eax] + add edi, ebx + mov [ebp+var_4], edx + mov dl, [edi] + cmp dl, [ecx+eax] + mov edx, [ebp+var_4] + mov [ebp+var_C], edi + jnz short loc_195A67D + mov eax, [esi+TStruct40.array_00.ItemCount] + mov ecx, [esi+TStruct40.array_00.MaxItemCount] + inc eax + cmp eax, ecx + jbe short loc_195A752 + mov [ebp+var_4], eax + shr eax, 1 + cmp ecx, eax + jbe short loc_195A707 + cmp ecx, 7FFFFFFFh + jbe short loc_195A702 + mov [ebp+var_4], 0FFFFFFFFh + jmp short loc_195A707 +; --------------------------------------------------------------------------- + +loc_195A702: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+187j + add ecx, ecx + mov [ebp+var_4], ecx + +loc_195A707: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+17Fj + ; TNameIndexStruct__CheckAndCopyNameFragment+190j + mov edx, [ebp+var_4] + push offset unk_53ABE00 + push edx + call j_operator_new_safe + xor ecx, ecx + add esp, 8 + mov edi, eax + cmp [esi+TStruct40.array_00.ItemCount], ecx + jbe short loc_195A736 + +loc_195A721: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+1C4j + lea edx, [ecx+edi] + test edx, edx + jz short loc_195A730 + mov eax, [esi+TStruct40.array_00.field_4] + mov al, [ecx+eax] + mov [edx], al + +loc_195A730: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+1B6j + inc ecx + cmp ecx, [esi+TStruct40.array_00.ItemCount] + jb short loc_195A721 + +loc_195A736: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+1AFj + mov eax, [esi+TStruct40.array_00.DataBuffer] + mov ecx, [ebp+var_4] + push eax + mov [esi+TStruct40.array_00.DataBuffer], edi + mov [esi+TStruct40.array_00.field_4], edi + mov [esi+TStruct40.array_00.ItemArray], edi + mov [esi+TStruct40.array_00.MaxItemCount], ecx + call operator_delete + mov edx, [ebp+pThis] + add esp, 4 + +loc_195A752: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+176j + mov edi, [esi+TStruct40.array_00.field_4] + add edi, [esi+TStruct40.array_00.ItemCount] + jz short loc_195A761 + mov eax, [ebp+var_C] + mov cl, [eax] + mov [edi], cl + +loc_195A761: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+1E8j + mov ecx, 1 + add [esi+TStruct40.array_00.ItemCount], ecx + add [esi+TStruct40.CharIndex], ecx + mov edx, [edx+20h] + mov eax, [esi+TStruct40.array_00.ItemCount] + mov ecx, ebx + mov edi, ebx + and ecx, 1Fh + mov ebx, 1 + shl ebx, cl + shr edi, 5 + mov ecx, [edx+edi*4] + and ecx, ebx + mov ebx, [ebp+dwDistance] + inc ebx + mov [ebp+dwDistance], ebx + test ecx, ecx + jnz short loc_195A806 + mov ecx, [esi+TStruct40.CharIndex] + mov edx, [ebp+pStruct1C] + cmp ecx, [edx+4] + jnb short loc_195A7A6 + mov edx, [ebp+pThis] + jmp loc_195A6C0 +; --------------------------------------------------------------------------- + +loc_195A7A6: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+22Cj + ; TNameIndexStruct__CheckAndCopyNameFragment+294j + mov ecx, [ebp+pThis] + mov edi, [ecx+8] + mov ecx, [esi+TStruct40.array_00.MaxItemCount] + inc eax + cmp eax, ecx + jbe short loc_195A7D4 + mov edx, eax + shr eax, 1 + cmp ecx, eax + jbe short loc_195A7CC + cmp ecx, 7FFFFFFFh + jbe short loc_195A7C9 + or edx, 0FFFFFFFFh + jmp short loc_195A7CC +; --------------------------------------------------------------------------- + +loc_195A7C9: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+252j + lea edx, [ecx+ecx] + +loc_195A7CC: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+24Aj + ; TNameIndexStruct__CheckAndCopyNameFragment+257j + push edx + mov ecx, esi + call TGenericArray__SetMaxItems_BYTE + +loc_195A7D4: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+242j + mov eax, [esi+TStruct40.array_00.field_4] + add eax, [esi+TStruct40.array_00.ItemCount] + jz short loc_195A7E1 + mov dl, [edi+ebx] + mov [eax], dl + +loc_195A7E1: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+26Aj + inc [esi+TStruct40.array_00.ItemCount] + mov edi, [ebp+pThis] + mov edi, [edi+20h] + mov eax, [esi+TStruct40.array_00.ItemCount] + mov ecx, ebx + and ecx, 1Fh + mov edx, 1 + shl edx, cl + mov ecx, ebx + shr ecx, 5 + inc ebx + and edx, [edi+ecx*4] + test edx, edx + jz short loc_195A7A6 + +loc_195A806: ; CODE XREF: TNameIndexStruct__CheckAndCopyNameFragment+DAj + ; TNameIndexStruct__CheckAndCopyNameFragment+221j + pop edi + pop esi + mov al, 1 + pop ebx + mov esp, ebp + pop ebp + retn 8 +TNameIndexStruct__CheckAndCopyNameFragment endp + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +sub_1959010 proc near ; CODE XREF: TArchiveDatabase__sub_1958B00+67p + ; TArchiveDatabase__sub_1958B00+1CFp + +pFragmentInfo = dword ptr -0Ch +var_8 = dword ptr -8 +var_1 = byte ptr -1 +pStruct1C = dword ptr 8 +arg_4 = dword ptr 0Ch + + push ebp + mov ebp, esp + mov eax, [ebp+pStruct1C] + sub esp, 0Ch + push ebx + push esi + mov esi, [eax+TMndxFindResult.pStruct40] + push edi + mov edi, ecx + mov ecx, [ebp+arg_4] + +loc_1959024: ; CODE XREF: sub_1959010+2CEj + mov eax, [edi+TFileNameDatabase.NameFragIndexMask] + and eax, ecx + lea ebx, [eax+eax*2] + mov eax, [edi+TFileNameDatabase.NameFragTable.ItemArray] + add ebx, ebx + add ebx, ebx + add eax, ebx + mov [ebp+pFragmentInfo], ebx + cmp ecx, [eax+NAME_ENTRY.NextHashModifier] + jnz loc_1959147 + mov edx, [eax+NAME_ENTRY.FragmentOffset] + mov ecx, edx + and ecx, 0FFFFFF00h + cmp ecx, 0FFFFFF00h + jz short loc_1959092 + mov ecx, [edi+TFileNameDatabase.NextDB.pDatabase] + push edx + test ecx, ecx + jz short loc_1959070 + mov edx, [ebp+pStruct1C] + push edx + call sub_1959010 + jmp short loc_195907F +; --------------------------------------------------------------------------- + +loc_1959070: ; CODE XREF: sub_1959010+53j + mov eax, [ebp+pStruct1C] + push eax + lea ecx, [edi+TFileNameDatabase.IndexStruct_174] + call TNameIndexStruct__CheckAndCopyNameFragment + +loc_195907F: ; CODE XREF: sub_1959010+5Ej + test al, al + jnz loc_195912E + +loc_1959087: ; CODE XREF: sub_1959010+90j + ; sub_1959010+1F3j + pop edi + pop esi + xor al, al + pop ebx + mov esp, ebp + pop ebp + retn 8 +; --------------------------------------------------------------------------- + +loc_1959092: ; CODE XREF: sub_1959010+48j + mov ecx, [ebp+pStruct1C] + mov eax, [ecx+TMndxFindResult.szSearchMask] + mov ecx, [esi+TStruct40.CharIndex] + mov byte ptr [ebp+arg_4+3], dl + cmp dl, [eax+ecx] + jnz short loc_1959087 + mov eax, [esi+TStruct40.array_00.ItemCount] + mov ecx, [esi+TStruct40.array_00.MaxItemCount] + inc eax + cmp eax, ecx + jbe short loc_1959119 + mov [ebp+var_8], eax + shr eax, 1 + cmp ecx, eax + jbe short loc_19590CD + cmp ecx, 7FFFFFFFh + jbe short loc_19590C7 + mov [ebp+var_8], 0FFFFFFFFh + jmp short loc_19590CD +; --------------------------------------------------------------------------- + +loc_19590C7: ; CODE XREF: sub_1959010+ACj + lea edx, [ecx+ecx] + mov [ebp+var_8], edx + +loc_19590CD: ; CODE XREF: sub_1959010+A4j + ; sub_1959010+B5j + mov eax, [ebp+var_8] + push offset unk_53ABE00 + push eax + call j_operator_new_safe + xor ecx, ecx + add esp, 8 + cmp [esi+TStruct40.array_00.ItemCount], ecx + jbe short loc_19590FD + +loc_19590E5: ; CODE XREF: sub_1959010+EBj + lea edx, [ecx+eax] + test edx, edx + jz short loc_19590F7 + mov ebx, [esi+TStruct40.array_00.field_4] + mov bl, [ecx+ebx] + mov [edx], bl + mov ebx, [ebp+pFragmentInfo] + +loc_19590F7: ; CODE XREF: sub_1959010+DAj + inc ecx + cmp ecx, [esi+TStruct40.array_00.ItemCount] + jb short loc_19590E5 + +loc_19590FD: ; CODE XREF: sub_1959010+D3j + mov ecx, [esi+TStruct40.array_00.DataBuffer] + mov edx, [ebp+var_8] + push ecx + mov [esi+TStruct40.array_00.DataBuffer], eax + mov [esi+TStruct40.array_00.field_4], eax + mov [esi+TStruct40.array_00.ItemArray], eax + mov [esi+TStruct40.array_00.MaxItemCount], edx + call operator_delete + mov dl, byte ptr [ebp+arg_4+3] + add esp, 4 + +loc_1959119: ; CODE XREF: sub_1959010+9Bj + mov eax, [esi+TStruct40.array_00.field_4] + add eax, [esi+TStruct40.array_00.ItemCount] + jz short loc_1959123 + mov [eax], dl + +loc_1959123: ; CODE XREF: sub_1959010+10Fj + mov eax, 1 + add [esi+TStruct40.array_00.ItemCount], eax + add [esi+TStruct40.CharIndex], eax + +loc_195912E: ; CODE XREF: sub_1959010+71j + mov eax, [edi+TFileNameDatabase.NameFragTable.ItemArray] + mov ecx, [ebx+eax] + mov [ebp+arg_4], ecx + test ecx, ecx + jz loc_19592ED + jmp loc_19592D5 +; --------------------------------------------------------------------------- + +loc_1959147: ; CODE XREF: sub_1959010+31j + mov eax, [edi+TFileNameDatabase.Struct68_D0.ItemIsPresent.ItemArray] + mov edx, ecx + and ecx, 1Fh + mov ebx, 1 + shl ebx, cl + shr edx, 5 + test [eax+edx*4], ebx + mov eax, [ebp+arg_4] + jz loc_195920E + mov ebx, [edi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] + push eax + lea ecx, [edi+TFileNameDatabase.Struct68_D0] + add ebx, eax + call TSparseArray__GetItemValue + mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry] + imul ecx, eax + mov eax, ecx + and ecx, 1Fh + mov edx, ecx + mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry] + add ecx, edx + shr eax, 5 + cmp ecx, 20h + mov ecx, [edi+TFileNameDatabase.FrgmDist_HiBits.ItemArray] + ja short loc_19591AB + mov eax, [ecx+eax*4] + mov ecx, edx + shr eax, cl + jmp short loc_19591CE +; --------------------------------------------------------------------------- + +loc_19591AB: ; CODE XREF: sub_1959010+190j + lea eax, [ecx+eax*4] + mov [ebp+pFragmentInfo], eax + mov eax, [eax+4] + mov ecx, 20h + sub ecx, edx + shl eax, cl + mov ecx, [ebp+pFragmentInfo] + mov ecx, [ecx] + mov [ebp+pFragmentInfo], ecx + mov ecx, edx + mov edx, [ebp+pFragmentInfo] + shr edx, cl + or eax, edx + +loc_19591CE: ; CODE XREF: sub_1959010+199j + and eax, [edi+TFileNameDatabase.FrgmDist_HiBits.EntryBitMask] + movzx edx, byte ptr [ebx] + mov ecx, [edi+TFileNameDatabase.NextDB.pDatabase] + shl eax, 8 + or eax, edx + push eax + test ecx, ecx + jz short loc_19591F2 + mov eax, [ebp+pStruct1C] + push eax + call sub_1959010 + jmp short loc_1959201 +; --------------------------------------------------------------------------- + +loc_19591F2: ; CODE XREF: sub_1959010+1D5j + mov ecx, [ebp+pStruct1C] + push ecx + lea ecx, [edi+TFileNameDatabase.IndexStruct_174] + call TNameIndexStruct__CheckAndCopyNameFragment + +loc_1959201: ; CODE XREF: sub_1959010+1E0j + test al, al + jz loc_1959087 + jmp loc_19592B6 +; --------------------------------------------------------------------------- + +loc_195920E: ; CODE XREF: sub_1959010+152j + mov edx, [edi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] + mov dl, [eax+edx] + mov ecx, [ebp+pStruct1C] + mov eax, [ecx+TMndxFindResult.szSearchMask] + mov ecx, [esi+TStruct40.CharIndex] + mov [ebp+var_1], dl + cmp dl, [eax+ecx] + jnz loc_1959087 + mov eax, [esi+TStruct40.array_00.ItemCount] + mov ecx, [esi+TStruct40.array_00.MaxItemCount] + inc eax + cmp eax, ecx + jbe short loc_19592A1 + mov ebx, eax + shr eax, 1 + mov [ebp+var_8], ebx + cmp ecx, eax + jbe short loc_1959254 + cmp ecx, 7FFFFFFFh + jbe short loc_195924E + or ebx, 0FFFFFFFFh + jmp short loc_1959251 +; --------------------------------------------------------------------------- + +loc_195924E: ; CODE XREF: sub_1959010+237j + lea ebx, [ecx+ecx] + +loc_1959251: ; CODE XREF: sub_1959010+23Cj + mov [ebp+var_8], ebx + +loc_1959254: ; CODE XREF: sub_1959010+22Fj + push offset unk_53ABE00 + push ebx + call j_operator_new_safe + xor ecx, ecx + add esp, 8 + cmp [esi+TStruct40.array_00.ItemCount], ecx + jbe short loc_1959288 + lea esp, [esp+0] + +loc_1959270: ; CODE XREF: sub_1959010+273j + lea edx, [ecx+eax] + test edx, edx + jz short loc_195927F + mov ebx, [esi+TStruct40.array_00.field_4] + mov bl, [ecx+ebx] + mov [edx], bl + +loc_195927F: ; CODE XREF: sub_1959010+265j + inc ecx + cmp ecx, [esi+TStruct40.array_00.ItemCount] + jb short loc_1959270 + mov ebx, [ebp+var_8] + +loc_1959288: ; CODE XREF: sub_1959010+257j + mov ecx, [esi+TStruct40.array_00.DataBuffer] + push ecx + mov [esi+TStruct40.array_00.DataBuffer], eax + mov [esi+TStruct40.array_00.field_4], eax + mov [esi+TStruct40.array_00.ItemArray], eax + mov [esi+TStruct40.array_00.MaxItemCount], ebx + call operator_delete + mov dl, [ebp+var_1] + add esp, 4 + +loc_19592A1: ; CODE XREF: sub_1959010+224j + mov eax, [esi+TStruct40.array_00.field_4] + add eax, [esi+TStruct40.array_00.ItemCount] + jz short loc_19592AB + mov [eax], dl + +loc_19592AB: ; CODE XREF: sub_1959010+297j + mov eax, 1 + add [esi+TStruct40.array_00.ItemCount], eax + add [esi+TStruct40.CharIndex], eax + +loc_19592B6: ; CODE XREF: sub_1959010+1F9j + mov ebx, [ebp+arg_4] + cmp ebx, [edi+TFileNameDatabase.field_214] + jbe short loc_19592ED + push ebx + mov ecx, edi + call sub_1959F50 + or edx, 0FFFFFFFFh + sub edx, ebx + add eax, edx + mov ecx, eax + mov [ebp+arg_4], eax + +loc_19592D5: ; CODE XREF: sub_1959010+132j + mov edx, [esi+TStruct40.CharIndex] + mov eax, [ebp+pStruct1C] + cmp edx, [eax+TMndxFindResult.cchSearchMask] + jb loc_1959024 + push ecx + push eax + mov ecx, edi + call sub_1958D70 + +loc_19592ED: ; CODE XREF: sub_1959010+12Cj + ; sub_1959010+2AFj + pop edi + pop esi + mov al, 1 + pop ebx + mov esp, ebp + pop ebp + retn 8 +sub_1959010 endp + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +sub_19582E0 proc near ; CODE XREF: TFileNameDatabase__sub_1958B00+253p + +arg_0 = dword ptr 8 + + push ebp + mov ebp, esp + push esi + mov esi, ecx + mov eax, [esi+0Ch] + mov ecx, [esi+10h] + inc eax + cmp eax, ecx + jbe short loc_1958311 + mov edx, eax + shr eax, 1 + cmp ecx, eax + jbe short loc_1958309 + cmp ecx, 7FFFFFFFh + jbe short loc_1958306 + or edx, 0FFFFFFFFh + jmp short loc_1958309 +; --------------------------------------------------------------------------- + +loc_1958306: ; CODE XREF: sub_19582E0+1Fj + lea edx, [ecx+ecx] + +loc_1958309: ; CODE XREF: sub_19582E0+17j + ; sub_19582E0+24j + push edx + mov ecx, esi + call TGenericArray__SetMaxItems_BYTE + +loc_1958311: ; CODE XREF: sub_19582E0+Fj + mov eax, [esi+4] + add eax, [esi+0Ch] + jz short loc_1958320 + mov ecx, [ebp+arg_0] + mov dl, [ecx] + mov [eax], dl + +loc_1958320: ; CODE XREF: sub_19582E0+37j + inc dword ptr [esi+0Ch] + pop esi + pop ebp + retn 4 +sub_19582E0 endp + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +TFileNameDatabase__sub_1958B00 proc near ; CODE XREF: TFileNameDatabase__sub_1959460+3Bp + +var_C = dword ptr -0Ch +ItemArrayOffset = dword ptr -8 +var_4 = dword ptr -4 +arg_0 = dword ptr 8 + + push ebp + mov ebp, esp + sub esp, 0Ch + mov edx, [ebp+pStruct1C] + push ebx + mov ebx, [edx+TMndxFindResult.szSearchMask] + push esi + push edi + mov edi, [edx+TMndxFindResult.pStruct40] + mov eax, [edi+TStruct40.CharIndex] + movzx eax, byte ptr [eax+ebx] + mov esi, ecx + mov ecx, [edi+TStruct40.HashValue] + mov ebx, ecx + shl ebx, 5 + xor eax, ebx + mov ebx, [esi+TFileNameDatabase.NameFragTable.ItemArray] + xor eax, ecx + and eax, [esi+TFileNameDatabase.NameFragIndexMask] + lea eax, [eax+eax*2] + add eax, eax + add eax, eax + mov [ebp+ItemArrayOffset], eax + cmp ecx, [eax+ebx] + jnz loc_1958BE5 + mov ecx, [eax+ebx+NAME_ENTRY.FragmentOffset] + mov ebx, ecx + and ebx, 0FFFFFF00h + cmp ebx, 0FFFFFF00h + jz short loc_1958B88 + mov eax, [esi+TFileNameDatabase.NextDB.pDatabase] + push ecx + push edx + test eax, eax + jz short loc_1958B6E + mov ecx, eax + call sub_1959010 + jmp short loc_1958B79 +; --------------------------------------------------------------------------- + +loc_1958B6E: ; CODE XREF: TArchiveDatabase__sub_1958B00+63j + lea ecx, [esi+TFileNameDatabase.IndexStruct_174] + call TNameIndexStruct__CheckAndCopyNameFragment + +loc_1958B79: ; CODE XREF: TArchiveDatabase__sub_1958B00+6Cj + test al, al + jnz short loc_1958BCA + +loc_1958B7D: ; CODE XREF: TArchiveDatabase__sub_1958B00+108j + ; TArchiveDatabase__sub_1958B00+1F3j + pop edi + pop esi + xor al, al + pop ebx + mov esp, ebp + pop ebp + retn 4 +; --------------------------------------------------------------------------- + +loc_1958B88: ; CODE XREF: TArchiveDatabase__sub_1958B00+57j + mov eax, [edi+TStruct40.array_00.ItemCount] + mov bl, cl + mov ecx, [edi+TStruct40.array_00.MaxItemCount] + inc eax + cmp eax, ecx + jbe short loc_1958BB5 + mov edx, eax + shr eax, 1 + cmp ecx, eax + jbe short loc_1958BAD + cmp ecx, 7FFFFFFFh + jbe short loc_1958BAA + or edx, 0FFFFFFFFh + jmp short loc_1958BAD +; --------------------------------------------------------------------------- + +loc_1958BAA: ; CODE XREF: TArchiveDatabase__sub_1958B00+A3j + lea edx, [ecx+ecx] + +loc_1958BAD: ; CODE XREF: TArchiveDatabase__sub_1958B00+9Bj + ; TArchiveDatabase__sub_1958B00+A8j + push edx + mov ecx, edi + call TGenericArray__SetMaxItems_BYTE + +loc_1958BB5: ; CODE XREF: TArchiveDatabase__sub_1958B00+93j + mov eax, [edi+TStruct40.array_00.field_4] + add eax, [edi+TStruct40.array_00.ItemCount] + jz short loc_1958BBF + mov [eax], bl + +loc_1958BBF: ; CODE XREF: TArchiveDatabase__sub_1958B00+BBj + mov eax, 1 + add [edi+TStruct40.array_00.ItemCount], eax + add [edi+TStruct40.CharIndex], eax + +loc_1958BCA: ; CODE XREF: TArchiveDatabase__sub_1958B00+7Bj + mov ecx, [esi+TFileNameDatabase.NameFragTable.ItemArray] + mov edx, [ebp+ItemArrayOffset] + mov eax, [ecx+edx+NAME_ENTRY.NextHashModifier] + mov [edi+TStruct40.HashValue], eax + +loc_1958BDA: ; CODE XREF: TArchiveDatabase__sub_1958B00+1E7j + pop edi + pop esi + mov al, 1 + pop ebx + mov esp, ebp + pop ebp + retn 4 +; --------------------------------------------------------------------------- + +loc_1958BE5: ; CODE XREF: TArchiveDatabase__sub_1958B00+3Fj + push ecx + mov ecx, esi + call TArchiveDatabase__sub_1959CB0 + mov ebx, [esi+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray] + inc eax + mov ecx, eax + and ecx, 1Fh + mov edx, 1 + shl edx, cl + mov ecx, eax + shr ecx, 5 + mov [ebp+ItemArrayOffset], eax + test [ebx+ecx*4], edx + jz loc_1958B7D + sub eax, [edi+TStruct40.HashValue] + mov [ebp+var_4], 0FFFFFFFFh + dec eax + mov [edi+TStruct40.HashValue], eax + lea esp, [esp+0] + +loc_1958C20: ; CODE XREF: TArchiveDatabase__sub_1958B00+230j + mov eax, [edi+TStruct40.HashValue] + mov ebx, [esi+TFileNameDatabase.Struct68_D0.ItemIsPresent.ItemArray] + mov ecx, eax + and ecx, 1Fh + mov edx, 1 + shl edx, cl + mov ecx, eax + shr ecx, 5 + test [ebx+ecx*4], edx + jz loc_1958CFB + mov ecx, [ebp+var_4] + cmp ecx, 0FFFFFFFFh + jnz short loc_1958C5E + push eax + lea ecx, [esi+TFileNameDatabase.Struct68_D0] + call TSparseArray__GetItemValue + mov ecx, eax + mov [ebp+var_4], eax + jmp short loc_1958C62 +; --------------------------------------------------------------------------- + +loc_1958C5E: ; CODE XREF: TArchiveDatabase__sub_1958B00+149j + inc ecx + mov [ebp+var_4], ecx + +loc_1958C62: ; CODE XREF: TArchiveDatabase__sub_1958B00+15Cj + mov edx, [edi+TStruct40.CharIndex] + mov [ebp+var_C], edx + mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.BitsPerEntry] + mov eax, edx + imul eax, ecx + mov ecx, eax + and eax, 1Fh + add edx, eax + shr ecx, 5 + cmp edx, 20h + mov edx, [esi+TFileNameDatabase.FrgmDist_HiBits.ItemArray] + ja short loc_1958C91 + mov edx, [edx+ecx*4] + mov ecx, eax + shr edx, cl + jmp short loc_1958CA8 +; --------------------------------------------------------------------------- + +loc_1958C91: ; CODE XREF: TArchiveDatabase__sub_1958B00+186j + lea ebx, [edx+ecx*4] + mov edx, [ebx+4] + mov ebx, [ebx] + mov ecx, 20h + sub ecx, eax + shl edx, cl + mov ecx, eax + shr ebx, cl + or edx, ebx + +loc_1958CA8: ; CODE XREF: TArchiveDatabase__sub_1958B00+18Fj + mov ecx, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] + and edx, [esi+TFileNameDatabase.FrgmDist_HiBits.EntryBitMask] + mov eax, [edi+TStruct40.HashValue] + movzx eax, byte ptr [ecx+eax] + mov ecx, [esi+TFileNameDatabase.NextDB.pDatabase] + shl edx, 8 + or eax, edx + push eax + test ecx, ecx + jz short loc_1958CD6 + mov edx, [ebp+pStruct1C] + push edx + call sub_1959010 + jmp short loc_1958CE5 +; --------------------------------------------------------------------------- + +loc_1958CD6: ; CODE XREF: TArchiveDatabase__sub_1958B00+1C9j + mov eax, [ebp+pStruct1C] + push eax + lea ecx, [esi+TFileNameDatabase.IndexStruct_174] + call TNameIndexStruct__CheckAndCopyNameFragment + +loc_1958CE5: ; CODE XREF: TArchiveDatabase__sub_1958B00+1D4j + test al, al + jnz loc_1958BDA + mov ecx, [ebp+var_C] + cmp [edi+TStruct40.CharIndex], ecx + jnz loc_1958B7D + jmp short loc_1958D11 +; --------------------------------------------------------------------------- + +loc_1958CFB: ; CODE XREF: TArchiveDatabase__sub_1958B00+13Dj + mov edx, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] + mov ebx, [ebp+pStruct1C] + mov ecx, [edi+TStruct40.CharIndex] + mov ebx, [ebx+TMndxFindResult.szSearchMask] + mov dl, [eax+edx] + cmp dl, [ecx+ebx] + jz short loc_1958D41 + +loc_1958D11: ; CODE XREF: TArchiveDatabase__sub_1958B00+1F9j + mov eax, [ebp+ItemArrayOffset] + inc [edi+TStruct40.HashValue] + inc eax + mov ecx, eax + and ecx, 1Fh + mov edx, 1 + shl edx, cl + mov ecx, [esi+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray] + mov [ebp+ItemArrayOffset], eax + shr eax, 5 + test [ecx+eax*4], edx + jnz loc_1958C20 + pop edi + pop esi + xor al, al + pop ebx + mov esp, ebp + pop ebp + retn 4 +; --------------------------------------------------------------------------- + +loc_1958D41: ; CODE XREF: TArchiveDatabase__sub_1958B00+20Fj + mov edx, [esi+TFileNameDatabase.FrgmDist_LoBits.ItemArray] + mov cl, [edx+eax] + lea edx, [ebp+pStruct1C+3] + mov byte ptr [ebp+pStruct1C+3], cl + push edx + mov ecx, edi + call sub_19582E0 + mov eax, 1 + add [edi+TStruct40.CharIndex], eax + pop edi + pop esi + pop ebx + mov esp, ebp + pop ebp + retn 4 +TFileNameDatabase__sub_1958B00 endp + +; =============== S U B R O U T I N E ======================================= + +; Attributes: bp-based frame + +TFileNameDatabase__sub_1959460 proc near ; CODE XREF: TFileNameDatabasePtr__sub_1956CE0+2Dp + +Struct14 = dword ptr -20h +var_1C = dword ptr -1Ch +var_18 = dword ptr -18h +var_14 = dword ptr -14h +var_10 = dword ptr -10h +pStruct14 = dword ptr -0Ch +pThis = dword ptr -8 +OneChar = byte ptr -1 +pStruct1C = dword ptr 8 + + push ebp + mov ebp, esp + sub esp, 20h + push ebx + push esi + push edi + mov edi, [ebp+pStruct1C] + mov esi, [edi+TMndxFindResult.pStruct40] + mov eax, [esi+TStruct40.SearchPhase] + mov ebx, ecx + mov [ebp+pThis], ebx + cmp eax, 4 + jz return_false + cmp eax, 2 + jz loc_1959530 + mov ecx, esi + call TStruct40__InitSearchBuffers + mov eax, [esi+TStruct40.CharIndex] + cmp eax, [edi+TMndxFindResult.cchSearchMask] + jnb short loc_19594B0 + +loc_1959498: ; CODE XREF: TFileNameDatabase__sub_1959460+4Ej + push edi + mov ecx, ebx + call TFileNameDatabase__sub_1958B00 + test al, al + jz loc_1959778 + mov ecx, [esi+TStruct40.CharIndex] + cmp ecx, [edi+TMndxFindResult.cchSearchMask] + jb short loc_1959498 + +loc_19594B0: ; CODE XREF: TFileNameDatabase__sub_1959460+36j + mov edx, [esi+TStruct40.HashValue] + or eax, 0FFFFFFFFh + mov [ebp+Struct14], edx + mov [ebp+var_14], eax + mov [ebp+var_10], eax + mov eax, [esi+TStruct40.array_00.ItemCount] + lea edx, [ebp+Struct14] + lea ecx, [esi+TStruct40.array_18] + push edx + mov [ebp+var_1C], 0 + mov [ebp+var_18], eax + call TGenericArray__InsertItem_STRUCT14 + mov ecx, [esi+TStruct40.HashValue] + mov eax, ecx + and ecx, 1Fh + mov edi, 1 + shl edi, cl + mov [esi+TStruct40.ItemCount], 1 + mov edx, [ebx+TFileNameDatabase.FileNameIndexes.ItemIsPresent.ItemArray] + shr eax, 5 + test [edx+eax*4], edi + jz short loc_1959530 + mov ecx, [esi+TStruct40.array_00.field_4] + mov eax, [esi+TStruct40.array_00.ItemCount] + mov edi, [ebp+pStruct1C] + mov [edi+TMndxFindResult.szFoundPath], ecx + mov [edi+TMndxFindResult.cchFoundPath], eax + mov esi, [esi+TStruct40.HashValue] + push esi + lea ecx, [ebx+TFileNameDatabase.FileNameIndexes] + call TSparseArray__GetItemValue + mov [edi+TMndxFindResult.FileNameIndex], eax + pop edi + pop esi + mov al, 1 + pop ebx + mov esp, ebp + pop ebp + retn 4 +; --------------------------------------------------------------------------- + +loc_1959522: ; CODE XREF: TFileNameDatabase__sub_1959460+26Bj + ; TFileNameDatabase__sub_1959460+2D9j + mov ebx, [ebp+pThis] + jmp short loc_1959530 +; --------------------------------------------------------------------------- + align 10h + +loc_1959530: ; CODE XREF: TFileNameDatabase__sub_1959460+23j + ; TFileNameDatabase__sub_1959460+97j + mov edx, [esi+TStruct40.ItemCount] + cmp edx, [esi+TStruct40.array_18.ItemCount] + jnz loc_19595BD + mov eax, [esi+TStruct40.array_18.ItemCount] + mov ecx, [esi+TStruct40.array_18.field_4] + lea eax, [eax+eax*4] + lea eax, [ecx+eax*4-14h] + mov [ebp+pStruct14], eax + mov eax, [eax+TStruct14.HashValue] + push eax + mov ecx, ebx + call TFileNameDatabase__sub_1959CB0 + mov edx, [ebp+pStruct14] + mov ecx, [esi+TStruct40.array_18.ItemCount] + inc eax + mov ebx, eax + sub ebx, [edx+TStruct14.HashValue] + mov edx, [esi+TStruct40.array_18.MaxItemCount] + inc ecx + dec ebx + mov [ebp+var_1C], eax + cmp ecx, edx + jbe short loc_1959591 + mov eax, ecx + shr ecx, 1 + cmp edx, ecx + jbe short loc_1959585 + mov eax, 0CCCCCCCh + cmp edx, 6666666h + ja short loc_1959585 + lea eax, [edx+edx] + +loc_1959585: ; CODE XREF: TFileNameDatabase__sub_1959460+113j + ; TFileNameDatabase__sub_1959460+120j + push eax + lea ecx, [esi+TStruct40.array_18] + call TGenericArray__SetMaxItems_STRUCT14 + mov eax, [ebp+var_1C] + +loc_1959591: ; CODE XREF: TFileNameDatabase__sub_1959460+10Bj + mov ecx, [esi+TStruct40.array_18.ItemCount] + mov edx, [esi+TStruct40.array_18.field_4] + lea ecx, [ecx+ecx*4] + lea ecx, [edx+ecx*4] + test ecx, ecx + jz short loc_19595B7 + mov [ecx+TStruct14.HashValue], ebx + mov [ecx+TStruct14.field_4], eax + xor eax, eax + mov [ecx+TStruct14.field_8], eax + or eax, 0FFFFFFFFh + mov [ecx+TStruct14.field_C], eax + or eax, 0FFFFFFFFh + mov [ecx+TStruct14.field_10], eax + +loc_19595B7: ; CODE XREF: TFileNameDatabase__sub_1959460+13Fj + inc [esi+TStruct40.array_18.ItemCount] + mov ebx, [ebp+pThis] + +loc_19595BD: ; CODE XREF: TFileNameDatabase__sub_1959460+D6j + mov eax, [esi+TStruct40.ItemCount] + mov ecx, [esi+TStruct40.array_18.field_4] + mov ebx, [ebx+TFileNameDatabase.Struct68_00.ItemIsPresent.ItemArray] + lea eax, [eax+eax*4] + lea edi, [ecx+eax*4] + mov eax, [edi+TStruct14.field_4] + mov ecx, eax + and ecx, 1Fh + mov edx, 1 + shl edx, cl + mov ecx, eax + shr ecx, 5 + test [ebx+ecx*4], edx + setnz cl + inc eax + mov [edi+TStruct14.field_4], eax + test cl, cl + jz loc_19596E9 + inc [esi+TStruct40.ItemCount] + mov ecx, [edi+TStruct14.HashValue] + mov eax, [ebp+pThis] + mov eax, [eax+TFileNameDatabase.Struct68_D0.ItemIsPresent.ItemArray] + mov edx, ecx + and ecx, 1Fh + mov ebx, 1 + shl ebx, cl + shr edx, 5 + test [eax+edx*4], ebx + mov ebx, [ebp+pThis] + jz short loc_1959665 + mov eax, [edi+TStruct14.field_C] + cmp eax, 0FFFFFFFFh + jnz short loc_195962F + mov eax, [edi+TStruct14.HashValue] + push eax + lea ecx, [ebx+TFileNameDatabase.Struct68_D0] + call TSparseArray__GetItemValue + jmp short loc_1959630 +; --------------------------------------------------------------------------- + +loc_195962F: ; CODE XREF: TFileNameDatabase__sub_1959460+1BDj + inc eax + +loc_1959630: ; CODE XREF: TFileNameDatabase__sub_1959460+1CDj + mov ecx, [edi+TStruct14.HashValue] + push eax + push ecx + mov ecx, ebx + mov [edi+TStruct14.field_C], eax + call sub_19573D0 + mov ecx, [ebx+TFileNameDatabase.NextDB.pDatabase] + push eax + test ecx, ecx + jz short loc_1959654 + mov edx, [ebp+pStruct1C] + push edx + call sub_1958D70 + jmp short loc_19596AE +; --------------------------------------------------------------------------- + +loc_1959654: ; CODE XREF: TFileNameDatabase__sub_1959460+1E7j + mov eax, [ebp+pStruct1C] + push eax + lea ecx, [ebx+TFileNameDatabase.IndexStruct_174] + call CopyNameFragment + jmp short loc_19596AE +; --------------------------------------------------------------------------- + +loc_1959665: ; CODE XREF: TFileNameDatabase__sub_1959460+1B5j + mov ecx, [ebx+TFileNameDatabase.FrgmDist_LoBits.ItemArray] + mov eax, [edi+TStruct14.HashValue] + mov dl, [eax+ecx] + mov eax, [esi+TStruct40.array_00.ItemCount] + mov ecx, [esi+TStruct40.array_00.MaxItemCount] + inc eax + mov [ebp+OneChar], dl + cmp eax, ecx + jbe short loc_195969E + mov edx, eax + shr eax, 1 + cmp ecx, eax + jbe short loc_1959696 + cmp ecx, 7FFFFFFFh + jbe short loc_1959693 + or edx, 0FFFFFFFFh + jmp short loc_1959696 +; --------------------------------------------------------------------------- + +loc_1959693: ; CODE XREF: TFileNameDatabase__sub_1959460+22Cj + lea edx, [ecx+ecx] + +loc_1959696: ; CODE XREF: TFileNameDatabase__sub_1959460+224j + ; TFileNameDatabase__sub_1959460+231j + push edx + mov ecx, esi + call TGenericArray__SetMaxItems_BYTE + +loc_195969E: ; CODE XREF: TFileNameDatabase__sub_1959460+21Cj + mov eax, [esi+TStruct40.array_00.field_4] + add eax, [esi+TStruct40.array_00.ItemCount] + jz short loc_19596AB + mov cl, [ebp+OneChar] + mov [eax], cl + +loc_19596AB: ; CODE XREF: TFileNameDatabase__sub_1959460+244j + inc [esi+TStruct40.array_00.ItemCount] + +loc_19596AE: ; CODE XREF: TFileNameDatabase__sub_1959460+1F2j + ; TFileNameDatabase__sub_1959460+203j + mov edx, [esi+TStruct40.array_00.ItemCount] + mov ecx, [edi+TStruct14.HashValue] + mov [edi+TStruct14.field_8], edx + mov edx, [ebx+TFileNameDatabase.FileNameIndexes.ItemIsPresent.ItemArray] + mov eax, ecx + and ecx, 1Fh + mov ebx, 1 + shl ebx, cl + shr eax, 5 + test [edx+eax*4], ebx + jz loc_1959522 + mov eax, [edi+TStruct14.field_10] + cmp eax, 0FFFFFFFFh + jnz short loc_1959754 + mov eax, [edi+TStruct14.HashValue] + mov ecx, [ebp+pThis] + push eax + add ecx, TFileNameDatabase.FileNameIndexes + call TSparseArray__GetItemValue + jmp short loc_1959755 +; --------------------------------------------------------------------------- + +loc_19596E9: ; CODE XREF: TFileNameDatabase__sub_1959460+18Cj + mov eax, [esi+TStruct40.ItemCount] + cmp eax, 1 + jz loc_1959778 + mov ecx, [esi+TStruct40.array_18.field_4] + lea eax, [eax+eax*4] + inc dword ptr [ecx+eax*4-14h] + lea eax, [ecx+eax*4-14h] + mov eax, [esi+TStruct40.ItemCount] + lea edx, [eax+eax*4] + mov eax, [esi+TStruct40.array_18.field_4] + mov edi, [eax+edx*4-20h] + mov eax, [esi+TStruct40.array_00.MaxItemCount] + cmp edi, eax + jbe short loc_1959749 + mov edx, edi + shr edx, 1 + mov ecx, edi + cmp eax, edx + jbe short loc_1959741 + cmp eax, 7FFFFFFFh + jbe short loc_195973E + or ecx, 0FFFFFFFFh + push ecx + mov ecx, esi + call TGenericArray__SetMaxItems_BYTE + dec [esi+TStruct40.ItemCount] + mov [esi+TStruct40.array_00.ItemCount], edi + jmp loc_1959522 +; --------------------------------------------------------------------------- + +loc_195973E: ; CODE XREF: TFileNameDatabase__sub_1959460+2C6j + lea ecx, [eax+eax] + +loc_1959741: ; CODE XREF: TFileNameDatabase__sub_1959460+2BFj + push ecx + mov ecx, esi + call TGenericArray__SetMaxItems_BYTE + +loc_1959749: ; CODE XREF: TFileNameDatabase__sub_1959460+2B5j + dec [esi+TStruct40.ItemCount] + mov [esi+TStruct40.array_00.ItemCount], edi + jmp loc_1959522 +; --------------------------------------------------------------------------- + +loc_1959754: ; CODE XREF: TFileNameDatabase__sub_1959460+277j + inc eax + +loc_1959755: ; CODE XREF: TFileNameDatabase__sub_1959460+287j + mov [edi+TStruct14.field_10], eax + mov ecx, [esi+TStruct40.array_00.ItemCount] + mov edx, [esi+TStruct40.array_00.field_4] + mov eax, [ebp+pStruct1C] + mov [eax+TMndxFindResult.szFoundPath], edx + mov [eax+TMndxFindResult.cchFoundPath], ecx + mov ecx, [edi+TStruct14.field_10] + pop edi + pop esi + mov [eax+TMndxFindResult.FileNameIndex], ecx + mov al, 1 + pop ebx + mov esp, ebp + pop ebp + retn 4 +; --------------------------------------------------------------------------- + +loc_1959778: ; CODE XREF: TFileNameDatabase__sub_1959460+42j + ; TFileNameDatabase__sub_1959460+28Fj + mov [esi+TStruct40.SearchPhase], 4 + +return_false: ; CODE XREF: TFileNameDatabase__sub_1959460+1Aj + pop edi + pop esi + xor al, al + pop ebx + mov esp, ebp + pop ebp + retn 4 +TFileNameDatabase__sub_1959460 endp + +; --------------------------------------------------------------------------- + +;------------------------------------------------------------------------------ +; Public functions callable from C++ + +; +; DWORD _cdecl sub_19573D0_x86(TFileNameDatabase * pDB, DWORD arg_0, DWORD arg_4); +; + +_sub_19573D0_x86 PROC + + push ebp + mov ebp, esp + mov ecx, [ebp+8] ; pDB + push [ebp+10h] ; arg_4 + push [ebp+0Ch] ; arg_0 + call sub_19573D0 + mov esp, ebp + pop ebp + ret + +_sub_19573D0_x86 ENDP + +; +; DWORD _cdecl sub_1957EF0_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C); +; + +_sub_1957EF0_x86 PROC + + push ebp + mov ebp, esp + mov ecx, [ebp+8] ; pDB + push [ebp+0Ch] ; pStruct1C + call TFileNameDatabase__FindFileInDatabase + mov esp, ebp + pop ebp + ret + +_sub_1957EF0_x86 ENDP + +; +; bool _cdecl _sub_1959460_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C); +; + +_sub_1959460_x86 PROC + + push ebp + mov ebp, esp + mov ecx, [ebp+8] ; pDB + push [ebp+0Ch] ; pStruct1C + call TFileNameDatabase__sub_1959460 + mov esp, ebp + pop ebp + ret + +_sub_1959460_x86 ENDP + +; +; bool _cdecl sub_1958B00_x86(TFileNameDatabase * pDB, TMndxFindResult * pStruct1C); +; + +_sub_1958B00_x86 PROC + + push ebp + mov ebp, esp + mov ecx, [ebp+8] ; pDB + push [ebp+0Ch] ; pStruct1C + call TFileNameDatabase__sub_1959460 + mov esp, ebp + pop ebp + ret + +_sub_1958B00_x86 ENDP + +; +; DWORD _cdecl GetItemValue_x86(TSparseArray * pStruct, DWORD dwKey); +; + +_GetItemValue_x86 PROC + + push ebp + mov ebp, esp + mov ecx, [ebp+8] ; pStruct68 + push [ebp+0Ch] ; dwKey + call TSparseArray__GetItemValue + mov esp, ebp + pop ebp + ret + +_GetItemValue_x86 ENDP + +; +; DWORD _cdecl sub_1959CB0_x86(TFileNameDatabase * pDB, DWORD dwKey); +; + +_sub_1959CB0_x86 PROC + + push ebp + mov ebp, esp + mov ecx, [ebp+8] ; pDB + push [ebp+0Ch] ; dwKey + call TArchiveDatabase__sub_1959CB0 + mov esp, ebp + pop ebp + ret + +_sub_1959CB0_x86 ENDP + +; +; DWORD _cdecl sub_1959F50_x86(TFileNameDatabase * pDB, DWORD arg_0); +; + +_sub_1959F50_x86 PROC + + push ebp + mov ebp, esp + mov ecx, [ebp+8] ; pDB + push [ebp+0Ch] ; dwKey + call sub_1959F50 + mov esp, ebp + pop ebp + ret + +_sub_1959F50_x86 ENDP + +END diff --git a/dep/CascLib/src/CascRootFile_Ovr.cpp b/dep/CascLib/src/CascRootFile_Ovr.cpp new file mode 100644 index 00000000000..205353c0120 --- /dev/null +++ b/dep/CascLib/src/CascRootFile_Ovr.cpp @@ -0,0 +1,199 @@ +/*****************************************************************************/ +/* CascRootFile_Ovr.cpp Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Support for loading Overwatch ROOT file */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 28.10.15 1.00 Lad The first version of CascRootFile_Ovr.cpp */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "CascLib.h" +#include "CascCommon.h" + +//----------------------------------------------------------------------------- +// Structure definitions for Overwatch root file + +typedef struct _CASC_FILE_ENTRY +{ + ENCODING_KEY EncodingKey; // Encoding key + ULONGLONG FileNameHash; // File name hash + DWORD dwFileName; // Offset of the file name in the name cache +} CASC_FILE_ENTRY, *PCASC_FILE_ENTRY; + +struct TRootHandler_Ovr : public TRootHandler +{ + // Linear global list of file entries + DYNAMIC_ARRAY FileTable; + + // Linear global list of names + DYNAMIC_ARRAY FileNames; + + // Global map of FileName -> FileEntry + PCASC_MAP pRootMap; +}; + +//----------------------------------------------------------------------------- +// Local functions + +static int InsertFileEntry( + TRootHandler_Ovr * pRootHandler, + const char * szFileName, + LPBYTE pbEncodingKey) +{ + PCASC_FILE_ENTRY pFileEntry; + size_t nLength = strlen(szFileName); + + // Attempt to insert the file name to the global buffer + szFileName = (char *)Array_Insert(&pRootHandler->FileNames, szFileName, nLength + 1); + if(szFileName == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Attempt to insert the entry to the array of file entries + pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1); + if(pFileEntry == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill the file entry + pFileEntry->EncodingKey = *(PENCODING_KEY)pbEncodingKey; + pFileEntry->FileNameHash = CalcFileNameHash(szFileName); + pFileEntry->dwFileName = Array_IndexOf(&pRootHandler->FileNames, szFileName); + + // Insert the file entry to the map + assert(Map_FindObject(pRootHandler->pRootMap, &pFileEntry->FileNameHash, NULL) == NULL); + Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash); + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// Implementation of Overwatch root file + +static int OvrHandler_Insert( + TRootHandler_Ovr * pRootHandler, + const char * szFileName, + LPBYTE pbEncodingKey) +{ + return InsertFileEntry(pRootHandler, szFileName, pbEncodingKey); +} + +static LPBYTE OvrHandler_Search(TRootHandler_Ovr * pRootHandler, TCascSearch * pSearch, PDWORD /* PtrFileSize */, PDWORD /* PtrLocaleFlags */) +{ + PCASC_FILE_ENTRY pFileEntry; + + // Are we still inside the root directory range? + while(pSearch->IndexLevel1 < pRootHandler->FileTable.ItemCount) + { + // Retrieve the file item + pFileEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, pSearch->IndexLevel1); + strcpy(pSearch->szFileName, (char *)Array_ItemAt(&pRootHandler->FileNames, pFileEntry->dwFileName)); + + // Prepare the pointer to the next search + pSearch->IndexLevel1++; + return pFileEntry->EncodingKey.Value; + } + + // No more entries + return NULL; +} + +static void OvrHandler_EndSearch(TRootHandler_Ovr * /* pRootHandler */, TCascSearch * /* pSearch */) +{ + // Do nothing +} + +static LPBYTE OvrHandler_GetKey(TRootHandler_Ovr * pRootHandler, const char * szFileName) +{ + ULONGLONG FileNameHash = CalcFileNameHash(szFileName); + + return (LPBYTE)Map_FindObject(pRootHandler->pRootMap, &FileNameHash, NULL); +} + +static void OvrHandler_Close(TRootHandler_Ovr * pRootHandler) +{ + if(pRootHandler != NULL) + { + // Free the file map + if(pRootHandler->pRootMap) + Map_Free(pRootHandler->pRootMap); + pRootHandler->pRootMap = NULL; + + // Free the array of the file names and file items + Array_Free(&pRootHandler->FileTable); + Array_Free(&pRootHandler->FileNames); + + // Free the root file itself + CASC_FREE(pRootHandler); + } +} + +//----------------------------------------------------------------------------- +// Public functions + +int RootHandler_CreateOverwatch(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile) +{ + TRootHandler_Ovr * pRootHandler; + ENCODING_KEY KeyBuffer; + QUERY_KEY EncodingKey = {KeyBuffer.Value, MD5_HASH_SIZE}; + void * pTextFile; + size_t nLength; + char szOneLine[0x200]; + char szFileName[MAX_PATH+1]; + DWORD dwFileCountMax = hs->pEncodingMap->TableSize; + int nError = ERROR_SUCCESS; + + // Allocate the root handler object + hs->pRootHandler = pRootHandler = CASC_ALLOC(TRootHandler_Ovr, 1); + if(pRootHandler == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill-in the handler functions + memset(pRootHandler, 0, sizeof(TRootHandler_Ovr)); + pRootHandler->Insert = (ROOT_INSERT)OvrHandler_Insert; + pRootHandler->Search = (ROOT_SEARCH)OvrHandler_Search; + pRootHandler->EndSearch = (ROOT_ENDSEARCH)OvrHandler_EndSearch; + pRootHandler->GetKey = (ROOT_GETKEY)OvrHandler_GetKey; + pRootHandler->Close = (ROOT_CLOSE)OvrHandler_Close; + + // Fill-in the flags + pRootHandler->dwRootFlags |= ROOT_FLAG_HAS_NAMES; + + // Allocate the linear array of file entries + nError = Array_Create(&pRootHandler->FileTable, CASC_FILE_ENTRY, 0x10000); + if(nError != ERROR_SUCCESS) + return nError; + + // Allocate the buffer for the file names + nError = Array_Create(&pRootHandler->FileNames, char, 0x10000); + if(nError != ERROR_SUCCESS) + return nError; + + // Create map of ROOT_ENTRY -> FileEntry + pRootHandler->pRootMap = Map_Create(dwFileCountMax, sizeof(ULONGLONG), FIELD_OFFSET(CASC_FILE_ENTRY, FileNameHash)); + if(pRootHandler->pRootMap == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Parse the ROOT file + pTextFile = ListFile_FromBuffer(pbRootFile, cbRootFile); + if(pTextFile != NULL) + { + // Skip the first line, containing "#MD5|CHUNK_ID|FILENAME|INSTALLPATH" + ListFile_GetNextLine(pTextFile, szOneLine, _maxchars(szOneLine)); + + // Parse the next lines + while((nLength = ListFile_GetNextLine(pTextFile, szOneLine, _maxchars(szOneLine))) > 0) + { + // Parse the line + nError = ParseRootFileLine(szOneLine, szOneLine + nLength, &EncodingKey, szFileName, _maxchars(szFileName)); + if(nError == ERROR_SUCCESS) + { + InsertFileEntry(pRootHandler, szFileName, KeyBuffer.Value); + } + } + + ListFile_Free(pTextFile); + } + + // Succeeded + return nError; +} diff --git a/dep/CascLib/src/CascRootFile_WoW6.cpp b/dep/CascLib/src/CascRootFile_WoW6.cpp new file mode 100644 index 00000000000..0c631f82b00 --- /dev/null +++ b/dep/CascLib/src/CascRootFile_WoW6.cpp @@ -0,0 +1,531 @@ +/*****************************************************************************/ +/* CascOpenStorage.cpp Copyright (c) Ladislav Zezula 2014 */ +/*---------------------------------------------------------------------------*/ +/* Storage functions for CASC */ +/* Note: WoW6 offsets refer to WoW.exe 6.0.3.19116 (32-bit) */ +/* SHA1: c10e9ffb7d040a37a356b96042657e1a0c95c0dd */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 29.04.14 1.00 Lad The first version of CascOpenStorage.cpp */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "CascLib.h" +#include "CascCommon.h" + +//----------------------------------------------------------------------------- +// Local structures + +#define ROOT_SEARCH_PHASE_INITIALIZING 0 +#define ROOT_SEARCH_PHASE_LISTFILE 1 +#define ROOT_SEARCH_PHASE_NAMELESS 2 +#define ROOT_SEARCH_PHASE_FINISHED 2 + +// On-disk version of locale block +typedef struct _FILE_LOCALE_BLOCK +{ + DWORD NumberOfFiles; // Number of entries + DWORD Flags; + DWORD Locales; // File locale mask (CASC_LOCALE_XXX) + + // Followed by a block of 32-bit integers (count: NumberOfFiles) + // Followed by the MD5 and file name hash (count: NumberOfFiles) + +} FILE_LOCALE_BLOCK, *PFILE_LOCALE_BLOCK; + +// On-disk version of root entry +typedef struct _FILE_ROOT_ENTRY +{ + ENCODING_KEY EncodingKey; // MD5 of the file + ULONGLONG FileNameHash; // Jenkins hash of the file name + +} FILE_ROOT_ENTRY, *PFILE_ROOT_ENTRY; + + +typedef struct _CASC_ROOT_BLOCK +{ + PFILE_LOCALE_BLOCK pLocaleBlockHdr; // Pointer to the locale block + PDWORD FileDataIds; // Pointer to the array of File Data IDs + PFILE_ROOT_ENTRY pRootEntries; + +} CASC_ROOT_BLOCK, *PCASC_ROOT_BLOCK; + +// Root file entry for CASC storages without MNDX root file (World of Warcraft 6.0+) +// Does not match to the in-file structure of the root entry +typedef struct _CASC_FILE_ENTRY +{ + ENCODING_KEY EncodingKey; // File encoding key (MD5) + ULONGLONG FileNameHash; // Jenkins hash of the file name + DWORD FileDataId; // File Data Index + DWORD Locales; // Locale flags of the file + +} CASC_FILE_ENTRY, *PCASC_FILE_ENTRY; + +struct TRootHandler_WoW6 : public TRootHandler +{ + // Linear global list of file entries + DYNAMIC_ARRAY FileTable; + + // Global map of FileName -> FileEntry + PCASC_MAP pRootMap; + + // For counting files + DWORD dwTotalFileCount; + DWORD FileDataId; +}; + +// Prototype for root file parsing routine +typedef int (*PARSE_ROOT)(TRootHandler_WoW6 * pRootHandler, PCASC_ROOT_BLOCK pBlockInfo); + +//----------------------------------------------------------------------------- +// Local functions + +static bool IsFileDataIdName(const char * szFileName) +{ + BYTE BinaryValue[4]; + + // File name must begin with "File", case insensitive + if(AsciiToUpperTable_BkSlash[szFileName[0]] == 'F' && + AsciiToUpperTable_BkSlash[szFileName[1]] == 'I' && + AsciiToUpperTable_BkSlash[szFileName[2]] == 'L' && + AsciiToUpperTable_BkSlash[szFileName[3]] == 'E') + { + // Then, 8 hexadecimal digits must follow + if(ConvertStringToBinary(szFileName + 4, 8, BinaryValue) == ERROR_SUCCESS) + { + // Must be followed by an extension or end-of-string + return (szFileName[0x0C] == 0 || szFileName[0x0C] == '.'); + } + } + + return false; +} + +// Search by FileDataId +PCASC_FILE_ENTRY FindRootEntry(DYNAMIC_ARRAY & FileTable, DWORD FileDataId) +{ + PCASC_FILE_ENTRY pStartEntry = (PCASC_FILE_ENTRY)FileTable.ItemArray; + PCASC_FILE_ENTRY pMidlEntry; + PCASC_FILE_ENTRY pEndEntry = pStartEntry + FileTable.ItemCount - 1; + int nResult; + + // Perform binary search on the table + while(pStartEntry < pEndEntry) + { + // Calculate the middle of the interval + pMidlEntry = pStartEntry + ((pEndEntry - pStartEntry) / 2); + + // Did we find it? + nResult = (int)FileDataId - (int)pMidlEntry->FileDataId; + if(nResult == 0) + return pMidlEntry; + + // Move the interval to the left or right + (nResult < 0) ? pEndEntry = pMidlEntry : pStartEntry = pMidlEntry + 1; + } + + return NULL; +} + +// Search by file name hash +// Also used in CascSearchFile +PCASC_FILE_ENTRY FindRootEntry(PCASC_MAP pRootMap, const char * szFileName, DWORD * PtrTableIndex) +{ + // Calculate the HASH value of the normalized file name + ULONGLONG FileNameHash = CalcFileNameHash(szFileName); + + // Perform the hash search + return (PCASC_FILE_ENTRY)Map_FindObject(pRootMap, &FileNameHash, PtrTableIndex); +} + +LPBYTE VerifyLocaleBlock(PCASC_ROOT_BLOCK pBlockInfo, LPBYTE pbFilePointer, LPBYTE pbFileEnd) +{ + // Validate the file locale block + pBlockInfo->pLocaleBlockHdr = (PFILE_LOCALE_BLOCK)pbFilePointer; + pbFilePointer = (LPBYTE)(pBlockInfo->pLocaleBlockHdr + 1); + if(pbFilePointer > pbFileEnd) + return NULL; + + // Validate the array of 32-bit integers + pBlockInfo->FileDataIds = (PDWORD)pbFilePointer; + pbFilePointer = (LPBYTE)(pBlockInfo->FileDataIds + pBlockInfo->pLocaleBlockHdr->NumberOfFiles); + if(pbFilePointer > pbFileEnd) + return NULL; + + // Validate the array of root entries + pBlockInfo->pRootEntries = (PFILE_ROOT_ENTRY)pbFilePointer; + pbFilePointer = (LPBYTE)(pBlockInfo->pRootEntries + pBlockInfo->pLocaleBlockHdr->NumberOfFiles); + if(pbFilePointer > pbFileEnd) + return NULL; + + // Return the position of the next block + return pbFilePointer; +} + +static int ParseRoot_CountFiles( + TRootHandler_WoW6 * pRootHandler, + PCASC_ROOT_BLOCK pRootBlock) +{ + // Add the file count to the total file count + pRootHandler->dwTotalFileCount += pRootBlock->pLocaleBlockHdr->NumberOfFiles; + return ERROR_SUCCESS; +} + +static int ParseRoot_AddRootEntries( + TRootHandler_WoW6 * pRootHandler, + PCASC_ROOT_BLOCK pRootBlock) +{ + PCASC_FILE_ENTRY pFileEntry; + + // Sanity checks + assert(pRootHandler->FileTable.ItemArray != NULL); + assert(pRootHandler->FileTable.ItemCountMax != 0); + + // WoW.exe (build 19116): Blocks with zero files are skipped + for(DWORD i = 0; i < pRootBlock->pLocaleBlockHdr->NumberOfFiles; i++) + { + // Create new entry, with overflow check + if(pRootHandler->FileTable.ItemCount >= pRootHandler->FileTable.ItemCountMax) + return ERROR_INSUFFICIENT_BUFFER; + pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1); + + // (004147A3) Prepare the CASC_FILE_ENTRY structure + pFileEntry->FileNameHash = pRootBlock->pRootEntries[i].FileNameHash; + pFileEntry->FileDataId = pRootHandler->FileDataId + pRootBlock->FileDataIds[i]; + pFileEntry->Locales = pRootBlock->pLocaleBlockHdr->Locales; + pFileEntry->EncodingKey = pRootBlock->pRootEntries[i].EncodingKey; + + // Also, insert the entry to the map + Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash); + + // Update the local File Data Id + assert((pFileEntry->FileDataId + 1) > pFileEntry->FileDataId); + pRootHandler->FileDataId = pFileEntry->FileDataId + 1; + + // Move to the next root entry + pFileEntry++; + } + + return ERROR_SUCCESS; +} + +static int ParseWowRootFileInternal( + TRootHandler_WoW6 * pRootHandler, + PARSE_ROOT pfnParseRoot, + LPBYTE pbRootFile, + LPBYTE pbRootFileEnd, + DWORD dwLocaleMask, + bool bLoadBlocksWithFlags80, + BYTE HighestBitValue) +{ + CASC_ROOT_BLOCK RootBlock; + + // Now parse the root file + while(pbRootFile < pbRootFileEnd) + { + // Validate the file locale block + pbRootFile = VerifyLocaleBlock(&RootBlock, pbRootFile, pbRootFileEnd); + if(pbRootFile == NULL) + break; + + // WoW.exe (build 19116): Entries with flag 0x100 set are skipped + if(RootBlock.pLocaleBlockHdr->Flags & 0x100) + continue; + + // WoW.exe (build 19116): Entries with flag 0x80 set are skipped if arg_4 is set to FALSE (which is by default) + if((RootBlock.pLocaleBlockHdr->Flags & 0x80) && bLoadBlocksWithFlags80 == 0) + continue; + + // WoW.exe (build 19116): Entries with (flags >> 0x1F) not equal to arg_8 are skipped + if((RootBlock.pLocaleBlockHdr->Flags >> 0x1F) != HighestBitValue) + continue; + + // WoW.exe (build 19116): Locales other than defined mask are skipped too + if((RootBlock.pLocaleBlockHdr->Locales & dwLocaleMask) == 0) + continue; + + // Now call the custom function + pfnParseRoot(pRootHandler, &RootBlock); + } + + return ERROR_SUCCESS; +} + +/* + // Code from WoW.exe + if(dwLocaleMask == CASC_LOCALE_DUAL_LANG) + { + // Is this english version of WoW? + if(arg_4 == CASC_LOCALE_BIT_ENUS) + { + LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_ENGB, false, HighestBitValue); + LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_ENUS, false, HighestBitValue); + return ERROR_SUCCESS; + } + + // Is this portuguese version of WoW? + if(arg_4 == CASC_LOCALE_BIT_PTBR) + { + LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_PTPT, false, HighestBitValue); + LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, CASC_LOCALE_PTBR, false, HighestBitValue); + } + } + + LoadWowRootFileLocales(hs, pbRootFile, cbRootFile, (1 << arg_4), false, HighestBitValue); +*/ + +static int ParseWowRootFile2( + TRootHandler_WoW6 * pRootHandler, + PARSE_ROOT pfnParseRoot, + LPBYTE pbRootFile, + LPBYTE pbRootFileEnd, + DWORD dwLocaleMask, + BYTE HighestBitValue) +{ + // Load the locale as-is + ParseWowRootFileInternal(pRootHandler, pfnParseRoot, pbRootFile, pbRootFileEnd, dwLocaleMask, false, HighestBitValue); + + // If we wanted enGB, we also load enUS for the missing files + if(dwLocaleMask == CASC_LOCALE_ENGB) + ParseWowRootFileInternal(pRootHandler, pfnParseRoot, pbRootFile, pbRootFileEnd, CASC_LOCALE_ENUS, false, HighestBitValue); + + if(dwLocaleMask == CASC_LOCALE_PTPT) + ParseWowRootFileInternal(pRootHandler, pfnParseRoot, pbRootFile, pbRootFileEnd, CASC_LOCALE_PTBR, false, HighestBitValue); + + return ERROR_SUCCESS; +} + +// WoW.exe: 004146C7 (BuildManifest::Load) +static int ParseWowRootFile( + TRootHandler_WoW6 * pRootHandler, + PARSE_ROOT pfnParseRoot, + LPBYTE pbRootFile, + LPBYTE pbRootFileEnd, + DWORD dwLocaleMask) +{ + ParseWowRootFile2(pRootHandler, pfnParseRoot, pbRootFile, pbRootFileEnd, dwLocaleMask, 0); + ParseWowRootFile2(pRootHandler, pfnParseRoot, pbRootFile, pbRootFileEnd, dwLocaleMask, 1); + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// Implementation of WoW6 root file + +static int WowHandler_Insert( + TRootHandler_WoW6 * pRootHandler, + const char * szFileName, + LPBYTE pbEncodingKey) +{ + PCASC_FILE_ENTRY pFileEntry; + DWORD FileDataId = 0; + + // Don't let the number of items to overflow + if(pRootHandler->FileTable.ItemCount >= pRootHandler->FileTable.ItemCountMax) + return ERROR_NOT_ENOUGH_MEMORY; + + // Insert the item to the linear file list + pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1); + if(pFileEntry != NULL) + { + // Get the file data ID of the previous item (0 if this is the first one) + if(pRootHandler->FileTable.ItemCount > 1) + FileDataId = pFileEntry[-1].FileDataId; + + // Fill-in the new entry + pFileEntry->EncodingKey = *(PENCODING_KEY)pbEncodingKey; + pFileEntry->FileNameHash = CalcFileNameHash(szFileName); + pFileEntry->FileDataId = FileDataId + 1; + pFileEntry->Locales = CASC_LOCALE_ALL; + + // Verify collisions (debug version only) + assert(Map_FindObject(pRootHandler->pRootMap, &pFileEntry->FileNameHash, NULL) == NULL); + + // Insert the entry to the map + Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash); + } + + return ERROR_SUCCESS; +} + +static LPBYTE WowHandler_Search(TRootHandler_WoW6 * pRootHandler, TCascSearch * pSearch, PDWORD /* PtrFileSize */, PDWORD PtrLocaleFlags) +{ + PCASC_FILE_ENTRY pFileEntry; + + // Only if we have a listfile + if(pSearch->pCache != NULL) + { + // Keep going through the listfile + while(ListFile_GetNext(pSearch->pCache, pSearch->szMask, pSearch->szFileName, MAX_PATH)) + { + // Find the root entry + pFileEntry = FindRootEntry(pRootHandler->pRootMap, pSearch->szFileName, NULL); + if(pFileEntry != NULL) + { + // Give the caller the locale mask + if(PtrLocaleFlags != NULL) + PtrLocaleFlags[0] = pFileEntry->Locales; + return pFileEntry->EncodingKey.Value; + } + } + } + + // No more files + return NULL; +} + +static LPBYTE WowHandler_GetKey(TRootHandler_WoW6 * pRootHandler, const char * szFileName) +{ + PCASC_FILE_ENTRY pFileEntry; + DWORD FileDataId; + BYTE FileDataIdLE[4]; + + // Open by FileDataId. The file name must be as following: + // File########.xxx, where '#' are hexa-decimal numbers (case insensitive). + // Extension is ignored in that case + if(IsFileDataIdName(szFileName)) + { + ConvertStringToBinary(szFileName + 4, 8, FileDataIdLE); + FileDataId = ConvertBytesToInteger_4(FileDataIdLE); + + pFileEntry = FindRootEntry(pRootHandler->FileTable, FileDataId); + } + else + { + // Find by the file name hash + pFileEntry = FindRootEntry(pRootHandler->pRootMap, szFileName, NULL); + } + + return (pFileEntry != NULL) ? pFileEntry->EncodingKey.Value : NULL; +} + +static void WowHandler_EndSearch(TRootHandler_WoW6 * /* pRootHandler */, TCascSearch * pSearch) +{ + if(pSearch->pRootContext != NULL) + CASC_FREE(pSearch->pRootContext); + pSearch->pRootContext = NULL; +} + +static void WowHandler_Close(TRootHandler_WoW6 * pRootHandler) +{ + if(pRootHandler != NULL) + { + Array_Free(&pRootHandler->FileTable); + Map_Free(pRootHandler->pRootMap); + CASC_FREE(pRootHandler); + } +} + +#ifdef _DEBUG +static void TRootHandlerWoW6_Dump( + TCascStorage * hs, + TDumpContext * dc, // Pointer to an opened file + LPBYTE pbRootFile, + DWORD cbRootFile, + const TCHAR * szListFile, + int nDumpLevel) +{ + PCASC_ENCODING_ENTRY pEncodingEntry; + CASC_ROOT_BLOCK BlockInfo; + PLISTFILE_MAP pListMap; + QUERY_KEY EncodingKey; + LPBYTE pbRootFileEnd = pbRootFile + cbRootFile; + LPBYTE pbFilePointer; + char szOneLine[0x100]; + DWORD i; + + // Create the listfile map + pListMap = ListFile_CreateMap(szListFile); + + // Dump the root entries + for(pbFilePointer = pbRootFile; pbFilePointer <= pbRootFileEnd; ) + { + // Validate the root block + pbFilePointer = VerifyLocaleBlock(&BlockInfo, pbFilePointer, pbRootFileEnd); + if(pbFilePointer == NULL) + break; + + // Dump the locale block + dump_print(dc, "Flags: %08X Locales: %08X NumberOfFiles: %u\n" + "=========================================================\n", + BlockInfo.pLocaleBlockHdr->Flags, + BlockInfo.pLocaleBlockHdr->Locales, + BlockInfo.pLocaleBlockHdr->NumberOfFiles); + + // Dump the hashes and encoding keys + for(i = 0; i < BlockInfo.pLocaleBlockHdr->NumberOfFiles; i++) + { + // Dump the entry + dump_print(dc, "%08X %08X-%08X %s %s\n", + (DWORD)(BlockInfo.FileDataIds[i]), + (DWORD)(BlockInfo.pRootEntries[i].FileNameHash >> 0x20), + (DWORD)(BlockInfo.pRootEntries[i].FileNameHash), + StringFromMD5(BlockInfo.pRootEntries[i].EncodingKey.Value, szOneLine), + ListFile_FindName(pListMap, BlockInfo.pRootEntries[i].FileNameHash)); + + // Find the encoding entry in the encoding table + if(nDumpLevel >= DUMP_LEVEL_ENCODING_FILE) + { + EncodingKey.pbData = BlockInfo.pRootEntries[i].EncodingKey.Value; + EncodingKey.cbData = MD5_HASH_SIZE; + pEncodingEntry = FindEncodingEntry(hs, &EncodingKey, NULL); + CascDumpEncodingEntry(hs, dc, pEncodingEntry, nDumpLevel); + } + } + + // Put extra newline + dump_print(dc, "\n"); + } + + ListFile_FreeMap(pListMap); +} +#endif + +//----------------------------------------------------------------------------- +// Public functions + +int RootHandler_CreateWoW6(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile, DWORD dwLocaleMask) +{ + TRootHandler_WoW6 * pRootHandler; + LPBYTE pbRootFileEnd = pbRootFile + cbRootFile; + int nError; + + // Verify the size + if(pbRootFile == NULL || cbRootFile <= sizeof(PFILE_LOCALE_BLOCK)) + nError = ERROR_FILE_CORRUPT; + + // Allocate the root handler object + hs->pRootHandler = pRootHandler = CASC_ALLOC(TRootHandler_WoW6, 1); + if(pRootHandler == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill-in the handler functions + memset(pRootHandler, 0, sizeof(TRootHandler_WoW6)); + pRootHandler->Insert = (ROOT_INSERT)WowHandler_Insert; + pRootHandler->Search = (ROOT_SEARCH)WowHandler_Search; + pRootHandler->EndSearch = (ROOT_ENDSEARCH)WowHandler_EndSearch; + pRootHandler->GetKey = (ROOT_GETKEY)WowHandler_GetKey; + pRootHandler->Close = (ROOT_CLOSE)WowHandler_Close; + +#ifdef _DEBUG + pRootHandler->Dump = TRootHandlerWoW6_Dump; // Support for ROOT file dump +#endif // _DEBUG + + // Count the files that are going to be loaded + ParseWowRootFile(pRootHandler, ParseRoot_CountFiles, pbRootFile, pbRootFileEnd, dwLocaleMask); + pRootHandler->dwTotalFileCount += CASC_EXTRA_FILES; + + // Create linear table that will contain all root items + nError = Array_Create(&pRootHandler->FileTable, CASC_FILE_ENTRY, pRootHandler->dwTotalFileCount); + if(nError != ERROR_SUCCESS) + return nError; + + // Create the map of FileHash ->FileEntry + pRootHandler->pRootMap = Map_Create(pRootHandler->dwTotalFileCount, sizeof(ULONGLONG), FIELD_OFFSET(CASC_FILE_ENTRY, FileNameHash)); + if(pRootHandler->pRootMap == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Parse the root file again and insert all files to the map + ParseWowRootFile(pRootHandler, ParseRoot_AddRootEntries, pbRootFile, pbRootFileEnd, dwLocaleMask); + return ERROR_SUCCESS; +} diff --git a/dep/CascLib/src/common/Common.cpp b/dep/CascLib/src/common/Common.cpp index 2dbdd470478..9c0f56dc9ba 100644 --- a/dep/CascLib/src/common/Common.cpp +++ b/dep/CascLib/src/common/Common.cpp @@ -99,7 +99,7 @@ void CopyString(char * szTarget, const wchar_t * szSource, size_t cchLength) szTarget[cchLength] = 0; } -char * NewStr(const char * szString, size_t nCharsToReserve) +char * CascNewStr(const char * szString, size_t nCharsToReserve) { char * szNewString = NULL; size_t nLength; @@ -118,7 +118,7 @@ char * NewStr(const char * szString, size_t nCharsToReserve) return szNewString; } -wchar_t * NewStr(const wchar_t * szString, size_t nCharsToReserve) +wchar_t * CascNewStr(const wchar_t * szString, size_t nCharsToReserve) { wchar_t * szNewString = NULL; size_t nLength; @@ -137,22 +137,20 @@ wchar_t * NewStr(const wchar_t * szString, size_t nCharsToReserve) return szNewString; } -TCHAR * NewStrFromAnsi(LPBYTE pbStringBegin, LPBYTE pbStringEnd) +TCHAR * CascNewStrFromAnsi(const char * szBegin, const char * szEnd) { TCHAR * szNewString = NULL; - TCHAR * szStringPtr = NULL; - size_t nLength = (size_t)(pbStringEnd - pbStringBegin); - if(pbStringEnd > pbStringBegin) + // Only if the entry is valid + if(szBegin != NULL && szEnd > szBegin) { - szNewString = szStringPtr = CASC_ALLOC(TCHAR, nLength + 1); + // Allocate and copy the string + szNewString = CASC_ALLOC(TCHAR, (szEnd - szBegin + 1)); if(szNewString != NULL) - { - CopyString(szStringPtr, (const char *)pbStringBegin, nLength); - szStringPtr[nLength] = 0; - } + CopyString(szNewString, szBegin, (szEnd - szBegin)); } + // Return the string return szNewString; } @@ -218,30 +216,60 @@ TCHAR * CombinePath(const TCHAR * szDirectory, const TCHAR * szSubDir) return szFullPath; } -void NormalizeFileName_UpperBkSlash(char * szTrgFileName, const char * szSrcFileName, size_t cchMaxChars) +TCHAR * CombinePathAndString(const TCHAR * szPath, const char * szString, size_t nLength) { - char * szTrgFileEnd = szTrgFileName + cchMaxChars; - size_t i; + TCHAR * szFullPath = NULL; + TCHAR * szSubDir; - // Normalize the file name: ToLower + BackSlashToSlash - for(i = 0; szSrcFileName[i] != 0 && szTrgFileName < szTrgFileEnd; i++) - szTrgFileName[i] = AsciiToUpperTable_BkSlash[szSrcFileName[i]]; + // Create the subdir string + szSubDir = CASC_ALLOC(TCHAR, nLength + 1); + if(szSubDir != NULL) + { + CopyString(szSubDir, szString, nLength); + szFullPath = CombinePath(szPath, szSubDir); + CASC_FREE(szSubDir); + } - assert(szSrcFileName[i] == 0); - szTrgFileName[i] = 0; + return szFullPath; } -void NormalizeFileName_LowerSlash(char * szTrgFileName, const char * szSrcFileName, size_t cchMaxChars) +size_t NormalizeFileName(const unsigned char * NormTable, char * szNormName, const char * szFileName, size_t cchMaxChars) { - char * szTrgFileEnd = szTrgFileName + cchMaxChars; + char * szNormNameEnd = szNormName + cchMaxChars; size_t i; // Normalize the file name: ToLower + BackSlashToSlash - for(i = 0; szSrcFileName[i] != 0 && szTrgFileName < szTrgFileEnd; i++) - szTrgFileName[i] = AsciiToLowerTable_Slash[szSrcFileName[i]]; + for(i = 0; szFileName[0] != 0 && szNormName < szNormNameEnd; i++) + *szNormName++ = NormTable[*szFileName++]; - assert(szSrcFileName[i] == 0); - szTrgFileName[i] = 0; + // Terminate the string + szNormName[0] = 0; + return i; +} + +size_t NormalizeFileName_UpperBkSlash(char * szNormName, const char * szFileName, size_t cchMaxChars) +{ + return NormalizeFileName(AsciiToUpperTable_BkSlash, szNormName, szFileName, cchMaxChars); +} + +size_t NormalizeFileName_LowerSlash(char * szNormName, const char * szFileName, size_t cchMaxChars) +{ + return NormalizeFileName(AsciiToLowerTable_Slash, szNormName, szFileName, cchMaxChars); +} + +ULONGLONG CalcFileNameHash(const char * szFileName) +{ + char szNormName[MAX_PATH+1]; + uint32_t dwHashHigh = 0; + uint32_t dwHashLow = 0; + size_t nLength; + + // Normalize the file name - convert to uppercase, slashes to backslashes + nLength = NormalizeFileName_UpperBkSlash(szNormName, szFileName, MAX_PATH); + + // Calculate the HASH value of the normalized file name + hashlittle2(szNormName, nLength, &dwHashHigh, &dwHashLow); + return ((ULONGLONG)dwHashHigh << 0x20) | dwHashLow; } int ConvertDigitToInt32(const TCHAR * szString, PDWORD PtrValue) @@ -256,6 +284,22 @@ int ConvertDigitToInt32(const TCHAR * szString, PDWORD PtrValue) return (Digit > 0x0F) ? ERROR_BAD_FORMAT : ERROR_SUCCESS; } +int ConvertStringToInt08(const char * szString, PDWORD PtrValue) +{ + BYTE DigitOne = AsciiToUpperTable_BkSlash[szString[0]] - '0'; + BYTE DigitTwo = AsciiToUpperTable_BkSlash[szString[1]] - '0'; + + // Fix the digits + if(DigitOne > 9) + DigitOne -= 'A' - '9' - 1; + if(DigitTwo > 9) + DigitTwo -= 'A' - '9' - 1; + + // Combine them into a value + PtrValue[0] = (DigitOne << 0x04) | DigitTwo; + return (DigitOne <= 0x0F && DigitTwo <= 0x0F) ? ERROR_SUCCESS : ERROR_BAD_FORMAT; +} + int ConvertStringToInt32(const TCHAR * szString, size_t nMaxDigits, PDWORD PtrValue) { // The number of digits must be even @@ -290,6 +334,41 @@ int ConvertStringToInt32(const TCHAR * szString, size_t nMaxDigits, PDWORD PtrVa return ERROR_SUCCESS; } +// Converts string blob to binary blob. +int ConvertStringToBinary( + const char * szString, + size_t nMaxDigits, + LPBYTE pbBinary) +{ + const char * szStringEnd = szString + nMaxDigits; + DWORD dwCounter = 0; + BYTE DigitValue; + BYTE ByteValue = 0; + + // Convert the string + while(szString < szStringEnd) + { + // Retrieve the digit converted to hexa + DigitValue = (BYTE)(AsciiToUpperTable_BkSlash[szString[0]] - '0'); + if(DigitValue > 9) + DigitValue -= 'A' - '9' - 1; + if(DigitValue > 0x0F) + return ERROR_BAD_FORMAT; + + // Insert the digit to the binary buffer + ByteValue = (ByteValue << 0x04) | DigitValue; + dwCounter++; + + // If we reached the second digit, it means that we need + // to flush the byte value and move on + if((dwCounter & 0x01) == 0) + *pbBinary++ = ByteValue; + szString++; + } + + return ERROR_SUCCESS; +} + char * StringFromBinary(LPBYTE pbBinary, size_t cbBinary, char * szBuffer) { char * szSaveBuffer = szBuffer; @@ -308,6 +387,11 @@ char * StringFromBinary(LPBYTE pbBinary, size_t cbBinary, char * szBuffer) return szSaveBuffer; } +char * StringFromMD5(LPBYTE md5, char * szBuffer) +{ + return StringFromBinary(md5, MD5_HASH_SIZE, szBuffer); +} + //----------------------------------------------------------------------------- // File name utilities @@ -341,87 +425,55 @@ const char * GetPlainFileName(const char * szFileName) bool CheckWildCard(const char * szString, const char * szWildCard) { - const char * szSubString; - int nSubStringLength; - int nMatchCount = 0; + const char * szWildCardPtr; - // When the mask is empty, it never matches - if(szWildCard == NULL || *szWildCard == 0) - return false; - - // If the wildcard contains just "*", then it always matches - if(szWildCard[0] == '*' && szWildCard[1] == 0) - return true; - - // Do normal test for(;;) { // If there is '?' in the wildcard, we skip one char - while(*szWildCard == '?') + while(szWildCard[0] == '?') { + if(szString[0] == 0) + return false; + szWildCard++; szString++; } - // If there is '*', means zero or more chars. We have to - // find the sequence after '*' - if(*szWildCard == '*') + // Handle '*' + szWildCardPtr = szWildCard; + if(szWildCardPtr[0] != 0) { - // More stars is equal to one star - while(*szWildCard == '*' || *szWildCard == '?') - szWildCard++; - - // If we found end of the wildcard, it's a match - if(*szWildCard == 0) - return true; - - // Determine the length of the substring in szWildCard - szSubString = szWildCard; - while(*szSubString != 0 && *szSubString != '?' && *szSubString != '*') - szSubString++; - nSubStringLength = (int)(szSubString - szWildCard); - nMatchCount = 0; - - // Now we have to find a substring in szString, - // that matches the substring in szWildCard - while(*szString != 0) + if(szWildCardPtr[0] == '*') { - // Calculate match count - while(nMatchCount < nSubStringLength) - { - if(AsciiToUpperTable_BkSlash[(BYTE)szString[nMatchCount]] != AsciiToUpperTable_BkSlash[(BYTE)szWildCard[nMatchCount]]) - break; - if(szString[nMatchCount] == 0) - break; - nMatchCount++; - } + szWildCardPtr++; + + if(szWildCardPtr[0] == '*') + continue; + + if(szWildCardPtr[0] == 0) + return true; - // If the match count has reached substring length, we found a match - if(nMatchCount == nSubStringLength) + if(AsciiToUpperTable_BkSlash[szWildCardPtr[0]] == AsciiToUpperTable_BkSlash[szString[0]]) { - szWildCard += nMatchCount; - szString += nMatchCount; - break; + if(CheckWildCard(szString, szWildCardPtr)) + return true; } + } + else + { + if(AsciiToUpperTable_BkSlash[szWildCardPtr[0]] != AsciiToUpperTable_BkSlash[szString[0]]) + return false; - // No match, move to the next char in szString - nMatchCount = 0; - szString++; + szWildCard = szWildCardPtr + 1; } + + if(szString[0] == 0) + return false; + szString++; } else { - // If we came to the end of the string, compare it to the wildcard - if(AsciiToUpperTable_BkSlash[(BYTE)*szString] != AsciiToUpperTable_BkSlash[(BYTE)*szWildCard]) - return false; - - // If we arrived to the end of the string, it's a match - if(*szString == 0) - return true; - - // Otherwise, continue in comparing - szWildCard++; - szString++; + return (szString[0] == 0) ? true : false; } } } diff --git a/dep/CascLib/src/common/Common.h b/dep/CascLib/src/common/Common.h index ae098adb084..484276a3bd7 100644 --- a/dep/CascLib/src/common/Common.h +++ b/dep/CascLib/src/common/Common.h @@ -28,14 +28,6 @@ extern unsigned char AsciiToLowerTable_Slash[256]; extern unsigned char AsciiToUpperTable_BkSlash[256]; extern unsigned char IntToHexChar[]; -//----------------------------------------------------------------------------- -// GetLastError/SetLastError support for non-Windows platform - -#ifndef PLATFORM_WINDOWS -int GetLastError(); -void SetLastError(int nError); -#endif // PLATFORM_WINDOWS - //----------------------------------------------------------------------------- // String manipulation @@ -43,19 +35,25 @@ void CopyString(char * szTarget, const char * szSource, size_t cchLength); void CopyString(wchar_t * szTarget, const char * szSource, size_t cchLength); void CopyString(char * szTarget, const wchar_t * szSource, size_t cchLength); -char * NewStr(const char * szString, size_t nCharsToReserve); -wchar_t * NewStr(const wchar_t * szString, size_t nCharsToReserve); +char * CascNewStr(const char * szString, size_t nCharsToReserve); +wchar_t * CascNewStr(const wchar_t * szString, size_t nCharsToReserve); -TCHAR * NewStrFromAnsi(LPBYTE pbStringBegin, LPBYTE pbStringEnd); +TCHAR * CascNewStrFromAnsi(const char * szBegin, const char * szEnd); TCHAR * CombinePath(const TCHAR * szPath, const TCHAR * szSubDir); +TCHAR * CombinePathAndString(const TCHAR * szPath, const char * szString, size_t nLength); + +size_t NormalizeFileName_UpperBkSlash(char * szNormName, const char * szFileName, size_t cchMaxChars); +size_t NormalizeFileName_LowerSlash(char * szNormName, const char * szFileName, size_t cchMaxChars); -void NormalizeFileName_UpperBkSlash(char * szTrgFileName, const char * szSrcFileName, size_t cchMaxChars); -void NormalizeFileName_LowerSlash(char * szTrgFileName, const char * szSrcFileName, size_t cchMaxChars); +ULONGLONG CalcFileNameHash(const char * szFileName); int ConvertDigitToInt32(const TCHAR * szString, PDWORD PtrValue); +int ConvertStringToInt08(const char * szString, PDWORD PtrValue); int ConvertStringToInt32(const TCHAR * szString, size_t nMaxDigits, PDWORD PtrValue); +int ConvertStringToBinary(const char * szString, size_t nMaxDigits, LPBYTE pbBinary); char * StringFromBinary(LPBYTE pbBinary, size_t cbBinary, char * szBuffer); +char * StringFromMD5(LPBYTE md5, char * szBuffer); //----------------------------------------------------------------------------- // File name utilities diff --git a/dep/CascLib/src/common/Directory.h b/dep/CascLib/src/common/Directory.h new file mode 100644 index 00000000000..ae97dca3d76 --- /dev/null +++ b/dep/CascLib/src/common/Directory.h @@ -0,0 +1,29 @@ +/*****************************************************************************/ +/* Directory.h Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Directory functions for CascLib */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 30.10.15 1.00 Lad The first version of Directory.h */ +/*****************************************************************************/ + +#ifndef __DIRECTORY_H__ +#define __DIRECTORY_H__ + +//----------------------------------------------------------------------------- +// Scanning a directory + +typedef bool (*INDEX_FILE_FOUND)(const TCHAR * szFileName, PDWORD IndexArray, PDWORD OldIndexArray, void * pvContext); + +bool DirectoryExists(const TCHAR * szDirectory); + +int ScanIndexDirectory( + const TCHAR * szIndexPath, + INDEX_FILE_FOUND pfnOnFileFound, + PDWORD IndexArray, + PDWORD OldIndexArray, + void * pvContext + ); + +#endif // __DIRECTORY_H__ diff --git a/dep/CascLib/src/common/DumpContext.cpp b/dep/CascLib/src/common/DumpContext.cpp new file mode 100644 index 00000000000..8783ff201ba --- /dev/null +++ b/dep/CascLib/src/common/DumpContext.cpp @@ -0,0 +1,153 @@ +/*****************************************************************************/ +/* DumpContext.cpp Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Implementation of dump context */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 16.03.15 1.00 Lad Created */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "../CascLib.h" +#include "../CascCommon.h" + +//----------------------------------------------------------------------------- +// Local functions + +static TCHAR * FormatFileName(TCascStorage * hs, const TCHAR * szNameFormat) +{ + TCHAR * szFileName; + TCHAR * szSrc; + TCHAR * szTrg; + + // Create copy of the file name + szFileName = szSrc = szTrg = CascNewStr(szNameFormat, 0); + if(szFileName != NULL) + { + // Format the file name + while(szSrc[0] != 0) + { + if(szSrc[0] == _T('%')) + { + // Replace "%build%" with a build number + if(!_tcsncmp(szSrc, _T("%build%"), 7)) + { + szTrg += _stprintf(szTrg, _T("%u"), hs->dwBuildNumber); + szSrc += 7; + continue; + } + } + + // Just copy the character + *szTrg++ = *szSrc++; + } + + // Terminate the target file name + szTrg[0] = 0; + } + + return szFileName; +} + +//----------------------------------------------------------------------------- +// Public functions + +TDumpContext * CreateDumpContext(TCascStorage * hs, const TCHAR * szNameFormat) +{ + TDumpContext * dc; + TCHAR * szFileName; + + // Validate the storage handle + if(hs != NULL) + { + // Calculate the number of bytes needed for dump context + dc = CASC_ALLOC(TDumpContext, 1); + if(dc != NULL) + { + // Initialize the dump context + memset(dc, 0, sizeof(TDumpContext)); + + // Format the real file name + szFileName = FormatFileName(hs, szNameFormat); + if(szFileName != NULL) + { + // Create the file + dc->pStream = FileStream_CreateFile(szFileName, 0); + if(dc->pStream != NULL) + { + // Initialize buffers + dc->pbBufferBegin = + dc->pbBufferPtr = dc->DumpBuffer; + dc->pbBufferEnd = dc->DumpBuffer + CASC_DUMP_BUFFER_SIZE; + + // Success + CASC_FREE(szFileName); + return dc; + } + + // File create failed --> delete the file name + CASC_FREE(szFileName); + } + + // Free the dump context + CASC_FREE(dc); + } + } + + return NULL; +} + +int dump_print(TDumpContext * dc, const char * szFormat, ...) +{ + va_list argList; + char szBuffer[0x200]; + int nLength = 0; + + // Only if the dump context is valid + if(dc != NULL) + { + // Print the buffer using sprintf + va_start(argList, szFormat); + nLength = vsprintf(szBuffer, szFormat, argList); + assert(nLength < 0x200); + va_end(argList); + + // Copy the string. Replace "\n" with "\n\r" + for(int i = 0; i < nLength; i++) + { + // Flush the buffer, if needed + if((dc->pbBufferPtr + 2) >= dc->pbBufferEnd) + { + FileStream_Write(dc->pStream, NULL, dc->pbBufferBegin, (DWORD)(dc->pbBufferPtr - dc->pbBufferBegin)); + dc->pbBufferPtr = dc->pbBufferBegin; + } + + // Copy the char + if(szBuffer[i] == 0x0A) + *dc->pbBufferPtr++ = 0x0D; + *dc->pbBufferPtr++ = szBuffer[i]; + } + } + + return nLength; +} + +int dump_close(TDumpContext * dc) +{ + // Only if the dump context is valid + if(dc != NULL) + { + // Flush the dump context if there are some data + if(dc->pbBufferPtr > dc->pbBufferBegin) + FileStream_Write(dc->pStream, NULL, dc->pbBufferBegin, (DWORD)(dc->pbBufferPtr - dc->pbBufferBegin)); + dc->pbBufferPtr = dc->pbBufferBegin; + + // Free the file stream and the entire context + if(dc->pStream != NULL) + FileStream_Close(dc->pStream); + CASC_FREE(dc); + } + + return 0; +} diff --git a/dep/CascLib/src/common/DumpContext.h b/dep/CascLib/src/common/DumpContext.h new file mode 100644 index 00000000000..6f725f5b942 --- /dev/null +++ b/dep/CascLib/src/common/DumpContext.h @@ -0,0 +1,38 @@ +/*****************************************************************************/ +/* DumpContext.h Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Interface for TDumpContext */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 16.03.15 1.00 Lad Created */ +/*****************************************************************************/ + +#ifndef __DUMP_CONTEXT_H__ +#define __DUMP_CONTEXT_H__ + +//----------------------------------------------------------------------------- +// Defines + +// Size of the buffer for the dump context +#define CASC_DUMP_BUFFER_SIZE 0x10000 + +// Structure for dump context +struct TDumpContext +{ + TFileStream * pStream; // Pointer to the open stream + LPBYTE pbBufferBegin; // Begin of the dump buffer + LPBYTE pbBufferPtr; // Current dump buffer pointer + LPBYTE pbBufferEnd; // End of the dump buffer + + BYTE DumpBuffer[CASC_DUMP_BUFFER_SIZE]; // Dump buffer +}; + +//----------------------------------------------------------------------------- +// Dump context functions + +TDumpContext * CreateDumpContext(struct _TCascStorage * hs, const TCHAR * szNameFormat); +int dump_print(TDumpContext * dc, const char * szFormat, ...); +int dump_close(TDumpContext * dc); + +#endif // __DUMP_CONTEXT_H__ diff --git a/dep/CascLib/src/common/DynamicArray.cpp b/dep/CascLib/src/common/DynamicArray.cpp new file mode 100644 index 00000000000..e744fbe3912 --- /dev/null +++ b/dep/CascLib/src/common/DynamicArray.cpp @@ -0,0 +1,101 @@ +/*****************************************************************************/ +/* DynamicArray.cpp Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Description: */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 30.10.15 1.00 Lad The first version of DynamicArray.cpp */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "../CascLib.h" +#include "../CascCommon.h" + +//----------------------------------------------------------------------------- +// Local functions + +static bool EnlargeArray(PDYNAMIC_ARRAY pArray, size_t NewItemCount) +{ + char * NewItemArray; + size_t ItemCountMax; + + // We expect the array to be already allocated + assert(pArray->ItemArray != NULL); + assert(pArray->ItemCountMax != 0); + + // Shall we enlarge the table? + if(NewItemCount > pArray->ItemCountMax) + { + // Calculate new table size + ItemCountMax = pArray->ItemCountMax; + while(ItemCountMax < NewItemCount) + ItemCountMax = ItemCountMax << 1; + + // Allocate new table + NewItemArray = CASC_REALLOC(char, pArray->ItemArray, pArray->ItemSize * ItemCountMax); + if(NewItemArray == NULL) + return false; + + // Set the new table size + pArray->ItemCountMax = ItemCountMax; + pArray->ItemArray = NewItemArray; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Public functions + +int Array_Create_(PDYNAMIC_ARRAY pArray, size_t ItemSize, size_t ItemCountMax) +{ + pArray->ItemArray = CASC_ALLOC(char, (ItemSize * ItemCountMax)); + if(pArray->ItemArray == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + pArray->ItemCountMax = ItemCountMax; + pArray->ItemCount = 0; + pArray->ItemSize = ItemSize; + return ERROR_SUCCESS; +} + +void * Array_Insert(PDYNAMIC_ARRAY pArray, const void * NewItems, size_t NewItemCount) +{ + char * NewItemPtr; + + // Try to enlarge the buffer, if needed + if(!EnlargeArray(pArray, pArray->ItemCount + NewItemCount)) + return NULL; + NewItemPtr = pArray->ItemArray + (pArray->ItemCount * pArray->ItemSize); + + // Copy the old item(s), if any + if(NewItems != NULL) + memcpy(NewItemPtr, NewItems, (NewItemCount * pArray->ItemSize)); + + // Increment the size of the array + pArray->ItemCount += NewItemCount; + return NewItemPtr; +} + +void * Array_ItemAt(PDYNAMIC_ARRAY pArray, size_t ItemIndex) +{ + assert(ItemIndex < pArray->ItemCount); + return pArray->ItemArray + (ItemIndex * pArray->ItemSize); +} + +size_t Array_IndexOf(PDYNAMIC_ARRAY pArray, const void * ArrayPtr) +{ + char * ArrayItem = (char *)ArrayPtr; + + assert(pArray->ItemArray <= ArrayItem && ArrayItem <= pArray->ItemArray + (pArray->ItemCount * pArray->ItemSize)); + return ((ArrayItem - pArray->ItemArray) / pArray->ItemSize); +} + +void Array_Free(PDYNAMIC_ARRAY pArray) +{ + if(pArray != NULL && pArray->ItemArray != NULL) + { + CASC_FREE(pArray->ItemArray); + } +} diff --git a/dep/CascLib/src/common/DynamicArray.h b/dep/CascLib/src/common/DynamicArray.h new file mode 100644 index 00000000000..11cefacdcc4 --- /dev/null +++ b/dep/CascLib/src/common/DynamicArray.h @@ -0,0 +1,37 @@ +/*****************************************************************************/ +/* DynamicArray.h Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Common array implementation */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 30.10.15 1.00 Lad The first version of DynamicArray.h */ +/*****************************************************************************/ + +#ifndef __DYNAMIC_ARRAY_H__ +#define __DYNAMIC_ARRAY_H__ + +//----------------------------------------------------------------------------- +// Structures + +typedef struct _DYNAMIC_ARRAY +{ + char * ItemArray; // Pointer to items + size_t ItemCountMax; // Current number of items + size_t ItemCount; // Total size of the buffer + size_t ItemSize; // Size of the single item + +} DYNAMIC_ARRAY, *PDYNAMIC_ARRAY; + +//----------------------------------------------------------------------------- +// Functions for managing the array + +int Array_Create_(PDYNAMIC_ARRAY pArray, size_t ItemSize, size_t ItemCountMax); +void * Array_Insert(PDYNAMIC_ARRAY pArray, const void * NewItems, size_t NewItemCount); +void * Array_ItemAt(PDYNAMIC_ARRAY pArray, size_t ItemIndex); +size_t Array_IndexOf(PDYNAMIC_ARRAY pArray, const void * ArrayPtr); +void Array_Free(PDYNAMIC_ARRAY pArray); + +#define Array_Create(pArray, type, ItemCountMax) Array_Create_(pArray, sizeof(type), ItemCountMax) + +#endif // __DYNAMIC_ARRAY__ diff --git a/dep/CascLib/src/common/FileStream.cpp b/dep/CascLib/src/common/FileStream.cpp index 8e541b44fca..ef9cc55d7ea 100644 --- a/dep/CascLib/src/common/FileStream.cpp +++ b/dep/CascLib/src/common/FileStream.cpp @@ -16,7 +16,6 @@ #define __CASCLIB_SELF__ #include "../CascLib.h" #include "../CascCommon.h" -#include "FileStream.h" #ifdef _MSC_VER #pragma comment(lib, "wininet.lib") // Internet functions for HTTP stream diff --git a/dep/CascLib/src/common/ListFile.cpp b/dep/CascLib/src/common/ListFile.cpp index 42131a2bc2c..b9915f0f31c 100644 --- a/dep/CascLib/src/common/ListFile.cpp +++ b/dep/CascLib/src/common/ListFile.cpp @@ -13,117 +13,118 @@ #include "../CascCommon.h" //----------------------------------------------------------------------------- -// Listfile entry structure +// Listfile cache structure -#define CACHE_BUFFER_SIZE 0x1000 // Size of the cache buffer +typedef struct _LISTFILE_CACHE +{ + char * pBegin; // The begin of the listfile cache + char * pPos; // Current position in the cache + char * pEnd; // The last character in the file cache -typedef bool (*RELOAD_CACHE)(void * pvCacheContext, LPBYTE pbBuffer, DWORD dwBytesToRead); -typedef void (*CLOSE_STREAM)(void * pvCacheContext); + // Followed by the cache (variable length) -struct TListFileCache -{ - RELOAD_CACHE pfnReloadCache; // Function for reloading the cache - CLOSE_STREAM pfnCloseStream; // Function for closing the stream - void * pvCacheContext; // Reload context passed to reload function - char * szMask; // Self-relative pointer to file mask - DWORD dwFileSize; // Total size of the cached file - DWORD dwFilePos; // Position of the cache in the file - BYTE * pBegin; // The begin of the listfile cache - BYTE * pPos; - BYTE * pEnd; // The last character in the file cache - - BYTE Buffer[CACHE_BUFFER_SIZE]; -// char MaskBuff[1] // Followed by the name mask (if any) -}; +} LISTFILE_CACHE, *PLISTFILE_CACHE; //----------------------------------------------------------------------------- -// Local functions +// Creating the listfile cache for the given amount of data -static bool ReloadCache_ExternalFile(void * pvCacheContext, LPBYTE pbBuffer, DWORD dwBytesToRead) +static PLISTFILE_CACHE CreateListFileCache(DWORD dwFileSize) { - TFileStream * pStream = (TFileStream *)pvCacheContext; + PLISTFILE_CACHE pCache; + + // Allocate cache for one file block + pCache = (PLISTFILE_CACHE)CASC_ALLOC(BYTE, sizeof(LISTFILE_CACHE) + dwFileSize); + if(pCache != NULL) + { + // Set the initial pointers + pCache->pBegin = + pCache->pPos = (char *)(pCache + 1); + pCache->pEnd = pCache->pBegin + dwFileSize; + } - return FileStream_Read(pStream, NULL, pbBuffer, dwBytesToRead); + // Return the cache + return pCache; } -static void CloseStream_ExternalFile(void * pvCacheContext) +//----------------------------------------------------------------------------- +// Functions for parsing an external listfile + +void * ListFile_OpenExternal(const TCHAR * szListFile) { - TFileStream * pStream = (TFileStream *)pvCacheContext; + PLISTFILE_CACHE pCache = NULL; + TFileStream * pStream; + ULONGLONG FileSize = 0; + + // Open the external listfile + pStream = FileStream_OpenFile(szListFile, STREAM_FLAG_READ_ONLY); + if(pStream != NULL) + { + // Retrieve the size of the external listfile + FileStream_GetSize(pStream, &FileSize); + if(0 < FileSize && FileSize <= 0x30000000) + { + // Create the in-memory cache for the entire listfile + // The listfile does not have any data loaded yet + pCache = CreateListFileCache((DWORD)FileSize); + if(pCache != NULL) + { + if(!FileStream_Read(pStream, NULL, pCache->pBegin, (DWORD)FileSize)) + { + ListFile_Free(pCache); + pCache = NULL; + } + } + } - return FileStream_Close(pStream); + // Close the file stream + FileStream_Close(pStream); + } + + return pCache; } +void * ListFile_FromBuffer(LPBYTE pbBuffer, DWORD cbBuffer) +{ + PLISTFILE_CACHE pCache = NULL; + + // Create the in-memory cache for the entire listfile + // The listfile does not have any data loaded yet + pCache = CreateListFileCache(cbBuffer); + if(pCache != NULL) + memcpy(pCache->pBegin, pbBuffer, cbBuffer); -// Reloads the cache. Returns number of characters -// that has been loaded into the cache. -static DWORD ReloadListFileCache(TListFileCache * pCache) + return pCache; +} + +// Performs the MD5-based check on the listfile +bool ListFile_VerifyMD5(void * pvListFile, LPBYTE pbHashMD5) { - DWORD dwBytesToRead = 0; + PLISTFILE_CACHE pCache = (PLISTFILE_CACHE)pvListFile; - // Only do something if the cache is empty - if(pCache->pPos >= pCache->pEnd) - { - // Move the file position forward - pCache->dwFilePos += CACHE_BUFFER_SIZE; - if(pCache->dwFilePos >= pCache->dwFileSize) - return 0; - - // Get the number of bytes remaining - dwBytesToRead = pCache->dwFileSize - pCache->dwFilePos; - if(dwBytesToRead > CACHE_BUFFER_SIZE) - dwBytesToRead = CACHE_BUFFER_SIZE; - - // Load the next data chunk to the cache - // If we didn't read anything, it might mean that the block - // of the file is not available - // We stop reading the file at this point, because the rest - // of the listfile is unreliable - if(!pCache->pfnReloadCache(pCache->pvCacheContext, pCache->Buffer, dwBytesToRead)) - return 0; - - // Set the buffer pointers - pCache->pBegin = - pCache->pPos = &pCache->Buffer[0]; - pCache->pEnd = pCache->pBegin + dwBytesToRead; - } + // Must be at the beginning + assert(pCache->pPos == pCache->pBegin); - return dwBytesToRead; + // Verify the MD5 hash for the entire block + return VerifyDataBlockHash(pCache->pBegin, (DWORD)(pCache->pEnd - pCache->pBegin), pbHashMD5); } -static size_t ReadListFileLine(TListFileCache * pCache, char * szLine, size_t nMaxChars) +size_t ListFile_GetNextLine(void * pvListFile, const char ** pszLineBegin, const char ** pszLineEnd) { - char * szLineBegin = szLine; - char * szLineEnd = szLine + nMaxChars - 1; + PLISTFILE_CACHE pCache = (PLISTFILE_CACHE)pvListFile; char * szExtraString = NULL; + char * szLineBegin; + char * szLineEnd; // Skip newlines, spaces, tabs and another non-printable stuff - for(;;) - { - // If we need to reload the cache, do it - if(pCache->pPos == pCache->pEnd) - { - if(ReloadListFileCache(pCache) == 0) - break; - } - - // If we found a non-whitespace character, stop - if(pCache->pPos[0] > 0x20) - break; - - // Skip the character + while(pCache->pPos < pCache->pEnd && pCache->pPos[0] <= 0x20) pCache->pPos++; - } + + // Remember the begin of the line + szLineBegin = pCache->pPos; // Copy the remaining characters - while(szLine < szLineEnd) + while(pCache->pPos < pCache->pEnd) { - // If we need to reload the cache, do it now and resume copying - if(pCache->pPos == pCache->pEnd) - { - if(ReloadListFileCache(pCache) == 0) - break; - } - // If we have found a newline, stop loading if(pCache->pPos[0] == 0x0D || pCache->pPos[0] == 0x0A) break; @@ -131,119 +132,64 @@ static size_t ReadListFileLine(TListFileCache * pCache, char * szLine, size_t nM // Blizzard listfiles can also contain information about patch: // Pass1\Files\MacOS\unconditional\user\Background Downloader.app\Contents\Info.plist~Patch(Data#frFR#base-frFR,1326) if(pCache->pPos[0] == '~') - szExtraString = szLine; + szExtraString = pCache->pPos; - // Copy the character - *szLine++ = *pCache->pPos++; + // Move the position by one character forward + pCache->pPos++; } - // Terminate line with zero - *szLine = 0; + // Remember the end of the line + szLineEnd = (szExtraString != NULL && szExtraString[0] == '~' && szExtraString[1] == 'P') ? szExtraString : pCache->pPos; - // If there was extra string after the file name, clear it - if(szExtraString != NULL) - { - if(szExtraString[0] == '~' && szExtraString[1] == 'P') - { - szLine = szExtraString; - *szExtraString = 0; - } - } - - // Return the length of the line - return (szLine - szLineBegin); + // Give the caller the positions of the begin and end of the line + pszLineBegin[0] = szLineBegin; + pszLineEnd[0] = szLineEnd; + return (size_t)(szLineEnd - szLineBegin); } -static TListFileCache * CreateListFileCache(RELOAD_CACHE pfnReloadCache, CLOSE_STREAM pfnCloseStream, void * pvCacheContext, DWORD dwFileSize) +size_t ListFile_GetNextLine(void * pvListFile, char * szBuffer, size_t nMaxChars) { - TListFileCache * pCache = NULL; - DWORD dwBytesToRead; - - // Allocate cache for one file block - pCache = (TListFileCache *)CASC_ALLOC(BYTE, sizeof(TListFileCache)); - if(pCache != NULL) - { - // Clear the entire structure - memset(pCache, 0, sizeof(TListFileCache)); - pCache->pfnReloadCache = pfnReloadCache; - pCache->pfnCloseStream = pfnCloseStream; - pCache->pvCacheContext = pvCacheContext; - pCache->dwFileSize = dwFileSize; - - // Load the file cache from the file - dwBytesToRead = CASCLIB_MIN(CACHE_BUFFER_SIZE, dwFileSize); - if(pfnReloadCache(pvCacheContext, pCache->Buffer, dwBytesToRead)) - { - // Allocate pointers - pCache->pBegin = pCache->pPos = &pCache->Buffer[0]; - pCache->pEnd = pCache->pBegin + dwBytesToRead; - } - else - { - ListFile_Free(pCache); - pCache = NULL; - } - } - - // Return the cache - return pCache; -} - -//----------------------------------------------------------------------------- -// Functions for parsing an external listfile + const char * szLineBegin = NULL; + const char * szLineEnd = NULL; + size_t nLength; -void * ListFile_OpenExternal(const TCHAR * szListFile) -{ - TListFileCache * pCache; - TFileStream * pStream; - ULONGLONG FileSize = 0; + // Retrieve the next line + nLength = ListFile_GetNextLine(pvListFile, &szLineBegin, &szLineEnd); - // Open the external listfile - pStream = FileStream_OpenFile(szListFile, STREAM_FLAG_READ_ONLY); - if(pStream != NULL) + // Check the length + if(nLength > nMaxChars) { - // Retrieve the size of the external listfile - FileStream_GetSize(pStream, &FileSize); - if(0 < FileSize && FileSize <= 0xFFFFFFFF) - { - // Create the cache for the listfile - pCache = CreateListFileCache(ReloadCache_ExternalFile, CloseStream_ExternalFile, pStream, (DWORD)FileSize); - if(pCache != NULL) - return pCache; - } - - // Close the file stream - FileStream_Close(pStream); + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return 0; } - return NULL; + // Copy the line to the user buffer + memcpy(szBuffer, szLineBegin, nLength); + szBuffer[nLength] = 0; + return nLength; } size_t ListFile_GetNext(void * pvListFile, const char * szMask, char * szBuffer, size_t nMaxChars) { - TListFileCache * pCache = (TListFileCache *)pvListFile; size_t nLength = 0; - int nError = ERROR_INVALID_PARAMETER; + int nError = ERROR_SUCCESS; // Check for parameters - if(pCache != NULL) + for(;;) { - for(;;) + // Read the (next) line + nLength = ListFile_GetNextLine(pvListFile, szBuffer, nMaxChars); + if(nLength == 0) { - // Read the (next) line - nLength = ReadListFileLine(pCache, szBuffer, nMaxChars); - if(nLength == 0) - { - nError = ERROR_NO_MORE_FILES; - break; - } + nError = ERROR_NO_MORE_FILES; + break; + } - // If some mask entered, check it - if(CheckWildCard(szBuffer, szMask)) - { - nError = ERROR_SUCCESS; - break; - } + // If some mask entered, check it + if(CheckWildCard(szBuffer, szMask)) + { + nError = ERROR_SUCCESS; + break; } } @@ -254,14 +200,9 @@ size_t ListFile_GetNext(void * pvListFile, const char * szMask, char * szBuffer, void ListFile_Free(void * pvListFile) { - TListFileCache * pCache = (TListFileCache *)pvListFile; - - // Valid parameter check - if(pCache != NULL) + if(pvListFile != NULL) { - if(pCache->pfnCloseStream != NULL) - pCache->pfnCloseStream(pCache->pvCacheContext); - CASC_FREE(pCache); + CASC_FREE(pvListFile); } } @@ -293,11 +234,8 @@ static PLISTFILE_MAP ListMap_Create() static PLISTFILE_MAP ListMap_InsertName(PLISTFILE_MAP pListMap, const char * szFileName, size_t nLength) { PLISTFILE_ENTRY pListEntry; - char szFileName2[MAX_PATH+1]; size_t cbToAllocate; size_t cbEntrySize; - uint32_t dwHashHigh = 0; - uint32_t dwHashLow = 0; // Make sure there is enough space in the list map cbEntrySize = sizeof(LISTFILE_ENTRY) + nLength; @@ -314,14 +252,10 @@ static PLISTFILE_MAP ListMap_InsertName(PLISTFILE_MAP pListMap, const char * szF // Get the pointer to the first entry pListEntry = (PLISTFILE_ENTRY)((LPBYTE)(pListMap + 1) + pListMap->cbBuffer); - - // Get the name hash - NormalizeFileName_UpperBkSlash(szFileName2, szFileName, MAX_PATH); - hashlittle2(szFileName2, nLength, &dwHashHigh, &dwHashLow); - - // Calculate the HASH value of the normalized file name - pListEntry->FileNameHash = ((ULONGLONG)dwHashHigh << 0x20) | dwHashLow; + pListEntry->FileNameHash = CalcFileNameHash(szFileName); pListEntry->cbEntrySize = (DWORD)cbEntrySize; + + // Copy the file name to the entry memcpy(pListEntry->szFileName, szFileName, nLength); pListEntry->szFileName[nLength] = 0; @@ -357,7 +291,7 @@ static PLISTFILE_MAP ListMap_Finish(PLISTFILE_MAP pListMap) pbEntry += pListEntry->cbEntrySize; // Insert the entry to the map - Map_InsertObject(pMap, pListEntry); + Map_InsertObject(pMap, pListEntry, &pListEntry->FileNameHash); } return pListMap; @@ -408,7 +342,7 @@ const char * ListFile_FindName(PLISTFILE_MAP pListMap, ULONGLONG FileNameHash) PLISTFILE_ENTRY pListEntry = NULL; if(pListMap != NULL) - pListEntry = (PLISTFILE_ENTRY)Map_FindObject(pListMap->pNameMap, &FileNameHash); + pListEntry = (PLISTFILE_ENTRY)Map_FindObject(pListMap->pNameMap, &FileNameHash, NULL); return (pListEntry != NULL) ? pListEntry->szFileName : ""; } diff --git a/dep/CascLib/src/common/ListFile.h b/dep/CascLib/src/common/ListFile.h index 9815160e1ea..84bec3ed751 100644 --- a/dep/CascLib/src/common/ListFile.h +++ b/dep/CascLib/src/common/ListFile.h @@ -37,6 +37,10 @@ typedef struct _LISTFILE_MAP // Functions for parsing an external listfile void * ListFile_OpenExternal(const TCHAR * szListFile); +void * ListFile_FromBuffer(LPBYTE pbBuffer, DWORD cbBuffer); +bool ListFile_VerifyMD5(void * pvListFile, LPBYTE pbHashMD5); +size_t ListFile_GetNextLine(void * pvListFile, const char ** pszLineBegin, const char ** pszLineEnd); +size_t ListFile_GetNextLine(void * pvListFile, char * szBuffer, size_t nMaxChars); size_t ListFile_GetNext(void * pvListFile, const char * szMask, char * szBuffer, size_t nMaxChars); void ListFile_Free(void * pvListFile); diff --git a/dep/CascLib/src/common/Map.cpp b/dep/CascLib/src/common/Map.cpp index 70697a158ab..30ae8ea0531 100644 --- a/dep/CascLib/src/common/Map.cpp +++ b/dep/CascLib/src/common/Map.cpp @@ -15,51 +15,82 @@ //----------------------------------------------------------------------------- // Local functions -static DWORD CalcHashIndex(PCASC_MAP pMap, void * pvIdentifier) +// Returns the extension, right after "." +static const char * String_GetExtension(const char * szString) { + const char * szExtension = strrchr(szString, '.'); + return (szExtension != NULL) ? szExtension + 1 : NULL; +} + +static DWORD CalcHashIndex_Key(PCASC_MAP pMap, void * pvKey) +{ + LPBYTE pbKey = (LPBYTE)pvKey; DWORD dwHash = 0x7EEE7EEE; - // Is it a string table? - if(pMap->KeyLength == KEY_LENGTH_STRING) - { - char * szString = (char *)pvIdentifier; + // Construct the hash from the first 8 digits + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[0]; + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[1]; + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[2]; + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[3]; + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[4]; + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[5]; + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[6]; + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbKey[7]; - for(size_t i = 0; szString[i] != 0; i++) - dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ szString[i]; - } - else - { - LPBYTE pbHash = (LPBYTE)pvIdentifier; + // Return the hash limited by the table size + return (dwHash % pMap->TableSize); +} + +static DWORD CalcHashIndex_String(PCASC_MAP pMap, const char * szString, const char * szStringEnd) +{ + LPBYTE pbKeyEnd = (LPBYTE)szStringEnd; + LPBYTE pbKey = (LPBYTE)szString; + DWORD dwHash = 0x7EEE7EEE; - // Construct the hash from the first 4 digits - for(size_t i = 0; i < pMap->KeyLength; i++) - dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ pbHash[i]; + // Hash the string itself + while(pbKey < pbKeyEnd) + { + dwHash = (dwHash >> 24) ^ (dwHash << 5) ^ dwHash ^ AsciiToUpperTable_BkSlash[pbKey[0]]; + pbKey++; } // Return the hash limited by the table size return (dwHash % pMap->TableSize); } -static bool CompareIdentifier(PCASC_MAP pMap, void * pvTableEntry, void * pvIdentifier) +static bool CompareObject_Key(PCASC_MAP pMap, void * pvObject, void * pvKey) { - // Is it a string table? - if(pMap->KeyLength == KEY_LENGTH_STRING) - { - char * szTableEntry = (char *)pvTableEntry; - char * szIdentifier = (char *)pvIdentifier; + LPBYTE pbObjectKey = (LPBYTE)pvObject + pMap->KeyOffset; - return (strcmp(szTableEntry, szIdentifier) == 0); - } - else + return (memcmp(pbObjectKey, pvKey, pMap->KeyLength) == 0); +} + +static bool CompareObject_String( + PCASC_MAP pMap, + const char * szExistingString, + const char * szString, + const char * szStringEnd) +{ + // Keep compiler happy + CASCLIB_UNUSED(pMap); + + // Compare the whole part, case insensitive + while(szString < szStringEnd) { - return (memcmp(pvTableEntry, pvIdentifier, pMap->KeyLength) == 0); + if(AsciiToUpperTable_BkSlash[*szExistingString] != AsciiToUpperTable_BkSlash[*szString]) + return false; + + szExistingString++; + szString++; } + + return true; } //----------------------------------------------------------------------------- // Public functions -PCASC_MAP Map_Create(DWORD dwMaxItems, DWORD dwKeyLength, DWORD dwMemberOffset) +PCASC_MAP Map_Create(DWORD dwMaxItems, DWORD dwKeyLength, DWORD dwKeyOffset) { PCASC_MAP pMap; size_t cbToAllocate; @@ -76,7 +107,7 @@ PCASC_MAP Map_Create(DWORD dwMaxItems, DWORD dwKeyLength, DWORD dwMemberOffset) memset(pMap, 0, cbToAllocate); pMap->KeyLength = dwKeyLength; pMap->TableSize = dwTableSize; - pMap->MemberOffset = dwMemberOffset; + pMap->KeyOffset = dwKeyOffset; } // Return the allocated map @@ -104,24 +135,28 @@ size_t Map_EnumObjects(PCASC_MAP pMap, void **ppvArray) return pMap->ItemCount; } -void * Map_FindObject(PCASC_MAP pMap, void * pvIdentifier) +void * Map_FindObject(PCASC_MAP pMap, void * pvKey, PDWORD PtrIndex) { - void * pvTableEntry; + void * pvObject; DWORD dwHashIndex; // Verify pointer to the map if(pMap != NULL) { // Construct the main index - dwHashIndex = CalcHashIndex(pMap, pvIdentifier); + dwHashIndex = CalcHashIndex_Key(pMap, pvKey); while(pMap->HashTable[dwHashIndex] != NULL) { // Get the pointer at that position - pvTableEntry = pMap->HashTable[dwHashIndex]; + pvObject = pMap->HashTable[dwHashIndex]; // Compare the hash - if(CompareIdentifier(pMap, pvTableEntry, pvIdentifier)) - return ((LPBYTE)pvTableEntry - pMap->MemberOffset); + if(CompareObject_Key(pMap, pvObject, pvKey)) + { + if(PtrIndex != NULL) + PtrIndex[0] = dwHashIndex; + return pvObject; + } // Move to the next entry dwHashIndex = (dwHashIndex + 1) % pMap->TableSize; @@ -132,9 +167,47 @@ void * Map_FindObject(PCASC_MAP pMap, void * pvIdentifier) return NULL; } -bool Map_InsertObject(PCASC_MAP pMap, void * pvIdentifier) +bool Map_InsertObject(PCASC_MAP pMap, void * pvNewObject, void * pvKey) +{ + void * pvExistingObject; + DWORD dwHashIndex; + + // Verify pointer to the map + if(pMap != NULL) + { + // Limit check + if((pMap->ItemCount + 1) >= pMap->TableSize) + return false; + + // Construct the hash index + dwHashIndex = CalcHashIndex_Key(pMap, pvKey); + while(pMap->HashTable[dwHashIndex] != NULL) + { + // Get the pointer at that position + pvExistingObject = pMap->HashTable[dwHashIndex]; + + // Check if hash being inserted conflicts with an existing hash + if(CompareObject_Key(pMap, pvExistingObject, pvKey)) + return false; + + // Move to the next entry + dwHashIndex = (dwHashIndex + 1) % pMap->TableSize; + } + + // Insert at that position + pMap->HashTable[dwHashIndex] = pvNewObject; + pMap->ItemCount++; + return true; + } + + // Failed + return false; +} + +bool Map_InsertString(PCASC_MAP pMap, const char * szString, bool bCutExtension) { - void * pvTableEntry; + const char * szExistingString; + const char * szStringEnd = NULL; DWORD dwHashIndex; // Verify pointer to the map @@ -144,15 +217,21 @@ bool Map_InsertObject(PCASC_MAP pMap, void * pvIdentifier) if((pMap->ItemCount + 1) >= pMap->TableSize) return false; + // Retrieve the length of the string without extension + if(bCutExtension) + szStringEnd = String_GetExtension(szString); + if(szStringEnd == NULL) + szStringEnd = szString + strlen(szString); + // Construct the hash index - dwHashIndex = CalcHashIndex(pMap, pvIdentifier); + dwHashIndex = CalcHashIndex_String(pMap, szString, szStringEnd); while(pMap->HashTable[dwHashIndex] != NULL) { // Get the pointer at that position - pvTableEntry = pMap->HashTable[dwHashIndex]; + szExistingString = (const char *)pMap->HashTable[dwHashIndex]; // Check if hash being inserted conflicts with an existing hash - if(CompareIdentifier(pMap, pvTableEntry, pvIdentifier)) + if(CompareObject_String(pMap, szExistingString, szString, szStringEnd)) return false; // Move to the next entry @@ -160,7 +239,7 @@ bool Map_InsertObject(PCASC_MAP pMap, void * pvIdentifier) } // Insert at that position - pMap->HashTable[dwHashIndex] = pvIdentifier; + pMap->HashTable[dwHashIndex] = (void *)szString; pMap->ItemCount++; return true; } @@ -169,6 +248,34 @@ bool Map_InsertObject(PCASC_MAP pMap, void * pvIdentifier) return false; } +const char * Map_FindString(PCASC_MAP pMap, const char * szString, const char * szStringEnd) +{ + const char * szExistingString; + DWORD dwHashIndex; + + // Verify pointer to the map + if(pMap != NULL) + { + // Construct the main index + dwHashIndex = CalcHashIndex_String(pMap, szString, szStringEnd); + while(pMap->HashTable[dwHashIndex] != NULL) + { + // Get the pointer at that position + szExistingString = (const char *)pMap->HashTable[dwHashIndex]; + + // Compare the hash + if(CompareObject_String(pMap, szExistingString, szString, szStringEnd)) + return szExistingString; + + // Move to the next entry + dwHashIndex = (dwHashIndex + 1) % pMap->TableSize; + } + } + + // Not found, sorry + return NULL; +} + void Map_Free(PCASC_MAP pMap) { if(pMap != NULL) diff --git a/dep/CascLib/src/common/Map.h b/dep/CascLib/src/common/Map.h index 40ea4238b81..7b0c1321e6c 100644 --- a/dep/CascLib/src/common/Map.h +++ b/dep/CascLib/src/common/Map.h @@ -20,20 +20,23 @@ typedef struct _CASC_MAP { size_t TableSize; size_t ItemCount; // Number of items in the map - size_t MemberOffset; // How far is the hash from the begin of the structure (in bytes) + size_t KeyOffset; // How far is the hash from the begin of the structure (in bytes) size_t KeyLength; // Length of the hash key void * HashTable[1]; // Pointer table } CASC_MAP, *PCASC_MAP; +typedef bool (*MAP_COMPARE)(PCASC_MAP pMap, void * pvObject, void * pvKey); + //----------------------------------------------------------------------------- // Functions -PCASC_MAP Map_Create(DWORD dwMaxItems, DWORD dwKeyLength, DWORD dwMemberOffset); +PCASC_MAP Map_Create(DWORD dwMaxItems, DWORD dwKeyLength, DWORD dwKeyOffset); size_t Map_EnumObjects(PCASC_MAP pMap, void **ppvArray); -void * Map_FindObject(PCASC_MAP pMap, void * pvIdentifier); -bool Map_InsertObject(PCASC_MAP pMap, void * pvIdentifier); -void Map_Sort(PCASC_MAP pMap); +void * Map_FindObject(PCASC_MAP pMap, void * pvKey, PDWORD PtrIndex); +bool Map_InsertObject(PCASC_MAP pMap, void * pvNewObject, void * pvKey); +const char * Map_FindString(PCASC_MAP pMap, const char * szString, const char * szStringEnd); +bool Map_InsertString(PCASC_MAP pMap, const char * szString, bool bCutExtension); void Map_Free(PCASC_MAP pMap); #endif // __HASHTOPTR_H__ diff --git a/dep/CascLib/src/common/RootHandler.cpp b/dep/CascLib/src/common/RootHandler.cpp new file mode 100644 index 00000000000..df9953f3ea6 --- /dev/null +++ b/dep/CascLib/src/common/RootHandler.cpp @@ -0,0 +1,78 @@ +/*****************************************************************************/ +/* RootHandler.cpp Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Implementation of root handler */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 09.03.15 1.00 Lad Created */ +/*****************************************************************************/ + +#define __CASCLIB_SELF__ +#include "../CascLib.h" +#include "../CascCommon.h" + +//----------------------------------------------------------------------------- +// Common support + +int RootHandler_Insert(TRootHandler * pRootHandler, const char * szFileName, LPBYTE pbEncodingKey) +{ + if(pRootHandler == NULL || pRootHandler->Insert == NULL) + return ERROR_NOT_SUPPORTED; + + return pRootHandler->Insert(pRootHandler, szFileName, pbEncodingKey); +} + +LPBYTE RootHandler_Search(TRootHandler * pRootHandler, struct _TCascSearch * pSearch, PDWORD PtrFileSize, PDWORD PtrLocaleFlags) +{ + // Check if the root structure is valid at all + if(pRootHandler == NULL) + return NULL; + + return pRootHandler->Search(pRootHandler, pSearch, PtrFileSize, PtrLocaleFlags); +} + +void RootHandler_EndSearch(TRootHandler * pRootHandler, struct _TCascSearch * pSearch) +{ + // Check if the root structure is valid at all + if(pRootHandler != NULL) + { + pRootHandler->EndSearch(pRootHandler, pSearch); + } +} + +LPBYTE RootHandler_GetKey(TRootHandler * pRootHandler, const char * szFileName) +{ + // Check if the root structure is valid at all + if(pRootHandler == NULL) + return NULL; + + return pRootHandler->GetKey(pRootHandler, szFileName); +} + +void RootHandler_Dump(TCascStorage * hs, LPBYTE pbRootHandler, DWORD cbRootHandler, const TCHAR * szNameFormat, const TCHAR * szListFile, int nDumpLevel) +{ + TDumpContext * dc; + + // Only if the ROOT provider suports the dump option + if(hs->pRootHandler != NULL && hs->pRootHandler->Dump != NULL) + { + // Create the dump file + dc = CreateDumpContext(hs, szNameFormat); + if(dc != NULL) + { + // Dump the content and close the file + hs->pRootHandler->Dump(hs, dc, pbRootHandler, cbRootHandler, szListFile, nDumpLevel); + dump_close(dc); + } + } +} + +void RootHandler_Close(TRootHandler * pRootHandler) +{ + // Check if the root structure is allocated at all + if(pRootHandler != NULL) + { + pRootHandler->Close(pRootHandler); + } +} diff --git a/dep/CascLib/src/common/RootHandler.h b/dep/CascLib/src/common/RootHandler.h new file mode 100644 index 00000000000..e1869e351cc --- /dev/null +++ b/dep/CascLib/src/common/RootHandler.h @@ -0,0 +1,88 @@ +/*****************************************************************************/ +/* RootHandler.h Copyright (c) Ladislav Zezula 2015 */ +/*---------------------------------------------------------------------------*/ +/* Interface for root handlers */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 09.03.15 1.00 Lad Created */ +/*****************************************************************************/ + +#ifndef __ROOT_HANDLER_H__ +#define __ROOT_HANDLER_H__ + +//----------------------------------------------------------------------------- +// Defines + +#define CASC_MNDX_ROOT_SIGNATURE 0x58444E4D // 'MNDX' +#define CASC_DIABLO3_ROOT_SIGNATURE 0x8007D0C4 +#define CASC_OVERWATCH_ROOT_SIGNATURE 0x35444D23 // '#MD5' + +#define ROOT_FLAG_HAS_NAMES 0x00000001 // The root file contains file names + +#define DUMP_LEVEL_ROOT_FILE 1 // Dump root file +#define DUMP_LEVEL_ENCODING_FILE 2 // Dump root file + encoding file +#define DUMP_LEVEL_INDEX_ENTRIES 3 // Dump root file + encoding file + index entries + +//----------------------------------------------------------------------------- +// Root file function prototypes + +typedef int (*ROOT_INSERT)( + struct TRootHandler * pRootHandler, // Pointer to an initialized root handler + const char * szFileName, // Pointer to the file name + LPBYTE pbEncodingKey // Pointer to the encoding key of the file name + ); + +typedef LPBYTE (*ROOT_SEARCH)( + struct TRootHandler * pRootHandler, // Pointer to an initialized root handler + struct _TCascSearch * pSearch, // Pointer to the initialized search structure + PDWORD PtrFileSize, // Pointer to receive file size (optional) + PDWORD PtrLocaleFlags // Pointer to receive locale flags (optional) + ); + +typedef void (*ROOT_ENDSEARCH)( + struct TRootHandler * pRootHandler, // Pointer to an initialized root handler + struct _TCascSearch * pSearch // Pointer to the initialized search structure + ); + +typedef LPBYTE (*ROOT_GETKEY)( + struct TRootHandler * pRootHandler, // Pointer to an initialized root handler + const char * szFileName // Pointer to the name of a file + ); + +typedef void (*ROOT_DUMP)( + struct _TCascStorage * hs, // Pointer to the open storage + TDumpContext * dc, // Opened dump context + LPBYTE pbRootHandler, // Pointer to the loaded ROOT file + DWORD cbRootHandler, // Length of the loaded ROOT file + const TCHAR * szListFile, + int nDumpLevel + ); + +typedef void (*ROOT_CLOSE)( + struct TRootHandler * pRootHandler // Pointer to an initialized root handler + ); + +struct TRootHandler +{ + ROOT_INSERT Insert; // Inserts an existing file name + ROOT_SEARCH Search; // Performs the root file search + ROOT_ENDSEARCH EndSearch; // Performs cleanup after searching + ROOT_GETKEY GetKey; // Retrieves encoding key for a file name + ROOT_DUMP Dump; + ROOT_CLOSE Close; // Closing the root file + + DWORD dwRootFlags; // Root flags - see the ROOT_FLAG_XXX +}; + +//----------------------------------------------------------------------------- +// Public functions + +int RootHandler_Insert(TRootHandler * pRootHandler, const char * szFileName, LPBYTE pbEncodingKey); +LPBYTE RootHandler_Search(TRootHandler * pRootHandler, struct _TCascSearch * pSearch, PDWORD PtrFileSize, PDWORD PtrLocaleFlags); +void RootHandler_EndSearch(TRootHandler * pRootHandler, struct _TCascSearch * pSearch); +LPBYTE RootHandler_GetKey(TRootHandler * pRootHandler, const char * szFileName); +void RootHandler_Dump(struct _TCascStorage * hs, LPBYTE pbRootHandler, DWORD cbRootHandler, const TCHAR * szNameFormat, const TCHAR * szListFile, int nDumpLevel); +void RootHandler_Close(TRootHandler * pRootHandler); + +#endif // __ROOT_HANDLER_H__ diff --git a/dep/CascLib/src/libtomcrypt/src/misc/crypt_argchk.c b/dep/CascLib/src/libtomcrypt/src/misc/crypt_argchk.c index 537516d80d9..1cd875f5260 100644 --- a/dep/CascLib/src/libtomcrypt/src/misc/crypt_argchk.c +++ b/dep/CascLib/src/libtomcrypt/src/misc/crypt_argchk.c @@ -19,8 +19,8 @@ #if (ARGTYPE == 0) void crypt_argchk(char *v, char *s, int d) { - fprintf(stderr, "LTC_ARGCHK '%s' failure on line %d of file %s\n", - v, d, s); + fprintf(stderr, "LTC_ARGCHK '%s' failure on line %d of file %s\n", + v, d, s); (void)raise(SIGABRT); } #endif -- cgit v1.2.3