From d5d2413e951165aa19e926d9f6ad63a818bbce78 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Sun, 12 Jun 2022 20:51:09 +0200 Subject: Fixed --- src/SBaseCommon.cpp | 1 - src/SBaseFileTable.cpp | 7 +- src/SFileAddFile.cpp | 6 +- src/SFileOpenFileEx.cpp | 4 +- src/StormCommon.h | 3 +- test/StormTest.cpp | 241 ++++++++++++++++++++++++++++++++---------------- 6 files changed, 169 insertions(+), 93 deletions(-) diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp index f90c009..4b2bd6d 100644 --- a/src/SBaseCommon.cpp +++ b/src/SBaseCommon.cpp @@ -1833,7 +1833,6 @@ void CalculateDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE md5_ha md5_done(&md5_state, md5_hash); } - //----------------------------------------------------------------------------- // Swapping functions diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp index 7d7a401..58e259f 100644 --- a/src/SBaseFileTable.cpp +++ b/src/SBaseFileTable.cpp @@ -1967,7 +1967,7 @@ void FreeBetTable(TMPQBetTable * pBetTable) //----------------------------------------------------------------------------- // Support for file table -TFileEntry * GetFileEntryLocale2(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex) +TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex) { TMPQHash * pHash; DWORD dwFileIndex; @@ -1998,11 +1998,6 @@ TFileEntry * GetFileEntryLocale2(TMPQArchive * ha, const char * szFileName, LCID return NULL; } -TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale) -{ - return GetFileEntryLocale2(ha, szFileName, lcLocale, NULL); -} - TFileEntry * GetFileEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex) { TMPQHash * pHash; diff --git a/src/SFileAddFile.cpp b/src/SFileAddFile.cpp index f71434e..a65244e 100644 --- a/src/SFileAddFile.cpp +++ b/src/SFileAddFile.cpp @@ -423,7 +423,7 @@ DWORD SFileAddFile_Init( if(!(dwFlags & MPQ_FILE_COMPRESS_MASK)) dwFlags &= ~MPQ_FILE_SECTOR_CRC; - // Fix Key is not allowed if the file is not enrypted + // Fix Key is not allowed if the file is not encrypted if(!(dwFlags & MPQ_FILE_ENCRYPTED)) dwFlags &= ~MPQ_FILE_FIX_KEY; @@ -441,7 +441,7 @@ DWORD SFileAddFile_Init( if(dwErrCode == ERROR_SUCCESS) { // Check if the file already exists in the archive - pFileEntry = GetFileEntryExact(ha, szFileName, lcLocale, &dwHashIndex); + pFileEntry = GetFileEntryLocale(ha, szFileName, lcLocale, &dwHashIndex); if(pFileEntry != NULL) { if(dwFlags & MPQ_FILE_REPLACEEXISTING) @@ -1285,7 +1285,7 @@ bool WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale) } // We have to check if the file+locale is not already there - pFileEntry = GetFileEntryExact(ha, hf->pFileEntry->szFileName, lcNewLocale, NULL); + pFileEntry = GetFileEntryLocale(ha, hf->pFileEntry->szFileName, lcNewLocale, NULL); if(pFileEntry != NULL) { SetLastError(ERROR_ALREADY_EXISTS); diff --git a/src/SFileOpenFileEx.cpp b/src/SFileOpenFileEx.cpp index d77f25e..96d8cfc 100644 --- a/src/SFileOpenFileEx.cpp +++ b/src/SFileOpenFileEx.cpp @@ -263,7 +263,7 @@ bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearch // If this MPQ has no patches, open the file from this MPQ directly if(ha->haPatch == NULL || dwSearchScope == SFILE_OPEN_BASE_FILE) { - pFileEntry = GetFileEntryLocale2(ha, szFileName, g_lcFileLocale, &dwHashIndex); + pFileEntry = GetFileEntryLocale(ha, szFileName, g_lcFileLocale, &dwHashIndex); } // If this MPQ is a patched archive, open the file as patched @@ -278,7 +278,7 @@ bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearch // This open option is reserved for opening MPQ internal listfile. // No argument validation. Tries to open file with neutral locale first, // then any other available. - pFileEntry = GetFileEntryLocale2(ha, szFileName, 0, &dwHashIndex); + pFileEntry = GetFileEntryLocale(ha, szFileName, 0, &dwHashIndex); break; case SFILE_OPEN_LOCAL_FILE: diff --git a/src/StormCommon.h b/src/StormCommon.h index 865d975..7ff55e8 100644 --- a/src/StormCommon.h +++ b/src/StormCommon.h @@ -282,8 +282,7 @@ TMPQBetTable * CreateBetTable(DWORD dwMaxFileCount); void FreeBetTable(TMPQBetTable * pBetTable); // Functions for finding files in the file table -TFileEntry * GetFileEntryLocale2(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex); -TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale); +TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex = NULL); TFileEntry * GetFileEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex); // Allocates file name in the file entry diff --git a/test/StormTest.cpp b/test/StormTest.cpp index 78eb94b..c4b3179 100644 --- a/test/StormTest.cpp +++ b/test/StormTest.cpp @@ -1386,80 +1386,20 @@ static TFileData * LoadLocalFile(TLogHelper * pLogger, LPCTSTR szFileName, bool return pFileData; } -static DWORD CompareTwoLocalFilesRR( - TLogHelper * pLogger, - TFileStream * pStream1, // Master file - TFileStream * pStream2, // Mirror file - int nIterations) // Number of iterations +static DWORD LoadLocalFileMD5(TLogHelper * pLogger, LPCTSTR szLocalFileName, LPBYTE md5_file_local) { - ULONGLONG RandomNumber = 0x12345678; // We need pseudo-random number that will repeat each run of the program - ULONGLONG RandomSeed; - ULONGLONG ByteOffset; - ULONGLONG FileSize1 = 1; - ULONGLONG FileSize2 = 2; - DWORD BytesToRead; - DWORD Difference; - LPBYTE pbBuffer1; - LPBYTE pbBuffer2; - DWORD cbBuffer = 0x100000; - DWORD dwErrCode = ERROR_SUCCESS; + TFileData * pFileData; - // Compare file sizes - FileStream_GetSize(pStream1, &FileSize1); - FileStream_GetSize(pStream2, &FileSize2); - if(FileSize1 != FileSize2) + // Load the local file to memory + if((pFileData = LoadLocalFile(pLogger, szLocalFileName, true)) == NULL) { - pLogger->PrintMessage("The files have different size"); - return ERROR_CAN_NOT_COMPLETE; + return pLogger->PrintError(_T("The file \"%s\" could not be loaded"), szLocalFileName); } - // Allocate both buffers - pbBuffer1 = STORM_ALLOC(BYTE, cbBuffer); - pbBuffer2 = STORM_ALLOC(BYTE, cbBuffer); - if(pbBuffer1 && pbBuffer2) - { - // Perform many random reads - for(int i = 0; i < nIterations; i++) - { - // Generate psudo-random offsrt and data size - ByteOffset = (RandomNumber % FileSize1); - BytesToRead = (DWORD)(RandomNumber % cbBuffer); - - // Show the progress message - pLogger->PrintProgress("Comparing file: Offset: " I64u_a ", Length: %u", ByteOffset, BytesToRead); - - // Only perform read if the byte offset is below - if(ByteOffset < FileSize1) - { - if((ByteOffset + BytesToRead) > FileSize1) - BytesToRead = (DWORD)(FileSize1 - ByteOffset); - - memset(pbBuffer1, 0xEE, cbBuffer); - memset(pbBuffer2, 0xAA, cbBuffer); - - FileStream_Read(pStream1, &ByteOffset, pbBuffer1, BytesToRead); - FileStream_Read(pStream2, &ByteOffset, pbBuffer2, BytesToRead); - - if(!CompareBlocks(pbBuffer1, pbBuffer2, BytesToRead, &Difference)) - { - pLogger->PrintMessage("Difference at %u (Offset " I64X_a ", Length %X)", Difference, ByteOffset, BytesToRead); - dwErrCode = ERROR_FILE_CORRUPT; - break; - } - - // Shuffle the random number - memcpy(&RandomSeed, pbBuffer1, sizeof(RandomSeed)); - RandomNumber = ((RandomNumber >> 0x11) | (RandomNumber << 0x29)) ^ (RandomNumber + RandomSeed); - } - } - } - - // Free both buffers - if(pbBuffer2 != NULL) - STORM_FREE(pbBuffer2); - if(pbBuffer1 != NULL) - STORM_FREE(pbBuffer1); - return dwErrCode; + // Calculate the hash + CalculateDataBlockHash(pFileData->FileData, pFileData->dwFileSize, md5_file_local); + STORM_FREE(pFileData); + return ERROR_SUCCESS; } static TFileData * LoadMpqFile(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName, LCID lcLocale = 0, bool bIgnoreOpedwErrCodes = false) @@ -1564,6 +1504,96 @@ static TFileData * LoadMpqFile(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileN return pFileData; } +static DWORD LoadMpqFileMD5(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szArchivedName, LPBYTE md5_file_in_mpq1) +{ + TFileData * pFileData; + + // Load the MPQ to memory + if((pFileData = LoadMpqFile(pLogger, hMpq, szArchivedName)) == NULL) + return pLogger->PrintError("The file \"%s\" is not in the archive", szArchivedName); + + // Calculate hash + CalculateDataBlockHash(pFileData->FileData, pFileData->dwFileSize, md5_file_in_mpq1); + STORM_FREE(pFileData); + return ERROR_SUCCESS; +} + +static DWORD CompareTwoLocalFilesRR( + TLogHelper * pLogger, + TFileStream * pStream1, // Master file + TFileStream * pStream2, // Mirror file + int nIterations) // Number of iterations +{ + ULONGLONG RandomNumber = 0x12345678; // We need pseudo-random number that will repeat each run of the program + ULONGLONG RandomSeed; + ULONGLONG ByteOffset; + ULONGLONG FileSize1 = 1; + ULONGLONG FileSize2 = 2; + DWORD BytesToRead; + DWORD Difference; + LPBYTE pbBuffer1; + LPBYTE pbBuffer2; + DWORD cbBuffer = 0x100000; + DWORD dwErrCode = ERROR_SUCCESS; + + // Compare file sizes + FileStream_GetSize(pStream1, &FileSize1); + FileStream_GetSize(pStream2, &FileSize2); + if(FileSize1 != FileSize2) + { + pLogger->PrintMessage("The files have different size"); + return ERROR_CAN_NOT_COMPLETE; + } + + // Allocate both buffers + pbBuffer1 = STORM_ALLOC(BYTE, cbBuffer); + pbBuffer2 = STORM_ALLOC(BYTE, cbBuffer); + if(pbBuffer1 && pbBuffer2) + { + // Perform many random reads + for(int i = 0; i < nIterations; i++) + { + // Generate psudo-random offsrt and data size + ByteOffset = (RandomNumber % FileSize1); + BytesToRead = (DWORD)(RandomNumber % cbBuffer); + + // Show the progress message + pLogger->PrintProgress("Comparing file: Offset: " I64u_a ", Length: %u", ByteOffset, BytesToRead); + + // Only perform read if the byte offset is below + if(ByteOffset < FileSize1) + { + if((ByteOffset + BytesToRead) > FileSize1) + BytesToRead = (DWORD)(FileSize1 - ByteOffset); + + memset(pbBuffer1, 0xEE, cbBuffer); + memset(pbBuffer2, 0xAA, cbBuffer); + + FileStream_Read(pStream1, &ByteOffset, pbBuffer1, BytesToRead); + FileStream_Read(pStream2, &ByteOffset, pbBuffer2, BytesToRead); + + if(!CompareBlocks(pbBuffer1, pbBuffer2, BytesToRead, &Difference)) + { + pLogger->PrintMessage("Difference at %u (Offset " I64X_a ", Length %X)", Difference, ByteOffset, BytesToRead); + dwErrCode = ERROR_FILE_CORRUPT; + break; + } + + // Shuffle the random number + memcpy(&RandomSeed, pbBuffer1, sizeof(RandomSeed)); + RandomNumber = ((RandomNumber >> 0x11) | (RandomNumber << 0x29)) ^ (RandomNumber + RandomSeed); + } + } + } + + // Free both buffers + if(pbBuffer2 != NULL) + STORM_FREE(pbBuffer2); + if(pbBuffer1 != NULL) + STORM_FREE(pbBuffer1); + return dwErrCode; +} + static bool CompareTwoFiles(TLogHelper * pLogger, TFileData * pFileData1, TFileData * pFileData2) { // Compare the file size @@ -4172,21 +4202,35 @@ static DWORD TestModifyArchive_ReplaceFile(LPCTSTR szMpqPlainName, LPCTSTR szFil char szArchivedName[MAX_PATH]; size_t nOffset = 0; DWORD dwErrCode; + BYTE md5_file_in_mpq1[MD5_DIGEST_SIZE]; + BYTE md5_file_in_mpq2[MD5_DIGEST_SIZE]; + BYTE md5_file_in_mpq3[MD5_DIGEST_SIZE]; + BYTE md5_file_local[MD5_DIGEST_SIZE]; + + // Get the name of archived file + if(!_tcsnicmp(szFileName, _T("AddFile-"), 8)) + nOffset = 8; + StringCopy(szArchivedName, _countof(szArchivedName), szFileName + nOffset); + CreateFullPathName(szLocalFileName, _countof(szLocalFileName), szMpqSubDir, szFileName); // Open an existing archive dwErrCode = OpenExistingArchiveWithCopy(&Logger, szMpqPlainName, szMpqPlainName, &hMpq); - // Add the given file + // Open the file, load to memory, calculate hash if(dwErrCode == ERROR_SUCCESS) { - // Get the name of archived file - if(!_tcsnicmp(szFileName, _T("AddFile-"), 8)) - nOffset = 8; - StringCopy(szArchivedName, _countof(szArchivedName), szFileName + nOffset); + dwErrCode = LoadMpqFileMD5(&Logger, hMpq, szArchivedName, md5_file_in_mpq1); + } - // Create the local file name - CreateFullPathName(szLocalFileName, _countof(szLocalFileName), szMpqSubDir, szFileName); + // Open the local file, calculate hash + if(dwErrCode == ERROR_SUCCESS) + { + dwErrCode = LoadLocalFileMD5(&Logger, szLocalFileName, md5_file_local); + } + // Add the given file + if(dwErrCode == ERROR_SUCCESS) + { // Add the file to MPQ dwErrCode = AddLocalFileToMpq(&Logger, hMpq, szArchivedName, @@ -4196,7 +4240,30 @@ static DWORD TestModifyArchive_ReplaceFile(LPCTSTR szMpqPlainName, LPCTSTR szFil true); } - // Reopen the MPQ and compact it + // Load the file from the MPQ again and compare both MD5's + if(dwErrCode == ERROR_SUCCESS) + { + // Load the file from the MPQ again + dwErrCode = LoadMpqFileMD5(&Logger, hMpq, szArchivedName, md5_file_in_mpq2); + if(dwErrCode == ERROR_SUCCESS) + { + // New MPQ file must be different from the old one + if(!memcmp(md5_file_in_mpq2, md5_file_in_mpq1, MD5_DIGEST_SIZE)) + { + Logger.PrintError("Data mismatch after adding the file \"%s\"", szArchivedName); + dwErrCode = ERROR_CHECKSUM_ERROR; + } + + // New MPQ file must be identical to the local one + if(memcmp(md5_file_in_mpq2, md5_file_local, MD5_DIGEST_SIZE)) + { + Logger.PrintError("Data mismatch after adding the file \"%s\"", szArchivedName); + dwErrCode = ERROR_CHECKSUM_ERROR; + } + } + } + + // Compact the MPQ if(dwErrCode == ERROR_SUCCESS) { // Compact the archive @@ -4210,13 +4277,26 @@ static DWORD TestModifyArchive_ReplaceFile(LPCTSTR szMpqPlainName, LPCTSTR szFil SFileCloseArchive(hMpq); } - // Try to open the archive again + // Try to open the archive again. Ignore the previous errors if(dwErrCode == ERROR_SUCCESS) { - CreateFullPathName(szLocalFileName, _countof(szLocalFileName), NULL, szMpqPlainName); dwErrCode = OpenExistingArchive(&Logger, szLocalFileName, 0, &hMpq); if(dwErrCode == ERROR_SUCCESS) + { + // Load the file from the MPQ again + dwErrCode = LoadMpqFileMD5(&Logger, hMpq, szArchivedName, md5_file_in_mpq3); + if(dwErrCode == ERROR_SUCCESS) + { + // New MPQ file must be the same like the local one + if(!memcmp(md5_file_in_mpq3, md5_file_local, MD5_DIGEST_SIZE)) + { + Logger.PrintError("Data mismatch after adding the file \"%s\"", szArchivedName); + dwErrCode = ERROR_CHECKSUM_ERROR; + } + } + SFileCloseArchive(hMpq); + } } return dwErrCode; @@ -4586,6 +4666,9 @@ int _tmain(int argc, TCHAR * argv[]) if(dwErrCode == ERROR_SUCCESS) dwErrCode = TestModifyArchive_ReplaceFile(_T("MPQ_2014_v4_Base.StormReplay"), _T("AddFile-replay.message.events")); + if(dwErrCode == ERROR_SUCCESS) + dwErrCode = TestModifyArchive_ReplaceFile(_T("MPQ_2022_v1_v4.329.w3x"), _T("AddFile-war3map.j")); + #ifdef _MSC_VER _CrtDumpMemoryLeaks(); #endif // _MSC_VER -- cgit v1.2.3