aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLadislav Zezula <E:\Ladik\Mail>2016-05-27 16:50:50 +0200
committerLadislav Zezula <E:\Ladik\Mail>2016-05-27 16:50:50 +0200
commit47b6b6eb4addd82a89d6bcd8fa92f9c0a09a5781 (patch)
tree5fb9c92f6352c9275d27d6ebb9aee87e20c75151
parentf1655f8afe2ef76d4906eb3e94dfd3c2b5241eb4 (diff)
+ Support for MPQs that have invalid (and ignored) flags in the block table
+ Support for MPQs that have malformed block indexes (0x8000xxxx or 0x4000xxxx)
-rw-r--r--src/SBaseFileTable.cpp22
-rw-r--r--src/SFileOpenArchive.cpp4
-rw-r--r--src/SFileOpenFileEx.cpp6
-rw-r--r--src/StormLib.h3
-rw-r--r--test/StormTest.cpp17
5 files changed, 36 insertions, 16 deletions
diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp
index b38dbc3..9d37ff1 100644
--- a/src/SBaseFileTable.cpp
+++ b/src/SBaseFileTable.cpp
@@ -581,23 +581,33 @@ int ConvertMpqHeaderToFormat4(
// Hash entry verification when the file table does not exist yet
bool IsValidHashEntry(TMPQArchive * ha, TMPQHash * pHash)
{
- TFileEntry * pFileEntry = ha->pFileTable + pHash->dwBlockIndex;
- return ((pHash->dwBlockIndex < ha->dwFileTableSize) && (pFileEntry->dwFlags & MPQ_FILE_EXISTS)) ? true : false;
+ TFileEntry * pFileEntry = ha->pFileTable + MPQ_BLOCK_INDEX(pHash->dwBlockIndex);
+ DWORD dwBlockIndex = MPQ_BLOCK_INDEX(pHash->dwBlockIndex);
+
+ pFileEntry = ha->pFileTable + dwBlockIndex;
+ return ((dwBlockIndex < ha->dwFileTableSize) && (pFileEntry->dwFlags & MPQ_FILE_EXISTS)) ? true : false;
}
// Hash entry verification when the file table does not exist yet
static bool IsValidHashEntry1(TMPQArchive * ha, TMPQHash * pHash, TMPQBlock * pBlockTable)
{
ULONGLONG ByteOffset;
- TMPQBlock * pBlock = pBlockTable + pHash->dwBlockIndex;
+ TMPQBlock * pBlock;
+ DWORD dwBlockIndex;
// We need to mask out the upper 4 bits of the block table index.
// This is because it gets shifted out when calculating block table offset
// BlockTableOffset = pHash->dwBlockIndex * 0x10
// Malformed MPQ maps may contain invalid entries
// Note that Storm.dll does not perfom this check
- if((pHash->dwBlockIndex & 0x0FFFFFFF) < ha->pHeader->dwBlockTableSize)
+ dwBlockIndex = MPQ_BLOCK_INDEX(pHash->dwBlockIndex);
+
+ // The block index is considered valid if it's less than block table size
+ if(dwBlockIndex < ha->pHeader->dwBlockTableSize)
{
+ // Calculate the block table position
+ pBlock = pBlockTable + dwBlockIndex;
+
// Check whether this is an existing file
// Also we do not allow to be file size greater than 2GB
if((pBlock->dwFlags & MPQ_FILE_EXISTS) && (pBlock->dwFSize & 0x8000000) == 0)
@@ -783,8 +793,8 @@ static int BuildFileTableFromBlockTable(
if(IsValidHashEntry1(ha, pHash, pBlockTable))
{
- DWORD dwBlockIndex = pHash->dwBlockIndex;
- DWORD dwNewIndex = pHash->dwBlockIndex;
+ DWORD dwBlockIndex = MPQ_BLOCK_INDEX(pHash->dwBlockIndex);
+ DWORD dwNewIndex = MPQ_BLOCK_INDEX(pHash->dwBlockIndex);
// Determine the new block index
if(DefragmentTable != NULL)
diff --git a/src/SFileOpenArchive.cpp b/src/SFileOpenArchive.cpp
index 6a249f2..2cb6698 100644
--- a/src/SFileOpenArchive.cpp
+++ b/src/SFileOpenArchive.cpp
@@ -369,8 +369,8 @@ bool WINAPI SFileOpenArchive(
// higher than 0x10000000, it would overflow in 32-bit version
// Observed in the malformed Warcraft III maps
// Example map: MPQ_2016_v1_ProtectedMap_TableSizeOverflow.w3x
- ha->pHeader->dwHashTableSize &= 0x0FFFFFFF;
- ha->pHeader->dwBlockTableSize &= 0x0FFFFFFF;
+ ha->pHeader->dwBlockTableSize = MPQ_BLOCK_INDEX(ha->pHeader->dwBlockTableSize);
+ ha->pHeader->dwHashTableSize = MPQ_BLOCK_INDEX(ha->pHeader->dwHashTableSize);
// Both MPQ_OPEN_NO_LISTFILE or MPQ_OPEN_NO_ATTRIBUTES trigger read only mode
if(dwFlags & (MPQ_OPEN_NO_LISTFILE | MPQ_OPEN_NO_ATTRIBUTES))
diff --git a/src/SFileOpenFileEx.cpp b/src/SFileOpenFileEx.cpp
index 3794680..afbfc78 100644
--- a/src/SFileOpenFileEx.cpp
+++ b/src/SFileOpenFileEx.cpp
@@ -309,8 +309,10 @@ bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearch
{
if(pFileEntry == NULL || (pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0)
nError = ERROR_FILE_NOT_FOUND;
- if(pFileEntry != NULL && pFileEntry->dwFlags & ~MPQ_FILE_VALID_FLAGS)
- nError = ERROR_NOT_SUPPORTED;
+
+ // Ignore unknown loading flags (example: MPQ_2016_v1_WME4_4.w3x)
+// if(pFileEntry != NULL && pFileEntry->dwFlags & ~MPQ_FILE_VALID_FLAGS)
+// nError = ERROR_NOT_SUPPORTED;
}
// Did the caller just wanted to know if the file exists?
diff --git a/src/StormLib.h b/src/StormLib.h
index 22658bd..c25a1a8 100644
--- a/src/StormLib.h
+++ b/src/StormLib.h
@@ -218,7 +218,6 @@ extern "C" {
#define MPQ_FILE_REPLACEEXISTING 0x80000000 // Replace when the file exist (SFileAddFile)
#define MPQ_FILE_COMPRESS_MASK 0x0000FF00 // Mask for a file being compressed
-#define MPQ_FILE_EXISTS_MASK 0xF00000FF // These must be either zero or MPQ_FILE_EXISTS
#define MPQ_FILE_VALID_FLAGS (MPQ_FILE_IMPLODE | \
MPQ_FILE_COMPRESS | \
@@ -231,6 +230,8 @@ extern "C" {
MPQ_FILE_SIGNATURE | \
MPQ_FILE_EXISTS)
+#define MPQ_BLOCK_INDEX(bi) ((bi) & 0x0FFFFFFF) // Index mask for block table index
+
// Compression types for multiple compressions
#define MPQ_COMPRESSION_HUFFMANN 0x01 // Huffmann compression (used on WAVE files only)
#define MPQ_COMPRESSION_ZLIB 0x02 // ZLIB compression
diff --git a/test/StormTest.cpp b/test/StormTest.cpp
index f0456e7..2d73bd9 100644
--- a/test/StormTest.cpp
+++ b/test/StormTest.cpp
@@ -4273,11 +4273,11 @@ int main(int argc, char * argv[])
// Not a test, but rather a tool for creating links to duplicated files
// if(nError == ERROR_SUCCESS)
// nError = FindFilePairs(ForEachFile_CreateArchiveLink, "2004 - WoW\\06080", "2004 - WoW\\06299");
-
- // Search all testing archives and verify their SHA1 hash
-// if(nError == ERROR_SUCCESS)
-// nError = FindFiles(ForEachFile_VerifyFileChecksum, szMpqSubDir);
/*
+ // Search all testing archives and verify their SHA1 hash
+ if(nError == ERROR_SUCCESS)
+ nError = FindFiles(ForEachFile_VerifyFileChecksum, szMpqSubDir);
+
// Test sparse compression
if(nError == ERROR_SUCCESS)
nError = TestSparseCompression();
@@ -4456,10 +4456,17 @@ int main(int argc, char * argv[])
// Open another protected map
if(nError == ERROR_SUCCESS)
nError = TestOpenArchive("MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x");
-*/
+
// Something like Somj 2.0
if(nError == ERROR_SUCCESS)
nError = TestOpenArchive("MPQ_2016_v1_ProtectedMap_Somj2.w3x");
+
+ // Protector from China (2016-05-27)
+ if(nError == ERROR_SUCCESS)
+ nError = TestOpenArchive("MPQ_2016_v1_WME4_4.w3x");
+*/
+ if(nError == ERROR_SUCCESS)
+ nError = TestOpenArchive("MPQ_2016_v1_AnotherProtectedMap.w3x");
/*
// Open the multi-file archive with wrong prefix to see how StormLib deals with it
if(nError == ERROR_SUCCESS)