aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/SBaseCommon.cpp1
-rw-r--r--src/SFileFindFile.cpp194
-rw-r--r--src/StormLib.h1
-rw-r--r--test/StormTest.cpp8
4 files changed, 130 insertions, 74 deletions
diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp
index 22b1221..9ae7c78 100644
--- a/src/SBaseCommon.cpp
+++ b/src/SBaseCommon.cpp
@@ -225,7 +225,6 @@ DWORD GetHashTableSizeForFileCount(DWORD dwFileCount)
ULONGLONG HashStringJenkins(const char * szFileName)
{
LPBYTE pbFileName = (LPBYTE)szFileName;
- char * szTemp;
char szNameBuff[0x108];
size_t nLength = 0;
unsigned int primary_hash = 1;
diff --git a/src/SFileFindFile.cpp b/src/SFileFindFile.cpp
index 198f960..828dbfb 100644
--- a/src/SFileFindFile.cpp
+++ b/src/SFileFindFile.cpp
@@ -208,94 +208,150 @@ static TFileEntry * FindPatchEntry(TMPQArchive * ha, TFileEntry * pFileEntry)
return pPatchEntry;
}
-// Performs one MPQ search
-static int DoMPQSearch(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData)
+static bool DoMPQSearch_FileEntry(
+ TMPQSearch * hs,
+ SFILE_FIND_DATA * lpFindFileData,
+ TMPQArchive * ha,
+ TMPQHash * pHashEntry,
+ TFileEntry * pFileEntry)
{
- TMPQArchive * ha = hs->ha;
- TFileEntry * pFileTableEnd;
TFileEntry * pPatchEntry;
- TFileEntry * pFileEntry;
+ HANDLE hFile = NULL;
const char * szFileName;
- HANDLE hFile;
- char szNameBuff[MAX_PATH];
+ size_t nPrefixLength = (ha->pPatchPrefix != NULL) ? ha->pPatchPrefix->nLength : 0;
DWORD dwBlockIndex;
- size_t nPrefixLength;
+ char szNameBuff[MAX_PATH];
- // Start searching with base MPQ
- while(ha != NULL)
+ // Is it a file but not a patch file?
+ if((pFileEntry->dwFlags & hs->dwFlagMask) == MPQ_FILE_EXISTS)
{
- // Now parse the file entry table in order to get all files.
- pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
- pFileEntry = ha->pFileTable + hs->dwNextIndex;
+ // Now we have to check if this file was not enumerated before
+ if(!FileWasFoundBefore(ha, hs, pFileEntry))
+ {
+// if(pFileEntry != NULL && !_stricmp(pFileEntry->szFileName, "TriggerLibs\\NativeLib.galaxy"))
+// DebugBreak();
- // Get the length of the patch prefix (0 if none)
- nPrefixLength = (ha->pPatchPrefix != NULL) ? ha->pPatchPrefix->nLength : 0;
+ // Find a patch to this file
+ pPatchEntry = FindPatchEntry(ha, pFileEntry);
+ if(pPatchEntry == NULL)
+ pPatchEntry = pFileEntry;
- // Parse the file table
- while(pFileEntry < pFileTableEnd)
- {
- // Increment the next index for subsequent search
- hs->dwNextIndex++;
+ // Prepare the block index
+ dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable);
- // Is it a file but not a patch file?
- if((pFileEntry->dwFlags & hs->dwFlagMask) == MPQ_FILE_EXISTS)
+ // Get the file name. If it's not known, we will create pseudo-name
+ szFileName = pFileEntry->szFileName;
+ if(szFileName == NULL)
{
- // Now we have to check if this file was not enumerated before
- if(!FileWasFoundBefore(ha, hs, pFileEntry))
+ // Open the file by its pseudo-name.
+ sprintf(szNameBuff, "File%08u.xxx", (unsigned int)dwBlockIndex);
+ if(SFileOpenFileEx((HANDLE)hs->ha, szNameBuff, SFILE_OPEN_BASE_FILE, &hFile))
{
-// if(pFileEntry != NULL && !_stricmp(pFileEntry->szFileName, "TriggerLibs\\NativeLib.galaxy"))
-// DebugBreak();
-
- // Find a patch to this file
- pPatchEntry = FindPatchEntry(ha, pFileEntry);
- if(pPatchEntry == NULL)
- pPatchEntry = pFileEntry;
-
- // Prepare the block index
- dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable);
+ SFileGetFileName(hFile, szNameBuff);
+ szFileName = szNameBuff;
+ SFileCloseFile(hFile);
+ }
+ }
- // Get the file name. If it's not known, we will create pseudo-name
- szFileName = pFileEntry->szFileName;
- if(szFileName == NULL)
+ // If the file name is still NULL, we cannot include the file to search results
+ if(szFileName != NULL)
+ {
+ // Check the file name against the wildcard
+ if(CheckWildCard(szFileName + nPrefixLength, hs->szSearchMask))
+ {
+ // Fill the found entry. hash entry and block index are taken from the base MPQ
+ lpFindFileData->dwHashIndex = HASH_ENTRY_FREE;
+ lpFindFileData->dwBlockIndex = dwBlockIndex;
+ lpFindFileData->dwFileSize = pPatchEntry->dwFileSize;
+ lpFindFileData->dwFileFlags = pPatchEntry->dwFlags;
+ lpFindFileData->dwCompSize = pPatchEntry->dwCmpSize;
+ lpFindFileData->lcLocale = 0; // pPatchEntry->lcLocale;
+
+ // Fill the filetime
+ lpFindFileData->dwFileTimeHi = (DWORD)(pPatchEntry->FileTime >> 32);
+ lpFindFileData->dwFileTimeLo = (DWORD)(pPatchEntry->FileTime);
+
+ // Fill-in the entries from hash table entry, if given
+ if(pHashEntry != NULL)
{
- // Open the file by its pseudo-name.
- sprintf(szNameBuff, "File%08u.xxx", (unsigned int)dwBlockIndex);
- if(SFileOpenFileEx((HANDLE)hs->ha, szNameBuff, SFILE_OPEN_BASE_FILE, &hFile))
- {
- SFileGetFileName(hFile, szNameBuff);
- szFileName = szNameBuff;
- SFileCloseFile(hFile);
- }
+ lpFindFileData->dwHashIndex = (DWORD)(pHashEntry - ha->pHashTable);
+ lpFindFileData->lcLocale = pHashEntry->lcLocale;
}
- // If the file name is still NULL, we cannot include the file to search results
- if(szFileName != NULL)
- {
- // Check the file name against the wildcard
- if(CheckWildCard(szFileName + nPrefixLength, hs->szSearchMask))
- {
- // Fill the found entry. hash entry and block index are taken from the base MPQ
- lpFindFileData->dwBlockIndex = dwBlockIndex;
- lpFindFileData->dwFileSize = pPatchEntry->dwFileSize;
- lpFindFileData->dwFileFlags = pPatchEntry->dwFlags;
- lpFindFileData->dwCompSize = pPatchEntry->dwCmpSize;
- lpFindFileData->lcLocale = 0; // pPatchEntry->lcLocale;
-
- // Fill the filetime
- lpFindFileData->dwFileTimeHi = (DWORD)(pPatchEntry->FileTime >> 32);
- lpFindFileData->dwFileTimeLo = (DWORD)(pPatchEntry->FileTime);
-
- // Fill the file name and plain file name
- strcpy(lpFindFileData->cFileName, szFileName + nPrefixLength);
- lpFindFileData->szPlainName = (char *)GetPlainFileName(lpFindFileData->cFileName);
- return ERROR_SUCCESS;
- }
- }
+ // Fill the file name and plain file name
+ strcpy(lpFindFileData->cFileName, szFileName + nPrefixLength);
+ lpFindFileData->szPlainName = (char *)GetPlainFileName(lpFindFileData->cFileName);
+ return true;
}
}
+ }
+ }
+
+ // Either not a valid item or was found before
+ return false;
+}
- pFileEntry++;
+static int DoMPQSearch_HashTable(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData, TMPQArchive * ha)
+{
+ TMPQHash * pHashTableEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
+ TMPQHash * pHash;
+
+ // Parse the file table
+ for(pHash = ha->pHashTable + hs->dwNextIndex; pHash < pHashTableEnd; pHash++)
+ {
+ // Increment the next index for subsequent search
+ hs->dwNextIndex++;
+
+ // Does this hash table entry point to a proper block table entry?
+ if(IsValidHashEntry(ha, pHash))
+ {
+ // Check if this file entry should be included in the search result
+ if(DoMPQSearch_FileEntry(hs, lpFindFileData, ha, pHash, ha->pFileTable + pHash->dwBlockIndex))
+ return ERROR_SUCCESS;
}
+ }
+
+ // No more files
+ return ERROR_NO_MORE_FILES;
+}
+
+static int DoMPQSearch_FileTable(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData, TMPQArchive * ha)
+{
+ TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
+ TFileEntry * pFileEntry;
+
+ // Parse the file table
+ for(pFileEntry = ha->pFileTable + hs->dwNextIndex; pFileEntry < pFileTableEnd; pFileEntry++)
+ {
+ // Increment the next index for subsequent search
+ hs->dwNextIndex++;
+
+ // Check if this file entry should be included in the search result
+ if(DoMPQSearch_FileEntry(hs, lpFindFileData, ha, NULL, pFileEntry))
+ return ERROR_SUCCESS;
+ }
+
+ // No more files
+ return ERROR_NO_MORE_FILES;
+}
+
+// Performs one MPQ search
+static int DoMPQSearch(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData)
+{
+ TMPQArchive * ha = hs->ha;
+ int nError;
+
+ // Start searching with base MPQ
+ while(ha != NULL)
+ {
+ // If the archive has hash table, we need to use hash table
+ // in order to catch hash table index and file locale.
+ // Note: If multiple hash table entries, point to the same block entry,
+ // we need, to report them all
+ nError = (ha->pHashTable != NULL) ? DoMPQSearch_HashTable(hs, lpFindFileData, ha)
+ : DoMPQSearch_FileTable(hs, lpFindFileData, ha);
+ if(nError == ERROR_SUCCESS)
+ return nError;
// If there is no more patches in the chain, stop it.
// This also keeps hs->ha non-NULL, which is required
diff --git a/src/StormLib.h b/src/StormLib.h
index a94d485..b6cb0c9 100644
--- a/src/StormLib.h
+++ b/src/StormLib.h
@@ -876,6 +876,7 @@ typedef struct _SFILE_FIND_DATA
{
char cFileName[MAX_PATH]; // Full name of the found file
char * szPlainName; // Plain name of the found file
+ DWORD dwHashIndex; // Hash table index for the file (HAH_ENTRY_FREE if no hash table)
DWORD dwBlockIndex; // Block table index for the file
DWORD dwFileSize; // File size in bytes
DWORD dwFileFlags; // MPQ file flags
diff --git a/test/StormTest.cpp b/test/StormTest.cpp
index f9d707a..26188ae 100644
--- a/test/StormTest.cpp
+++ b/test/StormTest.cpp
@@ -4119,7 +4119,7 @@ int main(int argc, char * argv[])
// Open a stream, paired with remote master (takes hell lot of time!)
// if(nError == ERROR_SUCCESS)
// nError = TestReadFile_MasterMirror("MPQ_2013_v4_alternate-downloaded.MPQ", "http://www.zezula.net\\mpqs\\alternate.zip", false);
-*/
+
// Search in listfile
if(nError == ERROR_SUCCESS)
nError = TestSearchListFile("ListFile_Blizzard.txt");
@@ -4214,11 +4214,11 @@ int main(int argc, char * argv[])
// Open an Warcraft III map locked by Spazy protector
if(nError == ERROR_SUCCESS)
nError = TestOpenArchive("MPQ_2015_v1_ProtectedMap_Spazy.w3x");
-
+*/
// Open an protected map
if(nError == ERROR_SUCCESS)
nError = TestOpenArchive("MPQ_2015_v1_flem1.w3x");
-
+/*-
// Open the multi-file archive with wrong prefix to see how StormLib deals with it
if(nError == ERROR_SUCCESS)
nError = TestOpenArchive_WillFail("flat-file://streaming/model.MPQ.0");
@@ -4403,7 +4403,7 @@ int main(int argc, char * argv[])
// Test replacing a file with zero size file
if(nError == ERROR_SUCCESS)
nError = TestModifyArchive_ReplaceFile("MPQ_2014_v4_Base.StormReplay", "AddFile-replay.message.events");
-
+*/
#ifdef _MSC_VER
_CrtDumpMemoryLeaks();
#endif // _MSC_VER