aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLadislav Zezula <zezula@volny.cz>2024-04-16 14:52:23 +0200
committerGitHub <noreply@github.com>2024-04-16 14:52:23 +0200
commit605222393594f5885b877bfc0086dae756674965 (patch)
treeaeabad8c5789d3a8a4605ed8ebab7539aac702e4 /src
parenta8f782a2d2602b20da0b9052c37a4ce85040ed27 (diff)
parent7fdae1508a001568d896300e951e83c0825a520d (diff)
Merge pull request #326 from ladislav-zezula/LZ_NewProtectedMPQ
Support for new MPQ protection
Diffstat (limited to 'src')
-rw-r--r--src/SBaseFileTable.cpp10
-rw-r--r--src/SFileOpenArchive.cpp39
-rw-r--r--src/SFileReadFile.cpp7
3 files changed, 45 insertions, 11 deletions
diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp
index fa388fc..a222ac5 100644
--- a/src/SBaseFileTable.cpp
+++ b/src/SBaseFileTable.cpp
@@ -479,8 +479,16 @@ DWORD ConvertMpqHeaderToFormat4(
{
case MPQ_FORMAT_VERSION_1:
- // Check for malformed MPQ header version 1.0
+ // Make sure that the MPQ Header is properly swapped
BSWAP_TMPQHEADER(pHeader, MPQ_FORMAT_VERSION_1);
+
+ // Check for blatantly wrong MPQ header by the hash table position
+ if(((ByteOffset + pHeader->dwHashTablePos) & 0xFFFFFFFF) > FileSize)
+ return ERROR_FAKE_MPQ_HEADER;
+ if(((ByteOffset + pHeader->dwBlockTablePos) & 0xFFFFFFFF) > FileSize)
+ return ERROR_FAKE_MPQ_HEADER;
+
+ // Check for malformed MPQ header version 1.0
if(pHeader->wFormatVersion != MPQ_FORMAT_VERSION_1 || pHeader->dwHeaderSize != MPQ_HEADER_SIZE_V1)
{
pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1;
diff --git a/src/SFileOpenArchive.cpp b/src/SFileOpenArchive.cpp
index 4b2d3b4..a97ecea 100644
--- a/src/SFileOpenArchive.cpp
+++ b/src/SFileOpenArchive.cpp
@@ -228,7 +228,7 @@ bool WINAPI SFileOpenArchive(
DWORD dwFlags,
HANDLE * phMpq)
{
- TMPQUserData * pUserData;
+ TMPQUserData * pUserData = NULL;
TFileStream * pStream = NULL; // Open file stream
TMPQArchive * ha = NULL; // Archive handle
TFileEntry * pFileEntry;
@@ -354,18 +354,25 @@ bool WINAPI SFileOpenArchive(
{
if(ha->pUserData == NULL && dwHeaderID == ID_MPQ_USERDATA)
{
+ // Copy the eventual user data to the separate buffer
+ memcpy(&ha->UserData, ha->HeaderData, sizeof(TMPQUserData));
+
// Verify if this looks like a valid user data
- pUserData = IsValidMpqUserData(ByteOffset, FileSize, ha->HeaderData);
+ pUserData = IsValidMpqUserData(ByteOffset, FileSize, &ha->UserData);
if(pUserData != NULL)
{
- // Fill the user data header
- ha->UserDataPos = ByteOffset;
- ha->pUserData = &ha->UserData;
- memcpy(ha->pUserData, pUserData, sizeof(TMPQUserData));
-
- // Continue searching from that position
- ByteOffset += ha->pUserData->dwHeaderOffs;
- break;
+ // Set the byte offset to the loaded user data
+ ULONGLONG TempByteOffset = ByteOffset + pUserData->dwHeaderOffs;
+
+ // Read the eventual MPQ header from the position where the user data points
+ if(!FileStream_Read(ha->pStream, &TempByteOffset, ha->HeaderData, sizeof(ha->HeaderData)))
+ {
+ dwErrCode = GetLastError();
+ break;
+ }
+
+ // Re-initialize the header ID
+ dwHeaderID = BSWAP_INT32_UNSIGNED(ha->HeaderData[0]);
}
}
}
@@ -405,12 +412,24 @@ bool WINAPI SFileOpenArchive(
// Move the pointers
ByteOffset += 0x200;
+ pUserData = NULL;
}
}
// Did we identify one of the supported headers?
if(dwErrCode == ERROR_SUCCESS)
{
+ // If we retrieved the offset from the user data offset, initialize the user data
+ if(pUserData != NULL)
+ {
+ // Fill the user data header
+ ha->pUserData = &ha->UserData;
+ ha->UserDataPos = ByteOffset;
+
+ // Set the real byte offset
+ ByteOffset = ByteOffset + pUserData->dwHeaderOffs;
+ }
+
// Set the user data position to the MPQ header, if none
if(ha->pUserData == NULL)
ha->UserDataPos = ByteOffset;
diff --git a/src/SFileReadFile.cpp b/src/SFileReadFile.cpp
index b0698c1..8ab5f48 100644
--- a/src/SFileReadFile.cpp
+++ b/src/SFileReadFile.cpp
@@ -194,6 +194,13 @@ static DWORD ReadMpqSectors(TMPQFile * hf, LPBYTE pbBuffer, DWORD dwByteOffset,
dwErrCode = ERROR_FILE_CORRUPT;
break;
}
+
+ // Special case (MPQ_2024_v1_300TK2.09p.w3x, file File00010254.blp):
+ // Extracted less than required. Fill the rest with zeros
+ if((DWORD)(cbOutSector) < dwBytesInThisSector)
+ {
+ memset(pbOutSector + cbOutSector, 0, dwBytesInThisSector - cbOutSector);
+ }
}
else
{