diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/CMakeLists.txt | 20 | ||||
| -rwxr-xr-x | test/StormTest.cpp | 215 | ||||
| -rw-r--r-- | test/TLogHelper.cpp | 141 | ||||
| -rw-r--r-- | test/stormlib-test-001.txt | 41 |
4 files changed, 305 insertions, 112 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..80c64c4 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.10) + +set(TEST_SRC_FILES + StormTest.cpp +) + +# Option to use the legacy hardcoded paths +option(STORMTEST_USE_OLD_PATHS "Use hardcoded OS-specific default paths for WORK_PATH_ROOT" ON) + +if(NOT STORMTEST_USE_OLD_PATHS) + set(WORK_PATH_ROOT "${CMAKE_CURRENT_BINARY_DIR}/work") + add_compile_definitions(WORK_PATH_ROOT="${WORK_PATH_ROOT}") +endif() + +find_package(ALSA REQUIRED) +add_executable(StormLib_test ${TEST_SRC_FILES}) +target_link_libraries(StormLib_test storm ALSA::ALSA) +install(TARGETS StormLib_test RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + +add_test(NAME StormLib_test COMMAND StormLib_test) diff --git a/test/StormTest.cpp b/test/StormTest.cpp index 5a442a5..bd07c88 100755 --- a/test/StormTest.cpp +++ b/test/StormTest.cpp @@ -1,4 +1,4 @@ -/*****************************************************************************/
+/*****************************************************************************/
/* StormTest.cpp Copyright (c) Ladislav Zezula 2003 */
/*---------------------------------------------------------------------------*/
/* Test module for StormLib */
@@ -155,16 +155,18 @@ typedef struct _WAVE_FILE_HEADER //------------------------------------------------------------------------------
// Local variables
-#ifdef STORMLIB_WINDOWS
-#define WORK_PATH_ROOT _T("\\Multimedia\\MPQs")
-#endif
+#ifndef WORK_PATH_ROOT
+ #ifdef STORMLIB_WINDOWS
+ #define WORK_PATH_ROOT _T("\\Multimedia\\MPQs")
+ #endif
-#ifdef STORMLIB_LINUX
-#define WORK_PATH_ROOT "/media/ladik/MPQs"
-#endif
+ #ifdef STORMLIB_LINUX
+ #define WORK_PATH_ROOT "/media/ladik/MPQs"
+ #endif
-#ifdef STORMLIB_HAIKU
-#define WORK_PATH_ROOT "~/StormLib/test"
+ #ifdef STORMLIB_HAIKU
+ #define WORK_PATH_ROOT "~/StormLib/test"
+ #endif
#endif
// Definition of the path separator
@@ -353,6 +355,13 @@ const char * GetFileText(PFILE_DATA pFileData) return szFileText;
}
+#ifdef STORMLIB_LINUX
+static void alsa_silent_error_handler(const char * file, int line, const char * function, int err, const char * fmt, ...)
+{
+ // Suppress ALSA error output, so do nothing
+}
+#endif
+
static void PlayWaveSound(PFILE_DATA pFileData)
{
#ifdef STORMLIB_WINDOWS
@@ -365,6 +374,10 @@ static void PlayWaveSound(PFILE_DATA pFileData) snd_pcm_t *pcm_handle;
unsigned int bitrate = pHeader->dwSamplesPerSec;
+ // Suppress ALSA error printing
+ snd_lib_error_set_handler(alsa_silent_error_handler);
+
+ // Open the default sound device and play the sound
if(snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, 0) >= 0)
{
snd_pcm_format_t format = (pHeader->wBitsPerSample == 16) ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_S8;
@@ -612,7 +625,7 @@ static DWORD CalculateFileHash(TLogHelper * pLogger, LPCTSTR szFullPath, LPTSTR cbBytesToRead = ((FileSize - ByteOffset) > cbFileBlock) ? cbFileBlock : (DWORD)(FileSize - ByteOffset);
if(!FileStream_Read(pStream, &ByteOffset, pbFileBlock, cbBytesToRead))
{
- dwErrCode = GetLastError();
+ dwErrCode = SErrGetLastError();
break;
}
@@ -856,7 +869,7 @@ static DWORD ForEachFile_VerifyFileHash(LPCTSTR szFullPath, void * lpContext) StringCopy(szHashTextA, _countof(szHashTextA), szHashText);
if(_strnicmp(szHashTextA, GetFileText(pFileData), (SHA256_DIGEST_SIZE * 2)))
{
- SetLastError(dwErrCode = ERROR_FILE_CORRUPT);
+ SErrSetLastError(dwErrCode = ERROR_FILE_CORRUPT);
pLogger->PrintError(_T("File hash check failed: %s"), szFullPath);
}
}
@@ -1038,7 +1051,7 @@ static DWORD GetFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileN }
else
{
- if(GetLastError() != ERROR_FILE_DELETED)
+ if(SErrGetLastError() != ERROR_FILE_DELETED)
{
pLogger->PrintError("Open failed: %s", szFileName);
}
@@ -1047,6 +1060,25 @@ static DWORD GetFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileN return nPatchCount;
}
+static DWORD SetLocaleForFileOperations(HANDLE hMpq, LPCSTR szFileName, LCID lcLocale)
+{
+ HANDLE hFile = NULL;
+ DWORD dwErrCode = ERROR_SUCCESS;
+
+ if(SFileOpenFileEx(hMpq, szFileName, 0, &hFile))
+ {
+ if(!SFileSetFileLocale(hFile, lcLocale))
+ dwErrCode = SErrGetLastError();
+ SFileSetLocale(lcLocale);
+ SFileCloseFile(hFile);
+ }
+ else
+ {
+ dwErrCode = SErrGetLastError();
+ }
+ return dwErrCode;
+}
+
static DWORD VerifyFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName, DWORD dwExpectedPatchCount)
{
DWORD dwPatchCount = 0;
@@ -1161,7 +1193,7 @@ static DWORD WriteMpqUserDataHeader( UserData.dwHeaderOffs = (dwByteCount + sizeof(TMPQUserData));
UserData.cbUserDataHeader = dwByteCount / 2;
if(!FileStream_Write(pStream, &ByteOffset, &UserData, sizeof(TMPQUserData)))
- dwErrCode = GetLastError();
+ dwErrCode = SErrGetLastError();
return dwErrCode;
}
@@ -1195,7 +1227,7 @@ static DWORD WriteFileData( // Write the data
if(!FileStream_Write(pStream, &ByteOffset, pbDataBuffer, cbToWrite))
{
- dwErrCode = GetLastError();
+ dwErrCode = SErrGetLastError();
break;
}
@@ -1233,14 +1265,14 @@ static DWORD CopyFileData( BytesToRead = ((EndOffset - ByteOffset) > BlockLength) ? BlockLength : (DWORD)(EndOffset - ByteOffset);
if(!FileStream_Read(pStream1, &ByteOffset, pbCopyBuffer, BytesToRead))
{
- dwErrCode = GetLastError();
+ dwErrCode = SErrGetLastError();
break;
}
// Write to the destination file
if(!FileStream_Write(pStream2, NULL, pbCopyBuffer, BytesToRead))
{
- dwErrCode = GetLastError();
+ dwErrCode = SErrGetLastError();
break;
}
@@ -1434,9 +1466,12 @@ static DWORD LoadMpqFile(TLogHelper & Logger, HANDLE hMpq, LPCSTR szFileName, LC DWORD dwBytesRead;
DWORD dwCrc32 = 0;
DWORD dwErrCode = ERROR_SUCCESS;
+ TCHAR szSafeName[1024];
- // Do nothing if the file name is invalid
- Logger.PrintProgress("Loading file %s ...", GetShortPlainName(szFileName));
+ // Print the file name to the console.
+ // Prevent bad UTF-8 sequences to go through
+ SMemUTF8ToFileName(szSafeName, _countof(szSafeName), szFileName, NULL, 0, NULL);
+ Logger.PrintProgress(_T("Loading file %s ..."), GetShortPlainName(szSafeName));
#if defined(_MSC_VER) && defined(_DEBUG)
//if(!_stricmp(szFileName, "(signature)"))
@@ -1514,7 +1549,7 @@ static DWORD LoadMpqFile(TLogHelper & Logger, HANDLE hMpq, LPCSTR szFileName, LC }
else
{
- if((dwSearchFlags & SEARCH_FLAG_IGNORE_ERRORS) == 0 && GetLastError() != ERROR_FILE_DELETED)
+ if((dwSearchFlags & SEARCH_FLAG_IGNORE_ERRORS) == 0 && SErrGetLastError() != ERROR_FILE_DELETED)
{
dwErrCode = Logger.PrintError("Open failed: %s", szFileName);
}
@@ -1658,7 +1693,7 @@ static DWORD SearchArchive( hFind = SFileFindFirstFile(hMpq, "*", &sf, szListFile);
if(hFind == NULL)
{
- dwErrCode = GetLastError();
+ dwErrCode = SErrGetLastError();
dwErrCode = (dwErrCode == ERROR_NO_MORE_FILES) ? ERROR_SUCCESS : dwErrCode;
return dwErrCode;
}
@@ -1861,11 +1896,11 @@ static DWORD OpenExistingArchive(TLogHelper * pLogger, LPCTSTR szFullPath, DWORD pLogger->PrintProgress(_T("Opening archive %s ..."), GetShortPlainName(szFullPath));
if(!SFileOpenArchive(szFullPath, 0, dwOpenFlags, &hMpq))
{
- switch(dwErrCode = GetLastError())
+ switch(dwErrCode = SErrGetLastError())
{
// case ERROR_BAD_FORMAT: // If the error is ERROR_BAD_FORMAT, try to open with MPQ_OPEN_FORCE_MPQ_V1
// bReopenResult = SFileOpenArchive(szMpqName, 0, dwFlags | MPQ_OPEN_FORCE_MPQ_V1, &hMpq);
-// dwErrCode = (bReopenResult == false) ? GetLastError() : ERROR_SUCCESS;
+// dwErrCode = (bReopenResult == false) ? SErrGetLastError() : ERROR_SUCCESS;
// break;
case ERROR_AVI_FILE: // Ignore the error if it's an AVI file or if the file is incomplete
@@ -1955,7 +1990,7 @@ static DWORD AddFileToMpq( }
else
{
- dwErrCode = GetLastError();
+ dwErrCode = SErrGetLastError();
}
// Check the expected error code
@@ -2001,7 +2036,7 @@ static DWORD AddLocalFileToMpq( {
if(bMustSucceed)
return pLogger->PrintError("Failed to add the file %s", szArchivedName);
- return GetLastError();
+ return SErrGetLastError();
}
// Verify the file unless it was lossy compression
@@ -2028,7 +2063,7 @@ static DWORD RemoveMpqFile(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName, // Perform the deletion
if(!SFileRemoveFile(hMpq, szFileName, 0))
- dwErrCode = GetLastError();
+ dwErrCode = SErrGetLastError();
if(dwErrCode != dwExpectedError)
return pLogger->PrintError("Unexpected result from SFileRemoveFile(%s)", szFileName);
@@ -2054,7 +2089,7 @@ static void TestGetFileInfo( // Call the get file info
bResult = SFileGetFileInfo(hMpqOrFile, InfoClass, pvFileInfo, cbFileInfo, pcbLengthNeeded);
if(!bResult)
- dwErrCode = GetLastError();
+ dwErrCode = SErrGetLastError();
// Check the expected results
if(bResult != bExpectedResult)
@@ -2753,7 +2788,7 @@ static DWORD TestOpenArchive( // Reset error code, if the failure is expected
if((dwErrCode != ERROR_SUCCESS || hMpq == NULL) && (dwFlags & TFLG_WILL_FAIL))
- SetLastError(dwErrCode = ERROR_SUCCESS);
+ SErrSetLastError(dwErrCode = ERROR_SUCCESS);
// Cleanup and exit
if(hMpq != NULL)
@@ -3052,6 +3087,61 @@ static DWORD TestCreateArchive(const TEST_INFO2 & TestInfo) return TestCreateArchive(szPlainNameT, TestInfo.szName2, TestInfo.dwFlags);
}
+static DWORD TestRenameFile(LPCTSTR szPlainName)
+{
+ TLogHelper Logger("TestRenameFile", szPlainName);
+ LPCSTR szSourceFile = "war3map.mmp";
+ LPCSTR szTargetFile = "war3map.wts";
+ HANDLE hMpq = NULL;
+ DWORD dwErrCode;
+ DWORD dwFailed = 0;
+ LCID LCID_RURU = 0x0419;
+ LCID LCID_ESES = 0x040A;
+
+ // Create copy of the archive and open it
+ dwErrCode = OpenExistingArchiveWithCopy(&Logger, szPlainName, szPlainName, &hMpq);
+ if(dwErrCode == ERROR_SUCCESS)
+ {
+ // Try to rename an existing file to "war3map.wts".
+ // This must fail because the file already exists.
+ if(SFileRenameFile(hMpq, szSourceFile, szTargetFile))
+ dwFailed++;
+
+ // Now change locale of an existing file to Russian
+ if(SetLocaleForFileOperations(hMpq, szSourceFile, LCID_RURU) != ERROR_SUCCESS)
+ dwFailed++;
+
+ // The rename should work now
+ if(!SFileRenameFile(hMpq, szSourceFile, szTargetFile))
+ dwFailed++;
+
+ // Changing the file locale to Neutral should fail now,
+ // because such file already exists
+ if(SetLocaleForFileOperations(hMpq, szTargetFile, 0) != ERROR_ALREADY_EXISTS)
+ dwFailed++;
+
+ // Pick another source file
+ szSourceFile = "war3map.shd";
+
+ // Change the file locale to Spain
+ if(SetLocaleForFileOperations(hMpq, szSourceFile, LCID_ESES) != ERROR_SUCCESS)
+ dwFailed++;
+
+ // This rename should also work, because there is no target file with Spanish locale
+ if(!SFileRenameFile(hMpq, szSourceFile, szTargetFile))
+ dwFailed++;
+
+ // Evaluate the result
+ if(dwFailed != 0)
+ dwErrCode = ERROR_CAN_NOT_COMPLETE;
+ SFileCloseArchive(hMpq);
+ }
+
+ // Restore the original file locale
+ SFileSetLocale(LANG_NEUTRAL);
+ return dwErrCode;
+}
+
static DWORD TestCreateArchive_TestGaps(LPCTSTR szPlainName)
{
TLogHelper Logger("TestCreateGaps", szPlainName);
@@ -3087,7 +3177,7 @@ static DWORD TestCreateArchive_TestGaps(LPCTSTR szPlainName) SFileCloseFile(hFile);
}
else
- dwErrCode = GetLastError();
+ dwErrCode = SErrGetLastError();
}
}
@@ -3106,7 +3196,7 @@ static DWORD TestCreateArchive_TestGaps(LPCTSTR szPlainName) SFileCloseFile(hFile);
}
else
- dwErrCode = GetLastError();
+ dwErrCode = SErrGetLastError();
}
// Now check the positions
@@ -3317,6 +3407,7 @@ static DWORD TestCreateArchive_FileFlagTest(LPCTSTR szPlainName) // Create paths for local file to be added
CreateFullPathName(szFileName1, _countof(szFileName1), szDataFileDir, _T("new-file.exe"));
CreateFullPathName(szFileName2, _countof(szFileName2), szDataFileDir, _T("new-file.bin"));
+ SFileSetLocale(LANG_NEUTRAL);
// Create an empty file that will serve as holder for the MPQ
dwErrCode = CreateEmptyFile(&Logger, szPlainName, 0x100000, szFullPath);
@@ -3864,30 +3955,40 @@ static DWORD TestUtf8Conversions(const BYTE * szTestString, const TCHAR * szList static void Test_PlayingSpace()
{
- HANDLE hFile = NULL;
- HANDLE hMpq = NULL;
+/*
+ HANDLE hMpq;
+ HANDLE hFile;
+ LPBYTE pbData;
+ DWORD dwFileSize = 529298;
+ DWORD dwBytesRead = 0;
- if(SFileOpenArchive(_T("E:\\DIABDAT.MPQ"), 0, 0, &hMpq))
+ if(SFileOpenArchive(_T("e:\\Ladik\\Incoming\\31525686D3A39C6B5CA4B2979367B809.w3x"), 0, 0, &hMpq))
{
- if(SFileOpenFileEx(hMpq, "d1221a.mpq", 0, &hFile))
+ if(SFileOpenFileEx(hMpq, "(listfile)", 0, &hFile))
{
- DWORD dwBytesRead = 0;
- BYTE Buffer[1024];
-
- SFileReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead, NULL);
+ if((pbData = STORM_ALLOC(BYTE, dwFileSize)) != NULL)
+ {
+ SFileReadFile(hFile, pbData, dwFileSize, &dwBytesRead, NULL);
+ STORM_FREE(pbData);
+ }
SFileCloseFile(hFile);
}
SFileCloseArchive(hMpq);
}
+*/
}
//-----------------------------------------------------------------------------
// Tables
static LPCTSTR szSigned1 = _T("STANDARD.SNP");
-static LPCTSTR szSigned2 = _T("War2Patch_202.exe");
-static LPCTSTR szSigned3 = _T("WoW-1.2.3.4211-enUS-patch.exe");
+static LPCTSTR szSigned2 = _T("StarDat.mpq");
+static LPCTSTR szSigned3 = _T("War2Patch_202.exe");
static LPCTSTR szSigned4 = _T("(10)DustwallowKeys.w3m");
+static LPCTSTR szSigned5 = _T("WoW-1.2.3.4211-enUS-patch.exe");
+static LPCTSTR szSigned6 = _T("WoW-1.11.2.5464-to-1.12.0.5595-enUS-patch.exe");
+static LPCTSTR szSigned7 = _T("WoW-3.0.1.8337-to-3.0.1.8392-enGB-patch.exe");
+static LPCTSTR szSigned8 = _T("wow-final.MPQ");
static LPCTSTR szDiabdatMPQ = _T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ");
@@ -4138,7 +4239,7 @@ static const TEST_INFO1 TestList_MasterMirror[] = static const TEST_INFO1 Test_OpenMpqs[] =
{
- // PoC's by Gabe Sherman from FuturesLab
+ // PoC's by Gabe Sherman, tinh0, Zao Yang
{_T("pocs/MPQ_2024_01_HeapOverrun.mpq"), NULL, "7008f95dcbc4e5d840830c176dec6969", 14},
{_T("pocs/MPQ_2024_02_StackOverflow.mpq"), NULL, "7093fcbcc9674b3e152e74e8e8a937bb", 4},
{_T("pocs/MPQ_2024_03_TooBigAlloc.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
@@ -4151,6 +4252,13 @@ static const TEST_INFO1 Test_OpenMpqs[] = {_T("pocs/MPQ_2024_10_HuffDecompressError.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
{_T("pocs/MPQ_2024_10_SparseDecompressError.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
{_T("pocs/MPQ_2024_11_HiBlockTablePosInvalid.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
+ {_T("pocs/MPQ_2025_01_SectorTableBeyondEOF.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
+ {_T("pocs/MPQ_2025_02_SectorOffsetSizeNotAligned.mpq"), NULL, "0cc175b9c0f1b6a831c399e269772661", TFLG_WILL_FAIL},
+ {_T("pocs/MPQ_2025_03_InvalidPatchInfo.mpq"), NULL, "93b885adfe0da089cdf634904fd59f71", TFLG_WILL_FAIL},
+ {_T("pocs/MPQ_2025_04_InvalidArchiveSize64.mpq"), NULL, "--------------------------------", TFLG_WILL_FAIL},
+ {_T("pocs/MPQ_2025_05_AddFileError.mpq"), NULL, "ce9b8afed4221a53663d391f10691ba6", TFLG_WILL_FAIL},
+ {_T("pocs/MPQ_2025_06_BadHashTableSize.mpq"), NULL, "00000000000000000000000000000000", TFLG_WILL_FAIL},
+ {_T("pocs/MPQ_2025_07_BadHetTableSize.mpq"), NULL, "00000000000000000000000000000000", TFLG_WILL_FAIL},
// Correct or damaged archives
{_T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"), NULL, "554b538541e42170ed41cb236483489e", 2910, &TwoFilesD1}, // Base MPQ from Diablo 1
@@ -4167,7 +4275,6 @@ static const TEST_INFO1 Test_OpenMpqs[] = {_T("MPQ_2002_v1_BlockTableCut.MPQ"), NULL, "a9499ab74d939303d8cda7c397c36275", 287}, // Truncated archive
{_T("MPQ_2010_v2_HasUserData.s2ma"), NULL, "feff9e2c86db716b6ff5ffc906181200", 52}, // MPQ that actually has user data
{_T("MPQ_2014_v1_AttributesOneEntryLess.w3x"), NULL, "90451b7052eb0f1d6f4bf69b2daff7f5", 116}, // Warcraft III map whose "(attributes)" file has (BlockTableSize-1) entries
- {_T("MPQ_2020_v1_AHF04patch.mix"), NULL, "d3c6aac48bc12813ef5ce4ad113e58bf", 2891}, // MIX file
{_T("MPQ_2010_v3_expansion-locale-frFR.MPQ"), NULL, "0c8fc921466f07421a281a05fad08b01", 53}, // MPQ archive v 3.0 (the only one I know)
{_T("mpqe-file://MPQ_2011_v2_EncryptedMpq.MPQE"), NULL, "10e4dcdbe95b7ad731c563ec6b71bc16", 82}, // Encrypted archive from Starcraft II installer
{_T("part-file://MPQ_2010_v2_HashTableCompressed.MPQ.part"),NULL, "d41d8cd98f00b204e9800998ecf8427e", 14263}, // Partial MPQ with compressed hash table
@@ -4178,10 +4285,10 @@ static const TEST_INFO1 Test_OpenMpqs[] = {_T("MPQ_2023_v1_Volcanis.scm"), NULL, "522c89ca96d6736427b01f7c80dd626f", 3}, // Map modified with unusual file compression: ZLIB+Huffman
{_T("MPQ_2023_v4_UTF8.s2ma"), NULL, "97b7a686650f3307d135e1d1b017a36a", 67}, // Map contaning files with Chinese names (UTF8-encoded)
{_T("MPQ_2023_v1_GreenTD.w3x"), NULL, "a8d91fc4e52d7c21ff7feb498c74781a", 2004}, // Corrupt sector checksum table in file #A0
+
{_T("MPQ_2023_v4_1F644C5A.SC2Replay"), NULL, "b225828ffbf5037553e6a1290187caab", 17}, // Corrupt patch info of the "(attributes)" file
{_T("<Chinese MPQ name>"), NULL, "67faeffd0c0aece205ac8b7282d8ad8e", 4697, &MpqUtf8}, // Chinese name of the MPQ
{_T("MPQ_2024_v1_BadUtf8_5.0.2.w3x"), NULL, "be34f9862758f021a1c6c77df3cd4f05", 6393, &LfBad1}, // Bad UTF-8 sequences in file names
-
// Protected archives
{_T("MPQ_2002_v1_ProtectedMap_InvalidUserData.w3x"), NULL, "b900364cc134a51ddeca21a13697c3ca", 79},
@@ -4215,11 +4322,13 @@ static const TEST_INFO1 Test_OpenMpqs[] = {_T("MPQ_2022_v1_OcOc_Bound_2.scx"), NULL, "25cad16a2fb4e883767a1f512fc1dce7", 16},
{_T("MPQ_2023_v1_Lusin2Rpg1.28.w3x"), NULL, "9c21352f06cf763fcf05e8a2691e6194", 10305, &HashVals},
{_T("MPQ_2024_v1_300TK2.09p.w3x"), NULL, "e442e3d2e7d457b9ba544544013b791f", 32588}, // Fake MPQ User data, fake MPQ header at offset 0x200
+ {_T("MPQ_2025_v1_Legion_TD_11_2d-BETA_2_TeamOZE.w3x"), NULL, "08efaaa11cafe5e8921a6f112b2fa458", 626}, // Fake MPQ User data, fake MPQ header at offset 0x200
// ASI plugins
- {_T("MPQ_2020_v1_HS0.1.asi"), NULL, "50cba7460a6e6d270804fb9776a7ec4f", 6022},
- {_T("MPQ_2022_v1_hs0.8.asi"), NULL, "6a40f733428001805bfe6e107ca9aec1", 11352}, // Items in hash table have platform = 0xFF
- {_T("MPQ_2022_v1_MoeMoeMod.asi"), NULL, "89b923c7cde06de48815844a5bbb0ec4", 2578},
+ {_T("mix-mpq/AHF04patch.mix"), NULL, "d3c6aac48bc12813ef5ce4ad113e58bf", 2891}, // MIX file
+ {_T("mix-mpq/hs0.1.asi"), NULL, "50cba7460a6e6d270804fb9776a7ec4f", 6022},
+ {_T("mix-mpq/hs0.8.asi"), NULL, "6a40f733428001805bfe6e107ca9aec1", 11352}, // Items in hash table have platform = 0xFF
+ {_T("mix-mpq/MoeMoeMod.asi"), NULL, "89b923c7cde06de48815844a5bbb0ec4", 2578},
// MPQ modifications from Chinese games
{_T("MPx_2013_v1_LongwuOnline.mpk"), NULL, "548f7db88284097f7e94c95a08c5bc24", 469}, // MPK archive from Longwu online
@@ -4244,11 +4353,14 @@ static const TEST_INFO1 Test_OpenMpqs[] = // Signed archives
{_T("MPQ_1997_v1_Diablo1_STANDARD.SNP"), szSigned1, "5ef18ef9a26b5704d8d46a344d976c89", 2 | TFLG_SIGCHECK_BEFORE},
- {_T("MPQ_1999_v1_WeakSignature.exe"), szSigned2, "c1084033d0bd5f7e2b9b78b600c0bba8", 24 | TFLG_SIGCHECK_BEFORE},
- {_T("MPQ_2003_v1_WeakSignatureEmpty.exe"), szSigned3, "97580f9f6d98ffc50191c2f07773e818", 12259 | TFLG_SIGCHECK_BEFORE},
+ {_T("MPQ_1998_v1_StarDat.mpq"), szSigned2, "2530cb937565fd41b1dc0443697096a2", 2925 | TFLG_SIGN_ARCHIVE | TFLG_SIGCHECK_AFTER},
+ {_T("MPQ_1999_v1_WeakSignature.exe"), szSigned3, "c1084033d0bd5f7e2b9b78b600c0bba8", 24 | TFLG_SIGCHECK_BEFORE},
+ {_T("MPQ_1999_v1_WeakSignature.exe"), szSigned3, "807fe2e4d38eccf5ee6bc88f5ee5940d", 25 | TFLG_SIGCHECK_BEFORE | TFLG_MODIFY | TFLG_SIGCHECK_AFTER},
{_T("MPQ_2002_v1_StrongSignature.w3m"), szSigned4, "7b725d87e07a2173c42fe2314b95fa6c", 17 | TFLG_SIGCHECK_BEFORE},
- {_T("MPQ_1998_v1_StarDat.mpq"), _T("MPQ_1998_v1_StarDat.mpq"), "2530cb937565fd41b1dc0443697096a2", 2925 | TFLG_SIGN_ARCHIVE | TFLG_SIGCHECK_AFTER},
- {_T("MPQ_1999_v1_WeakSignature.exe"), szSigned2, "807fe2e4d38eccf5ee6bc88f5ee5940d", 25 | TFLG_SIGCHECK_BEFORE | TFLG_MODIFY | TFLG_SIGCHECK_AFTER},
+ {_T("MPQ_2003_v1_WeakSignatureEmpty.exe"), szSigned5, "1e24a80dafa5285a0aee9470263e5b7c", 12259 | TFLG_SIGCHECK_BEFORE},
+ {_T("MPQ_2006_v1_WoW-1.11.2.5464-patch.exe_"), szSigned6, "6d1ccbfc344b6a2bc4ddf14867e45fea", 952 | TFLG_SIGCHECK_BEFORE},
+ {_T("MPQ_2007_v2_StrongSignature1.exe"), szSigned7, "c553320a2f841ccb86c0643f58d8488a", 23 | TFLG_SIGCHECK_BEFORE},
+ {_T("MPQ_2007_v2_StrongSignature2.MPQ"), szSigned8, "53cedaf7ba8c67b2e2ca95d5eb2b9380", 1622 | TFLG_SIGCHECK_BEFORE},
// Multi-file archive with wrong prefix to see how StormLib deals with it
{_T("flat-file://streaming/model.MPQ.0"), _T("flat-file://model.MPQ.0"), NULL, 0 | TFLG_WILL_FAIL},
@@ -4482,6 +4594,11 @@ int _tmain(int argc, TCHAR * argv[]) #endif
#ifdef TEST_MISC_MPQS
+
+ // Test creating of an archive the same way like MPQ Editor does
+ if(dwErrCode == ERROR_SUCCESS)
+ dwErrCode = TestRenameFile(_T("MPQ_2002_v1_StrongSignature.w3m"));
+
// Test creating of an archive the same way like MPQ Editor does
if(dwErrCode == ERROR_SUCCESS)
dwErrCode = TestCreateArchive_TestGaps(_T("StormLibTest_GapsTest.mpq"));
diff --git a/test/TLogHelper.cpp b/test/TLogHelper.cpp index 6eb97f6..dc8804b 100644 --- a/test/TLogHelper.cpp +++ b/test/TLogHelper.cpp @@ -17,6 +17,7 @@ #endif
#ifdef _MSC_VER
+#define fmt_I64u_w L"%I64u"
#define fmt_I64u_t _T("%I64u")
#define fmt_I64u_a "%I64u"
#define fmt_I64X_t _T("%I64X")
@@ -42,6 +43,58 @@ //-----------------------------------------------------------------------------
// Local functions
+template <typename XCHAR>
+XCHAR * StringEnd(XCHAR * sz)
+{
+ while(sz[0] != 0)
+ sz++;
+ return sz;
+}
+
+// ANSI version of the function - expects UTF-8 encoding
+size_t ConsoleLength(const char * ptr, const char * end)
+{
+ size_t ccBytesEaten;
+ size_t nLength = 0;
+ DWORD dwErrCode;
+
+ while(ptr < end)
+ {
+ DWORD dwCodePoint = 0;
+
+ // Decode a single UTF-8 character
+ dwErrCode = UTF8_DecodeCodePoint((BYTE *)(ptr), (BYTE *)(end), dwCodePoint, ccBytesEaten);
+ if(dwErrCode != ERROR_SUCCESS && dwErrCode != ERROR_NO_UNICODE_TRANSLATION)
+ break;
+
+ // Chinese chars occupy 1 extra char slot on console
+ if(0x5000 <= ptr[0] && ptr[0] <= 0xA000)
+ nLength++;
+ ptr += ccBytesEaten;
+ nLength++;
+ }
+ return nLength;
+}
+
+#ifdef TEST_PLATFORM_WINDOWS
+size_t ConsoleLength(const wchar_t * ptr, const wchar_t * end)
+{
+ size_t nLength = 0;
+
+ while(ptr < end)
+ {
+ DWORD dwCodePoint = ptr[0];
+
+ // Chinese chars occupy more space
+ if(0x5000 <= dwCodePoint && dwCodePoint <= 0xA000)
+ nLength++;
+ ptr += 1;
+ nLength++;
+ }
+ return nLength;
+}
+#endif
+
inline DWORD TestInterlockedIncrement(DWORD * PtrValue)
{
#ifdef TEST_PLATFORM_WINDOWS
@@ -55,35 +108,31 @@ inline DWORD TestInterlockedIncrement(DWORD * PtrValue) inline DWORD Test_GetLastError()
{
-#if defined(CASCLIB_PLATFORM_WINDOWS)
- return GetCascError();
-#else
- return GetLastError();
-#endif
+ return SErrGetLastError();
}
-#ifdef STORMLIB_WINDOWS
+#ifdef TEST_PLATFORM_WINDOWS
wchar_t * CopyFormatCharacter(wchar_t * szBuffer, const wchar_t *& szFormat)
{
- static const wchar_t * szStringFormat = _T("%s");
- static const wchar_t * szUint64Format = fmt_I64u_t;
+ static const wchar_t * szStringFormat = L"%s";
+ static const wchar_t * szUint64Format = fmt_I64u_w;
// String format
if(szFormat[0] == '%')
{
if(szFormat[1] == 's')
{
- _tcscpy(szBuffer, szStringFormat);
+ wcscpy(szBuffer, szStringFormat);
szFormat += 2;
- return szBuffer + _tcslen(szStringFormat);
+ return szBuffer + wcslen(szStringFormat);
}
// Replace %I64u with the proper platform-dependent suffix
if(szFormat[1] == 'I' && szFormat[2] == '6' && szFormat[3] == '4' && szFormat[4] == 'u')
{
- _tcscpy(szBuffer, szUint64Format);
+ wcscpy(szBuffer, szUint64Format);
szFormat += 5;
- return szBuffer + _tcslen(szUint64Format);
+ return szBuffer + wcslen(szUint64Format);
}
}
@@ -91,7 +140,7 @@ wchar_t * CopyFormatCharacter(wchar_t * szBuffer, const wchar_t *& szFormat) *szBuffer++ = *szFormat++;
return szBuffer;
}
-#endif // STORMLIB_WINDOWS
+#endif // TEST_PLATFORM_WINDOWS
char * CopyFormatCharacter(char * szBuffer, const char *& szFormat)
{
@@ -185,9 +234,7 @@ class TLogHelper #ifdef TEST_PLATFORM_WINDOWS
InitializeCriticalSection(&Locker);
TickCount = GetTickCount();
-#endif
-#ifdef STORMLIB_WINDOWS
SetConsoleOutputCP(CP_UTF8); // Set the UTF-8 code page to handle national-specific names
SetConsoleCP(CP_UTF8);
#endif
@@ -281,7 +328,7 @@ class TLogHelper va_start(argList, format);
int nLength = 0;
-#ifdef STORMLIB_WINDOWS
+#ifdef TEST_PLATFORM_WINDOWS
char * szBuffer;
int ccBuffer = 0x1000;
@@ -302,7 +349,7 @@ class TLogHelper return nLength;
}
-#ifdef STORMLIB_WINDOWS
+#ifdef TEST_PLATFORM_WINDOWS
int printf_console(const wchar_t * format, ...)
{
va_list argList;
@@ -329,19 +376,19 @@ class TLogHelper template <typename XCHAR>
DWORD PrintWithClreol(const XCHAR * szFormat, va_list argList, bool bPrintLastError, bool bPrintEndOfLine)
{
- char * szBufferPtr;
- char * szBufferEnd;
- size_t nNewPrinted;
+ XCHAR * szBufferPtr;
+ XCHAR * szBufferEnd;
size_t nLength = 0;
DWORD dwErrCode = Test_GetLastError();
- XCHAR szMessage[0x200];
- char szBuffer[0x200];
+ XCHAR szPercentS[] = {'%', 's', 0};
+ XCHAR szMessage[0x200] = {0};
+ XCHAR szBuffer[0x200] = {0};
bool bPrintPrefix = TEST_PRINT_PREFIX;
// Always start the buffer with '\r'
szBufferEnd = szBuffer + _countof(szBuffer);
- szBufferPtr = szBuffer;
- *szBufferPtr++ = '\r';
+ szBufferPtr = szBuffer + 1;
+ szBuffer[0] = '\r';
// Print the prefix, if needed
if(szMainTitle != NULL && bPrintPrefix)
@@ -356,49 +403,41 @@ class TLogHelper // Construct the message
TestStrPrintfV(szMessage, _countof(szMessage), szFormat, argList);
StringCopy(szBufferPtr, (szBufferEnd - szBufferPtr), szMessage);
- szBufferPtr = szBufferPtr + strlen(szBufferPtr);
+ szBufferPtr = StringEnd(szBufferPtr);
// Append the last error
if(bPrintLastError)
{
- nLength = TestStrPrintf(szBufferPtr, (szBufferEnd - szBufferPtr), " (error code: %u)", dwErrCode);
+ XCHAR szErrMsg[] = {' ', '(', 'e', 'r', 'r', 'o', 'r', ' ', 'c', 'o', 'd', 'e', ':', ' ', '%', 'u', ')', 0, 0};
+ nLength = TestStrPrintf(szBufferPtr, (szBufferEnd - szBufferPtr), szErrMsg, dwErrCode);
szBufferPtr += nLength;
}
- // Remember how much did we print
- nNewPrinted = (szBufferPtr - szBuffer);
-
- // Shall we pad the string?
- if((nLength = (szBufferPtr - szBuffer - 1)) < nPrevPrinted)
- {
- size_t nPadding = nPrevPrinted - nLength;
-
- if((size_t)(nLength + nPadding) > (size_t)(szBufferEnd - szBufferPtr))
- nPadding = (szBufferEnd - szBufferPtr);
+ // Pad the string with zeros, if needed
+ while(szBufferPtr < (szBuffer + nPrevPrinted))
+ *szBufferPtr++ = ' ';
- memset(szBufferPtr, ' ', nPadding);
- szBufferPtr += nPadding;
- }
+ // Remember how much did we print
+ nPrevPrinted = ConsoleLength(szBuffer, szBufferPtr);
- // Shall we add new line?
- if((bPrintEndOfLine != false) && (szBufferPtr < szBufferEnd))
- *szBufferPtr++ = '\n';
+ // Always add one extra space *AFTER* calculating length
+ if(szBufferPtr < szBufferEnd)
+ *szBufferPtr++ = ' ';
*szBufferPtr = 0;
- // Remember if we printed a message
- if(bPrintEndOfLine != false)
+ // Print the message to the console
+ printf_console(szPercentS, szBuffer);
+ nMessageCounter++;
+
+ // If we shall print the newline, do it
+ if(bPrintEndOfLine)
{
bMessagePrinted = true;
nPrevPrinted = 0;
- }
- else
- {
- nPrevPrinted = nNewPrinted;
+ printf("\n");
}
// Finally print the message
- printf_console("%s", szBuffer);
- nMessageCounter++;
return dwErrCode;
}
@@ -618,7 +657,7 @@ class TLogHelper const TCHAR * szSubTitle1; // Title of the text (can be name of the tested file)
const TCHAR * szSubTitle2; // Title of the text (can be name of the tested file)
size_t nMessageCounter;
- size_t nPrevPrinted; // Length of the previously printed message
+ size_t nPrevPrinted;
time_t dwPrevTickCount;
bool bMessagePrinted;
};
diff --git a/test/stormlib-test-001.txt b/test/stormlib-test-001.txt index a1b2449..a87e5ba 100644 --- a/test/stormlib-test-001.txt +++ b/test/stormlib-test-001.txt @@ -28,6 +28,16 @@ TestReadingMpq (pocs/MPQ_2024_09_InvalidSectorSize.mpq) succeeded. TestReadingMpq (pocs/MPQ_2024_10_HuffDecompressError.mpq) succeeded. TestReadingMpq (pocs/MPQ_2024_10_SparseDecompressError.mpq) succeeded. TestReadingMpq (pocs/MPQ_2024_11_HiBlockTablePosInvalid.mpq) succeeded. +TestReadingMpq: Error loading the file (listfile) (error code: 38) +TestReadingMpq (pocs/MPQ_2025_01_SectorTableBeyondEOF.mpq) succeeded. +TestReadingMpq: Warning: CRC32 error on (listfile) +TestReadingMpq: Warning: CRC32 error on (listfile) +TestReadingMpq (pocs/MPQ_2025_02_SectorOffsetSizeNotAligned.mpq) succeeded. +TestReadingMpq (pocs/MPQ_2025_03_InvalidPatchInfo.mpq) succeeded. +TestReadingMpq (pocs/MPQ_2025_04_InvalidArchiveSize64.mpq) succeeded. +TestReadingMpq (pocs/MPQ_2025_05_AddFileError.mpq) succeeded. +TestReadingMpq (pocs/MPQ_2025_06_BadHashTableSize.mpq) succeeded. +TestReadingMpq (pocs/MPQ_2025_07_BadHetTableSize.mpq) succeeded. TestReadingMpq (MPQ_1997_v1_Diablo1_DIABDAT.MPQ) succeeded. TestReadingMpq (MPQ_1997_v1_patch_rt_SC1B.mpq) succeeded. TestReadingMpq (MPQ_1997_v1_StarDat_SC1B.mpq) succeeded. @@ -47,7 +57,6 @@ TestReadingMpq: Warning: CRC32 error on (listfile) TestReadingMpq: Warning: CRC32 error on (listfile) TestReadingMpq: Warning: CRC32 error on File00000003.xxx TestReadingMpq (MPQ_2014_v1_AttributesOneEntryLess.w3x) succeeded. -TestReadingMpq (MPQ_2020_v1_AHF04patch.mix) succeeded. TestReadingMpq (MPQ_2010_v3_expansion-locale-frFR.MPQ) succeeded. TestReadingMpq (mpqe-file://MPQ_2011_v2_EncryptedMpq.MPQE) succeeded. TestReadingMpq (part-file://MPQ_2010_v2_HashTableCompressed.MPQ.part) succeeded. @@ -93,9 +102,11 @@ TestReadingMpq (MPQ_2022_v1_Sniper.scx) succeeded. TestReadingMpq (MPQ_2022_v1_OcOc_Bound_2.scx) succeeded. TestReadingMpq (MPQ_2023_v1_Lusin2Rpg1.28.w3x) succeeded. TestReadingMpq (MPQ_2024_v1_300TK2.09p.w3x) succeeded. -TestReadingMpq (MPQ_2020_v1_HS0.1.asi) succeeded. -TestReadingMpq (MPQ_2022_v1_hs0.8.asi) succeeded. -TestReadingMpq (MPQ_2022_v1_MoeMoeMod.asi) succeeded. +TestReadingMpq (MPQ_2025_v1_Legion_TD_11_2d-BETA_2_TeamOZE.w3x) succeeded. +TestReadingMpq (mix-mpq/AHF04patch.mix) succeeded. +TestReadingMpq (mix-mpq/hs0.1.asi) succeeded. +TestReadingMpq (mix-mpq/hs0.8.asi) succeeded. +TestReadingMpq (mix-mpq/MoeMoeMod.asi) succeeded. TestReadingMpq (MPx_2013_v1_LongwuOnline.mpk) succeeded. TestReadingMpq (MPx_2013_v1_WarOfTheImmortals.sqp) succeeded. TestReadingMpq (MPx_2022_v1_Music.mpk) succeeded. @@ -114,11 +125,16 @@ TestReadingMpq (MPQ_2013_v4_Mods#Liberty.SC2Mod#enGB.SC2Data) succeeded. TestReadingMpq (MPQ_2014_v4_base-Win.MPQ) succeeded. TestReadingMpq (MPQ_2014_v4_base-Win.MPQ) succeeded. TestReadingMpq (MPQ_1997_v1_Diablo1_STANDARD.SNP) succeeded. -TestReadingMpq (MPQ_1999_v1_WeakSignature.exe) succeeded. -TestReadingMpq (MPQ_2003_v1_WeakSignatureEmpty.exe) succeeded. -TestReadingMpq (MPQ_2002_v1_StrongSignature.w3m) succeeded. TestReadingMpq (MPQ_1998_v1_StarDat.mpq) succeeded. TestReadingMpq (MPQ_1999_v1_WeakSignature.exe) succeeded. +TestReadingMpq (MPQ_1999_v1_WeakSignature.exe) succeeded. +TestReadingMpq (MPQ_2002_v1_StrongSignature.w3m) succeeded. +TestReadingMpq (MPQ_2003_v1_WeakSignatureEmpty.exe) succeeded. +TestReadingMpq: Warning: CRC32 error on (signature) +TestReadingMpq: Warning: CRC32 error on (signature) +TestReadingMpq (MPQ_2006_v1_WoW-1.11.2.5464-patch.exe_) succeeded. +TestReadingMpq (MPQ_2007_v2_StrongSignature1.exe) succeeded. +TestReadingMpq (MPQ_2007_v2_StrongSignature2.MPQ) succeeded. TestReadingMpq (flat-file://streaming/model.MPQ.0) succeeded. TestReadingMpq (MPQ_2013_vX_Battle.net.MPQ) succeeded. TestReadingMpq (MPQ_1997_v1_Diablo1_DIABDAT.MPQ) succeeded. @@ -142,14 +158,15 @@ TestModifyMpq (MPQ_2023_v1_StarcraftMap.scm) succeeded. TestVerifyHash succeeded. CreateNewMpq (StormLibTest_EmptyMpq_v2.mpq) succeeded. CreateNewMpq (StormLibTest_EmptyMpq_v4.mpq) succeeded. -CreateNewMpq (StormLibTest_Český.mpq) succeeded. . -CreateNewMpq (StormLibTest_Русский.mpq) succeeded. ... +CreateNewMpq (StormLibTest_Český.mpq) succeeded. +CreateNewMpq (StormLibTest_Русский.mpq) succeeded. CreateNewMpq (StormLibTest_ελληνικά.mpq) succeeded. -CreateNewMpq (StormLibTest_日本語.mpq) succeeded. .. -CreateNewMpq (StormLibTest_简体中文.mpq) succeeded.... -CreateNewMpq (StormLibTest_الععربية.mpq) succeeded.... +CreateNewMpq (StormLibTest_日本語.mpq) succeeded. +CreateNewMpq (StormLibTest_简体中文.mpq) succeeded. +CreateNewMpq (StormLibTest_الععربية.mpq) succeeded. CreateNewMpq (StormLibTest_NonStdNames.mpq) succeeded. CreateNewMpq (StormLibTest_MpqEditorTest.mpq) succeeded. +TestRenameFile (MPQ_2002_v1_StrongSignature.w3m) succeeded. TestCreateGaps (StormLibTest_GapsTest.mpq) succeeded. TestCreateFull (StormLibTest_FileTableFull.mpq) succeeded. TestCreateFull (StormLibTest_FileTableFull.mpq) succeeded. |
