diff options
author | Ladislav Zezula <ladislav.zezula@avg.com> | 2013-12-09 14:51:40 +0100 |
---|---|---|
committer | Ladislav Zezula <ladislav.zezula@avg.com> | 2013-12-09 14:51:40 +0100 |
commit | 5106d34fdaaf6378abf0fa8bb0b30d54a487e398 (patch) | |
tree | c5a25c22fdb67a0c0f0021c49380d081ff2679eb /src | |
parent | cc0ed30d33eb020c4fda8b7ceeb7fde7a0af9b41 (diff) |
+ Bugfixes
Diffstat (limited to 'src')
-rw-r--r-- | src/SBaseCommon.cpp | 3 | ||||
-rw-r--r-- | src/SBaseFileTable.cpp | 161 | ||||
-rw-r--r-- | src/SFileAttributes.cpp | 36 | ||||
-rw-r--r-- | src/SFileCompactArchive.cpp | 3 | ||||
-rw-r--r-- | src/SFileCreateArchive.cpp | 6 | ||||
-rw-r--r-- | src/SFileOpenArchive.cpp | 30 | ||||
-rw-r--r-- | src/StormCommon.h | 21 | ||||
-rw-r--r-- | src/StormLib.h | 3 |
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 |