From 6f89c7ba8530c37f1f5a6048406cb18c40e5a458 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Mon, 16 Jan 2023 06:46:34 +0100 Subject: Fixed bug, refactor TLogHelper.cpp --- test/StormTest.cpp | 170 ++++++------ test/TLogHelper.cpp | 722 ++++++++++++++++++++++++++----------------------- test/stormlib-test.txt | 12 +- 3 files changed, 479 insertions(+), 425 deletions(-) (limited to 'test') diff --git a/test/StormTest.cpp b/test/StormTest.cpp index addbdfc..97a3663 100644 --- a/test/StormTest.cpp +++ b/test/StormTest.cpp @@ -998,7 +998,7 @@ static DWORD VerifyFilePosition( { if(ByteOffset != ExpectedPosition) { - pLogger->PrintMessage(_T("The file position is different than expected (expected: ") I64u_t _T(", current: ") I64u_t, ExpectedPosition, ByteOffset); + pLogger->PrintMessage(_T("The file position is different than expected (expected: ") fmt_I64u_t _T(", current: ") fmt_I64u_t, ExpectedPosition, ByteOffset); dwErrCode = ERROR_FILE_CORRUPT; } } @@ -1304,7 +1304,7 @@ static void WINAPI CompactCallback(void * pvUserData, DWORD dwWork, ULONGLONG By if(pLogger != NULL) pLogger->PrintProgress("%s (%I64u of %I64u) ...", szWork, BytesDone, TotalBytes); else - printf("%s (" I64u_a " of " I64u_a ") ... \r", szWork, BytesDone, TotalBytes); + printf("%s (" fmt_I64u_a " of " fmt_I64u_a ") ... \r", szWork, BytesDone, TotalBytes); } } @@ -1563,7 +1563,7 @@ static DWORD CompareTwoLocalFilesRR( BytesToRead = (DWORD)(RandomNumber % cbBuffer); // Show the progress message - pLogger->PrintProgress("Comparing file: Offset: " I64u_a ", Length: %u", ByteOffset, BytesToRead); + pLogger->PrintProgress("Comparing file: Offset: " fmt_I64u_a ", Length: %u", ByteOffset, BytesToRead); // Only perform read if the byte offset is below if(ByteOffset < FileSize1) @@ -1579,7 +1579,7 @@ static DWORD CompareTwoLocalFilesRR( if(!CompareBlocks(pbBuffer1, pbBuffer2, BytesToRead, &Difference)) { - pLogger->PrintMessage("Difference at %u (Offset " I64X_a ", Length %X)", Difference, ByteOffset, BytesToRead); + pLogger->PrintMessage("Difference at %u (Offset " fmt_I64X_a ", Length %X)", Difference, ByteOffset, BytesToRead); dwErrCode = ERROR_FILE_CORRUPT; break; } @@ -2271,7 +2271,7 @@ static void WINAPI TestReadFile_DownloadCallback( TLogHelper * pLogger = (TLogHelper *)UserData; if(ByteOffset != 0 && DataLength != 0) - pLogger->PrintProgress("Downloading data (offset: " I64X_a ", length: %X)", ByteOffset, DataLength); + pLogger->PrintProgress("Downloading data (offset: " fmt_I64X_a ", length: %X)", ByteOffset, DataLength); else pLogger->PrintProgress("Download complete."); } @@ -4346,68 +4346,69 @@ static const TEST_INFO TestList_MasterMirror[] = static const TEST_INFO Test_Mpqs[] = { + // Correct or damaged archives - //{_T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"), NULL, 0, "music\\dintro.wav", "File00000023.xxx"}, - //{_T("MPQ_1997_v1_patch_rt_SC1B.mpq"), NULL, TEST_DATA("43fe7d362955be68a708486e399576a7", 10)}, // From Starcraft 1 BETA - //{_T("MPQ_1997_v1_StarDat_SC1B.mpq"), NULL, TEST_DATA("0094b23f28cfff7386071ef3bd19a577", 2468)}, // From Starcraft 1 BETA - //{_T("MPQ_1997_v1_INSTALL_SC1B.EXE_"), NULL, TEST_DATA("3248460c89bb6f8e3b8fc3e08de7ffbb", 79)}, // From Starcraft 1 BETA - //{_T("MPQ_2016_v1_D2XP_IX86_1xx_114a.mpq"), NULL, TEST_DATA("255d87a62f3c9518f72cf723a1818946", 221), "waitingroombkgd.dc6"}, // Update MPQ from Diablo II (patch 2016) - //{_T("MPQ_2018_v1_icon_error.w3m"), NULL, TEST_DATA("fcefa25fb50c391e8714f2562d1e10ff", 19), "file00000002.blp"}, - //{_T("MPQ_1997_v1_Diablo1_STANDARD.SNP"), Bliz, TEST_DATA("5ef18ef9a26b5704d8d46a344d976c89", 2)}, // File whose archive's (signature) file has flags = 0x90000000 - //{_T("MPQ_2012_v2_EmptyMpq.MPQ"), NULL, TEST_DATA("00000000000000000000000000000000", 0)}, // Empty archive (found in WoW cache - it's just a header) - //{_T("MPQ_2013_v4_EmptyMpq.MPQ"), NULL, TEST_DATA("00000000000000000000000000000000", 0)}, // Empty archive (created artificially - it's just a header) - //{_T("MPQ_2013_v4_patch-base-16357.MPQ"), NULL, TEST_DATA("d41d8cd98f00b204e9800998ecf8427e", 1)}, // Empty archive (found in WoW cache - it's just a header) - //{_T("MPQ_2011_v4_InvalidHetEntryCount.MPQ"), NULL, TEST_DATA("be4b49ecc3942d1957249f9da0021659", 6)}, // Empty archive (with invalid HET entry count) - //{_T("MPQ_2002_v1_BlockTableCut.MPQ"), NULL, TEST_DATA("a9499ab74d939303d8cda7c397c36275", 287)}, // Truncated archive - //{_T("MPQ_2010_v2_HasUserData.s2ma"), NULL, TEST_DATA("feff9e2c86db716b6ff5ffc906181200", 52)}, // MPQ that actually has user data - //{_T("MPQ_2014_v1_AttributesOneEntryLess.w3x"), NULL, TEST_DATA("90451b7052eb0f1d6f4bf69b2daff7f5", 116)}, // Warcraft III map whose "(attributes)" file has (BlockTableSize-1) entries - //{_T("MPQ_2020_v1_AHF04patch.mix"), NULL, TEST_DATA("d3c6aac48bc12813ef5ce4ad113e58bf", 2891)}, // MIX file - //{_T("MPQ_2010_v3_expansion-locale-frFR.MPQ"), NULL, TEST_DATA("0c8fc921466f07421a281a05fad08b01", 53)}, // MPQ archive v 3.0 (the only one I know) - //{_T("mpqe-file://MPQ_2011_v2_EncryptedMpq.MPQE"), NULL, TEST_DATA("10e4dcdbe95b7ad731c563ec6b71bc16", 82)}, // Encrypted archive from Starcraft II installer - //{_T("part-file://MPQ_2010_v2_HashTableCompressed.MPQ.part"),0, TEST_DATA("d41d8cd98f00b204e9800998ecf8427e", 14263)}, // Partial MPQ with compressed hash table - //{_T("blk4-file://streaming/model.MPQ.0"), NULL, TEST_DATA("e06b00efb2fc7e7469dd8b3b859ae15d", 39914)}, // Archive that is merged with multiple files - - //// Protected archives - //{_T("MPQ_2002_v1_ProtectedMap_InvalidUserData.w3x"), NULL, TEST_DATA("b900364cc134a51ddeca21a13697c3ca", 79)}, - //{_T("MPQ_2002_v1_ProtectedMap_InvalidMpqFormat.w3x"), NULL, TEST_DATA("db67e894da9de618a1cdf86d02d315ff", 117)}, - //{_T("MPQ_2002_v1_ProtectedMap_Spazzler.w3x"), NULL, TEST_DATA("72d7963aa799a7fb4117c55b7beabaf9", 470)}, // Warcraft III map locked by the Spazzler protector - //{_T("MPQ_2014_v1_ProtectedMap_Spazzler2.w3x"), NULL, TEST_DATA("72d7963aa799a7fb4117c55b7beabaf9", 470)}, // Warcraft III map locked by the Spazzler protector - //{_T("MPQ_2014_v1_ProtectedMap_Spazzler3.w3x"), NULL, TEST_DATA("e55aad2dd33cf68b372ca8e30dcb78a7", 130)}, // Warcraft III map locked by the Spazzler protector - //{_T("MPQ_2002_v1_ProtectedMap_BOBA.w3m"), NULL, TEST_DATA("7b725d87e07a2173c42fe2314b95fa6c", 17)}, // Warcraft III map locked by the BOBA protector - //{_T("MPQ_2015_v1_ProtectedMap_KangTooJee.w3x"), NULL, TEST_DATA("44111a3edf7645bc44bb1afd3a813576", 1715)}, - //{_T("MPQ_2015_v1_ProtectedMap_Somj2hM16.w3x"), NULL, TEST_DATA("b411f9a51a6e9a9a509150c8d66ba359", 92)}, - //{_T("MPQ_2015_v1_ProtectedMap_Spazy.w3x"), NULL, TEST_DATA("6e491bd055511435dcb4d9c8baed0516", 4089)}, // Warcraft III map locked by Spazy protector - //{_T("MPQ_2015_v1_MessListFile.mpq"), NULL, TEST_DATA("15e25d5be124d8ad71519f967997efc2", 8)}, - //{_T("MPQ_2016_v1_ProtectedMap_TableSizeOverflow.w3x"), NULL, TEST_DATA("ad81b43cbd37bbfa27e4bed4c17e6a81", 176)}, - //{_T("MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x"), NULL, TEST_DATA("d6e712c275a26dc51f16b3a02f6187df", 228)}, - //{_T("MPQ_2016_v1_ProtectedMap_Somj2.w3x"), NULL, TEST_DATA("457cdbf97a9ca41cfe8ea130dafaa0bb", 21)}, // Something like Somj 2.0 - //{_T("MPQ_2016_v1_WME4_4.w3x"), NULL, TEST_DATA("7ec2f4d0f3982d8b12d88bc08ef0c1fb", 640)}, // Protector from China (2016-05-27) - //{_T("MPQ_2016_v1_SP_(4)Adrenaline.w3x"), NULL, TEST_DATA("b6f6d56f4f8aaef04c2c4b1f08881a8b", 16)}, - //{_T("MPQ_2016_v1_ProtectedMap_1.4.w3x"), NULL, TEST_DATA("3c7908b29d3feac9ec952282390a242d", 5027)}, - //{_T("MPQ_2016_v1_KoreanFile.w3m"), NULL, TEST_DATA("805d1f75712472a81c6df27b2a71f946", 18)}, - //{_T("MPQ_2017_v1_Eden_RPG_S2_2.5J.w3x"), NULL, TEST_DATA("cbe1fd7ed5ed2fc005fba9beafcefe40", 16334)}, // Protected by PG1.11.973 - //{_T("MPQ_2017_v1_BigDummyFiles.w3x"), NULL, TEST_DATA("f4d2ee9d85d2c4107e0b2d00ff302dd7", 9086)}, - //{_T("MPQ_2017_v1_TildeInFileName.mpq"), NULL, TEST_DATA("f203e3979247a4dbf7f3828695ac810c", 5)}, - //{_T("MPQ_2018_v1_EWIX_v8_7.w3x"), NULL, TEST_DATA("12c0f4e15c7361b7c13acd37a181d83b", 857), "BlueCrystal.mdx"}, - //{_T("MPQ_2020_v4_FakeMpqHeaders.SC2Mod"), NULL, TEST_DATA("f45392f6523250c943990a017c230b41", 24)}, // Archive that has two fake headers before the real one - //{_T("MPQ_2020_v4_NP_Protect_1.s2ma"), NULL, TEST_DATA("1a1ea40ac1165bcdb4f2e434edfc7636", 21)}, // SC2 map that is protected by the NP_Protect - //{_T("MPQ_2020_v4_NP_Protect_2.s2ma"), NULL, TEST_DATA("7d1a379da8bd966da1f4fa6e4646049b", 55)}, // SC2 map that is protected by the NP_Protect - //{_T("MPQ_2015_v1_flem1.w3x"), NULL, TEST_DATA("1c4c13e627658c473e84d94371e31f37", 20)}, - //{_T("MPQ_2002_v1_ProtectedMap_HashTable_FakeValid.w3x"), NULL, TEST_DATA("5250975ed917375fc6540d7be436d4de", 114)}, - //{_T("MPQ_2021_v1_CantExtractCHK.scx"), NULL, TEST_DATA("055fd548a789c910d9dd37472ecc1e66", 28)}, - //{_T("MPQ_2022_v1_Sniper.scx"), NULL, TEST_DATA("2e955271b70b79344ad85b698f6ce9d8", 64)}, // Multiple items in hash table for staredit\scenario.chk (locale=0, platform=0) - //{_T("MPQ_2022_v1_OcOc_Bound_2.scx"), NULL, TEST_DATA("25cad16a2fb4e883767a1f512fc1dce7", 16)}, - - //// ASI plugins - //{_T("MPQ_2020_v1_HS0.1.asi"), NULL, TEST_DATA("50cba7460a6e6d270804fb9776a7ec4f", 6022)}, - //{_T("MPQ_2022_v1_hs0.8.asi"), NULL, TEST_DATA("6a40f733428001805bfe6e107ca9aec1", 11352)}, // Items in hash table have platform = 0xFF - //{_T("MPQ_2022_v1_MoeMoeMod.asi"), NULL, TEST_DATA("89b923c7cde06de48815844a5bbb0ec4", 2578)}, - - //// MPQ modifications from Chinese games - //{_T("MPx_2013_v1_LongwuOnline.mpk"), NULL, TEST_DATA("548f7db88284097f7e94c95a08c5bc24", 469)}, // MPK archive from Longwu online - //{_T("MPx_2013_v1_WarOfTheImmortals.sqp"), WotI, TEST_DATA("a048f37f7c6162a96253d8081722b6d9", 9396)}, // SQP archive from War of the Immortals - {_T("MPx_2022_v1_Music.mpk"), NULL, TEST_DATA("fc369cff4ff4b573dd024de963e4cdd5", 650)}, // MPK archive from Warriors of the Ghost Valley - {_T("MPx_2022_v1_Scp.mpk"), NULL, TEST_DATA("9cb453dc159f2e667c14f48957fd9e77", 113)}, // MPK archive from Warriors of the Ghost Valley + {_T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"), NULL, 0, "music\\dintro.wav", "File00000023.xxx"}, + {_T("MPQ_1997_v1_patch_rt_SC1B.mpq"), NULL, TEST_DATA("43fe7d362955be68a708486e399576a7", 10)}, // From Starcraft 1 BETA + {_T("MPQ_1997_v1_StarDat_SC1B.mpq"), NULL, TEST_DATA("0094b23f28cfff7386071ef3bd19a577", 2468)}, // From Starcraft 1 BETA + {_T("MPQ_1997_v1_INSTALL_SC1B.EXE_"), NULL, TEST_DATA("3248460c89bb6f8e3b8fc3e08de7ffbb", 79)}, // From Starcraft 1 BETA + {_T("MPQ_2016_v1_D2XP_IX86_1xx_114a.mpq"), NULL, TEST_DATA("255d87a62f3c9518f72cf723a1818946", 221), "waitingroombkgd.dc6"}, // Update MPQ from Diablo II (patch 2016) + {_T("MPQ_2018_v1_icon_error.w3m"), NULL, TEST_DATA("fcefa25fb50c391e8714f2562d1e10ff", 19), "file00000002.blp"}, + {_T("MPQ_1997_v1_Diablo1_STANDARD.SNP"), Bliz, TEST_DATA("5ef18ef9a26b5704d8d46a344d976c89", 2)}, // File whose archive's (signature) file has flags = 0x90000000 + {_T("MPQ_2012_v2_EmptyMpq.MPQ"), NULL, TEST_DATA("00000000000000000000000000000000", 0)}, // Empty archive (found in WoW cache - it's just a header) + {_T("MPQ_2013_v4_EmptyMpq.MPQ"), NULL, TEST_DATA("00000000000000000000000000000000", 0)}, // Empty archive (created artificially - it's just a header) + {_T("MPQ_2013_v4_patch-base-16357.MPQ"), NULL, TEST_DATA("d41d8cd98f00b204e9800998ecf8427e", 1)}, // Empty archive (found in WoW cache - it's just a header) + {_T("MPQ_2011_v4_InvalidHetEntryCount.MPQ"), NULL, TEST_DATA("be4b49ecc3942d1957249f9da0021659", 6)}, // Empty archive (with invalid HET entry count) + {_T("MPQ_2002_v1_BlockTableCut.MPQ"), NULL, TEST_DATA("a9499ab74d939303d8cda7c397c36275", 287)}, // Truncated archive + {_T("MPQ_2010_v2_HasUserData.s2ma"), NULL, TEST_DATA("feff9e2c86db716b6ff5ffc906181200", 52)}, // MPQ that actually has user data + {_T("MPQ_2014_v1_AttributesOneEntryLess.w3x"), NULL, TEST_DATA("90451b7052eb0f1d6f4bf69b2daff7f5", 116)}, // Warcraft III map whose "(attributes)" file has (BlockTableSize-1) entries + {_T("MPQ_2020_v1_AHF04patch.mix"), NULL, TEST_DATA("d3c6aac48bc12813ef5ce4ad113e58bf", 2891)}, // MIX file + {_T("MPQ_2010_v3_expansion-locale-frFR.MPQ"), NULL, TEST_DATA("0c8fc921466f07421a281a05fad08b01", 53)}, // MPQ archive v 3.0 (the only one I know) + {_T("mpqe-file://MPQ_2011_v2_EncryptedMpq.MPQE"), NULL, TEST_DATA("10e4dcdbe95b7ad731c563ec6b71bc16", 82)}, // Encrypted archive from Starcraft II installer + {_T("part-file://MPQ_2010_v2_HashTableCompressed.MPQ.part"),0, TEST_DATA("d41d8cd98f00b204e9800998ecf8427e", 14263)}, // Partial MPQ with compressed hash table + {_T("blk4-file://streaming/model.MPQ.0"), NULL, TEST_DATA("e06b00efb2fc7e7469dd8b3b859ae15d", 39914)}, // Archive that is merged with multiple files + + // Protected archives + {_T("MPQ_2002_v1_ProtectedMap_InvalidUserData.w3x"), NULL, TEST_DATA("b900364cc134a51ddeca21a13697c3ca", 79)}, + {_T("MPQ_2002_v1_ProtectedMap_InvalidMpqFormat.w3x"), NULL, TEST_DATA("db67e894da9de618a1cdf86d02d315ff", 117)}, + {_T("MPQ_2002_v1_ProtectedMap_Spazzler.w3x"), NULL, TEST_DATA("72d7963aa799a7fb4117c55b7beabaf9", 470)}, // Warcraft III map locked by the Spazzler protector + {_T("MPQ_2014_v1_ProtectedMap_Spazzler2.w3x"), NULL, TEST_DATA("72d7963aa799a7fb4117c55b7beabaf9", 470)}, // Warcraft III map locked by the Spazzler protector + {_T("MPQ_2014_v1_ProtectedMap_Spazzler3.w3x"), NULL, TEST_DATA("e55aad2dd33cf68b372ca8e30dcb78a7", 130)}, // Warcraft III map locked by the Spazzler protector + {_T("MPQ_2002_v1_ProtectedMap_BOBA.w3m"), NULL, TEST_DATA("7b725d87e07a2173c42fe2314b95fa6c", 17)}, // Warcraft III map locked by the BOBA protector + {_T("MPQ_2015_v1_ProtectedMap_KangTooJee.w3x"), NULL, TEST_DATA("44111a3edf7645bc44bb1afd3a813576", 1715)}, + {_T("MPQ_2015_v1_ProtectedMap_Somj2hM16.w3x"), NULL, TEST_DATA("b411f9a51a6e9a9a509150c8d66ba359", 92)}, + {_T("MPQ_2015_v1_ProtectedMap_Spazy.w3x"), NULL, TEST_DATA("6e491bd055511435dcb4d9c8baed0516", 4089)}, // Warcraft III map locked by Spazy protector + {_T("MPQ_2015_v1_MessListFile.mpq"), NULL, TEST_DATA("15e25d5be124d8ad71519f967997efc2", 8)}, + {_T("MPQ_2016_v1_ProtectedMap_TableSizeOverflow.w3x"), NULL, TEST_DATA("ad81b43cbd37bbfa27e4bed4c17e6a81", 176)}, + {_T("MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x"), NULL, TEST_DATA("d6e712c275a26dc51f16b3a02f6187df", 228)}, + {_T("MPQ_2016_v1_ProtectedMap_Somj2.w3x"), NULL, TEST_DATA("457cdbf97a9ca41cfe8ea130dafaa0bb", 21)}, // Something like Somj 2.0 + {_T("MPQ_2016_v1_WME4_4.w3x"), NULL, TEST_DATA("7ec2f4d0f3982d8b12d88bc08ef0c1fb", 640)}, // Protector from China (2016-05-27) + {_T("MPQ_2016_v1_SP_(4)Adrenaline.w3x"), NULL, TEST_DATA("b6f6d56f4f8aaef04c2c4b1f08881a8b", 16)}, + {_T("MPQ_2016_v1_ProtectedMap_1.4.w3x"), NULL, TEST_DATA("3c7908b29d3feac9ec952282390a242d", 5027)}, + {_T("MPQ_2016_v1_KoreanFile.w3m"), NULL, TEST_DATA("805d1f75712472a81c6df27b2a71f946", 18)}, + {_T("MPQ_2017_v1_Eden_RPG_S2_2.5J.w3x"), NULL, TEST_DATA("cbe1fd7ed5ed2fc005fba9beafcefe40", 16334)}, // Protected by PG1.11.973 + {_T("MPQ_2017_v1_BigDummyFiles.w3x"), NULL, TEST_DATA("f4d2ee9d85d2c4107e0b2d00ff302dd7", 9086)}, + {_T("MPQ_2017_v1_TildeInFileName.mpq"), NULL, TEST_DATA("f203e3979247a4dbf7f3828695ac810c", 5)}, + {_T("MPQ_2018_v1_EWIX_v8_7.w3x"), NULL, TEST_DATA("12c0f4e15c7361b7c13acd37a181d83b", 857), "BlueCrystal.mdx"}, + {_T("MPQ_2020_v4_FakeMpqHeaders.SC2Mod"), NULL, TEST_DATA("f45392f6523250c943990a017c230b41", 24)}, // Archive that has two fake headers before the real one + {_T("MPQ_2020_v4_NP_Protect_1.s2ma"), NULL, TEST_DATA("1a1ea40ac1165bcdb4f2e434edfc7636", 21)}, // SC2 map that is protected by the NP_Protect + {_T("MPQ_2020_v4_NP_Protect_2.s2ma"), NULL, TEST_DATA("7d1a379da8bd966da1f4fa6e4646049b", 55)}, // SC2 map that is protected by the NP_Protect + {_T("MPQ_2015_v1_flem1.w3x"), NULL, TEST_DATA("1c4c13e627658c473e84d94371e31f37", 20)}, + {_T("MPQ_2002_v1_ProtectedMap_HashTable_FakeValid.w3x"), NULL, TEST_DATA("5250975ed917375fc6540d7be436d4de", 114)}, + {_T("MPQ_2021_v1_CantExtractCHK.scx"), NULL, TEST_DATA("055fd548a789c910d9dd37472ecc1e66", 28)}, + {_T("MPQ_2022_v1_Sniper.scx"), NULL, TEST_DATA("2e955271b70b79344ad85b698f6ce9d8", 64)}, // Multiple items in hash table for staredit\scenario.chk (locale=0, platform=0) + {_T("MPQ_2022_v1_OcOc_Bound_2.scx"), NULL, TEST_DATA("25cad16a2fb4e883767a1f512fc1dce7", 16)}, + + // ASI plugins + {_T("MPQ_2020_v1_HS0.1.asi"), NULL, TEST_DATA("50cba7460a6e6d270804fb9776a7ec4f", 6022)}, + {_T("MPQ_2022_v1_hs0.8.asi"), NULL, TEST_DATA("6a40f733428001805bfe6e107ca9aec1", 11352)}, // Items in hash table have platform = 0xFF + {_T("MPQ_2022_v1_MoeMoeMod.asi"), NULL, TEST_DATA("89b923c7cde06de48815844a5bbb0ec4", 2578)}, + + // MPQ modifications from Chinese games + {_T("MPx_2013_v1_LongwuOnline.mpk"), NULL, TEST_DATA("548f7db88284097f7e94c95a08c5bc24", 469)}, // MPK archive from Longwu online + {_T("MPx_2013_v1_WarOfTheImmortals.sqp"), WotI, TEST_DATA("a048f37f7c6162a96253d8081722b6d9", 9396)}, // SQP archive from War of the Immortals + {_T("MPx_2022_v1_Music.mpk"), NULL, TEST_DATA("fc369cff4ff4b573dd024de963e4cdd5", 650)}, // MPK archive from Warriors of the Ghost Valley + {_T("MPx_2022_v1_Scp.mpk"), NULL, TEST_DATA("9cb453dc159f2e667c14f48957fd9e77", 113)}, // MPK archive from Warriors of the Ghost Valley {_T("MPx_2022_v1_UI.mpk"), NULL, TEST_DATA("677a36b458d528a3158ced3dfb711e49", 3086)}, // MPK archive from Warriors of the Ghost Valley }; @@ -4429,6 +4430,13 @@ static const TEST_INFO Patched_Mpqs[] = //----------------------------------------------------------------------------- // Main +#define TEST_COMMAND_LINE +#define TEST_LOCAL_LISTFILE +#define TEST_STREAM_OPERATIONS +#define TEST_MASTER_MIRROR +#define TEST_SINGLE_MPQS +#define TEST_PATCHED_MPQS + int _tmain(int argc, TCHAR * argv[]) { DWORD dwErrCode = ERROR_SUCCESS; @@ -4441,30 +4449,26 @@ int _tmain(int argc, TCHAR * argv[]) printf("==== Test Suite for StormLib version %s ====\n", STORMLIB_VERSION_STRING); dwErrCode = InitializeMpqDirectory(argv, argc); - // +#ifdef TEST_COMMAND_LINE // Test-open MPQs from the command line. They must be plain name // and must be placed in the Test-MPQs folder - // - for(int i = 2; i < argc; i++) { TestArchive(argv[i], Bliz, 0, "Scripts\\War3map.j", NULL); } +#endif // TEST_COMMAND_LINE - // +#ifdef TEST_LOCAL_LISTFILE // Tests on a local listfile - // - if(dwErrCode == ERROR_SUCCESS) { TestOnLocalListFile(_T("FLAT-MAP:ListFile_Blizzard.txt")); dwErrCode = TestOnLocalListFile(_T("ListFile_Blizzard.txt")); } +#endif // TEST_LOCAL_LISTFILE - // +#ifdef TEST_STREAM_OPERATIONS // Test file stream operations - // - if(dwErrCode == ERROR_SUCCESS) { for(size_t i = 0; i < _countof(TestList_StreamOps); i++) @@ -4474,11 +4478,10 @@ int _tmain(int argc, TCHAR * argv[]) break; } } +#endif TEST_STREAM_OPERATIONS - // +#ifdef TEST_MASTER_MIRROR // Test master-mirror reading operations - // - if(dwErrCode == ERROR_SUCCESS) { for(size_t i = 0; i < _countof(TestList_MasterMirror); i++) @@ -4490,11 +4493,10 @@ int _tmain(int argc, TCHAR * argv[]) break; } } +#endif // TEST_MASTER_MIRROR - // +#ifdef TEST_SINGLE_MPQS // Test opening various archives - correct, damaged, protected - // - if(dwErrCode == ERROR_SUCCESS) { for(size_t i = 0; i < _countof(Test_Mpqs); i++) @@ -4508,11 +4510,10 @@ int _tmain(int argc, TCHAR * argv[]) dwErrCode = ERROR_SUCCESS; } } +#endif // TEST_LOCAL_MPQs - // +#ifdef TEST_PATCHED_MPQS // Test opening patched archives - correct, damaged, protected - // - if(dwErrCode == ERROR_SUCCESS) { for(size_t i = 0; i < _countof(Patched_Mpqs); i++) @@ -4527,6 +4528,7 @@ int _tmain(int argc, TCHAR * argv[]) dwErrCode = ERROR_SUCCESS; } } +#endif // TEST_PATCHED_MPQS // Veryfy SHA1 of each MPQ that we have in the list if(dwErrCode == ERROR_SUCCESS) diff --git a/test/TLogHelper.cpp b/test/TLogHelper.cpp index 3a82368..cdfa692 100644 --- a/test/TLogHelper.cpp +++ b/test/TLogHelper.cpp @@ -6,457 +6,503 @@ /*---------------------------------------------------------------------------*/ /* Date Ver Who Comment */ /* -------- ---- --- ------- */ -/* 26.11.13 1.00 Lad The first version of TLogHelper.cpp */ +/* 26.11.13 1.00 Lad Created */ /*****************************************************************************/ //----------------------------------------------------------------------------- -// Definition of the TLogHelper class - -class TLogHelper -{ - public: - - TLogHelper(const char * szNewMainTitle = NULL, const TCHAR * szNewSubTitle1 = NULL, const TCHAR * szNewSubTitle2 = NULL); - ~TLogHelper(); - -#if defined(UNICODE) || defined(UNICODE) - // TCHAR-based functions. They are only needed on UNICODE builds. - // On ANSI builds is TCHAR = char, so we don't need them at all - int PrintWithClreol(const TCHAR * szFormat, va_list argList, bool bPrintPrefix, bool bPrintLastError, bool bPrintEndOfLine); - void PrintProgress(const TCHAR * szFormat, ...); - void PrintMessage(const TCHAR * szFormat, ...); - int PrintErrorVa(const TCHAR * szFormat, ...); - int PrintError(const TCHAR * szFormat, const TCHAR * szFileName = NULL); -#endif // defined(UNICODE) || defined(UNICODE) - - // ANSI functions - 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); - - // Print final verdict - DWORD PrintVerdict(DWORD dwErrCode = ERROR_SUCCESS); - - const char * UserString; - unsigned int UserCount; - unsigned int UserTotal; - bool bDontPrintResult; - - protected: +// String replacements for format strings -#if defined(UNICODE) || defined(UNICODE) - TCHAR * CopyFormatCharacter(TCHAR * szBuffer, const TCHAR *& szFormat); +#if defined(STORMLIB_WINDOWS) || defined(CASCLIB_PLATFORM_WINDOWS) +#define TEST_PLATFORM_WINDOWS #endif - char * CopyFormatCharacter(char * szBuffer, const char *& szFormat); - int GetConsoleWidth(); - - const char * szMainTitle; // Title of the text (usually name) - 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 nTextLength; // Length of the previous progress message - bool bMessagePrinted; -}; - -//----------------------------------------------------------------------------- -// String replacements for format strings #ifdef _MSC_VER -#define I64u_t _T("%I64u") -#define I64u_a "%I64u" -#define I64X_t _T("%I64X") -#define I64X_a "%I64X" +#define fmt_I64u_t _T("%I64u") +#define fmt_I64u_a "%I64u" +#define fmt_I64X_t _T("%I64X") +#define fmt_I64X_a "%I64X" #else -#define I64u_t _T("%llu") -#define I64u_a "%llu" -#define I64X_t _T("%llX") -#define I64X_a "%llX" +#define fmt_I64u_t _T("%llu") +#define fmt_I64u_a "%llu" +#define fmt_I64X_t _T("%llX") +#define fmt_I64X_a "%llX" #endif -//----------------------------------------------------------------------------- -// Constructor and destructor +#ifdef __STORMLIB_SELF__ +#define TEST_MIN STORMLIB_MIN +#else +#define TEST_MIN CASCLIB_MIN +#endif +//----------------------------------------------------------------------------- +// Local functions -TLogHelper::TLogHelper(const char * szNewMainTitle, const TCHAR * szNewSubTitle1, const TCHAR * szNewSubTitle2) +inline DWORD TestInterlockedIncrement(DWORD * PtrValue) { - TCHAR szMainTitleT[0x80]; - - UserString = ""; - UserCount = 1; - UserTotal = 1; +#ifdef TEST_PLATFORM_WINDOWS + return (DWORD)InterlockedIncrement((LONG *)(PtrValue)); +#elif defined(__GNUC__) + return __sync_add_and_fetch(PtrValue, 1); +#else +#define INTERLOCKED_NOT_SUPPORTED + return ++(*PtrValue); +#endif +} - // Fill the test line structure - szMainTitle = szNewMainTitle; - szSubTitle1 = szNewSubTitle1; - szSubTitle2 = szNewSubTitle2; - nTextLength = 0; - bMessagePrinted = false; - bDontPrintResult = false; +inline DWORD Test_GetLastError() +{ +#if defined(CASCLIB_PLATFORM_WINDOWS) + return GetCascError(); +#else + return GetLastError(); +#endif +} - // Copy the UNICODE main title - StringCopy(szMainTitleT, _countof(szMainTitleT), szMainTitle); +void TestStrCopy(char * szTarget, size_t cchTarget, const char * szSource, size_t cchSource = -1) +{ + size_t cchToCopy; - // Print the initial information - if(szMainTitle != NULL) + if(cchTarget > 0) { - if(szSubTitle1 != NULL && szSubTitle2 != NULL) - _tprintf(_T("Running %s (%s+%s) ..."), szMainTitleT, szSubTitle1, szSubTitle2); - else if(szSubTitle1 != NULL) - _tprintf(_T("Running %s (%s) ..."), szMainTitleT, szSubTitle1); - else - _tprintf(_T("Running %s ..."), szMainTitleT); + // Make sure we know the length + if(cchSource == -1) + cchSource = strlen(szSource); + cchToCopy = TEST_MIN((cchTarget - 1), cchSource); + + // Copy the string + memcpy(szTarget, szSource, cchToCopy); + szTarget[cchToCopy] = 0; } } -TLogHelper::~TLogHelper() +void TestStrCopy(char * szTarget, size_t cchTarget, const wchar_t * szSource, size_t cchSource = -1) { - // Print a verdict, if no verdict was printed yet - if(bMessagePrinted == false) - { - PrintVerdict(ERROR_SUCCESS); - } + size_t cchToCopy; -#if defined(_MSC_VER) && defined(_DEBUG) - if(_CrtDumpMemoryLeaks()) + if(cchTarget > 0) { - PrintMessage(_T("Memory leak(s) detected.\n")); + // Make sure we know the length + if(cchSource == -1) + cchSource = wcslen(szSource); + cchToCopy = TEST_MIN((cchTarget - 1), cchSource); + + wcstombs(szTarget, szSource, cchToCopy); + szTarget[cchToCopy] = 0; } -#endif // _MSC_VER } -//----------------------------------------------------------------------------- -// TCHAR-based functions. They are only needed on UNICODE builds. -// On ANSI builds is TCHAR = char, so we don't need them at all - -#if defined(UNICODE) || defined(UNICODE) -int TLogHelper::PrintWithClreol(const TCHAR * szFormat, va_list argList, bool bPrintPrefix, bool bPrintLastError, bool bPrintEndOfLine) +wchar_t * CopyFormatCharacter(wchar_t * szBuffer, const wchar_t *& szFormat) { - TCHAR szFormatBuff[0x200]; - TCHAR szMessage[0x200]; - TCHAR * szBuffer = szFormatBuff; - int nRemainingWidth; - int nConsoleWidth = GetConsoleWidth(); - int nLength = 0; - int nError = GetLastError(); - - // Always start the buffer with '\r' - *szBuffer++ = '\r'; - - // Print the prefix, if needed - if(szMainTitle != NULL && bPrintPrefix) - { - while(szMainTitle[nLength] != 0) - *szBuffer++ = szMainTitle[nLength++]; - - *szBuffer++ = ':'; - *szBuffer++ = ' '; - } + static const wchar_t * szStringFormat = _T("%s"); + static const wchar_t * szUint64Format = fmt_I64u_t; - // Copy the message format itself. Replace %s with "%s", unless it's (%s) - if(szFormat != NULL) + // String format + if(szFormat[0] == '%') { - while(szFormat[0] != 0) + if(szFormat[1] == 's') { - szBuffer = CopyFormatCharacter(szBuffer, szFormat); + _tcscpy(szBuffer, szStringFormat); + szFormat += 2; + return szBuffer + _tcslen(szStringFormat); } - } - // Append the last error - if(bPrintLastError) - { - nLength = _stprintf(szBuffer, _T(" (error code: %u)"), nError); - szBuffer += nLength; + // Replace %I64u with the proper platform-dependent suffix + if(szFormat[1] == 'I' && szFormat[2] == '6' && szFormat[3] == '4' && szFormat[4] == 'u') + { + _tcscpy(szBuffer, szUint64Format); + szFormat += 5; + return szBuffer + _tcslen(szUint64Format); + } } - // Create the result string - szBuffer[0] = 0; - nLength = _vstprintf(szMessage, szFormatBuff, argList); - szBuffer = szMessage + nLength; + // Copy the character as-is + *szBuffer++ = *szFormat++; + return szBuffer; +} - // Shall we pad the string? - if(nLength < nConsoleWidth) +char * CopyFormatCharacter(char * szBuffer, const char *& szFormat) +{ + static const char * szStringFormat = "\"%s\""; + static const char * szUint64Format = fmt_I64u_a; + + // String format + if(szFormat[0] == '%') { - // Calculate the remaining width - nRemainingWidth = nConsoleWidth - nLength - 1; + if(szFormat[1] == 's') + { + TestStrCopy(szBuffer, 32, szStringFormat); + szFormat += 2; + return szBuffer + strlen(szStringFormat); + } - // Pad the string with spaces to fill it up to the end of the line - for(int i = 0; i < nRemainingWidth; i++) - *szBuffer++ = 0x20; + // Replace %I64u with the proper platform-dependent suffix + if(szFormat[1] == 'I' && szFormat[2] == '6' && szFormat[3] == '4' && szFormat[4] == 'u') + { + TestStrCopy(szBuffer, 32, szUint64Format); + szFormat += 5; + return szBuffer + strlen(szUint64Format); + } } - // Put the newline, if requested - *szBuffer++ = bPrintEndOfLine ? '\n' : 0; - *szBuffer = 0; - - // Remember if we printed a message - if(bPrintEndOfLine) - bMessagePrinted = true; + // Copy the character as-is + *szBuffer++ = *szFormat++; + return szBuffer; +} - // Spit out the text in one single printf - _tprintf(_T("%s"), szMessage); - return nError; +size_t TestStrPrintfV(char * buffer, size_t nCount, const char * format, va_list argList) +{ + return vsnprintf(buffer, nCount, format, argList); } -void TLogHelper::PrintProgress(const TCHAR * szFormat, ...) +size_t TestStrPrintf(char * buffer, size_t nCount, const char * format, ...) { va_list argList; + size_t length; - va_start(argList, szFormat); - PrintWithClreol(szFormat, argList, true, false, false); + // Start the argument list + va_start(argList, format); + length = TestStrPrintfV(buffer, nCount, format, argList); va_end(argList); + + return length; } -void TLogHelper::PrintMessage(const TCHAR * szFormat, ...) +size_t TestStrPrintfV(wchar_t * buffer, size_t nCount, const wchar_t * format, va_list argList) { - va_list argList; - - va_start(argList, szFormat); - PrintWithClreol(szFormat, argList, true, false, true); - va_end(argList); +#ifdef TEST_PLATFORM_WINDOWS + return _vsnwprintf(buffer, nCount, format, argList); +#else + return vswprintf(buffer, nCount, format, argList); +#endif } -int TLogHelper::PrintErrorVa(const TCHAR * szFormat, ...) +size_t TestStrPrintf(wchar_t * buffer, size_t nCount, const wchar_t * format, ...) { va_list argList; - int nResult; + size_t length; - va_start(argList, szFormat); - nResult = PrintWithClreol(szFormat, argList, true, true, true); + // Start the argument list + va_start(argList, format); + length = TestStrPrintfV(buffer, nCount, format, argList); va_end(argList); - return nResult; + return length; } -int TLogHelper::PrintError(const TCHAR * szFormat, const TCHAR * szFileName) -{ - return PrintErrorVa(szFormat, szFileName); -} -#endif // defined(UNICODE) || defined(UNICODE) - //----------------------------------------------------------------------------- -// ANSI functions +// Definition of the TLogHelper class -DWORD TLogHelper::PrintWithClreol(const char * szFormat, va_list argList, bool bPrintPrefix, bool bPrintLastError, bool bPrintEndOfLine) +class TLogHelper { - char szFormatBuff[0x200]; - char szMessage[0x200]; - char * szBuffer = szFormatBuff; - int nRemainingWidth; - int nConsoleWidth = GetConsoleWidth(); - int nLength = 0; - DWORD dwErrCode = GetLastError(); - - // Always start the buffer with '\r' - *szBuffer++ = '\r'; - - // Print the prefix, if needed - if(szMainTitle != NULL && bPrintPrefix) - { - while(szMainTitle[nLength] != 0) - *szBuffer++ = (char)szMainTitle[nLength++]; + public: - *szBuffer++ = ':'; - *szBuffer++ = ' '; - } + // + // Constructor and destructor + // - // Copy the message format itself. Replace %s with "%s", unless it's (%s) - if(szFormat != NULL) + TLogHelper(const char * szNewMainTitle = NULL, const TCHAR * szNewSubTitle1 = NULL, const TCHAR * szNewSubTitle2 = NULL) { - while(szFormat[0] != 0) + TCHAR szMainTitleT[0x80]; + + // Fill the variables + memset(this, 0, sizeof(TLogHelper)); + + UserString = ""; + UserCount = 1; + UserTotal = 1; + + // Fill the test line structure + szMainTitle = szNewMainTitle; + szSubTitle1 = szNewSubTitle1; + szSubTitle2 = szNewSubTitle2; + + // Copy the UNICODE main title + StringCopy(szMainTitleT, _countof(szMainTitleT), szMainTitle); + + // Print the initial information + if(szNewMainTitle != NULL) { - szBuffer = CopyFormatCharacter(szBuffer, szFormat); + if(szSubTitle1 != NULL && szSubTitle2 != NULL) + nPrevPrinted = _tprintf(_T("Running %s (%s+%s) ..."), szMainTitleT, szSubTitle1, szSubTitle2); + else if(szSubTitle1 != NULL) + nPrevPrinted = _tprintf(_T("Running %s (%s) ..."), szMainTitleT, szSubTitle1); + else + nPrevPrinted = _tprintf(_T("Running %s ..."), szMainTitleT); } } - // Append the last error - if(bPrintLastError) + TLogHelper::~TLogHelper() { - nLength = sprintf(szBuffer, " (error code: %u)", dwErrCode); - szBuffer += nLength; + // Print a verdict, if no verdict was printed yet + if(bMessagePrinted == false) + { + PrintVerdict(ERROR_SUCCESS); + } + + + printf("\n"); } - // Create the result string - szBuffer[0] = 0; - nLength = vsprintf(szMessage, szFormatBuff, argList); + // + // Measurement of elapsed time + // - // Shall we pad the string? - szBuffer = szMessage + nLength; - if(nLength < nConsoleWidth) + bool TimeElapsed(DWORD Milliseconds) { - // Calculate the remaining width - nRemainingWidth = nConsoleWidth - nLength - 1; + bool bTimeElapsed = false; + +#ifdef TEST_PLATFORM_WINDOWS + if(GetTickCount() > (TickCount + Milliseconds)) + { + TickCount = GetTickCount(); + if(TestInterlockedIncrement(&TimeTrigger) == 1) + { + bTimeElapsed = true; + } + } - // Pad the string with spaces to fill it up to the end of the line - for(int i = 0; i < nRemainingWidth; i++) - *szBuffer++ = 0x20; +#endif + return bTimeElapsed; } - // Put the newline, if requested - *szBuffer++ = bPrintEndOfLine ? '\n' : '\r'; - *szBuffer = 0; + // + // Printing functions + // - // Remember if we printed a message - if(bPrintEndOfLine) - bMessagePrinted = true; + template + DWORD PrintWithClreol(const XCHAR * szFormat, va_list argList, bool bPrintPrefix, bool bPrintLastError, bool bPrintEndOfLine) + { + char * szBufferPtr; + char * szBufferEnd; + size_t nNewPrinted; + size_t nLength = 0; + DWORD dwErrCode = Test_GetLastError(); + XCHAR szMessage[0x200]; + char szBuffer[0x200]; + + // Always start the buffer with '\r' + szBufferEnd = szBuffer + _countof(szBuffer); + szBufferPtr = szBuffer; + *szBufferPtr++ = '\r'; + + // Print the prefix, if needed + if(szMainTitle != NULL && bPrintPrefix) + { + while(szMainTitle[nLength] != 0) + *szBufferPtr++ = szMainTitle[nLength++]; - // Spit out the text in one single printf - printf("%s", szMessage); - return dwErrCode; -} + *szBufferPtr++ = ':'; + *szBufferPtr++ = ' '; + } -void TLogHelper::PrintProgress(const char * szFormat, ...) -{ - va_list argList; + // Construct the message + nLength = TestStrPrintfV(szMessage, _countof(szMessage), szFormat, argList); + TestStrCopy(szBufferPtr, (szBufferEnd - szBufferPtr), szMessage); + szBufferPtr += nLength; - va_start(argList, szFormat); - PrintWithClreol(szFormat, argList, true, false, false); - va_end(argList); -} + // Append the last error + if(bPrintLastError) + { + nLength = TestStrPrintf(szBufferPtr, (szBufferEnd - szBufferPtr), " (error code: %u)", dwErrCode); + szBufferPtr += nLength; + } -void TLogHelper::PrintMessage(const char * szFormat, ...) -{ - va_list argList; + // Remember how much did we print + nNewPrinted = (szBufferPtr - szBuffer); - va_start(argList, szFormat); - PrintWithClreol(szFormat, argList, true, false, true); - va_end(argList); -} + // Shall we pad the string? + if((nLength = (szBufferPtr - szBuffer - 1)) < nPrevPrinted) + { + size_t nPadding = nPrevPrinted - nLength; -DWORD TLogHelper::PrintErrorVa(const char * szFormat, ...) -{ - va_list argList; - DWORD dwErrCode; + if((size_t)(nLength + nPadding) > (size_t)(szBufferEnd - szBufferPtr)) + nPadding = (szBufferEnd - szBufferPtr); - va_start(argList, szFormat); - dwErrCode = PrintWithClreol(szFormat, argList, true, true, true); - va_end(argList); + memset(szBufferPtr, ' ', nPadding); + szBufferPtr += nPadding; + } - return dwErrCode; -} + // Shall we add new line? + if((bPrintEndOfLine != false) && (szBufferPtr < szBufferEnd)) + *szBufferPtr++ = '\n'; + *szBufferPtr = 0; -DWORD TLogHelper::PrintError(const char * szFormat, const char * szFileName) -{ - return PrintErrorVa(szFormat, szFileName); -} + // Remember if we printed a message + if(bPrintEndOfLine != false) + { + bMessagePrinted = true; + nPrevPrinted = 0; + } + else + { + nPrevPrinted = nNewPrinted; + } -//----------------------------------------------------------------------------- -// Print final verdict + // Finally print the message + printf("%s", szBuffer); + nMessageCounter++; + return dwErrCode; + } -DWORD TLogHelper::PrintVerdict(DWORD dwErrCode) -{ - LPCTSTR szSaveSubTitle1 = szSubTitle1; - LPCTSTR szSaveSubTitle2 = szSubTitle2; - TCHAR szSaveMainTitle[0x80]; - - // Set both to NULL so they won't be printed - StringCopy(szSaveMainTitle, _countof(szSaveMainTitle), szMainTitle); - szSubTitle1 = NULL; - szSubTitle2 = NULL; - szMainTitle = NULL; - - // Print the final information - if(szSaveMainTitle[0] != 0) + template + void PrintProgress(const XCHAR * szFormat, ...) { - if(bDontPrintResult == false) - { - LPCTSTR szVerdict = (dwErrCode == ERROR_SUCCESS) ? _T("succeeded") : _T("failed"); + va_list argList; - if(szSaveSubTitle1 != NULL && szSaveSubTitle2 != NULL) - PrintMessage(_T("%s (%s+%s) %s."), szSaveMainTitle, szSaveSubTitle1, szSaveSubTitle2, szVerdict); - else if(szSaveSubTitle1 != NULL) - PrintMessage(_T("%s (%s) %s."), szSaveMainTitle, szSaveSubTitle1, szVerdict); - else - PrintMessage(_T("%s %s."), szSaveMainTitle, szVerdict); - } - else + // Always reset the time trigger + TimeTrigger = 0; + + // Only print progress when the cooldown is ready + if(ProgressReady()) { - PrintProgress(" "); - printf("\r"); + va_start(argList, szFormat); + PrintWithClreol(szFormat, argList, true, false, false); + va_end(argList); } } - // Return the error code so the caller can pass it fuhrter - return dwErrCode; -} + template + void PrintMessage(const XCHAR * szFormat, ...) + { + va_list argList; -//----------------------------------------------------------------------------- -// Protected functions + va_start(argList, szFormat); + PrintWithClreol(szFormat, argList, true, false, true); + va_end(argList); + } -#ifdef _UNICODE -TCHAR * TLogHelper::CopyFormatCharacter(TCHAR * szBuffer, const TCHAR *& szFormat) -{ -// static LPCTSTR szStringFormat = _T("\"%s\""); - static LPCTSTR szStringFormat = _T("%s"); - static LPCTSTR szUint64Format = I64u_t; + void PrintTotalTime() + { + DWORD TotalTime = SetEndTime(); - // String format - if(szFormat[0] == '%') + if(TotalTime != 0) + PrintMessage("TotalTime: %u.%u second(s)", (TotalTime / 1000), (TotalTime % 1000)); + PrintMessage("Work complete."); + } + + template + int PrintErrorVa(const XCHAR * szFormat, ...) { - if(szFormat[1] == 's') - { - _tcscpy(szBuffer, szStringFormat); - szFormat += 2; - return szBuffer + _tcslen(szStringFormat); - } + va_list argList; + int nResult; - // Replace %I64u with the proper platform-dependent suffix - if(szFormat[1] == 'I' && szFormat[2] == '6' && szFormat[3] == '4' && szFormat[4] == 'u') + va_start(argList, szFormat); + nResult = PrintWithClreol(szFormat, argList, true, true, true); + va_end(argList); + + return nResult; + } + + template + int PrintError(const XCHAR * szFormat, const XCHAR * szFileName = NULL) + { + return PrintErrorVa(szFormat, szFileName); + } + + // Print final verdict + DWORD PrintVerdict(DWORD dwErrCode = ERROR_SUCCESS) + { + LPCTSTR szSaveSubTitle1 = szSubTitle1; + LPCTSTR szSaveSubTitle2 = szSubTitle2; + TCHAR szSaveMainTitle[0x80]; + + // Set both to NULL so they won't be printed + StringCopy(szSaveMainTitle, _countof(szSaveMainTitle), szMainTitle); + szSubTitle1 = NULL; + szSubTitle2 = NULL; + szMainTitle = NULL; + + // Print the final information + if(szSaveMainTitle[0] != 0) { - _tcscpy(szBuffer, szUint64Format); - szFormat += 5; - return szBuffer + _tcslen(szUint64Format); + if(DontPrintResult == false) + { + LPCTSTR szVerdict = (dwErrCode == ERROR_SUCCESS) ? _T("succeeded") : _T("failed"); + + if(szSaveSubTitle1 != NULL && szSaveSubTitle2 != NULL) + PrintMessage(_T("%s (%s+%s) %s."), szSaveMainTitle, szSaveSubTitle1, szSaveSubTitle2, szVerdict); + else if(szSaveSubTitle1 != NULL) + PrintMessage(_T("%s (%s) %s."), szSaveMainTitle, szSaveSubTitle1, szVerdict); + else + PrintMessage(_T("%s %s."), szSaveMainTitle, szVerdict); + } + else + { + PrintProgress(" "); + printf("\r"); + } } + + // Return the error code so the caller can pass it fuhrter + return dwErrCode; } - // Copy the character as-is - *szBuffer++ = *szFormat++; - return szBuffer; -} -#endif + // + // Time functions + // -char * TLogHelper::CopyFormatCharacter(char * szBuffer, const char *& szFormat) -{ - static const char * szStringFormat = "\"%s\""; - static const char * szUint64Format = I64u_a; + ULONGLONG GetCurrentThreadTime() + { +#ifdef _WIN32 + ULONGLONG TempTime = 0; - // String format - if(szFormat[0] == '%') + GetSystemTimeAsFileTime((LPFILETIME)(&TempTime)); + return ((TempTime) / 10 / 1000); + + //ULONGLONG KernelTime = 0; + //ULONGLONG UserTime = 0; + //ULONGLONG TempTime = 0; + + //GetThreadTimes(GetCurrentThread(), (LPFILETIME)&TempTime, (LPFILETIME)&TempTime, (LPFILETIME)&KernelTime, (LPFILETIME)&UserTime); + //return ((KernelTime + UserTime) / 10 / 1000); +#else + return time(NULL) * 1000; +#endif + } + + bool ProgressReady() { - if(szFormat[1] == 's') - { - strcpy(szBuffer, szStringFormat); - szFormat += 2; - return szBuffer + strlen(szStringFormat); - } + time_t dwTickCount = time(NULL); + bool bResult = false; - // Replace %I64u with the proper platform-dependent suffix - if(szFormat[1] == 'I' && szFormat[2] == '6' && szFormat[3] == '4' && szFormat[4] == 'u') + if(dwTickCount > dwPrevTickCount) { - strcpy(szBuffer, szUint64Format); - szFormat += 5; - return szBuffer + strlen(szUint64Format); + dwPrevTickCount = dwTickCount; + bResult = true; } + + return bResult; } - // Copy the character as-is - *szBuffer++ = *szFormat++; - return szBuffer; -} + ULONGLONG SetStartTime() + { + StartTime = GetCurrentThreadTime(); + return StartTime; + } -int TLogHelper::GetConsoleWidth() -{ -#ifdef STORMLIB_WINDOWS + DWORD SetEndTime() + { + EndTime = GetCurrentThreadTime(); + return (DWORD)(EndTime - StartTime); + } - CONSOLE_SCREEN_BUFFER_INFO ScreenInfo; - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &ScreenInfo); - return (int)(ScreenInfo.srWindow.Right - ScreenInfo.srWindow.Left); + ULONGLONG StartTime; // Start time of an operation, in milliseconds + ULONGLONG EndTime; // End time of an operation, in milliseconds + const char * UserString; + unsigned int UserCount; + unsigned int UserTotal; + DWORD TickCount; + DWORD TimeTrigger; // For triggering elapsed timers + DWORD DontPrintResult:1; // If true, supress printing result from the destructor -#else - // On non-Windows platforms, we assume that width of the console line - // is 80 characters - return 120; + protected: -#endif -} + const char * szMainTitle; // Title of the text (usually name) + 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 + time_t dwPrevTickCount; + bool bMessagePrinted; +}; diff --git a/test/stormlib-test.txt b/test/stormlib-test.txt index 947a387..2cdaed2 100644 --- a/test/stormlib-test.txt +++ b/test/stormlib-test.txt @@ -1,4 +1,4 @@ -Microsoft Windows [Version 10.0.19044.2006] +Microsoft Windows [Version 10.0.19045.2486] (c) Microsoft Corporation. All rights reserved. E:\Ladik\AppDir\StormLib\bin\StormLib_test\x64\Release>StormLib_test.exe @@ -35,8 +35,6 @@ TestMpq (MPQ_2014_v1_AttributesOneEntryLess.w3x) succeeded. TestMpq (MPQ_2020_v1_AHF04patch.mix) succeeded. TestMpq (MPQ_2010_v3_expansion-locale-frFR.MPQ) succeeded. TestMpq (mpqe-file://MPQ_2011_v2_EncryptedMpq.MPQE) succeeded. -TestMpq (MPx_2013_v1_LongwuOnline.mpk) succeeded. -TestMpq (MPx_2013_v1_WarOfTheImmortals.sqp) succeeded. TestMpq (part-file://MPQ_2010_v2_HashTableCompressed.MPQ.part) succeeded. TestMpq (blk4-file://streaming/model.MPQ.0) succeeded. TestMpq (MPQ_2002_v1_ProtectedMap_InvalidUserData.w3x) succeeded. @@ -71,6 +69,11 @@ TestMpq (MPQ_2022_v1_OcOc_Bound_2.scx) succeeded. TestMpq (MPQ_2020_v1_HS0.1.asi) succeeded. TestMpq (MPQ_2022_v1_hs0.8.asi) succeeded. TestMpq (MPQ_2022_v1_MoeMoeMod.asi) succeeded. +TestMpq (MPx_2013_v1_LongwuOnline.mpk) succeeded. +TestMpq (MPx_2013_v1_WarOfTheImmortals.sqp) succeeded. +TestMpq (MPx_2022_v1_Music.mpk) succeeded. +TestMpq (MPx_2022_v1_Scp.mpk) succeeded. +TestMpq (MPx_2022_v1_UI.mpk) succeeded. PatchedMPQ (MPQ_1998_v1_StarCraft.mpq) succeeded. PatchedMPQ (MPQ_2012_v4_OldWorld.MPQ) succeeded. PatchedMPQ (MPQ_2013_v4_world.MPQ) succeeded. @@ -176,6 +179,9 @@ VerifyFileHash succeeded. VerifyFileHash succeeded. VerifyFileHash succeeded. VerifyFileHash succeeded. +VerifyFileHash succeeded. +VerifyFileHash succeeded. +VerifyFileHash succeeded. OpenEachMpqTest ((10)DustwallowKeys.w3m) succeeded. OpenEachMpqTest (MPQ_1997_v1_Diablo1_DIABDAT.MPQ) succeeded. OpenEachMpqTest (MPQ_1997_v1_Diablo1_single_0.sv) succeeded. -- cgit v1.2.3