From 809005c7f025bcc55bfa4ede78cb4cc45d3c0e6c Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Sat, 21 Nov 2020 04:27:09 +0100 Subject: * Release 9.23 * Fixed regressions * Fixed test program --- test/StormTest.cpp | 1108 +++++++++++++++++++-------------------------------- test/TLogHelper.cpp | 30 +- 2 files changed, 428 insertions(+), 710 deletions(-) (limited to 'test') diff --git a/test/StormTest.cpp b/test/StormTest.cpp index 47a8cb5..8f9cd71 100644 --- a/test/StormTest.cpp +++ b/test/StormTest.cpp @@ -35,12 +35,8 @@ //------------------------------------------------------------------------------ // Local structures -#define TEST_OPEN_MPQ 0x00000000 -#define TEST_LOAD_FILE_CHECK_CRC 0x00010000 -#define TEST_OPEN_COMPARE_TWO_FILES 0x00020000 -#define TEST_MASK 0xFFFF0000 - -#define TEST_SETPOS 0x00000001 +#define TEST_FLAG_PROTECTED 0x01000000 +#define TEST_FLAG_FILE_COUNT 0x00FFFFFF typedef struct _TEST_INFO { @@ -60,7 +56,7 @@ static const TCHAR szListFileDir[] = { '1', '9', '9', '5', ' ', '-', ' ', 'T', ' #endif #ifdef STORMLIB_LINUX -#define WORK_PATH_ROOT "/home/ladik/StormLib/test" +#define WORK_PATH_ROOT "/media/ladik/MPQs" static const TCHAR szListFileDir[] = { '1', '9', '9', '5', ' ', '-', ' ', 'T', 'e', 's', 't', ' ', 'M', 'P', 'Q', 's', '\\', 'l', 'i', 's', 't', 'f', 'i', 'l', 'e', 's', '-', (TCHAR)0xe6, (TCHAR)0x96, (TCHAR)0xB0, (TCHAR)0xE5, (TCHAR)0xBB, (TCHAR)0xBA, (TCHAR)0xE6, (TCHAR)0x96, (TCHAR)0x87, (TCHAR)0xE4, (TCHAR)0xBB, (TCHAR)0xB6, (TCHAR)0xE5, (TCHAR)0xA4, (TCHAR)0xB9, 0 }; #endif @@ -486,62 +482,6 @@ static bool CopyStringAndVerifyConversion( return (_tcsicmp(szBufferT, szFoundFile) == 0) ? true : false; } -static void CalculateRelativePath(LPCSTR szFullPath1, LPCSTR szFullPath2, char * szBuffer) -{ - LPCSTR szPathPart1 = szFullPath1; - LPCSTR szPathPart2 = szFullPath2; - LPCSTR szNextPart1; - LPCSTR szNextPart2; - int nEqualParts = 0; - int nStepsUp = 0; - - // Parse both paths and find all path parts that are equal - for(;;) - { - // Find the next part of the first path - szNextPart1 = FindNextPathPart(szPathPart1, 1); - if(szNextPart1 == szPathPart1) - break; - - szNextPart2 = FindNextPathPart(szPathPart2, 1); - if(szNextPart2 == szPathPart2) - break; - - // Are these equal? - if((szNextPart2 - szPathPart2) != (szNextPart1 - szPathPart1)) - break; - if(_strnicmp(szPathPart1, szPathPart2, (szNextPart1 - szPathPart1 - 1))) - break; - - // Increment the number of path parts that are equal - szPathPart1 = szNextPart1; - szPathPart2 = szNextPart2; - nEqualParts++; - } - - // If we found at least one equal part, we can create relative path - if(nEqualParts != 0) - { - // Calculate how many steps up we need to go - nStepsUp = GetPathSeparatorCount(szPathPart2); - - // Append "../" nStepsUp-times - for(int i = 0; i < nStepsUp; i++) - { - *szBuffer++ = '.'; - *szBuffer++ = '.'; - *szBuffer++ = '/'; - } - - // Append the rest of the path. Also change DOS backslashes to slashes - CopyPathPart(szBuffer, szPathPart1); - return; - } - - // Failed. Just copy the source path as it is - strcpy(szBuffer, szFullPath1); -} - static size_t ConvertSha1ToText(const unsigned char * sha1_digest, TCHAR * szSha1Text) { LPCSTR szTable = "0123456789abcdef"; @@ -864,19 +804,23 @@ static int InitializeMpqDirectory(TCHAR * argv[], int argc) TLogHelper Logger("InitWorkDir"); TFileStream * pStream; TCHAR szFullPath[MAX_PATH]; - LPCTSTR szWhereFrom = NULL; - LPCTSTR szDirName; + LPCTSTR szWhereFrom = _T("default"); + LPCTSTR szDirName = WORK_PATH_ROOT; - // Retrieve the name of the MPQ directory + // Retrieve the first argument if(argc > 1 && argv[1] != NULL) { - szWhereFrom = _T("command line"); - szDirName = argv[1]; - } - else - { - szWhereFrom = _T("default"); - szDirName = WORK_PATH_ROOT; + // Check if it's a directory + pStream = FileStream_OpenFile(argv[1], STREAM_FLAG_READ_ONLY); + if(pStream == NULL) + { + szWhereFrom = _T("command line"); + szDirName = argv[1]; + } + else + { + FileStream_Close(pStream); + } } // Copy the name of the MPQ directory. @@ -912,33 +856,33 @@ static int InitializeMpqDirectory(TCHAR * argv[], int argc) return ERROR_SUCCESS; } -static int GetFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName) +static DWORD GetFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName) { TCHAR * szPatchName; HANDLE hFile; TCHAR szPatchChain[0x400]; + DWORD dwErrCode = ERROR_SUCCESS; int nPatchCount = 0; - int nError = ERROR_SUCCESS; // Open the MPQ file if(SFileOpenFileEx(hMpq, szFileName, 0, &hFile)) { // Notify the user - pLogger->PrintProgress(_T("Verifying patch chain for %s ..."), GetShortPlainName(szFileName)); + pLogger->PrintProgress("Verifying patch chain for %s ...", GetShortPlainName(szFileName)); // Query the patch chain if(!SFileGetFileInfo(hFile, SFileInfoPatchChain, szPatchChain, sizeof(szPatchChain), NULL)) - nError = pLogger->PrintError("Failed to retrieve the patch chain on %s", szFileName); + dwErrCode = pLogger->PrintError("Failed to retrieve the patch chain on %s", szFileName); // Is there anything at all in the patch chain? - if(nError == ERROR_SUCCESS && szPatchChain[0] == 0) + if(dwErrCode == ERROR_SUCCESS && szPatchChain[0] == 0) { pLogger->PrintError("The patch chain for %s is empty", szFileName); - nError = ERROR_FILE_CORRUPT; + dwErrCode = ERROR_FILE_CORRUPT; } // Now calculate the number of patches - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { // Get the pointer to the patch szPatchName = szPatchChain; @@ -966,7 +910,7 @@ static int GetFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileNam return nPatchCount; } -static int VerifyFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName, int nExpectedPatchCount) +static DWORD VerifyFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName, int nExpectedPatchCount) { int nPatchCount = 0; @@ -977,21 +921,21 @@ static int VerifyFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFile // Check if there are any patches at all if(nExpectedPatchCount != 0 && nPatchCount == 0) { - pLogger->PrintMessage(_T("There are no patches for %s"), szFileName); + pLogger->PrintMessage("There are no patches for %s", szFileName); return ERROR_FILE_CORRUPT; } // Check if the number of patches fits if(nPatchCount != nExpectedPatchCount) { - pLogger->PrintMessage(_T("Unexpected number of patches for %s"), szFileName); + pLogger->PrintMessage("Unexpected number of patches for %s", szFileName); return ERROR_FILE_CORRUPT; } return ERROR_SUCCESS; } -static int CreateEmptyFile(TLogHelper * pLogger, LPCTSTR szPlainName, ULONGLONG FileSize, TCHAR * szBuffer) +static DWORD CreateEmptyFile(TLogHelper * pLogger, LPCTSTR szPlainName, ULONGLONG FileSize, TCHAR * szBuffer) { TFileStream * pStream; TCHAR szFullPath[MAX_PATH]; @@ -1015,13 +959,13 @@ static int CreateEmptyFile(TLogHelper * pLogger, LPCTSTR szPlainName, ULONGLONG return ERROR_SUCCESS; } -static int VerifyFilePosition( +static DWORD VerifyFilePosition( TLogHelper * pLogger, TFileStream * pStream, ULONGLONG ExpectedPosition) { ULONGLONG ByteOffset = 0; - int nError = ERROR_SUCCESS; + DWORD dwErrCode = ERROR_SUCCESS; // Retrieve the file position if(FileStream_GetPos(pStream, &ByteOffset)) @@ -1029,15 +973,15 @@ static int VerifyFilePosition( if(ByteOffset != ExpectedPosition) { pLogger->PrintMessage(_T("The file position is different than expected (expected: ") I64u_t _T(", current: ") I64u_t, ExpectedPosition, ByteOffset); - nError = ERROR_FILE_CORRUPT; + dwErrCode = ERROR_FILE_CORRUPT; } } else { - nError = pLogger->PrintError(_T("Failed to retrieve the file offset")); + dwErrCode = pLogger->PrintError(_T("Failed to retrieve the file offset")); } - return nError; + return dwErrCode; } static int VerifyFileMpqHeader(TLogHelper * pLogger, TFileStream * pStream, ULONGLONG * pByteOffset) @@ -1341,10 +1285,11 @@ static void WINAPI CompactCallback(void * pvUserData, DWORD dwWork, ULONGLONG By //----------------------------------------------------------------------------- // MPQ file utilities -#define TEST_FLAG_LOAD_FILES 0x00000001 // Test function should load all files in the MPQ -#define TEST_FLAG_HASH_FILES 0x00000002 // Test function should load all files in the MPQ -#define TEST_FLAG_PLAY_WAVES 0x00000004 // Play extracted WAVE files -#define TEST_FLAG_MOST_PATCHED 0x00000008 // Find the most patched file +#define SEARCH_FLAG_LOAD_FILES 0x00000001 // Test function should load all files in the MPQ +#define SEARCH_FLAG_HASH_FILES 0x00000002 // Test function should load all files in the MPQ +#define SEARCH_FLAG_PLAY_WAVES 0x00000004 // Play extracted WAVE files +#define SEARCH_FLAG_MOST_PATCHED 0x00000008 // Find the most patched file +#define SEARCH_FLAG_IGNORE_ERRORS 0x00000010 // Ignore files that failed to open struct TFileData { @@ -1496,7 +1441,7 @@ static int CompareTwoLocalFilesRR( return nError; } -static TFileData * LoadMpqFile(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName, LCID lcLocale = 0) +static TFileData * LoadMpqFile(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName, LCID lcLocale = 0, bool bIgnoreOpenErrors = false) { TFileData * pFileData = NULL; HANDLE hFile; @@ -1518,74 +1463,81 @@ static TFileData * LoadMpqFile(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileN SFileSetLocale(lcLocale); // Open the file from MPQ - if(!SFileOpenFileEx(hMpq, szFileName, 0, &hFile)) - dwErrCode = pLogger->PrintError("Open failed: %s", szFileName); + if(SFileOpenFileEx(hMpq, szFileName, 0, &hFile)) + { + // Get the CRC32 of the file + SFileGetFileInfo(hFile, SFileInfoCRC32, &dwCrc32, sizeof(dwCrc32), NULL); - // Get the CRC32 of the file - SFileGetFileInfo(hFile, SFileInfoCRC32, &dwCrc32, sizeof(dwCrc32), NULL); + // Get the size of the file + if(dwErrCode == ERROR_SUCCESS) + { + dwFileSizeLo = SFileGetFileSize(hFile, &dwFileSizeHi); + if(dwFileSizeLo == SFILE_INVALID_SIZE || dwFileSizeHi != 0) + dwErrCode = pLogger->PrintError("Failed to query the file size"); + } - // Get the size of the file - if(dwErrCode == ERROR_SUCCESS) - { - dwFileSizeLo = SFileGetFileSize(hFile, &dwFileSizeHi); - if(dwFileSizeLo == SFILE_INVALID_SIZE || dwFileSizeHi != 0) - dwErrCode = pLogger->PrintError("Failed to query the file size"); - } + // Spazzler protector: Creates fake files with size of 0x7FFFE7CA + if(dwErrCode == ERROR_SUCCESS) + { + if(dwFileSizeLo > 0x1FFFFFFF) + dwErrCode = ERROR_FILE_CORRUPT; + } - // Spazzler protector: Creates fake files with size of 0x7FFFE7CA - if(dwErrCode == ERROR_SUCCESS) - { - if(dwFileSizeLo > 0x1FFFFFFF) - dwErrCode = ERROR_FILE_CORRUPT; - } + // Allocate buffer for the file content + if(dwErrCode == ERROR_SUCCESS) + { + pFileData = (TFileData *)STORM_ALLOC(BYTE, sizeof(TFileData) + dwFileSizeLo); + if(pFileData == NULL) + { + pLogger->PrintError("Failed to allocate buffer for the file content"); + dwErrCode = ERROR_NOT_ENOUGH_MEMORY; + } + } - // Allocate buffer for the file content - if(dwErrCode == ERROR_SUCCESS) - { - pFileData = (TFileData *)STORM_ALLOC(BYTE, sizeof(TFileData) + dwFileSizeLo); - if(pFileData == NULL) + // get the file index of the MPQ file + if(dwErrCode == ERROR_SUCCESS) { - pLogger->PrintError("Failed to allocate buffer for the file content"); - dwErrCode = ERROR_NOT_ENOUGH_MEMORY; + // Store the file size + memset(pFileData, 0, sizeof(TFileData) + dwFileSizeLo); + pFileData->dwFileSize = dwFileSizeLo; + pFileData->dwCrc32 = dwCrc32; + + // Retrieve the block index and file flags + if(!SFileGetFileInfo(hFile, SFileInfoFileIndex, &pFileData->dwBlockIndex, sizeof(DWORD), NULL)) + dwErrCode = pLogger->PrintError("Failed retrieve the file index of %s", szFileName); + if(!SFileGetFileInfo(hFile, SFileInfoFlags, &pFileData->dwFlags, sizeof(DWORD), NULL)) + dwErrCode = pLogger->PrintError("Failed retrieve the file flags of %s", szFileName); } - } - // get the file index of the MPQ file - if(dwErrCode == ERROR_SUCCESS) - { - // Store the file size - memset(pFileData, 0, sizeof(TFileData) + dwFileSizeLo); - pFileData->dwFileSize = dwFileSizeLo; - pFileData->dwCrc32 = dwCrc32; + // Load the entire file + if(dwErrCode == ERROR_SUCCESS) + { + // Read the file data + SFileReadFile(hFile, pFileData->FileData, dwFileSizeLo, &dwBytesRead, NULL); + if(dwBytesRead != dwFileSizeLo) + dwErrCode = ERROR_FILE_CORRUPT; + } - // Retrieve the block index and file flags - if(!SFileGetFileInfo(hFile, SFileInfoFileIndex, &pFileData->dwBlockIndex, sizeof(DWORD), NULL)) - dwErrCode = pLogger->PrintError("Failed retrieve the file index of %s", szFileName); - if(!SFileGetFileInfo(hFile, SFileInfoFlags, &pFileData->dwFlags, sizeof(DWORD), NULL)) - dwErrCode = pLogger->PrintError("Failed retrieve the file flags of %s", szFileName); - } + // If failed, free the buffer + if(dwErrCode != ERROR_SUCCESS) + { + SetLastError(dwErrCode); + if(pFileData != NULL) + STORM_FREE(pFileData); + pFileData = NULL; + } - // Load the entire file - if(dwErrCode == ERROR_SUCCESS) - { - // Read the file data - SFileReadFile(hFile, pFileData->FileData, dwFileSizeLo, &dwBytesRead, NULL); - if(dwBytesRead != dwFileSizeLo) -// dwErrCode = pLogger->PrintError("Read failed: %s", szFileName); - dwErrCode = ERROR_FILE_CORRUPT; + SFileCloseFile(hFile); } - - // If failed, free the buffer - if(dwErrCode != ERROR_SUCCESS) + else { - STORM_FREE(pFileData); - SetLastError(dwErrCode); - pFileData = NULL; + if(bIgnoreOpenErrors == false) + { + dwErrCode = pLogger->PrintError("Open failed: %s", szFileName); + } } - // Close the file and return what we got - if(hFile != NULL) - SFileCloseFile(hFile); + // Return what we got return pFileData; } @@ -1617,7 +1569,7 @@ static bool CompareTwoFiles(TLogHelper * pLogger, TFileData * pFileData1, TFileD static DWORD SearchArchive( TLogHelper * pLogger, HANDLE hMpq, - DWORD dwTestFlags = 0, + DWORD dwSearchFlags = 0, DWORD * pdwFileCount = NULL, LPBYTE pbFileHash = NULL) { @@ -1629,6 +1581,7 @@ static DWORD SearchArchive( TCHAR szListFile[MAX_PATH] = _T(""); char szMostPatched[MAX_PATH] = ""; DWORD dwErrCode = ERROR_SUCCESS; + bool bIgnoreOpenErrors = (dwSearchFlags & SEARCH_FLAG_IGNORE_ERRORS) ? true : false; bool bFound = true; int nMaxPatchCount = 0; int nPatchCount = 0; @@ -1640,7 +1593,7 @@ static DWORD SearchArchive( md5_init(&md5state); // Initiate the MPQ search - pLogger->PrintProgress("Searching the archive ..."); + pLogger->PrintProgress("Searching the archive (initializing) ..."); hFind = SFileFindFirstFile(hMpq, "*", &sf, szListFile); if(hFind == NULL) { @@ -1650,6 +1603,7 @@ static DWORD SearchArchive( } // Perform the search + pLogger->PrintProgress("Searching the archive ..."); while(bFound == true) { // Increment number of files @@ -1658,7 +1612,7 @@ static DWORD SearchArchive( // if(!_stricmp(sf.cFileName, "war3map.j")) // DebugBreak(); - if(dwTestFlags & TEST_FLAG_MOST_PATCHED) + if(dwSearchFlags & SEARCH_FLAG_MOST_PATCHED) { // Load the patch count nPatchCount = GetFilePatchCount(pLogger, hMpq, sf.cFileName); @@ -1672,18 +1626,18 @@ static DWORD SearchArchive( } // Load the file to memory, if required - if(dwTestFlags & TEST_FLAG_LOAD_FILES) + if(dwSearchFlags & SEARCH_FLAG_LOAD_FILES) { // Load the entire file to the MPQ - pFileData = LoadMpqFile(pLogger, hMpq, sf.cFileName, sf.lcLocale); + pFileData = LoadMpqFile(pLogger, hMpq, sf.cFileName, sf.lcLocale, bIgnoreOpenErrors); if(pFileData != NULL) { // Hash the file data, if needed - if((dwTestFlags & TEST_FLAG_HASH_FILES) && !IsInternalMpqFileName(sf.cFileName)) + if((dwSearchFlags & SEARCH_FLAG_HASH_FILES) && !IsInternalMpqFileName(sf.cFileName)) md5_process(&md5state, pFileData->FileData, pFileData->dwFileSize); // Play sound files, if required - if((dwTestFlags & TEST_FLAG_PLAY_WAVES) && strstr(sf.cFileName, ".wav") != NULL) + if((dwSearchFlags & SEARCH_FLAG_PLAY_WAVES) && strstr(sf.cFileName, ".wav") != NULL) { #ifdef _MSC_VER pLogger->PrintProgress("Playing sound %s", sf.cFileName); @@ -1704,7 +1658,7 @@ static DWORD SearchArchive( pdwFileCount[0] = dwFileCount; // Give the hash, if required - if(pbFileHash != NULL && (dwTestFlags & TEST_FLAG_HASH_FILES)) + if(pbFileHash != NULL && (dwSearchFlags & SEARCH_FLAG_HASH_FILES)) md5_done(&md5state, pbFileHash); return dwErrCode; @@ -2132,35 +2086,42 @@ static void TestGetFileInfo( DWORD cbFileInfo, DWORD * pcbLengthNeeded, bool bExpectedResult, - int nExpectedError) + DWORD dwExpectedErrCode) { + DWORD dwErrCode = ERROR_SUCCESS; bool bResult; - int nError = ERROR_SUCCESS; // Call the get file info bResult = SFileGetFileInfo(hMpqOrFile, InfoClass, pvFileInfo, cbFileInfo, pcbLengthNeeded); if(!bResult) - nError = GetLastError(); + dwErrCode = GetLastError(); if(bResult != bExpectedResult) pLogger->PrintMessage("Different result of SFileGetFileInfo."); - if(nError != nExpectedError) - pLogger->PrintMessage("Different error from SFileGetFileInfo (expected %u, returned %u)", nExpectedError, nError); + if(dwErrCode != dwExpectedErrCode) + pLogger->PrintMessage("Different error from SFileGetFileInfo (expected %u, returned %u)", dwExpectedErrCode, dwErrCode); } // StormLib is able to open local files (as well as the original Storm.dll) // I want to keep this for occasional use -static int TestOpenLocalFile(LPCTSTR szPlainName) +static DWORD TestOnLocalListFile(LPCTSTR szPlainName) { - TLogHelper Logger("OpenLocalFile", szPlainName); + TLogHelper Logger("LocalListFile", szPlainName); + SFILE_FIND_DATA sf; HANDLE hFile; + HANDLE hFind; DWORD dwFileSizeHi = 0; DWORD dwFileSizeLo = 0; + TCHAR szFullPath[MAX_PATH]; char szFileName1[MAX_PATH]; char szFileName2[MAX_PATH]; - char szFileLine[0x40]; + char szFileLine[0x40] = {0}; + int nFileCount = 0; + // Get the full name of the local file CreateFullPathName(szFileName1, _countof(szFileName1), szMpqSubDir, szPlainName); + + // Test opening the local file if(SFileOpenFileEx(NULL, szFileName1, SFILE_OPEN_LOCAL_FILE, &hFile)) { // Retrieve the file name. It must match the name under which the file was open @@ -2170,30 +2131,23 @@ static int TestOpenLocalFile(LPCTSTR szPlainName) // Retrieve the file size dwFileSizeLo = SFileGetFileSize(hFile, &dwFileSizeHi); - if(dwFileSizeHi != 0 || dwFileSizeLo != 3904784) + if(dwFileSizeHi != 0 || dwFileSizeLo != 0x04385a4e) Logger.PrintMessage("Local file size mismatch"); // Read the first line - memset(szFileLine, 0, sizeof(szFileLine)); SFileReadFile(hFile, szFileLine, 18, NULL, NULL); - if(strcmp(szFileLine, "(1)Enslavers01.scm")) + if(strcmp(szFileLine, "accountbilling.url")) Logger.PrintMessage("Content of the listfile does not match"); SFileCloseFile(hFile); } + else + return Logger.PrintError("Failed to open local listfile"); - return ERROR_SUCCESS; -} + // We need unicode listfile name + StringCopy(szFullPath, _countof(szFullPath), szFileName1); -static int TestSearchListFile(LPCTSTR szPlainName) -{ - SFILE_FIND_DATA sf; - TLogHelper Logger("SearchListFile", szPlainName); - TCHAR szFullPath[MAX_PATH]; - HANDLE hFind; - int nFileCount = 0; - - CreateFullPathName(szFullPath, _countof(szFullPath), szMpqSubDir, szPlainName); + // Start searching in the listfile hFind = SListFileFindFirstFile(NULL, szFullPath, "*", &sf); if(hFind != NULL) { @@ -2206,6 +2160,9 @@ static int TestSearchListFile(LPCTSTR szPlainName) SListFileFindClose(hFind); } + else + return Logger.PrintError("Failed to search local listfile"); + return ERROR_SUCCESS; } @@ -2391,28 +2348,29 @@ static int TestFileStreamOperations(LPCTSTR szPlainName, DWORD dwStreamFlags) return nError; } -static DWORD TestArchive_LoadFiles(TLogHelper * pLogger, HANDLE hMpq, ...) +static DWORD TestArchive_LoadFiles(TLogHelper * pLogger, HANDLE hMpq, bool bIgnoreOpenErrors, ...) { TFileData * pFileData; const char * szFileName; va_list argList; DWORD dwErrCode = ERROR_SUCCESS; - va_start(argList, hMpq); + va_start(argList, bIgnoreOpenErrors); while((szFileName = va_arg(argList, const char *)) != NULL) { if(SFileHasFile(hMpq, szFileName)) { pFileData = LoadMpqFile(pLogger, hMpq, szFileName); - if(pFileData != NULL) + if(pFileData == NULL && bIgnoreOpenErrors == false) { - STORM_FREE(pFileData); - pFileData = NULL; + pLogger->PrintError("Error loading the file %s", szFileName); + dwErrCode = ERROR_FILE_CORRUPT; + break; } else { - dwErrCode = pLogger->PrintError("Error loading the file %s", szFileName); - break; + STORM_FREE(pFileData); + pFileData = NULL; } } } @@ -2445,27 +2403,51 @@ static DWORD TestArchive_SetPos(HANDLE hMpq, const char * szFileName) static DWORD TestArchive( LPCTSTR szPlainName, // Plain name of the MPQ LPCTSTR szListFile, // Listfile name (NULL if none) - DWORD dwWhatToDo, // Flags what to do + DWORD dwFlags, // Flags LPCSTR szFileName1, LPCSTR szFileName2) { + TFileData * pFileData1 = NULL; TFileData * pFileData2 = NULL; - TFileData * pFileData = NULL; TLogHelper Logger("TestMpq", szPlainName); -// HANDLE hFile = NULL; + LPCSTR szExpectedMD5 = NULL; HANDLE hMpq = NULL; DWORD dwFileCount = 0; + DWORD dwSearchFlags = 0; DWORD dwErrCode; DWORD dwCrc32 = 0; + DWORD dwExpectedFileCount = 0; + DWORD dwMpqFlags = 0; TCHAR szFullName[MAX_PATH]; + BYTE ExpectedMD5[MD5_DIGEST_SIZE]; + BYTE OverallMD5[MD5_DIGEST_SIZE]; + bool bIgnoreOpenErrors = false; // If the file is a partial MPQ, don't load all files - bool bIsPartialMpq = (_tcsstr(szPlainName, _T(".MPQ.part")) != NULL); + if(_tcsstr(szPlainName, _T(".MPQ.part")) == NULL) + dwSearchFlags |= SEARCH_FLAG_LOAD_FILES; + + // If the MPQ is a protected MPQ, do different tests + if(dwFlags & TEST_FLAG_PROTECTED) + { + dwExpectedFileCount = (dwFlags & TEST_FLAG_FILE_COUNT); + if((szExpectedMD5 = szFileName1) != NULL) + dwSearchFlags |= SEARCH_FLAG_HASH_FILES; + szFileName2 = szFileName1 = NULL; + } // Copy the archive so we won't fuck up the original one dwErrCode = OpenExistingArchiveWithCopy(&Logger, szPlainName, NULL, &hMpq); - if(dwErrCode == ERROR_SUCCESS) + while(dwErrCode == ERROR_SUCCESS) { + // Check for malformed MPQs + SFileGetFileInfo(hMpq, SFileMpqFlags, &dwMpqFlags, sizeof(dwMpqFlags), NULL); + if(dwMpqFlags & MPQ_FLAG_MALFORMED) + { + dwSearchFlags |= SEARCH_FLAG_IGNORE_ERRORS; + bIgnoreOpenErrors = true; + } + // If the listfile was given, add it to the MPQ if(szListFile && szListFile[0]) { @@ -2475,256 +2457,96 @@ static DWORD TestArchive( Logger.PrintMessage("Failed to add the listfile to the MPQ"); } - // Perform work-specific duty - switch(dwWhatToDo & TEST_MASK) - { - case TEST_LOAD_FILE_CHECK_CRC: - - // Load the entire file - pFileData = LoadMpqFile(&Logger, hMpq, szFileName1); - if(pFileData == NULL) - { - dwErrCode = Logger.PrintError("Failed to load the file %s", szFileName1); - break; - } - - // Compare the CRC32, if available - dwCrc32 = crc32(0, (Bytef *)pFileData->FileData, (uInt)pFileData->dwFileSize); - if(dwCrc32 != pFileData->dwCrc32) - Logger.PrintError("Warning: CRC32 error on %s", szFileName1); - break; - - case TEST_OPEN_COMPARE_TWO_FILES: - - // Load the first file - pFileData = LoadMpqFile(&Logger, hMpq, szFileName1); - if(pFileData == NULL) - { - dwErrCode = Logger.PrintError("Failed to load the file %s", "File00000023.xxx"); - break; - } - - // Load the second file - pFileData2 = LoadMpqFile(&Logger, hMpq, szFileName2); - if(pFileData2 == NULL) - { - dwErrCode = Logger.PrintError("Failed to load the file %s", "music\\dintro.wav"); - break; - } + // Attempt to open the (listfile), (attributes), (signature) + dwErrCode = TestArchive_LoadFiles(&Logger, hMpq, bIgnoreOpenErrors, LISTFILE_NAME, ATTRIBUTES_NAME, SIGNATURE_NAME, NULL); + if(dwErrCode != ERROR_SUCCESS) + break; - // Compare both files - if(!CompareTwoFiles(&Logger, pFileData, pFileData2)) - dwErrCode = Logger.PrintError("The file has different size/content when open without name"); + // If szFileName1 was given, load it and check its CRC + if(szFileName1 && szFileName1[0]) + { + // Test setting position + dwErrCode = TestArchive_SetPos(hMpq, szFileName1); + if(dwErrCode != ERROR_SUCCESS) break; - case TEST_OPEN_MPQ: - - // Attempt to open the (listfile), (attributes), (signature) - dwErrCode = TestArchive_LoadFiles(&Logger, hMpq, LISTFILE_NAME, ATTRIBUTES_NAME, SIGNATURE_NAME, NULL); - if(dwErrCode != ERROR_SUCCESS) - break; - - // Test setting position - if((dwWhatToDo & TEST_SETPOS) && (szFileName1 != NULL)) - { - dwErrCode = TestArchive_SetPos(hMpq, szFileName1); - if(dwErrCode != ERROR_SUCCESS) - break; - } - - // Search the archive - dwErrCode = SearchArchive(&Logger, hMpq, (bIsPartialMpq ? 0 : TEST_FLAG_LOAD_FILES), &dwFileCount); + // Load the entire file 1 + pFileData1 = LoadMpqFile(&Logger, hMpq, szFileName1); + if(pFileData1 == NULL) + { + dwErrCode = Logger.PrintError("Failed to load the file %s", szFileName1); break; - } - } - - // Common cleanup - if(pFileData2 != NULL) - STORM_FREE(pFileData2); - if(pFileData != NULL) - STORM_FREE(pFileData); - if(hMpq != NULL) - SFileCloseArchive(hMpq); - return dwErrCode; -} - -static int TestOpenArchive(LPCTSTR szPlainName, LPCTSTR szListFile = NULL, LPCSTR szFileName = NULL, bool bDontCopyArchive = false) -{ - TLogHelper Logger("OpenMpqTest", szPlainName); - TFileData * pFileData; - LPCTSTR szCopyName = (bDontCopyArchive) ? NULL : szPlainName; - HANDLE hMpq; - HANDLE hFile; - DWORD dwFileCount = 0; - DWORD dwTestFlags; - TCHAR szListFileBuff[MAX_PATH]; - bool bIsPartialMpq = false; - int nError; - - // If the file is a partial MPQ, don't load all files - bIsPartialMpq = (_tcsstr(szPlainName, _T(".MPQ.part")) != NULL); - - // Copy the archive so we won't fuck up the original one - nError = OpenExistingArchiveWithCopy(&Logger, szPlainName, szCopyName, &hMpq); - if(nError == ERROR_SUCCESS) - { - // If the listfile was given, add it to the MPQ - if(szListFile != NULL) - { - Logger.PrintProgress(_T("Adding listfile %s ..."), szListFile); - CreateFullPathName(szListFileBuff, _countof(szListFileBuff), szListFileDir, szListFile); - nError = SFileAddListFile(hMpq, szListFileBuff); - if(nError != ERROR_SUCCESS) - Logger.PrintMessage("Failed to add the listfile to the MPQ"); - } + } - // Attempt to open the (listfile) - if(SFileHasFile(hMpq, LISTFILE_NAME)) - { - pFileData = LoadMpqFile(&Logger, hMpq, LISTFILE_NAME); - if(pFileData != NULL) - STORM_FREE(pFileData); + // Check the CRC of file1, if available + if(pFileData1->dwCrc32) + { + // Compare the CRC32, if available + dwCrc32 = crc32(0, (Bytef *)pFileData1->FileData, (uInt)pFileData1->dwFileSize); + if(dwCrc32 != pFileData1->dwCrc32) + Logger.PrintError("Warning: CRC32 error on %s", szFileName1); + } } - // Attempt to open the (attributes) - if(SFileHasFile(hMpq, ATTRIBUTES_NAME)) + // If szFileName2 was given, load it + if(szFileName2 && szFileName2[0]) { - pFileData = LoadMpqFile(&Logger, hMpq, ATTRIBUTES_NAME); - if(pFileData != NULL) - STORM_FREE(pFileData); + // Load the entire file 2 + pFileData2 = LoadMpqFile(&Logger, hMpq, szFileName2); + if(pFileData2 == NULL) + { + dwErrCode = Logger.PrintError("Failed to load the file %s", szFileName2); + break; + } } - // Attempt to open the (signature) - if(SFileHasFile(hMpq, SIGNATURE_NAME)) + // If two files were given, compare them + if(pFileData1 && pFileData2) { - pFileData = LoadMpqFile(&Logger, hMpq, SIGNATURE_NAME); - if(pFileData != NULL) - STORM_FREE(pFileData); + // Compare both files + if(!CompareTwoFiles(&Logger, pFileData1, pFileData2)) + { + dwErrCode = Logger.PrintError("The file has different size/content of files"); + break; + } } - // Attempt to open an arbitrary file - if(szFileName != NULL && szFileName[0] != 0) + // Search the archive + dwErrCode = SearchArchive(&Logger, hMpq, dwSearchFlags, &dwFileCount, OverallMD5); + + // Shall we check the file count and overall MD5? + if(dwExpectedFileCount != 0) { - if(SFileOpenFileEx(hMpq, "1.blp", 0, &hFile)) + if(dwFileCount != dwExpectedFileCount) { - DWORD dwFileSize; - DWORD dwBytesRead = 0; - BYTE Buffer[0x10]; - - dwFileSize = SFileGetFileSize(hFile, NULL); - if(dwFileSize > sizeof(Buffer)) - { - SFileSetFilePointer(hFile, dwFileSize - sizeof(Buffer), NULL, FILE_BEGIN); - SFileReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead, NULL); - } - - SFileCloseFile(hFile); + Logger.PrintMessage("File count mismatch(expected: %u, found:%u)", dwExpectedFileCount, dwFileCount); + dwErrCode = ERROR_CAN_NOT_COMPLETE; + break; } } - // Search the archive and load every file - dwTestFlags = bIsPartialMpq ? 0 : TEST_FLAG_LOAD_FILES; - nError = SearchArchive(&Logger, hMpq, dwTestFlags, &dwFileCount); - SFileCloseArchive(hMpq); - } - - return nError; -} - -static int TestOpenArchive_SetPos(LPCTSTR szPlainName, LPCSTR szFileName) -{ - TLogHelper Logger("SetPosTest", szPlainName); - HANDLE hFile = NULL; - HANDLE hMpq = NULL; - TCHAR szMpqName[MAX_PATH]; - char szFullPath[MAX_PATH]; - int nError = ERROR_SUCCESS; - - // Create the full path name for the archive - CreateFullPathName(szFullPath, _countof(szFullPath), szMpqSubDir, szPlainName); - StringCopy(szMpqName, _countof(szMpqName), szFullPath); - - // Try to open the archive. It is expected to fail - Logger.PrintProgress("Opening archive %s", szPlainName); - if(SFileOpenArchive(szMpqName, 0, MPQ_OPEN_READ_ONLY, &hMpq)) - { - if(SFileOpenFileEx(hMpq, szFileName, 0, &hFile)) + // Shall we check overall MD5? + if(szExpectedMD5 && szExpectedMD5[0]) { - // First, use the SFileSetFilePointer WITHOUT the high-dword position - if(nError == ERROR_SUCCESS) - nError = TestSetFilePointers(hFile, false); - - // First, use the SFileSetFilePointer WITH the high-dword position - if(nError == ERROR_SUCCESS) - nError = TestSetFilePointers(hFile, true); - - // Close the file - SFileCloseFile(hFile); + BinaryFromString(szExpectedMD5, ExpectedMD5, MD5_DIGEST_SIZE); + if(memcmp(ExpectedMD5, OverallMD5, MD5_DIGEST_SIZE)) + { + Logger.PrintMessage("Extracted files MD5 mismatch"); + dwErrCode = ERROR_CAN_NOT_COMPLETE; + break; + } } - else - nError = GetLastError(); - - // Close the archive - SFileCloseArchive(hMpq); + break; } - else - nError = GetLastError(); - - return nError; -} - -static int TestOpenArchive_ProtectedMap(LPCTSTR szPlainName, LPCTSTR szListFile = NULL, DWORD dwExpectedFileCount = 0, LPCSTR szExpectedMD5 = NULL) -{ - TLogHelper Logger("ProtectedMapTest", szPlainName); - HANDLE hMpq; - DWORD dwTestFlags = TEST_FLAG_LOAD_FILES | TEST_FLAG_HASH_FILES; - DWORD dwFileCount = 0; - BYTE ExpectedMD5[MD5_DIGEST_SIZE]; - BYTE OverallMD5[MD5_DIGEST_SIZE]; - TCHAR szListFileBuff[MAX_PATH]; - int nError; - - // Copy the archive so we won't fuck up the original one - nError = OpenExistingArchiveWithCopy(&Logger, szPlainName, szPlainName, &hMpq); - if(nError == ERROR_SUCCESS) - { - // If the listfile was given, add it to the MPQ - if(szListFile != NULL) - { - Logger.PrintProgress(_T("Adding listfile %s ..."), szListFile); - CreateFullPathName(szListFileBuff, _countof(szListFileBuff), szMpqSubDir, szListFile); - nError = SFileAddListFile(hMpq, szListFileBuff); - if(nError != ERROR_SUCCESS) - Logger.PrintMessage("Failed to add the listfile to the MPQ"); - } - // Search the archive and load every file - nError = SearchArchive(&Logger, hMpq, dwTestFlags, &dwFileCount, OverallMD5); + // Common cleanup + if(pFileData2 != NULL) + STORM_FREE(pFileData2); + if(pFileData1 != NULL) + STORM_FREE(pFileData1); + if(hMpq != NULL) SFileCloseArchive(hMpq); - } - - // Check the file count and hash, if required - if(nError == ERROR_SUCCESS && dwExpectedFileCount != 0) - { - if(dwFileCount != dwExpectedFileCount) - { - Logger.PrintMessage("File count mismatch(expected: %u, found:%u)", dwExpectedFileCount, dwFileCount); - nError = ERROR_CAN_NOT_COMPLETE; - } - } - - // Check the overall hash, if required - if(nError == ERROR_SUCCESS && szExpectedMD5 != NULL && szExpectedMD5[0] != 0) - { - BinaryFromString(szExpectedMD5, ExpectedMD5, MD5_DIGEST_SIZE); - if(memcmp(ExpectedMD5, OverallMD5, MD5_DIGEST_SIZE)) - { - Logger.PrintMessage("Extracted files MD5 mismatch"); - nError = ERROR_CAN_NOT_COMPLETE; - } - } - - return nError; + return dwErrCode; } // Open an empty archive (found in WoW cache - it's just a header) @@ -2769,7 +2591,7 @@ static int TestOpenArchive_Corrupt(LPCTSTR szPlainName) // Opens a patched MPQ archive -static int TestOpenArchive_Patched(LPCTSTR PatchList[], LPCSTR szPatchedFile, int nExpectedPatchCount, bool bExpectedToFail = false) +static DWORD TestOpenArchive_Patched(LPCTSTR PatchList[], LPCSTR szPatchedFile, int nExpectedPatchCount, bool bExpectedToFail = false) { TLogHelper Logger("OpenPatchedMpqTest", PatchList[0]); HANDLE hMpq; @@ -2777,18 +2599,18 @@ static int TestOpenArchive_Patched(LPCTSTR PatchList[], LPCSTR szPatchedFile, in BYTE Buffer[0x100]; DWORD dwFileCount = 0; DWORD BytesRead = 0; - int nError; + DWORD dwErrCode; // Open a patched MPQ archive - nError = OpenPatchedArchive(&Logger, &hMpq, PatchList); - if(nError == ERROR_SUCCESS) + dwErrCode = OpenPatchedArchive(&Logger, &hMpq, PatchList); + if(dwErrCode == ERROR_SUCCESS) { // Check patch count if(szPatchedFile != NULL) - nError = VerifyFilePatchCount(&Logger, hMpq, szPatchedFile, nExpectedPatchCount); + dwErrCode = VerifyFilePatchCount(&Logger, hMpq, szPatchedFile, nExpectedPatchCount); // Try to open and read the file - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { if(SFileOpenFileEx(hMpq, szPatchedFile, 0, &hFile)) { @@ -2798,17 +2620,17 @@ static int TestOpenArchive_Patched(LPCTSTR PatchList[], LPCSTR szPatchedFile, in } // Search the archive and load every file - if(nError == ERROR_SUCCESS) - nError = SearchArchive(&Logger, hMpq, TEST_FLAG_LOAD_FILES, &dwFileCount); + if(dwErrCode == ERROR_SUCCESS) + dwErrCode = SearchArchive(&Logger, hMpq, SEARCH_FLAG_LOAD_FILES | SEARCH_FLAG_IGNORE_ERRORS, &dwFileCount); // Close the archive SFileCloseArchive(hMpq); } // Clear the error if patch prefix was not found - if(nError == ERROR_CANT_FIND_PATCH_PREFIX && bExpectedToFail) - nError = ERROR_SUCCESS; - return nError; + if(dwErrCode == ERROR_CANT_FIND_PATCH_PREFIX && bExpectedToFail) + dwErrCode = ERROR_SUCCESS; + return dwErrCode; } // Open an archive for read-only access @@ -2877,21 +2699,21 @@ static int TestOpenArchive_GetFileInfo(LPCTSTR szPlainName1, LPCTSTR szPlainName TestGetFileInfo(&Logger, NULL, SFileMpqBetHeader, NULL, 0, NULL, false, ERROR_INVALID_HANDLE); // Valid handle but invalid value of file info class (false, ERROR_INVALID_PARAMETER) - TestGetFileInfo(&Logger, NULL, (SFileInfoClass)0xFFF, NULL, 0, NULL, false, ERROR_INVALID_PARAMETER); + TestGetFileInfo(&Logger, NULL, (SFileInfoClass)0xFFF, NULL, 0, NULL, false, ERROR_INVALID_HANDLE); - // Valid archive handle but file info class is for file (false, ERROR_INVALID_HANDLE) + // Invalid archive handle and file info class is for file (false, ERROR_INVALID_HANDLE) TestGetFileInfo(&Logger, NULL, SFileInfoNameHash1, NULL, 0, NULL, false, ERROR_INVALID_HANDLE); // Valid handle and all parameters NULL - // Returns (true, ERROR_SUCCESS), if BET table is present, otherwise (false, ERROR_CAN_NOT_COMPLETE) + // Returns (true, ERROR_SUCCESS), if BET table is present, otherwise (false, ERROR_FILE_NOT_FOUND) TestGetFileInfo(&Logger, hMpq1, SFileMpqBetHeader, NULL, 0, NULL, false, ERROR_FILE_NOT_FOUND); - TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, NULL, 0, NULL, true, ERROR_SUCCESS); + TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, NULL, 0, NULL, false, ERROR_INSUFFICIENT_BUFFER); // Now try to retrieve the required size of the BET table header - TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, NULL, 0, &cbLength, true, ERROR_SUCCESS); + TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, NULL, 0, &cbLength, false, ERROR_INSUFFICIENT_BUFFER); // When we call SFileInfo with buffer = NULL and nonzero buffer size, it is ignored - TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, NULL, 3, &cbLength, true, ERROR_SUCCESS); + TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, NULL, 3, &cbLength, false, ERROR_INSUFFICIENT_BUFFER); // When we call SFileInfo with buffer != NULL and nonzero buffer size, it should return error TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, DataBuff, 3, &cbLength, false, ERROR_INSUFFICIENT_BUFFER); @@ -2903,11 +2725,11 @@ static int TestOpenArchive_GetFileInfo(LPCTSTR szPlainName1, LPCTSTR szPlainName TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, DataBuff, sizeof(DataBuff), &cbLength, true, ERROR_SUCCESS); // Try to retrieve strong signature from the MPQ - TestGetFileInfo(&Logger, hMpq1, SFileMpqStrongSignature, NULL, 0, NULL, true, ERROR_SUCCESS); + TestGetFileInfo(&Logger, hMpq1, SFileMpqStrongSignature, NULL, 0, NULL, false, ERROR_INSUFFICIENT_BUFFER); TestGetFileInfo(&Logger, hMpq4, SFileMpqStrongSignature, NULL, 0, NULL, false, ERROR_FILE_NOT_FOUND); // Strong signature is returned including the signature ID - TestGetFileInfo(&Logger, hMpq1, SFileMpqStrongSignature, NULL, 0, &cbLength, true, ERROR_SUCCESS); + TestGetFileInfo(&Logger, hMpq1, SFileMpqStrongSignature, NULL, 0, &cbLength, false, ERROR_INSUFFICIENT_BUFFER); assert(cbLength == MPQ_STRONG_SIGNATURE_SIZE + 4); // Retrieve the signature @@ -3137,8 +2959,7 @@ static int TestOpenArchive_SignExisting(LPCTSTR szPlainName) return nError; } -// Open an empty archive (found in WoW cache - it's just a header) -static int TestOpenArchive_CompactArchive(LPCTSTR szPlainName, LPCTSTR szCopyName, bool bAddUserData) +static DWORD TestOpenArchive_CompactArchive(LPCTSTR szPlainName, LPCTSTR szCopyName, bool bAddUserData) { TLogHelper Logger("CompactMpqTest", szPlainName); ULONGLONG PreMpqDataSize = (bAddUserData) ? 0x400 : 0; @@ -3149,64 +2970,64 @@ static int TestOpenArchive_CompactArchive(LPCTSTR szPlainName, LPCTSTR szCopyNam TCHAR szFullPath[MAX_PATH]; BYTE FileHash1[MD5_DIGEST_SIZE]; BYTE FileHash2[MD5_DIGEST_SIZE]; - int nError; + DWORD dwErrCode; // Create copy of the archive, with interleaving some user data - nError = CreateFileCopy(&Logger, szPlainName, szCopyName, szFullPath, _countof(szFullPath), PreMpqDataSize, UserDataSize); + dwErrCode = CreateFileCopy(&Logger, szPlainName, szCopyName, szFullPath, _countof(szFullPath), PreMpqDataSize, UserDataSize); // Open the archive and load some files - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { // Open the archive - nError = OpenExistingArchive(&Logger, szFullPath, 0, &hMpq); - if(nError != ERROR_SUCCESS) - return nError; + dwErrCode = OpenExistingArchive(&Logger, szFullPath, 0, &hMpq); + if(dwErrCode != ERROR_SUCCESS) + return dwErrCode; // Verify presence of (listfile) and (attributes) CheckIfFileIsPresent(&Logger, hMpq, LISTFILE_NAME, true); CheckIfFileIsPresent(&Logger, hMpq, ATTRIBUTES_NAME, true); // Search the archive and load every file - nError = SearchArchive(&Logger, hMpq, TEST_FLAG_LOAD_FILES | TEST_FLAG_HASH_FILES, &dwFileCount1, FileHash1); + dwErrCode = SearchArchive(&Logger, hMpq, SEARCH_FLAG_LOAD_FILES | SEARCH_FLAG_HASH_FILES, &dwFileCount1, FileHash1); SFileCloseArchive(hMpq); } // Try to compact the MPQ - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { // Open the archive again - nError = OpenExistingArchive(&Logger, szFullPath, 0, &hMpq); - if(nError != ERROR_SUCCESS) - return nError; + dwErrCode = OpenExistingArchive(&Logger, szFullPath, 0, &hMpq); + if(dwErrCode != ERROR_SUCCESS) + return dwErrCode; // Compact the archive Logger.PrintProgress("Compacting archive %s ...", GetShortPlainName(szFullPath)); if(!SFileSetCompactCallback(hMpq, CompactCallback, &Logger)) - nError = Logger.PrintError(_T("Failed to compact archive %s"), szFullPath); + dwErrCode = Logger.PrintError(_T("Failed to compact archive %s"), szFullPath); SFileCompactArchive(hMpq, NULL, false); SFileCloseArchive(hMpq); } // Open the archive and load some files - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { // Open the archive - nError = OpenExistingArchive(&Logger, szFullPath, 0, &hMpq); - if(nError != ERROR_SUCCESS) - return nError; + dwErrCode = OpenExistingArchive(&Logger, szFullPath, 0, &hMpq); + if(dwErrCode != ERROR_SUCCESS) + return dwErrCode; // Verify presence of (listfile) and (attributes) CheckIfFileIsPresent(&Logger, hMpq, LISTFILE_NAME, true); CheckIfFileIsPresent(&Logger, hMpq, ATTRIBUTES_NAME, true); // Search the archive and load every file - nError = SearchArchive(&Logger, hMpq, TEST_FLAG_LOAD_FILES | TEST_FLAG_HASH_FILES, &dwFileCount2, FileHash2); + dwErrCode = SearchArchive(&Logger, hMpq, SEARCH_FLAG_LOAD_FILES | SEARCH_FLAG_HASH_FILES, &dwFileCount2, FileHash2); SFileCloseArchive(hMpq); } // Compare the file counts and their hashes - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { if(dwFileCount2 != dwFileCount1) Logger.PrintMessage("Different file count after compacting archive: %u vs %u", dwFileCount2, dwFileCount1); @@ -3215,7 +3036,7 @@ static int TestOpenArchive_CompactArchive(LPCTSTR szPlainName, LPCTSTR szCopyNam Logger.PrintMessage("Different file hash after compacting archive"); } - return nError; + return dwErrCode; } static int ForEachFile_VerifyFileChecksum(LPCTSTR szFullPath) @@ -3403,7 +3224,7 @@ static int TestCreateArchive_Deprotect(LPCSTR szPlainName) BYTE FileHash2[MD5_DIGEST_SIZE]; DWORD dwFileCount1 = 0; DWORD dwFileCount2 = 0; - DWORD dwTestFlags = TEST_FLAG_LOAD_FILES | TEST_FLAG_HASH_FILES; + DWORD dwTestFlags = SEARCH_FLAG_LOAD_FILES | SEARCH_FLAG_HASH_FILES; int nError = ERROR_SUCCESS; // First copy: The original (untouched) file @@ -3898,7 +3719,7 @@ static int TestCreateArchive_UnicodeNames() return nError; } -static int TestCreateArchive_FileFlagTest(LPCTSTR szPlainName) +static DWORD TestCreateArchive_FileFlagTest(LPCTSTR szPlainName) { TLogHelper Logger("FileFlagTest", szPlainName); HANDLE hMpq = NULL; // Handle of created archive @@ -3910,29 +3731,28 @@ static int TestCreateArchive_FileFlagTest(LPCTSTR szPlainName) char szArchivedName[MAX_PATH]; DWORD dwMaxFileCount = 0; DWORD dwFileCount = 0; - size_t i; - int nError; + DWORD dwErrCode; // Create paths for local file to be added CreateFullPathName(szFileName1, _countof(szFileName1), szMpqSubDir, _T("AddFile.exe")); CreateFullPathName(szFileName2, _countof(szFileName2), szMpqSubDir, _T("AddFile.bin")); // Create an empty file that will serve as holder for the MPQ - nError = CreateEmptyFile(&Logger, szPlainName, 0x100000, szFullPath); + dwErrCode = CreateEmptyFile(&Logger, szPlainName, 0x100000, szFullPath); // Create new MPQ archive over that file - if(nError == ERROR_SUCCESS) - nError = CreateNewArchive(&Logger, szPlainName, MPQ_CREATE_ARCHIVE_V1 | MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES, 17, &hMpq); + if(dwErrCode == ERROR_SUCCESS) + dwErrCode = CreateNewArchive(&Logger, szPlainName, MPQ_CREATE_ARCHIVE_V1 | MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES, 17, &hMpq); // Add the same file multiple times - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { dwMaxFileCount = SFileGetMaxFileCount(hMpq); - for(i = 0; AddFlags[i] != 0xFFFFFFFF; i++) + for(size_t i = 0; AddFlags[i] != 0xFFFFFFFF; i++) { sprintf(szArchivedName, "FileTest_%02u.exe", (unsigned int)i); - nError = AddLocalFileToMpq(&Logger, hMpq, szArchivedName, szFileName1, AddFlags[i], 0); - if(nError != ERROR_SUCCESS) + dwErrCode = AddLocalFileToMpq(&Logger, hMpq, szArchivedName, szFileName1, AddFlags[i], 0); + if(dwErrCode != ERROR_SUCCESS) break; dwFileCount++; @@ -3940,41 +3760,41 @@ static int TestCreateArchive_FileFlagTest(LPCTSTR szPlainName) } // Delete a file in the middle of the file table - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { Logger.PrintProgress("Removing file %s ...", szMiddleFile); - nError = RemoveMpqFile(&Logger, hMpq, szMiddleFile, ERROR_SUCCESS); + dwErrCode = RemoveMpqFile(&Logger, hMpq, szMiddleFile, ERROR_SUCCESS); dwFileCount--; } // Add one more file - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { - nError = AddLocalFileToMpq(&Logger, hMpq, "FileTest_xx.exe", szFileName1); + dwErrCode = AddLocalFileToMpq(&Logger, hMpq, "FileTest_xx.exe", szFileName1); dwFileCount++; } // Try to decrement max file count. This must succeed - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { Logger.PrintProgress("Attempting to decrement max file count ..."); if(SFileSetMaxFileCount(hMpq, 5)) - nError = Logger.PrintError("Max file count decremented, even if it should fail"); + dwErrCode = Logger.PrintError("Max file count decremented, even if it should fail"); } // Add ZeroSize.txt several times under a different locale - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { - for(i = 0; LocaleIDs[i] != 0xFFFF; i++) + for(size_t i = 0; LocaleIDs[i] != 0xFFFF; i++) { bool bMustSucceed = ((dwFileCount + 2) < dwMaxFileCount); SFileSetLocale(LocaleIDs[i]); - nError = AddLocalFileToMpq(&Logger, hMpq, "ZeroSize_1.txt", szFileName2); - if(nError != ERROR_SUCCESS) + dwErrCode = AddLocalFileToMpq(&Logger, hMpq, "ZeroSize_1.txt", szFileName2); + if(dwErrCode != ERROR_SUCCESS) { if(bMustSucceed == false) - nError = ERROR_SUCCESS; + dwErrCode = ERROR_SUCCESS; break; } @@ -3983,18 +3803,18 @@ static int TestCreateArchive_FileFlagTest(LPCTSTR szPlainName) } // Add ZeroSize.txt again several times under a different locale - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { - for(i = 0; LocaleIDs[i] != 0xFFFF; i++) + for(size_t i = 0; LocaleIDs[i] != 0xFFFF; i++) { bool bMustSucceed = ((dwFileCount + 2) < dwMaxFileCount); SFileSetLocale(LocaleIDs[i]); - nError = AddLocalFileToMpq(&Logger, hMpq, "ZeroSize_2.txt", szFileName2, 0, 0, bMustSucceed); - if(nError != ERROR_SUCCESS) + dwErrCode = AddLocalFileToMpq(&Logger, hMpq, "ZeroSize_2.txt", szFileName2, 0, 0, bMustSucceed); + if(dwErrCode != ERROR_SUCCESS) { if(bMustSucceed == false) - nError = ERROR_SUCCESS; + dwErrCode = ERROR_SUCCESS; break; } @@ -4003,45 +3823,45 @@ static int TestCreateArchive_FileFlagTest(LPCTSTR szPlainName) } // Verify how many files did we add to the MPQ - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { if(dwFileCount + 2 != dwMaxFileCount) { Logger.PrintErrorVa("Number of files added to MPQ was unexpected (expected %u, added %u)", dwFileCount, dwMaxFileCount - 2); - nError = ERROR_FILE_CORRUPT; + dwErrCode = ERROR_FILE_CORRUPT; } } // Test rename function - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { Logger.PrintProgress("Testing rename files ..."); SFileSetLocale(LANG_NEUTRAL); if(!SFileRenameFile(hMpq, "FileTest_08.exe", "FileTest_08a.exe")) - nError = Logger.PrintError("Failed to rename the file"); + dwErrCode = Logger.PrintError("Failed to rename the file"); } - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { if(!SFileRenameFile(hMpq, "FileTest_08a.exe", "FileTest_08.exe")) - nError = Logger.PrintError("Failed to rename the file"); + dwErrCode = Logger.PrintError("Failed to rename the file"); } - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { if(SFileRenameFile(hMpq, "FileTest_10.exe", "FileTest_10a.exe")) { Logger.PrintError("Rename test succeeded even if it shouldn't"); - nError = ERROR_FILE_CORRUPT; + dwErrCode = ERROR_FILE_CORRUPT; } } - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { if(SFileRenameFile(hMpq, "FileTest_10a.exe", "FileTest_10.exe")) { Logger.PrintError("Rename test succeeded even if it shouldn't"); - nError = ERROR_FILE_CORRUPT; + dwErrCode = ERROR_FILE_CORRUPT; } } @@ -4051,9 +3871,9 @@ static int TestCreateArchive_FileFlagTest(LPCTSTR szPlainName) hMpq = NULL; // Try to reopen the archive - if(nError == ERROR_SUCCESS) - nError = OpenExistingArchive(&Logger, szFullPath, 0, NULL); - return nError; + if(dwErrCode == ERROR_SUCCESS) + dwErrCode = OpenExistingArchive(&Logger, szFullPath, 0, NULL); + return dwErrCode; } static int TestCreateArchive_WaveCompressionsTest(LPCTSTR szPlainName, LPCTSTR szWaveFile) @@ -4097,7 +3917,7 @@ static int TestCreateArchive_WaveCompressionsTest(LPCTSTR szPlainName, LPCTSTR s nError = OpenExistingArchiveWithCopy(&Logger, NULL, szPlainName, &hMpq); if(nError == ERROR_SUCCESS) { - SearchArchive(&Logger, hMpq, TEST_FLAG_LOAD_FILES | TEST_FLAG_PLAY_WAVES, &dwFoundFiles, NULL); + SearchArchive(&Logger, hMpq, SEARCH_FLAG_LOAD_FILES | SEARCH_FLAG_PLAY_WAVES, &dwFoundFiles, NULL); SFileCloseArchive(hMpq); } @@ -4263,20 +4083,20 @@ static int TestCreateArchive_BigArchive(LPCTSTR szPlainName) } // "MPQ_2014_v4_Heroes_Replay.MPQ", "AddFile-replay.message.events" -static int TestModifyArchive_ReplaceFile(LPCTSTR szMpqPlainName, LPCTSTR szFileName) +static DWORD TestModifyArchive_ReplaceFile(LPCTSTR szMpqPlainName, LPCTSTR szFileName) { TLogHelper Logger("ModifyTest", szMpqPlainName); HANDLE hMpq = NULL; TCHAR szLocalFileName[MAX_PATH]; char szArchivedName[MAX_PATH]; size_t nOffset = 0; - int nError; + DWORD dwErrCode; // Open an existing archive - nError = OpenExistingArchiveWithCopy(&Logger, szMpqPlainName, szMpqPlainName, &hMpq); + dwErrCode = OpenExistingArchiveWithCopy(&Logger, szMpqPlainName, szMpqPlainName, &hMpq); // Add the given file - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { // Get the name of archived file if(!_tcsnicmp(szFileName, _T("AddFile-"), 8)) @@ -4287,38 +4107,38 @@ static int TestModifyArchive_ReplaceFile(LPCTSTR szMpqPlainName, LPCTSTR szFileN CreateFullPathName(szLocalFileName, _countof(szLocalFileName), szMpqSubDir, szFileName); // Add the file to MPQ - nError = AddLocalFileToMpq(&Logger, hMpq, - szArchivedName, - szLocalFileName, - MPQ_FILE_REPLACEEXISTING | MPQ_FILE_COMPRESS | MPQ_FILE_SINGLE_UNIT, - MPQ_COMPRESSION_ZLIB, - true); + dwErrCode = AddLocalFileToMpq(&Logger, hMpq, + szArchivedName, + szLocalFileName, + MPQ_FILE_REPLACEEXISTING | MPQ_FILE_COMPRESS | MPQ_FILE_SINGLE_UNIT, + MPQ_COMPRESSION_ZLIB, + true); } // Reopen the MPQ and compact it - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { // Compact the archive Logger.PrintProgress("Compacting archive %s ...", szMpqPlainName); if(!SFileSetCompactCallback(hMpq, CompactCallback, &Logger)) - nError = Logger.PrintError(_T("Failed to compact archive %s"), szMpqPlainName); + dwErrCode = Logger.PrintError(_T("Failed to compact archive %s"), szMpqPlainName); if(!SFileCompactArchive(hMpq, NULL, 0)) - nError = GetLastError(); + dwErrCode = GetLastError(); SFileCloseArchive(hMpq); } // Try to open the archive again - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { CreateFullPathName(szLocalFileName, _countof(szLocalFileName), NULL, szMpqPlainName); - nError = OpenExistingArchive(&Logger, szLocalFileName, 0, &hMpq); - if(nError == ERROR_SUCCESS) + dwErrCode = OpenExistingArchive(&Logger, szLocalFileName, 0, &hMpq); + if(dwErrCode == ERROR_SUCCESS) SFileCloseArchive(hMpq); } - return nError; + return dwErrCode; } //----------------------------------------------------------------------------- @@ -4349,28 +4169,53 @@ static const TEST_INFO TestList_MasterMirror[] = static const TEST_INFO Test_Mpqs[] = { - {_T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"), NULL, TEST_OPEN_COMPARE_TWO_FILES, "music\\dintro.wav", "File00000023.xxx"}, - {_T("MPQ_2016_v1_D2XP_IX86_1xx_114a.mpq"), NULL, TEST_LOAD_FILE_CHECK_CRC, "waitingroombkgd.dc6" }, // The update MPQ from Diablo II (patch 2016) - {_T("MPQ_2018_v1_icon_error.w3m"), NULL, TEST_LOAD_FILE_CHECK_CRC, "file00000002.blp" }, - - {_T("MPQ_1997_v1_Diablo1_STANDARD.SNP"), _T("ListFile_Blizzard.txt"), TEST_OPEN_MPQ }, // Open a file whose archive's (signature) file has flags = 0x90000000 - {_T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"), NULL, TEST_OPEN_MPQ | TEST_SETPOS, "music\\dtowne.wav" }, // Test the SFileSetFilePointer operations - {_T("MPQ_2012_v2_EmptyMpq.MPQ") }, // Open an empty archive (found in WoW cache - it's just a header) - {_T("MPQ_2013_v4_EmptyMpq.MPQ") }, // Open an empty archive (created artificially - it's just a header) - {_T("MPQ_2013_v4_patch-base-16357.MPQ") }, // Open an empty archive (found in WoW cache - it's just a header) - {_T("MPQ_2011_v4_InvalidHetEntryCount.MPQ") }, // Open an empty archive (A buggy MPQ with invalid HET entry count) - {_T("MPQ_2002_v1_BlockTableCut.MPQ") }, // Open a truncated archive - - // TODO: Doesn't work anymore - //{_T("MPQ_2010_v2_HasUserData.s2ma") }, // Open a MPQ that actually has user data - - {_T("MPQ_2014_v1_AttributesOneEntryLess.w3x") }, // Open an Warcraft III map whose "(attributes)" file has (BlockTableSize-1) entries - {_T("MPQ_2020_v1_AHF04patch.mix") }, // Open a MIX file - {_T("MPQ_2010_v3_expansion-locale-frFR.MPQ") }, // Open a MPQ archive v 3.0 - {_T("mpqe-file://MPQ_2011_v2_EncryptedMpq.MPQE") }, // Open an encrypted archive from Starcraft II installer - {_T("MPx_2013_v1_LongwuOnline.mpk") }, // Open a MPK archive from Longwu online - {_T("MPx_2013_v1_WarOfTheImmortals.sqp"), _T("ListFile_WarOfTheImmortals.txt") }, // Open a SQP archive from War of the Immortals - {_T("part-file://MPQ_2010_v2_HashTableCompressed.MPQ.part") }, // Open a partial MPQ with compressed hash table + // Correct or damaged archives + {_T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"), NULL, 0, "music\\dintro.wav", "File00000023.xxx"}, + {_T("MPQ_2016_v1_D2XP_IX86_1xx_114a.mpq"), NULL, 0, "waitingroombkgd.dc6"}, // Update MPQ from Diablo II (patch 2016) + {_T("MPQ_2018_v1_icon_error.w3m"), NULL, 0, "file00000002.blp"}, + {_T("MPQ_1997_v1_Diablo1_STANDARD.SNP"), _T("ListFile_Blizzard.txt")}, // File whose archive's (signature) file has flags = 0x90000000 + {_T("MPQ_2012_v2_EmptyMpq.MPQ") }, // Empty archive (found in WoW cache - it's just a header) + {_T("MPQ_2013_v4_EmptyMpq.MPQ") }, // Empty archive (created artificially - it's just a header) + {_T("MPQ_2013_v4_patch-base-16357.MPQ") }, // Empty archive (found in WoW cache - it's just a header) + {_T("MPQ_2011_v4_InvalidHetEntryCount.MPQ") }, // Empty archive (A buggy MPQ with invalid HET entry count) + {_T("MPQ_2002_v1_BlockTableCut.MPQ") }, // Truncated archive + {_T("MPQ_2010_v2_HasUserData.s2ma") }, // MPQ that actually has user data + {_T("MPQ_2014_v1_AttributesOneEntryLess.w3x") }, // Warcraft III map whose "(attributes)" file has (BlockTableSize-1) entries + {_T("MPQ_2020_v1_AHF04patch.mix") }, // MIX file + {_T("MPQ_2010_v3_expansion-locale-frFR.MPQ") }, // MPQ archive v 3.0 + {_T("mpqe-file://MPQ_2011_v2_EncryptedMpq.MPQE") }, // Encrypted archive from Starcraft II installer + {_T("MPx_2013_v1_LongwuOnline.mpk") }, // MPK archive from Longwu online + {_T("MPx_2013_v1_WarOfTheImmortals.sqp"), _T("ListFile_WarOfTheImmortals.txt") }, // SQP archive from War of the Immortals + {_T("part-file://MPQ_2010_v2_HashTableCompressed.MPQ.part") }, // Partial MPQ with compressed hash table + {_T("blk4-file://streaming/model.MPQ.0")}, // Archive that is merged with multiple files + {_T("MPQ_2002_v1_ProtectedMap_InvalidUserData.w3x")}, + {_T("MPQ_2002_v1_ProtectedMap_InvalidMpqFormat.w3x")}, + {_T("MPQ_2002_v1_ProtectedMap_Spazzler.w3x")}, // Warcraft III map locked by the Spazzler protector + {_T("MPQ_2014_v1_ProtectedMap_Spazzler2.w3x")}, // Warcraft III map locked by the Spazzler protector + {_T("MPQ_2014_v1_ProtectedMap_Spazzler3.w3x")}, // Warcraft III map locked by the Spazzler protector + {_T("MPQ_2002_v1_ProtectedMap_BOBA.w3m")}, // Warcraft III map locked by the BOBA protector + {_T("MPQ_2015_v1_ProtectedMap_KangTooJee.w3x")}, + {_T("MPQ_2015_v1_ProtectedMap_Somj2hM16.w3x")}, + {_T("MPQ_2015_v1_ProtectedMap_Spazy.w3x")}, // Warcraft III map locked by Spazy protector + {_T("MPQ_2015_v1_MessListFile.mpq")}, + {_T("MPQ_2016_v1_ProtectedMap_TableSizeOverflow.w3x")}, + {_T("MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x")}, + {_T("MPQ_2016_v1_ProtectedMap_Somj2.w3x")}, // Something like Somj 2.0 + {_T("MPQ_2016_v1_WME4_4.w3x")}, // Protector from China (2016-05-27) + {_T("MPQ_2016_v1_SP_(4)Adrenaline.w3x")}, + {_T("MPQ_2016_v1_ProtectedMap_1.4.w3x")}, + {_T("MPQ_2016_v1_KoreanFile.w3m")}, + {_T("MPQ_2017_v1_Eden_RPG_S2_2.5J.w3x")}, // Load map protected by PG1.11.973 + {_T("MPQ_2017_v1_BigDummyFiles.w3x")}, + {_T("MPQ_2017_v1_TildeInFileName.mpq")}, + {_T("MPQ_2018_v1_EWIX_v8_7.w3x"), NULL, 0, "BlueCrystal.mdx"}, + {_T("MPQ_2020_v4_FakeMpqHeaders.SC2Mod")}, // Archive that has two fake headers before the real one + {_T("MPQ_2020_v4_NP_Protect_1.s2ma")}, // SC2 map that is protected by the NP_Protect + {_T("MPQ_2020_v4_NP_Protect_2.s2ma")}, // SC2 map that is protected by the NP_Protect + + // Protected archives + {_T("MPQ_2015_v1_flem1.w3x"), NULL, TEST_FLAG_PROTECTED | 20, "1c4c13e627658c473e84d94371e31f37"}, + {_T("MPQ_2002_v1_ProtectedMap_HashTable_FakeValid.w3x"), NULL, TEST_FLAG_PROTECTED | 114, "5250975ed917375fc6540d7be436d4de"}, }; //----------------------------------------------------------------------------- @@ -4389,89 +4234,60 @@ int _tmain(int argc, TCHAR * argv[]) dwErrCode = InitializeMpqDirectory(argv, argc); // - // Open all files from the command line + // Tests on a local listfile // - for(int i = 1; i < argc; i++) + if(dwErrCode == ERROR_SUCCESS) { - //SFILE_FIND_DATA sf; - HANDLE hFile = NULL; - HANDLE hMpq = NULL; - BYTE Buffer[0x40]; - - if(SFileOpenArchive(argv[i], 0, 0, &hMpq)) - { - if(SFileOpenFileEx(hMpq, "koKR.SC2Data\\LocalizedData\\ObjectStrings.txt", 0, &hFile)) - { - SFileReadFile(hFile, Buffer, sizeof(Buffer), NULL, NULL); - SFileCloseFile(hFile); - } - - //if((hFind = SFileFindFirstFile(hMpq, "*", &sf, NULL)) != NULL) - //{ - // SFileFindNextFile(hFind, &sf); - // SFileFindClose(hFind); - //} - - SFileCloseArchive(hMpq); - } + dwErrCode = TestOnLocalListFile(_T("ListFile_Blizzard.txt")); } // - // Search all testing archives and verify their SHA1 hash - // - - //if(dwErrCode == ERROR_SUCCESS) - //{ - // dwErrCode = FindFiles(ForEachFile_VerifyFileChecksum, szMpqSubDir); - //} - - // - // Test file stream operations + // Open all files from the command line // - //if(dwErrCode == ERROR_SUCCESS) - //{ - // for(size_t i = 0; i < _countof(TestList_StreamOps); i++) - // { - // dwErrCode = TestFileStreamOperations(TestList_StreamOps[i].szMpqName1, TestList_StreamOps[i].dwFlags); - // if(dwErrCode != ERROR_SUCCESS) - // break; - // } - //} + for(int i = 1; i < argc; i++) + { + ForEachFile_OpenArchive(argv[i]); + } // - // Test master-mirror reading operations + // Search all testing archives and verify their SHA1 hash // - //if(dwErrCode == ERROR_SUCCESS) - //{ - // for(size_t i = 0; i < _countof(TestList_MasterMirror); i++) - // { - // dwErrCode = TestReadFile_MasterMirror(TestList_MasterMirror[i].szMpqName1, - // TestList_MasterMirror[i].szMpqName2, - // TestList_MasterMirror[i].dwFlags != 0); - // if(dwErrCode != ERROR_SUCCESS) - // break; - // } - //} + if(dwErrCode == ERROR_SUCCESS) + { + dwErrCode = FindFiles(ForEachFile_VerifyFileChecksum, szMpqSubDir); + } // - // Search in listfile + // Test file stream operations // if(dwErrCode == ERROR_SUCCESS) { - dwErrCode = TestSearchListFile(_T("ListFile_Blizzard.txt")); + for(size_t i = 0; i < _countof(TestList_StreamOps); i++) + { + dwErrCode = TestFileStreamOperations(TestList_StreamOps[i].szMpqName1, TestList_StreamOps[i].dwFlags); + if(dwErrCode != ERROR_SUCCESS) + break; + } } // - // Test opening local file with SFileOpenFileEx + // Test master-mirror reading operations // if(dwErrCode == ERROR_SUCCESS) { - dwErrCode = TestOpenLocalFile(_T("ListFile_Blizzard.txt")); + for(size_t i = 0; i < _countof(TestList_MasterMirror); i++) + { + dwErrCode = TestReadFile_MasterMirror(TestList_MasterMirror[i].szMpqName1, + TestList_MasterMirror[i].szMpqName2, + TestList_MasterMirror[i].dwFlags != 0); + if(dwErrCode != ERROR_SUCCESS) + break; + } } // @@ -4492,96 +4308,10 @@ int _tmain(int argc, TCHAR * argv[]) } } - // Open an protected map - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive_ProtectedMap(_T("MPQ_2015_v1_flem1.w3x"), NULL, 20, "1c4c13e627658c473e84d94371e31f37"); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive_ProtectedMap(_T("MPQ_2002_v1_ProtectedMap_HashTable_FakeValid.w3x"), NULL, 114, "5250975ed917375fc6540d7be436d4de"); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2002_v1_ProtectedMap_InvalidUserData.w3x")); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2002_v1_ProtectedMap_InvalidMpqFormat.w3x")); - - // Open an Warcraft III map locked by the Spazzler protector - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2002_v1_ProtectedMap_Spazzler.w3x")); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2014_v1_ProtectedMap_Spazzler2.w3x")); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2014_v1_ProtectedMap_Spazzler3.w3x")); - - // Open an Warcraft III map locked by the BOBA protector - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2002_v1_ProtectedMap_BOBA.w3m")); - - // Open an Warcraft III map locked by a protector - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2015_v1_ProtectedMap_KangTooJee.w3x")); - - // Open an Warcraft III map locked by a protector - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2015_v1_ProtectedMap_Somj2hM16.w3x")); - - // Open an Warcraft III map locked by Spazy protector - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2015_v1_ProtectedMap_Spazy.w3x")); - - // Open an Warcraft III map locked by Spazy protector - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2015_v1_MessListFile.mpq")); - - // Open another protected map - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2016_v1_ProtectedMap_TableSizeOverflow.w3x")); - - // Open another protected map - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x")); - - // Something like Somj 2.0 - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2016_v1_ProtectedMap_Somj2.w3x")); - - // Protector from China (2016-05-27) - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2016_v1_WME4_4.w3x")); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2016_v1_SP_(4)Adrenaline.w3x")); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2016_v1_ProtectedMap_1.4.w3x")); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2016_v1_KoreanFile.w3m")); - - // Load map protected by PG1.11.973 - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2017_v1_Eden_RPG_S2_2.5J.w3x")); - - // Load map protected by PG1.11.973 - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2017_v1_BigDummyFiles.w3x"), NULL, "1.blp"); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2017_v1_TildeInFileName.mpq"), NULL, "1.blp"); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2018_v1_EWIX_v8_7.w3x"), NULL, "BlueCrystal.mdx"); - // Open the multi-file archive with wrong prefix to see how StormLib deals with it if(dwErrCode == ERROR_SUCCESS) dwErrCode = TestOpenArchive_WillFail(_T("flat-file://streaming/model.MPQ.0")); - // Open an archive that is merged with multiple files - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("blk4-file://streaming/model.MPQ.0"), NULL, NULL, true); - // Open every MPQ that we have in the storage if(dwErrCode == ERROR_SUCCESS) dwErrCode = FindFiles(ForEachFile_OpenArchive, NULL); @@ -4590,18 +4320,6 @@ int _tmain(int argc, TCHAR * argv[]) if(dwErrCode == ERROR_SUCCESS) dwErrCode = TestOpenArchive_Corrupt(_T("MPQ_2013_vX_Battle.net.MPQ")); - // Test on an archive that has two fake headers before the real one - if (dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2020_v4_FakeMpqHeaders.SC2Mod")); - - // Test on an SC2 map that is protected by the NP_Protect - if (dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2020_v4_NP_Protect_1.s2ma")); - - // Test on an SC2 map that is protected by the NP_Protect - if (dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2020_v4_NP_Protect_2.s2ma")); - // Open a patched archive if(dwErrCode == ERROR_SUCCESS) dwErrCode = TestOpenArchive_Patched(PatchList_StarCraft, "music\\terran1.wav", 0); @@ -4632,7 +4350,7 @@ int _tmain(int argc, TCHAR * argv[]) // Open a patched archive if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive_Patched(PatchList_SC2_32283_enGB, "LocalizedData\\GameHotkeys.txt", 0, true); + dwErrCode = TestOpenArchive_Patched(PatchList_SC2_32283_enGB, "Assets\\Textures\\startupimage.dds", 0, true); // Open a patched archive where the "StreamingBuckets.txt" in the patch doesn't contain MPQ_FILE_PATCH_FILE if(dwErrCode == ERROR_SUCCESS) diff --git a/test/TLogHelper.cpp b/test/TLogHelper.cpp index 9bf4f6d..fca85ec 100644 --- a/test/TLogHelper.cpp +++ b/test/TLogHelper.cpp @@ -30,11 +30,11 @@ class TLogHelper #endif // defined(UNICODE) || defined(UNICODE) // ANSI functions - int PrintWithClreol(const char * szFormat, va_list argList, bool bPrintPrefix, bool bPrintLastError, bool bPrintEndOfLine); - void PrintProgress(const char * szFormat, ...); - void PrintMessage(const char * szFormat, ...); - int PrintErrorVa(const char * szFormat, ...); - int PrintError(const char * szFormat, const char * szFileName = NULL); + DWORD PrintWithClreol(const char * szFormat, va_list argList, bool bPrintPrefix, bool bPrintLastError, bool bPrintEndOfLine); + void PrintProgress(const char * szFormat, ...); + void PrintMessage(const char * szFormat, ...); + DWORD PrintErrorVa(const char * szFormat, ...); + DWORD PrintError(const char * szFormat, const char * szFileName = NULL); const char * UserString; unsigned int UserCount; @@ -140,7 +140,7 @@ TLogHelper::~TLogHelper() #if defined(_MSC_VER) && defined(_DEBUG) if(_CrtDumpMemoryLeaks()) { - PrintMessage("Memory leak detected after %s\n.", szSaveMainTitle); + PrintMessage(_T("Memory leak(s) detected after %s.\n"), szSaveMainTitle); } #endif // _MSC_VER } @@ -257,7 +257,7 @@ int TLogHelper::PrintError(const TCHAR * szFormat, const TCHAR * szFileName) //----------------------------------------------------------------------------- // ANSI functions -int TLogHelper::PrintWithClreol(const char * szFormat, va_list argList, bool bPrintPrefix, bool bPrintLastError, bool bPrintEndOfLine) +DWORD TLogHelper::PrintWithClreol(const char * szFormat, va_list argList, bool bPrintPrefix, bool bPrintLastError, bool bPrintEndOfLine) { char szFormatBuff[0x200]; char szMessage[0x200]; @@ -265,7 +265,7 @@ int TLogHelper::PrintWithClreol(const char * szFormat, va_list argList, bool bPr int nRemainingWidth; int nConsoleWidth = GetConsoleWidth(); int nLength = 0; - int nError = GetLastError(); + DWORD dwErrCode = GetLastError(); // Always start the buffer with '\r' *szBuffer++ = '\r'; @@ -292,7 +292,7 @@ int TLogHelper::PrintWithClreol(const char * szFormat, va_list argList, bool bPr // Append the last error if(bPrintLastError) { - nLength = sprintf(szBuffer, " (error code: %u)", nError); + nLength = sprintf(szBuffer, " (error code: %u)", dwErrCode); szBuffer += nLength; } @@ -322,7 +322,7 @@ int TLogHelper::PrintWithClreol(const char * szFormat, va_list argList, bool bPr // Spit out the text in one single printf printf("%s", szMessage); - return nError; + return dwErrCode; } void TLogHelper::PrintProgress(const char * szFormat, ...) @@ -343,19 +343,19 @@ void TLogHelper::PrintMessage(const char * szFormat, ...) va_end(argList); } -int TLogHelper::PrintErrorVa(const char * szFormat, ...) +DWORD TLogHelper::PrintErrorVa(const char * szFormat, ...) { va_list argList; - int nResult; + DWORD dwErrCode; va_start(argList, szFormat); - nResult = PrintWithClreol(szFormat, argList, true, true, true); + dwErrCode = PrintWithClreol(szFormat, argList, true, true, true); va_end(argList); - return nResult; + return dwErrCode; } -int TLogHelper::PrintError(const char * szFormat, const char * szFileName) +DWORD TLogHelper::PrintError(const char * szFormat, const char * szFileName) { return PrintErrorVa(szFormat, szFileName); } -- cgit v1.2.3