From 630de2ee1925d1d1b9bf1404e189a5a319ee3c1e Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Mon, 2 Jun 2025 20:28:39 +0200 Subject: Fixed bug in test program that caused bad cosmetic effects during log print --- .vscode/launch.json | 2 +- src/SFileOpenArchive.cpp | 2 +- src/SMemUtf8.cpp | 4 +- src/StormCommon.h | 6 +++ test/StormTest.cpp | 32 +++++++------ test/TLogHelper.cpp | 113 ++++++++++++++++++++++++++++++++------------- test/stormlib-test-001.txt | 20 ++++---- 7 files changed, 117 insertions(+), 62 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index e9457ca..e9418f6 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "name": "(gdb) Launch", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/build/StormLib_test", + "program": "${workspaceFolder}/build/test/StormLib_test", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", diff --git a/src/SFileOpenArchive.cpp b/src/SFileOpenArchive.cpp index 7b55a8c..17fc7c9 100644 --- a/src/SFileOpenArchive.cpp +++ b/src/SFileOpenArchive.cpp @@ -30,7 +30,7 @@ typedef struct _IMAGE_DOS_HEADER { USHORT e_magic; - USHORT dummy[0x1B]; + USHORT dummy[0x1D]; DWORD e_lfanew; } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; diff --git a/src/SMemUtf8.cpp b/src/SMemUtf8.cpp index 5832422..7f03e77 100644 --- a/src/SMemUtf8.cpp +++ b/src/SMemUtf8.cpp @@ -92,7 +92,7 @@ static DWORD UTF8_DecodeSequence(const BYTE * pbString, BYTE BitsMask, size_t cc } // https://en.wikipedia.org/wiki/UTF-8 -static DWORD UTF8_DecodeCodePoint(const BYTE * pbString, const BYTE * pbStringEnd, DWORD & dwCodePoint, size_t & ccBytesEaten) +DWORD UTF8_DecodeCodePoint(const BYTE * pbString, const BYTE * pbStringEnd, DWORD & dwCodePoint, size_t & ccBytesEaten) { // Reset the number of bytes eaten dwCodePoint = SFILE_UTF8_INVALID_CHARACTER; @@ -165,7 +165,7 @@ static size_t UTF8_EncodeSequence(DWORD dwCodePoint, BYTE LeadingByte, DWORD dwF return dwFollowByteCount + 1; } -static size_t UTF8_EncodeCodePoint(DWORD dwCodePoint, LPBYTE Utf8Buffer) +size_t UTF8_EncodeCodePoint(DWORD dwCodePoint, LPBYTE Utf8Buffer) { // 0x00 - 0x7F, 1 byte if(dwCodePoint < 0x80) diff --git a/src/StormCommon.h b/src/StormCommon.h index bf82039..52f5cd0 100644 --- a/src/StormCommon.h +++ b/src/StormCommon.h @@ -276,6 +276,12 @@ void StringCat(TCHAR * szTarget, size_t cchTargetMax, const TCHAR * szSource); void StringCat(TCHAR * szTarget, size_t cchTargetMax, const char * szSource); #endif +//----------------------------------------------------------------------------- +// UTF-8 support + +DWORD UTF8_DecodeCodePoint(const BYTE * pbString, const BYTE * pbStringEnd, DWORD & dwCodePoint, size_t & ccBytesEaten); +size_t UTF8_EncodeCodePoint(DWORD dwCodePoint, LPBYTE Utf8Buffer); + //----------------------------------------------------------------------------- // Encryption and decryption functions diff --git a/test/StormTest.cpp b/test/StormTest.cpp index 2992238..dba91f3 100755 --- a/test/StormTest.cpp +++ b/test/StormTest.cpp @@ -3866,6 +3866,7 @@ static DWORD TestUtf8Conversions(const BYTE * szTestString, const TCHAR * szList static void Test_PlayingSpace() { +/* HANDLE hMpq; HANDLE hFile; @@ -3881,6 +3882,7 @@ static void Test_PlayingSpace() } SFileCloseArchive(hMpq); } +*/ } //----------------------------------------------------------------------------- @@ -4178,7 +4180,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 @@ -4189,10 +4190,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(""), 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}, @@ -4228,9 +4229,10 @@ static const TEST_INFO1 Test_OpenMpqs[] = {_T("MPQ_2024_v1_300TK2.09p.w3x"), NULL, "e442e3d2e7d457b9ba544544013b791f", 32588}, // 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 @@ -4349,17 +4351,17 @@ static const LPCSTR Test_CreateMpq_Localized[] = //----------------------------------------------------------------------------- // Main -//#define TEST_COMMAND_LINE -//#define TEST_LOCAL_LISTFILE -//#define TEST_STREAM_OPERATIONS -//#define TEST_MASTER_MIRROR -//#define TEST_OPEN_MPQ -//#define TEST_REOPEN_MPQ -//#define TEST_VERIFY_SIGNATURE -//#define TEST_REPLACE_FILE -//#define TEST_VERIFY_HASHES +#define TEST_COMMAND_LINE +#define TEST_LOCAL_LISTFILE +#define TEST_STREAM_OPERATIONS +#define TEST_MASTER_MIRROR +#define TEST_OPEN_MPQ +#define TEST_REOPEN_MPQ +#define TEST_VERIFY_SIGNATURE +#define TEST_REPLACE_FILE +#define TEST_VERIFY_HASHES #define TEST_CREATE_MPQS -//#define TEST_MISC_MPQS +#define TEST_MISC_MPQS int _tmain(int argc, TCHAR * argv[]) { diff --git a/test/TLogHelper.cpp b/test/TLogHelper.cpp index f58575b..df1492a 100644 --- a/test/TLogHelper.cpp +++ b/test/TLogHelper.cpp @@ -43,6 +43,58 @@ //----------------------------------------------------------------------------- // Local functions +template +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 @@ -63,7 +115,7 @@ inline DWORD Test_GetLastError() #endif } -#ifdef STORMLIB_WINDOWS +#ifdef TEST_PLATFORM_WINDOWS wchar_t * CopyFormatCharacter(wchar_t * szBuffer, const wchar_t *& szFormat) { static const wchar_t * szStringFormat = L"%s"; @@ -92,7 +144,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) { @@ -186,9 +238,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 @@ -282,7 +332,7 @@ class TLogHelper va_start(argList, format); int nLength = 0; -#ifdef STORMLIB_WINDOWS +#ifdef TEST_PLATFORM_WINDOWS char * szBuffer; int ccBuffer = 0x1000; @@ -303,7 +353,7 @@ class TLogHelper return nLength; } -#ifdef STORMLIB_WINDOWS +#ifdef TEST_PLATFORM_WINDOWS int printf_console(const wchar_t * format, ...) { va_list argList; @@ -330,18 +380,19 @@ class TLogHelper template DWORD PrintWithClreol(const XCHAR * szFormat, va_list argList, bool bPrintLastError, bool bPrintEndOfLine) { - char * szBufferPtr; - char * szBufferEnd; + 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,45 +407,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; } - // Shall we pad the string? - if((nLength = (szBufferPtr - szBuffer)) < nPrevPrinted) - { - size_t nPadding = nPrevPrinted - nLength; - - if((size_t)(nLength + nPadding) > (size_t)(szBufferEnd - szBufferPtr)) - nPadding = (szBufferEnd - szBufferPtr); - - memset(szBufferPtr, ' ', nPadding); - szBufferPtr += nPadding; - } + // Pad the string with zeros, if needed + while(szBufferPtr < (szBuffer + nPrevPrinted)) + *szBufferPtr++ = ' '; // Remember how much did we print - nPrevPrinted = (szBufferPtr - szBuffer); + nPrevPrinted = ConsoleLength(szBuffer, szBufferPtr); - // Shall we add new line? - if((bPrintEndOfLine) && (szBufferPtr < szBufferEnd)) - *szBufferPtr++ = '\n'; + // Always add one extra space *AFTER* calculating length + if(szBufferPtr < szBufferEnd) + *szBufferPtr++ = ' '; *szBufferPtr = 0; - // Remember if we printed a message + // 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; + printf("\n"); } // Finally print the message - printf_console("%s", szBuffer); - nMessageCounter++; return dwErrCode; } @@ -614,7 +661,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 1b9d95e..c386367 100644 --- a/test/stormlib-test-001.txt +++ b/test/stormlib-test-001.txt @@ -55,7 +55,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. @@ -69,7 +68,7 @@ TestReadingMpq (MPQ_2023_v4_UTF8.s2ma) succeeded. TestReadingMpq (MPQ_2023_v1_GreenTD.w3x) succeeded. TestReadingMpq (MPQ_2023_v4_1F644C5A.SC2Replay) succeeded. TestReadingMpq () succeeded. -TestReadingMpq (MPQ_2024_v1_BadUtf8_5.0.2.w3x) succeeded. +TestReadingMpq (MPQ_2024_v1_BadUtf8_5.0.2.w3x) succeeded. ... .. TestReadingMpq (MPQ_2002_v1_ProtectedMap_InvalidUserData.w3x) succeeded. TestReadingMpq (MPQ_2002_v1_ProtectedMap_InvalidMpqFormat.w3x) succeeded. TestReadingMpq (MPQ_2002_v1_ProtectedMap_Spazzler.w3x) succeeded. @@ -101,9 +100,10 @@ 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 (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. @@ -155,12 +155,12 @@ 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. TestCreateGaps (StormLibTest_GapsTest.mpq) succeeded. -- cgit v1.2.3