aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLadislav Zezula <ladislav.zezula@avast.com>2023-01-06 12:55:59 +0100
committerLadislav Zezula <ladislav.zezula@avast.com>2023-01-06 12:55:59 +0100
commit8a16217c5167240cada465727f67fdaf23b08f86 (patch)
tree239625a4136d511ec688bf25c5dcfb4dc8a45aee
parentf5988112ec08e1f4f6d86c31bdec6e93a2e3f4e2 (diff)
Added support for non-encrypted MPK files
-rw-r--r--make-msvc.bat6
-rw-r--r--src/SBaseFileTable.cpp2
-rw-r--r--src/SBaseSubTypes.cpp106
-rw-r--r--src/StormLib.h2
-rw-r--r--test/StormTest.cpp119
5 files changed, 143 insertions, 92 deletions
diff --git a/make-msvc.bat b/make-msvc.bat
index 783e1e2..d81eef2 100644
--- a/make-msvc.bat
+++ b/make-msvc.bat
@@ -20,9 +20,9 @@ if exist "%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2017\Enterprise\VC\Auxilia
if exist "%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_20xx=%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat
if exist "%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_20xx=%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvarsall.bat
if exist "%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_20xx=%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat
-if exist "%PROGRAM_FILES_X64%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_20xx=%PROGRAM_FILES_X64%\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat
-if exist "%PROGRAM_FILES_X64%\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_20xx=%PROGRAM_FILES_X64%\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvarsall.bat
-if exist "%PROGRAM_FILES_X64%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_20xx=%PROGRAM_FILES_X64%\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat
+if exist "%PROGRAM_FILES_X64%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_20xx=%PROGRAM_FILES_X64%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat
+if exist "%PROGRAM_FILES_X64%\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_20xx=%PROGRAM_FILES_X64%\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvarsall.bat
+if exist "%PROGRAM_FILES_X64%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_20xx=%PROGRAM_FILES_X64%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat
:: Build all libraries using Visual Studio 2008 and 2019
if not "x%VCVARS_2008%" == "x" call :BuildLibs "%VCVARS_2008%" x86 %LIB_NAME%_vs08.sln \vs2008
diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp
index b68de51..a579fbd 100644
--- a/src/SBaseFileTable.cpp
+++ b/src/SBaseFileTable.cpp
@@ -2425,12 +2425,10 @@ TMPQBlock * LoadBlockTable(TMPQArchive * ha, bool /* bDontFixEntries */)
break;
case MPQ_SUBTYPE_SQP:
-
pBlockTable = LoadSqpBlockTable(ha);
break;
case MPQ_SUBTYPE_MPK:
-
pBlockTable = LoadMpkBlockTable(ha);
break;
}
diff --git a/src/SBaseSubTypes.cpp b/src/SBaseSubTypes.cpp
index 59be7e8..ff6c459 100644
--- a/src/SBaseSubTypes.cpp
+++ b/src/SBaseSubTypes.cpp
@@ -285,10 +285,13 @@ TMPQBlock * LoadSqpBlockTable(TMPQArchive * ha)
/* */
/*****************************************************************************/
+#define MPK_BLOCK_TABLE_LONGWU 0x86364E6D // MPK table ID for Longwu Online
+#define MPK_BLOCK_TABLE_WOTGV 0x6d4e3686 // MPK table ID for Warriors of the Ghost Valley
+
#define MPK_FILE_UNKNOWN_0001 0x00000001 // Seems to be always present
#define MPK_FILE_UNKNOWN_0010 0x00000010 // Seems to be always present
#define MPK_FILE_COMPRESSED 0x00000100 // Indicates a compressed file
-#define MPK_FILE_UNKNOWN_2000 0x00002000 // Seems to be always present
+#define MPK_FILE_ENCRYPTED 0x00002000 // Indicates an encrypted file
#define MPK_FILE_EXISTS 0x01000000 // Seems to be always present
typedef struct _TMPKHeader
@@ -335,14 +338,26 @@ typedef struct _TMPKHash
} TMPKHash;
-typedef struct _TMPKBlock
+// MPK block for Longwu Online
+struct TMPKBlock1
+{
+ DWORD dwFlags; // 0x1121 - Compressed , 0x1120 - Not compressed
+ DWORD dwFilePos; // Offset of the beginning of the file, relative to the beginning of the archive.
+ DWORD dwFSize; // Uncompressed file size
+ DWORD dwCSize; // Compressed file size
+ DWORD dwMagic; // 0x86364E6D for Longwu Online
+};
+
+// MPK block for Warriors of the Ghost Valley
+struct TMPKBlock2
{
DWORD dwFlags; // 0x1121 - Compressed , 0x1120 - Not compressed
DWORD dwFilePos; // Offset of the beginning of the file, relative to the beginning of the archive.
DWORD dwFSize; // Uncompressed file size
DWORD dwCSize; // Compressed file size
- DWORD dwUnknown; // 0x86364E6D
-} TMPKBlock;
+ DWORD dwMagic; // 0x6d4e3686
+ DWORD dwFlags1; // Unknown
+};
//-----------------------------------------------------------------------------
// Local variables - MPK file format
@@ -398,6 +413,8 @@ DWORD ConvertMpkHeaderToFormat4(
// Can't open the archive with certain flags
if(dwFlags & MPQ_OPEN_FORCE_MPQ_V1)
return ERROR_FILE_CORRUPT;
+ if(pMpkHeader->dwVersion != ID_MPK_VERSION_2000)
+ return ERROR_FILE_CORRUPT;
// Translate the MPK header into a MPQ header
// Note: Hash table size and block table size are in bytes, not in entries
@@ -408,7 +425,7 @@ DWORD ConvertMpkHeaderToFormat4(
Header.dwHashTablePos = BSWAP_INT32_UNSIGNED(pMpkHeader->dwHashTablePos);
Header.dwHashTableSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwHashTableSize) / sizeof(TMPKHash);
Header.dwBlockTablePos = BSWAP_INT32_UNSIGNED(pMpkHeader->dwBlockTablePos);
- Header.dwBlockTableSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwBlockTableSize) / sizeof(TMPKBlock);
+ Header.dwBlockTableSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwBlockTableSize);
// Header.dwUnknownPos = BSWAP_INT32_UNSIGNED(pMpkHeader->dwUnknownPos);
// Header.dwUnknownSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwUnknownSize);
assert(Header.dwHeaderSize == sizeof(TMPKHeader));
@@ -562,6 +579,12 @@ TMPQHash * LoadMpkHashTable(TMPQArchive * ha)
return pHashTable;
}
+static DWORD GetMpkBlockID(void * pMpkBlockTable)
+{
+ DWORD * TableItems = (DWORD *)(pMpkBlockTable);
+ return TableItems[4];
+}
+
static DWORD ConvertMpkFlagsToMpqFlags(DWORD dwMpkFlags)
{
DWORD dwMpqFlags = MPQ_FILE_EXISTS;
@@ -569,49 +592,72 @@ static DWORD ConvertMpkFlagsToMpqFlags(DWORD dwMpkFlags)
// Check for flags that are always present
assert((dwMpkFlags & MPK_FILE_UNKNOWN_0001) != 0);
assert((dwMpkFlags & MPK_FILE_UNKNOWN_0010) != 0);
- assert((dwMpkFlags & MPK_FILE_UNKNOWN_2000) != 0);
assert((dwMpkFlags & MPK_FILE_EXISTS) != 0);
// Append the compressed flag
dwMpqFlags |= (dwMpkFlags & MPK_FILE_COMPRESSED) ? MPQ_FILE_COMPRESS : 0;
+ dwMpqFlags |= (dwMpkFlags & MPK_FILE_ENCRYPTED) ? MPQ_FILE_ENCRYPTED : 0;
// All files in the MPQ seem to be single unit files
- dwMpqFlags |= MPQ_FILE_ENCRYPTED | MPQ_FILE_SINGLE_UNIT;
+ dwMpqFlags |= MPQ_FILE_SINGLE_UNIT;
return dwMpqFlags;
}
+static TMPQBlock * LoadMpkBlockTable(TMPQArchive * ha, void * pMpkBlockTable, DWORD nItemSize)
+{
+ TMPQHeader * pHeader = ha->pHeader;
+ TMPQBlock * pBlockTable;
+ TMPQBlock * pMpqBlock;
+ LPBYTE pbMpkBlockPtr = (LPBYTE)(pMpkBlockTable);
+ LPBYTE pbMpkBlockEnd = pbMpkBlockPtr + pHeader->dwBlockTableSize;
+
+ // Fixup the number of items in the MPK block table
+ pHeader->dwBlockTableSize = pHeader->dwBlockTableSize / nItemSize;
+
+ // Allocate buffer for MPQ-like block table
+ pBlockTable = pMpqBlock = STORM_ALLOC(TMPQBlock, pHeader->dwBlockTableSize);
+ if(pBlockTable != NULL)
+ {
+ while(pbMpkBlockPtr < pbMpkBlockEnd)
+ {
+ TMPKBlock2 * pMpkBlock = (TMPKBlock2 *)(pbMpkBlockPtr);
+
+ // Translate the MPK block table entry to MPQ block table entry
+ pMpqBlock->dwFilePos = pMpkBlock->dwFilePos;
+ pMpqBlock->dwCSize = pMpkBlock->dwCSize;
+ pMpqBlock->dwFSize = pMpkBlock->dwFSize;
+ pMpqBlock->dwFlags = ConvertMpkFlagsToMpqFlags(pMpkBlock->dwFlags);
+
+ // Move both
+ pbMpkBlockPtr += nItemSize;
+ pMpqBlock++;
+ }
+ }
+
+ return pBlockTable;
+}
+
TMPQBlock * LoadMpkBlockTable(TMPQArchive * ha)
{
TMPQHeader * pHeader = ha->pHeader;
- TMPKBlock * pMpkBlockTable;
- TMPKBlock * pMpkBlockEnd;
TMPQBlock * pBlockTable = NULL;
- TMPKBlock * pMpkBlock;
- TMPQBlock * pMpqBlock;
+ void * pMpkBlockTable;
- // Load and decrypt the MPK block table
- pMpkBlockTable = pMpkBlock = (TMPKBlock *)LoadMpkTable(ha, pHeader->dwBlockTablePos, pHeader->dwBlockTableSize * sizeof(TMPKBlock));
+ // Load the MPK block table. At this moment, we don't know the version of the blobk table
+ pMpkBlockTable = LoadMpkTable(ha, pHeader->dwBlockTablePos, pHeader->dwBlockTableSize);
if(pMpkBlockTable != NULL)
{
- // Allocate buffer for MPQ-like block table
- pBlockTable = pMpqBlock = STORM_ALLOC(TMPQBlock, pHeader->dwBlockTableSize);
- if(pBlockTable != NULL)
+ switch(GetMpkBlockID(pMpkBlockTable))
{
- // Convert the MPK block table to MPQ block table
- pMpkBlockEnd = pMpkBlockTable + pHeader->dwBlockTableSize;
- while(pMpkBlock < pMpkBlockEnd)
- {
- // Translate the MPK block table entry to MPQ block table entry
- pMpqBlock->dwFilePos = pMpkBlock->dwFilePos;
- pMpqBlock->dwCSize = pMpkBlock->dwCSize;
- pMpqBlock->dwFSize = pMpkBlock->dwFSize;
- pMpqBlock->dwFlags = ConvertMpkFlagsToMpqFlags(pMpkBlock->dwFlags);
-
- // Move both
- pMpkBlock++;
- pMpqBlock++;
- }
+ case MPK_BLOCK_TABLE_WOTGV:
+ pBlockTable = LoadMpkBlockTable(ha, pMpkBlockTable, sizeof(TMPKBlock2));
+ break;
+
+ case MPK_BLOCK_TABLE_LONGWU:
+ default:
+ pBlockTable = LoadMpkBlockTable(ha, pMpkBlockTable, sizeof(TMPKBlock1));
+ break;
}
// Free the MPK block table
diff --git a/src/StormLib.h b/src/StormLib.h
index 85f5c4b..e45f99d 100644
--- a/src/StormLib.h
+++ b/src/StormLib.h
@@ -150,6 +150,8 @@ extern "C" {
#define ID_MPQ_USERDATA 0x1B51504D // MPQ userdata entry ('MPQ\x1B')
#define ID_MPK 0x1A4B504D // MPK archive header ID ('MPK\x1A')
+#define ID_MPK_VERSION_2000 0x30303032 // MPK version ("2000")
+
#define ERROR_AVI_FILE 10000 // Not a MPQ file, but an AVI file.
#define ERROR_UNKNOWN_FILE_KEY 10001 // Returned by SFileReadFile when can't find file key
#define ERROR_CHECKSUM_ERROR 10002 // Returned by SFileReadFile when sector CRC doesn't match
diff --git a/test/StormTest.cpp b/test/StormTest.cpp
index ad38b4d..addbdfc 100644
--- a/test/StormTest.cpp
+++ b/test/StormTest.cpp
@@ -4347,63 +4347,68 @@ 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("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("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)},
+ //{_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
};
static const TEST_INFO Patched_Mpqs[] =