diff options
-rw-r--r-- | src/SBaseCommon.cpp | 1 | ||||
-rw-r--r-- | src/SFileFindFile.cpp | 194 | ||||
-rw-r--r-- | src/StormLib.h | 1 | ||||
-rw-r--r-- | test/StormTest.cpp | 8 |
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 |