aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLadislav Zezula <ladislav.zezula@avg.com>2013-12-09 14:51:40 +0100
committerLadislav Zezula <ladislav.zezula@avg.com>2013-12-09 14:51:40 +0100
commit5106d34fdaaf6378abf0fa8bb0b30d54a487e398 (patch)
treec5a25c22fdb67a0c0f0021c49380d081ff2679eb /src
parentcc0ed30d33eb020c4fda8b7ceeb7fde7a0af9b41 (diff)
+ Bugfixes
Diffstat (limited to 'src')
-rw-r--r--src/SBaseCommon.cpp3
-rw-r--r--src/SBaseFileTable.cpp161
-rw-r--r--src/SFileAttributes.cpp36
-rw-r--r--src/SFileCompactArchive.cpp3
-rw-r--r--src/SFileCreateArchive.cpp6
-rw-r--r--src/SFileOpenArchive.cpp30
-rw-r--r--src/StormCommon.h21
-rw-r--r--src/StormLib.h3
8 files changed, 178 insertions, 85 deletions
diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp
index 3bb10de..a0e789b 100644
--- a/src/SBaseCommon.cpp
+++ b/src/SBaseCommon.cpp
@@ -710,8 +710,7 @@ void * LoadMpqTable(
pbMpqTable = pbToRead = STORM_ALLOC(BYTE, dwTableSize);
if(pbMpqTable != NULL)
{
- // "interface.MPQ.part" in trial version of World of Warcraft
- // has block table and hash table compressed.
+ // Check if the MPQ table is encrypted
if(dwCompressedSize < dwTableSize)
{
// Allocate temporary buffer for holding compressed data
diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp
index 6b4eada..bf6be59 100644
--- a/src/SBaseFileTable.cpp
+++ b/src/SBaseFileTable.cpp
@@ -229,47 +229,53 @@ void SetBits(
//-----------------------------------------------------------------------------
// Support for MPQ header
-static DWORD GetArchiveSize32(TMPQArchive * ha, TMPQBlock * pBlockTable, DWORD dwBlockTableSize)
+static DWORD GetMaxFileOffset32(TMPQArchive * ha, TMPQBlock * pBlockTable, DWORD dwBlockTableSize)
{
TMPQHeader * pHeader = ha->pHeader;
- ULONGLONG FileSize = 0;
- DWORD dwArchiveSize = pHeader->dwHeaderSize;
+ DWORD dwMaxFileOffset = ha->pHeader->dwArchiveSize;
DWORD dwByteOffset;
DWORD dwBlockIndex;
- // Increment by hash table size
- dwByteOffset = pHeader->dwHashTablePos + (pHeader->dwHashTableSize * sizeof(TMPQHash));
- if(dwByteOffset > dwArchiveSize)
- dwArchiveSize = dwByteOffset;
+ // We can call this only for malformed archives v 1.0
+ assert(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1);
+ assert((ha->dwFlags & MPQ_FLAG_MALFORMED) != 0);
+
+ // If the block table is at the end, decrement the limit by the block table
+ if(pHeader->dwBlockTablePos + (pHeader->dwBlockTableSize * sizeof(TMPQBlock)) >= dwMaxFileOffset)
+ dwMaxFileOffset = pHeader->dwBlockTablePos;
+
+ // If the hash table is at the end, decrement the limit by the hash table
+ if(pHeader->dwHashTablePos + (pHeader->dwHashTableSize * sizeof(TMPQBlock)) >= dwMaxFileOffset)
+ dwMaxFileOffset = pHeader->dwHashTablePos;
+
+ // Return what we found
+ return dwMaxFileOffset;
+}
- // Increment by block table size
- dwByteOffset = pHeader->dwBlockTablePos + (pHeader->dwBlockTableSize * sizeof(TMPQBlock));
- if(dwByteOffset > dwArchiveSize)
- dwArchiveSize = dwByteOffset;
+static ULONGLONG DetermineEndOfArchive_V1_V2(
+ TMPQArchive * ha,
+ ULONGLONG MpqOffset,
+ ULONGLONG FileSize)
+{
+ ULONGLONG ByteOffset;
+ ULONGLONG EndOfMpq = FileSize;
+ DWORD SignatureHeader = 0;
- // If any of the MPQ files is beyond the hash table/block table, set the end to the file size
- for(dwBlockIndex = 0; dwBlockIndex < dwBlockTableSize; dwBlockIndex++)
+ // Check if there is a signature header
+ if((EndOfMpq - MpqOffset) > (MPQ_STRONG_SIGNATURE_SIZE + 4))
{
- // Only count files that exists
- if(pBlockTable[dwBlockIndex].dwFlags & MPQ_FILE_EXISTS)
- {
- // If this file begins past the end of tables,
- // assume that the hash/block table is not at the end of the archive
- if(pBlockTable[dwBlockIndex].dwFilePos > dwArchiveSize)
- {
- FileStream_GetSize(ha->pStream, &FileSize);
- dwArchiveSize = (DWORD)(FileSize - ha->MpqPos);
- break;
- }
- }
+ ByteOffset = EndOfMpq - MPQ_STRONG_SIGNATURE_SIZE - 4;
+ FileStream_Read(ha->pStream, &ByteOffset, &SignatureHeader, sizeof(DWORD));
+ if(BSWAP_INT32_UNSIGNED(SignatureHeader) == MPQ_STRONG_SIGNATURE_ID)
+ EndOfMpq = EndOfMpq - MPQ_STRONG_SIGNATURE_SIZE - 4;
}
- // Return what we found
- return dwArchiveSize;
+ // Return the returned archive size
+ return (EndOfMpq - MpqOffset);
}
// This function converts the MPQ header so it always looks like version 4
-static ULONGLONG GetArchiveSize64(TMPQHeader * pHeader)
+/*static ULONGLONG GetArchiveSize64(TMPQHeader * pHeader)
{
ULONGLONG ArchiveSize = pHeader->dwHeaderSize;
ULONGLONG ByteOffset = pHeader->dwHeaderSize;
@@ -316,13 +322,16 @@ static ULONGLONG GetArchiveSize64(TMPQHeader * pHeader)
return ArchiveSize;
}
-
+*/
int ConvertMpqHeaderToFormat4(
TMPQArchive * ha,
+ ULONGLONG MpqOffset,
ULONGLONG FileSize,
DWORD dwFlags)
{
TMPQHeader * pHeader = (TMPQHeader *)ha->HeaderData;
+ ULONGLONG BlockTablePos64 = 0;
+ ULONGLONG HashTablePos64 = 0;
ULONGLONG ByteOffset;
USHORT wFormatVersion = BSWAP_INT16_UNSIGNED(pHeader->wFormatVersion);
int nError = ERROR_SUCCESS;
@@ -342,7 +351,7 @@ int ConvertMpqHeaderToFormat4(
if(pHeader->dwHeaderSize != MPQ_HEADER_SIZE_V1)
{
pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1;
- ha->dwFlags |= MPQ_FLAG_PROTECTED;
+ ha->dwFlags |= MPQ_FLAG_MALFORMED;
}
//
@@ -351,35 +360,87 @@ int ConvertMpqHeaderToFormat4(
// ("w3xmaster" protector).
//
- // Fill the rest of the header with zeros
+ Label_ArchiveVersion1:
+ if(pHeader->dwHashTablePos <= pHeader->dwHeaderSize)
+ ha->dwFlags |= MPQ_FLAG_MALFORMED;
+ if(pHeader->dwBlockTablePos <= pHeader->dwHeaderSize)
+ ha->dwFlags |= MPQ_FLAG_MALFORMED;
+ if(pHeader->dwArchiveSize != pHeader->dwBlockTablePos + (pHeader->dwBlockTableSize * sizeof(TMPQBlock)))
+ ha->dwFlags |= MPQ_FLAG_MALFORMED;
+
+ // Fill the rest of the header
memset((LPBYTE)pHeader + MPQ_HEADER_SIZE_V1, 0, sizeof(TMPQHeader) - MPQ_HEADER_SIZE_V1);
pHeader->BlockTableSize64 = pHeader->dwBlockTableSize * sizeof(TMPQBlock);
pHeader->HashTableSize64 = pHeader->dwHashTableSize * sizeof(TMPQHash);
pHeader->ArchiveSize64 = pHeader->dwArchiveSize;
+
+ // Determine the archive size on malformed MPQs
+ if(ha->dwFlags & MPQ_FLAG_MALFORMED)
+ {
+ pHeader->ArchiveSize64 = DetermineEndOfArchive_V1_V2(ha, MpqOffset, FileSize);
+ pHeader->dwArchiveSize = (DWORD)pHeader->ArchiveSize64;
+ }
break;
case MPQ_FORMAT_VERSION_2:
- // Check for malformed MPQ header version 2.0
+ // Check for malformed MPQ header version 1.0
BSWAP_TMPQHEADER(pHeader, MPQ_FORMAT_VERSION_2);
if(pHeader->dwHeaderSize != MPQ_HEADER_SIZE_V2)
{
pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1;
- pHeader->HiBlockTablePos64 = 0;
- pHeader->wHashTablePosHi = 0;
- pHeader->wBlockTablePosHi = 0;
- ha->dwFlags |= MPQ_FLAG_PROTECTED;
+ ha->dwFlags |= MPQ_FLAG_MALFORMED;
+ goto Label_ArchiveVersion1;
}
// Fill the rest of the header with zeros
memset((LPBYTE)pHeader + MPQ_HEADER_SIZE_V2, 0, sizeof(TMPQHeader) - MPQ_HEADER_SIZE_V2);
- if(pHeader->wHashTablePosHi || pHeader->dwHashTablePos)
- pHeader->HashTableSize64 = pHeader->dwHashTableSize * sizeof(TMPQHash);
- if(pHeader->wBlockTablePosHi || pHeader->dwBlockTablePos)
- pHeader->BlockTableSize64 = pHeader->dwBlockTableSize * sizeof(TMPQBlock);
- if(pHeader->HiBlockTablePos64)
- pHeader->HiBlockTableSize64 = pHeader->dwBlockTableSize * sizeof(USHORT);
- pHeader->ArchiveSize64 = GetArchiveSize64(pHeader);
+
+ // Calculate the expected hash table size
+ pHeader->HashTableSize64 = (pHeader->dwHashTableSize * sizeof(TMPQHash));
+ HashTablePos64 = MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos);
+
+ // Calculate the expected block table size
+ pHeader->BlockTableSize64 = (pHeader->dwBlockTableSize * sizeof(TMPQBlock));
+ BlockTablePos64 = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
+
+ // We require the block table to follow hash table
+ if(BlockTablePos64 > HashTablePos64)
+ {
+ // HashTableSize64 may be less than TblSize * sizeof(TMPQHash).
+ // That means that the hash table is compressed.
+ pHeader->HashTableSize64 = BlockTablePos64 - HashTablePos64;
+
+ // Calculate the compressed block table size
+ if(pHeader->HiBlockTablePos64 != 0)
+ {
+ // BlockTableSize64 may be less than TblSize * sizeof(TMPQBlock).
+ // That means that the hash table is compressed.
+ pHeader->BlockTableSize64 = pHeader->HiBlockTablePos64 - BlockTablePos64;
+ assert(pHeader->BlockTableSize64 <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock)));
+
+ // Determine the size of the hi-block table
+ pHeader->HiBlockTableSize64 = DetermineEndOfArchive_V1_V2(ha, MpqOffset, FileSize) - pHeader->HiBlockTablePos64;
+ assert(pHeader->HiBlockTableSize64 == (pHeader->dwBlockTableSize * sizeof(USHORT)));
+
+ // Recalculate the archive size
+ pHeader->ArchiveSize64 = pHeader->HiBlockTablePos64 + pHeader->HiBlockTableSize64;
+ }
+ else
+ {
+ // Block table size is the end of the archive minus the block table position
+ pHeader->BlockTableSize64 = DetermineEndOfArchive_V1_V2(ha, MpqOffset, FileSize) - BlockTablePos64;
+ assert(pHeader->BlockTableSize64 <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock)));
+
+ // dwArchiveSize in the header v 2.0 is 32-bit only
+ pHeader->ArchiveSize64 = BlockTablePos64 + pHeader->BlockTableSize64;
+ }
+ }
+ else
+ {
+ pHeader->ArchiveSize64 = pHeader->dwArchiveSize;
+ ha->dwFlags |= MPQ_FLAG_MALFORMED;
+ }
break;
case MPQ_FORMAT_VERSION_3:
@@ -2123,7 +2184,7 @@ static void FixBlockTableSize(
{
dwFixedTableSize = (DWORD)((FileDataStart - BlockTableStart) / sizeof(TMPQBlock));
BlockTableEnd = FileDataStart;
- ha->dwFlags |= MPQ_FLAG_PROTECTED;
+ ha->dwFlags |= MPQ_FLAG_MALFORMED;
}
}
@@ -2159,7 +2220,7 @@ static void FixCompressedFileSize(
TMPQBlock * pBlock;
size_t nElements = 0;
size_t nIndex;
- DWORD dwArchiveSize;
+ DWORD dwMaxFileOffs;
// Only perform this check on MPQs version 1.0
assert(pHeader->dwHeaderSize == MPQ_HEADER_SIZE_V1);
@@ -2169,7 +2230,7 @@ static void FixCompressedFileSize(
if(SortTable != NULL)
{
// Calculate the end of the archive
- dwArchiveSize = GetArchiveSize32(ha, pBlockTable, pHeader->dwBlockTableSize);
+ dwMaxFileOffs = GetMaxFileOffset32(ha, pBlockTable, pHeader->dwBlockTableSize);
// Put all blocks to a sort table
for(pBlock = pBlockTable; pBlock < pBlockTableEnd; pBlock++)
@@ -2191,12 +2252,12 @@ static void FixCompressedFileSize(
TMPQBlock * pBlock1 = SortTable[nIndex + 1];
TMPQBlock * pBlock0 = SortTable[nIndex];
- pBlock0->dwCSize = (pBlock->dwFlags & MPQ_FILE_COMPRESS_MASK) ? (pBlock1->dwFilePos - pBlock0->dwFilePos) : pBlock0->dwFSize;
+ pBlock0->dwCSize = (pBlock0->dwFlags & MPQ_FILE_COMPRESS_MASK) ? (pBlock1->dwFilePos - pBlock0->dwFilePos) : pBlock0->dwFSize;
}
// Fix the last entry
pBlock = SortTable[nElements - 1];
- pBlock->dwCSize = dwArchiveSize - pBlock->dwFilePos;
+ pBlock->dwCSize = (pBlock->dwFlags & MPQ_FILE_COMPRESS_MASK) ? (dwMaxFileOffs - pBlock->dwFilePos) : pBlock->dwFSize;
}
STORM_FREE(SortTable);
@@ -2239,7 +2300,7 @@ TMPQBlock * LoadBlockTable(TMPQArchive * ha, bool bDontFixEntries)
pHeader->BlockTableSize64 = FileSize - ByteOffset;
pHeader->dwBlockTableSize = (DWORD)(pHeader->BlockTableSize64 / sizeof(TMPQBlock));
dwTableSize = dwCmpSize = (DWORD)pHeader->BlockTableSize64;
- ha->dwFlags |= MPQ_FLAG_PROTECTED;
+ ha->dwFlags |= MPQ_FLAG_MALFORMED;
}
//
@@ -2259,7 +2320,7 @@ TMPQBlock * LoadBlockTable(TMPQArchive * ha, bool bDontFixEntries)
FixBlockTableSize(ha, pBlockTable);
// Defense against protectors that set invalid compressed size
- if((ha->dwFlags & MPQ_FLAG_PROTECTED) && (bDontFixEntries == false))
+ if((ha->dwFlags & MPQ_FLAG_MALFORMED) && (bDontFixEntries == false))
FixCompressedFileSize(ha, pBlockTable);
}
break;
diff --git a/src/SFileAttributes.cpp b/src/SFileAttributes.cpp
index 7f12028..a0ba774 100644
--- a/src/SFileAttributes.cpp
+++ b/src/SFileAttributes.cpp
@@ -40,16 +40,39 @@ static DWORD GetSizeOfAttributesFile(DWORD dwAttrFlags, DWORD dwFileTableSize)
cbAttrFile += dwFileTableSize * sizeof(ULONGLONG);
if(dwAttrFlags & MPQ_ATTRIBUTE_MD5)
cbAttrFile += dwFileTableSize * MD5_DIGEST_SIZE;
-
- // The bit array has been create without the last bit belonging to (attributes)
+
+ // The bit array has been created without the last bit belonging to (attributes)
// When the number of files is a multiplier of 8 plus one, then the size of (attributes)
// if 1 byte less than expected.
// Example: wow-update-13164.MPQ: BlockTableSize = 0x62E1, but there's only 0xC5C bytes
if(dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT)
cbAttrFile += (dwFileTableSize + 6) / 8;
+
+ return cbAttrFile;
+}
+
+#ifdef _DEBUG
+static DWORD GetSizeOfAttributesFile_v2(DWORD dwAttrFlags, DWORD dwFileTableSize)
+{
+ DWORD cbAttrFile = sizeof(MPQ_ATTRIBUTES_HEADER);
+
+ // Calculate size of the (attributes) file
+ if(dwAttrFlags & MPQ_ATTRIBUTE_CRC32)
+ cbAttrFile += dwFileTableSize * sizeof(DWORD);
+ if(dwAttrFlags & MPQ_ATTRIBUTE_FILETIME)
+ cbAttrFile += dwFileTableSize * sizeof(ULONGLONG);
+ if(dwAttrFlags & MPQ_ATTRIBUTE_MD5)
+ cbAttrFile += dwFileTableSize * MD5_DIGEST_SIZE;
+
+ // interface.MPQ.part from WoW build 10958 has
+ // the MPQ_ATTRIBUTE_PATCH_BIT set, but there's an array of DWORDs instead.
+ // The array is filled with zeros, so we don't know what it should contain
+ if(dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT)
+ cbAttrFile += dwFileTableSize * sizeof(DWORD);
return cbAttrFile;
}
+#endif
static int LoadAttributesFile(TMPQArchive * ha, LPBYTE pbAttrFile, DWORD cbAttrFile)
{
@@ -67,9 +90,14 @@ static int LoadAttributesFile(TMPQArchive * ha, LPBYTE pbAttrFile, DWORD cbAttrF
if(pAttrHeader->dwVersion != MPQ_ATTRIBUTES_V1)
return ERROR_BAD_FORMAT;
- // Verify the flags and size of the file
+ // Verify the size of the file
assert((pAttrHeader->dwFlags & ~MPQ_ATTRIBUTE_ALL) == 0);
- assert(GetSizeOfAttributesFile(pAttrHeader->dwFlags, dwBlockTableSize) == cbAttrFile);
+
+ // Verify the size of the file
+#ifdef _DEBUG
+ assert(cbAttrFile == GetSizeOfAttributesFile(pAttrHeader->dwFlags, dwBlockTableSize) ||
+ cbAttrFile == GetSizeOfAttributesFile_v2(pAttrHeader->dwFlags, dwBlockTableSize));
+#endif
ha->dwAttrFlags = pAttrHeader->dwFlags;
pbAttrPtr = (LPBYTE)(pAttrHeader + 1);
diff --git a/src/SFileCompactArchive.cpp b/src/SFileCompactArchive.cpp
index 64c599d..ad9801b 100644
--- a/src/SFileCompactArchive.cpp
+++ b/src/SFileCompactArchive.cpp
@@ -332,14 +332,13 @@ static int CopyMpqFileSectors(
{
// At this point, number of bytes written should be exactly
// the same like the compressed file size. If it isn't,
- // there's something wrong (an unknown archive version, MPQ protection, ...)
+ // there's something wrong (an unknown archive version, MPQ malformation, ...)
//
// Note: Diablo savegames have very weird layout, and the file "hero"
// seems to have improper compressed size. Instead of real compressed size,
// the "dwCmpSize" member of the block table entry contains
// uncompressed size of file data + size of the sector table.
// If we compact the archive, Diablo will refuse to load the game
- // Seems like some sort of protection to me.
//
// Note: Some patch files in WOW patches don't count the patch header
// into compressed size
diff --git a/src/SFileCreateArchive.cpp b/src/SFileCreateArchive.cpp
index 2b51efa..4ae71e9 100644
--- a/src/SFileCreateArchive.cpp
+++ b/src/SFileCreateArchive.cpp
@@ -80,11 +80,15 @@ bool WINAPI SFileCreateArchive(const TCHAR * szMpqName, DWORD dwCreateFlags, DWO
CreateInfo.dwStreamFlags = STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE;
CreateInfo.dwFileFlags1 = (dwCreateFlags & MPQ_CREATE_LISTFILE) ? MPQ_FILE_EXISTS : 0;
CreateInfo.dwFileFlags2 = (dwCreateFlags & MPQ_CREATE_ATTRIBUTES) ? MPQ_FILE_EXISTS : 0;
- CreateInfo.dwAttrFlags = (dwCreateFlags & MPQ_CREATE_ATTRIBUTES) ? MPQ_ATTRIBUTE_ALL : 0;
+ CreateInfo.dwAttrFlags = (dwCreateFlags & MPQ_CREATE_ATTRIBUTES) ? (MPQ_ATTRIBUTE_CRC32 | MPQ_ATTRIBUTE_FILETIME | MPQ_ATTRIBUTE_MD5) : 0;
CreateInfo.dwSectorSize = (CreateInfo.dwMpqVersion >= MPQ_FORMAT_VERSION_3) ? 0x4000 : 0x1000;
CreateInfo.dwRawChunkSize = (CreateInfo.dwMpqVersion >= MPQ_FORMAT_VERSION_4) ? 0x4000 : 0;
CreateInfo.dwMaxFileCount = dwMaxFileCount;
+ // Set the proper attribute parts
+ if((CreateInfo.dwMpqVersion >= MPQ_FORMAT_VERSION_3) && (dwCreateFlags & MPQ_CREATE_ATTRIBUTES))
+ CreateInfo.dwAttrFlags |= MPQ_ATTRIBUTE_PATCH_BIT;
+
// Backward compatibility: SFileCreateArchive always used to add (listfile)
// We would break loads of applications if we change that
CreateInfo.dwFileFlags1 = MPQ_FILE_EXISTS;
diff --git a/src/SFileOpenArchive.cpp b/src/SFileOpenArchive.cpp
index b05cff3..417b43d 100644
--- a/src/SFileOpenArchive.cpp
+++ b/src/SFileOpenArchive.cpp
@@ -213,7 +213,7 @@ bool WINAPI SFileOpenArchive(
// Initialize handle structure and allocate structure for MPQ header
if(nError == ERROR_SUCCESS)
{
- ULONGLONG SearchPos = 0;
+ ULONGLONG SearchOffset = 0;
DWORD dwHeaderID;
memset(ha, 0, sizeof(TMPQArchive));
@@ -230,23 +230,23 @@ bool WINAPI SFileOpenArchive(
ha->dwFlags |= MPQ_FLAG_CHECK_SECTOR_CRC;
// Find the offset of MPQ header within the file
- while(SearchPos < FileSize)
+ while(SearchOffset < FileSize)
{
DWORD dwBytesAvailable = MPQ_HEADER_SIZE_V4;
// Cut the bytes available, if needed
- if((FileSize - SearchPos) < MPQ_HEADER_SIZE_V4)
- dwBytesAvailable = (DWORD)(FileSize - SearchPos);
+ if((FileSize - SearchOffset) < MPQ_HEADER_SIZE_V4)
+ dwBytesAvailable = (DWORD)(FileSize - SearchOffset);
// Read the eventual MPQ header
- if(!FileStream_Read(ha->pStream, &SearchPos, ha->HeaderData, dwBytesAvailable))
+ if(!FileStream_Read(ha->pStream, &SearchOffset, ha->HeaderData, dwBytesAvailable))
{
nError = GetLastError();
break;
}
// There are AVI files from Warcraft III with 'MPQ' extension.
- if(SearchPos == 0 && IsAviFile(ha->HeaderData))
+ if(SearchOffset == 0 && IsAviFile(ha->HeaderData))
{
nError = ERROR_AVI_FILE;
break;
@@ -257,16 +257,16 @@ bool WINAPI SFileOpenArchive(
if(dwHeaderID == ID_MPQ_USERDATA && ha->pUserData == NULL && (dwFlags & MPQ_OPEN_FORCE_MPQ_V1) == 0)
{
// Verify if this looks like a valid user data
- pUserData = IsValidMpqUserData(SearchPos, FileSize, ha->HeaderData);
+ pUserData = IsValidMpqUserData(SearchOffset, FileSize, ha->HeaderData);
if(pUserData != NULL)
{
// Fill the user data header
- ha->UserDataPos = SearchPos;
+ ha->UserDataPos = SearchOffset;
ha->pUserData = &ha->UserData;
memcpy(ha->pUserData, pUserData, sizeof(TMPQUserData));
// Continue searching from that position
- SearchPos += ha->pUserData->dwHeaderOffs;
+ SearchOffset += ha->pUserData->dwHeaderOffs;
continue;
}
}
@@ -275,7 +275,7 @@ bool WINAPI SFileOpenArchive(
if(dwHeaderID == ID_MPQ)
{
// Now convert the header to version 4
- nError = ConvertMpqHeaderToFormat4(ha, FileSize, dwFlags);
+ nError = ConvertMpqHeaderToFormat4(ha, SearchOffset, FileSize, dwFlags);
break;
}
@@ -295,7 +295,7 @@ bool WINAPI SFileOpenArchive(
}
// Move to the next possible offset
- SearchPos += 0x200;
+ SearchOffset += 0x200;
}
// Did we identify one of the supported headers?
@@ -303,11 +303,11 @@ bool WINAPI SFileOpenArchive(
{
// Set the user data position to the MPQ header, if none
if(ha->pUserData == NULL)
- ha->UserDataPos = SearchPos;
+ ha->UserDataPos = SearchOffset;
// Set the position of the MPQ header
ha->pHeader = (TMPQHeader *)ha->HeaderData;
- ha->MpqPos = SearchPos;
+ ha->MpqPos = SearchOffset;
// Sector size must be nonzero.
if(ha->pHeader->wSectorSize == 0)
@@ -376,8 +376,8 @@ bool WINAPI SFileOpenArchive(
nError = BuildFileTable(ha);
}
- // Verify the file table, if no kind of protection was detected
- if(nError == ERROR_SUCCESS && (ha->dwFlags & MPQ_FLAG_PROTECTED) == 0)
+ // Verify the file table, if no kind of malformation was detected
+ if(nError == ERROR_SUCCESS && (ha->dwFlags & MPQ_FLAG_MALFORMED) == 0)
{
TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
ULONGLONG RawFilePos;
diff --git a/src/StormCommon.h b/src/StormCommon.h
index bfe99f7..aeedbca 100644
--- a/src/StormCommon.h
+++ b/src/StormCommon.h
@@ -74,20 +74,21 @@
// MPQ signature information
// Size of each signature type
-#define MPQ_WEAK_SIGNATURE_SIZE 64
-#define MPQ_STRONG_SIGNATURE_SIZE 256
+#define MPQ_WEAK_SIGNATURE_SIZE 64
+#define MPQ_STRONG_SIGNATURE_SIZE 256
+#define MPQ_STRONG_SIGNATURE_ID 0x5349474E // ID of the strong signature ("NGIS")
// MPQ signature info
typedef struct _MPQ_SIGNATURE_INFO
{
- ULONGLONG BeginMpqData; // File offset where the hashing starts
- ULONGLONG BeginExclude; // Begin of the excluded area (used for (signature) file)
- ULONGLONG EndExclude; // End of the excluded area (used for (signature) file)
- ULONGLONG EndMpqData; // File offset where the hashing ends
- ULONGLONG EndOfFile; // Size of the entire file
+ ULONGLONG BeginMpqData; // File offset where the hashing starts
+ ULONGLONG BeginExclude; // Begin of the excluded area (used for (signature) file)
+ ULONGLONG EndExclude; // End of the excluded area (used for (signature) file)
+ ULONGLONG EndMpqData; // File offset where the hashing ends
+ ULONGLONG EndOfFile; // Size of the entire file
BYTE Signature[MPQ_STRONG_SIGNATURE_SIZE + 0x10];
- DWORD cbSignatureSize; // Length of the signature
- DWORD SignatureTypes; // See SIGNATURE_TYPE_XXX
+ DWORD cbSignatureSize; // Length of the signature
+ DWORD SignatureTypes; // See SIGNATURE_TYPE_XXX
} MPQ_SIGNATURE_INFO, *PMPQ_SIGNATURE_INFO;
@@ -167,7 +168,7 @@ TMPQFile * IsValidFileHandle(HANDLE hFile);
//-----------------------------------------------------------------------------
// Support for MPQ file tables
-int ConvertMpqHeaderToFormat4(TMPQArchive * ha, ULONGLONG FileSize, DWORD dwFlags);
+int ConvertMpqHeaderToFormat4(TMPQArchive * ha, ULONGLONG MpqOffset, ULONGLONG FileSize, DWORD dwFlags);
TMPQHash * FindFreeHashEntry(TMPQArchive * ha, DWORD dwStartIndex, DWORD dwName1, DWORD dwName2, LCID lcLocale);
TMPQHash * GetFirstHashEntry(TMPQArchive * ha, const char * szFileName);
diff --git a/src/StormLib.h b/src/StormLib.h
index 3659c23..9cdb28b 100644
--- a/src/StormLib.h
+++ b/src/StormLib.h
@@ -174,7 +174,7 @@ extern "C" {
// Flags for TMPQArchive::dwFlags
#define MPQ_FLAG_READ_ONLY 0x00000001 // If set, the MPQ has been open for read-only access
#define MPQ_FLAG_CHANGED 0x00000002 // If set, the MPQ tables have been changed
-#define MPQ_FLAG_PROTECTED 0x00000004 // Some kind of protector detected (W3M maps)
+#define MPQ_FLAG_MALFORMED 0x00000004 // Malformed data structure detected (W3M map protectors)
#define MPQ_FLAG_CHECK_SECTOR_CRC 0x00000008 // Checking sector CRC when reading files
#define MPQ_FLAG_LISTFILE_INVALID 0x00000020 // If set, it means that the (listfile) has been invalidated
#define MPQ_FLAG_ATTRIBUTES_INVALID 0x00000040 // If set, it means that the (attributes) has been invalidated
@@ -286,6 +286,7 @@ extern "C" {
// Deprecated
#define MPQ_OPEN_READ_ONLY STREAM_FLAG_READ_ONLY
#define MPQ_OPEN_ENCRYPTED STREAM_PROVIDER_ENCRYPTED
+#define MPQ_OPEN_PARTIAL STREAM_PROVIDER_PARTIAL
// Flags for SFileCreateArchive
#define MPQ_CREATE_LISTFILE 0x00100000 // Also add the (listfile) file