diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/SBaseCommon.cpp | 5 | ||||
-rw-r--r-- | src/SBaseFileTable.cpp | 12 | ||||
-rw-r--r-- | src/SBaseSubTypes.cpp | 27 | ||||
-rw-r--r-- | src/SFileAddFile.cpp | 2 | ||||
-rw-r--r-- | src/SFileCreateArchive.cpp | 29 | ||||
-rw-r--r-- | src/SFileFindFile.cpp | 4 | ||||
-rw-r--r-- | src/SFileOpenArchive.cpp | 31 | ||||
-rw-r--r-- | src/SFileReadFile.cpp | 10 | ||||
-rw-r--r-- | src/StormCommon.h | 1 | ||||
-rw-r--r-- | src/StormLib.h | 13 |
10 files changed, 81 insertions, 53 deletions
diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp index a1aa78e..98d541a 100644 --- a/src/SBaseCommon.cpp +++ b/src/SBaseCommon.cpp @@ -1334,11 +1334,12 @@ DWORD AllocateSectorOffsets(TMPQFile * hf, bool bLoadFromFile) // They are mostly empty on WoW release MPQs, but on MPQs from PTR,
// they contain random non-zero data. Their meaning is unknown.
//
- // These extra values are, however, include in the dwCmpSize in the file
+ // These extra values are, however, included in the dwCmpSize in the file
// table. We cannot ignore them, because compacting archive would fail
//
- if(hf->SectorOffsets[0] > dwSectorOffsLen)
+ // Clear the lower 2 bits in order to make sure that the value is aligned to 4 bytes
+ if((hf->SectorOffsets[0] & 0xFFFFFFFC) > dwSectorOffsLen)
{
// MPQ protectors put some ridiculous values there. We must limit the extra bytes
if(hf->SectorOffsets[0] > (dwSectorOffsLen + 0x400))
diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp index 7d52f7c..97fa3a2 100644 --- a/src/SBaseFileTable.cpp +++ b/src/SBaseFileTable.cpp @@ -893,15 +893,11 @@ static DWORD BuildFileTableFromBlockTable( TMPQHash * pHash;
LPDWORD DefragmentTable = NULL;
DWORD dwItemCount = 0;
- DWORD dwFlagMask;
// Sanity checks
assert(ha->pFileTable != NULL);
assert(ha->dwFileTableSize >= ha->dwMaxFileCount);
- // MPQs for Warcraft III doesn't know some flags, namely MPQ_FILE_SINGLE_UNIT and MPQ_FILE_PATCH_FILE
- dwFlagMask = (ha->dwFlags & MPQ_FLAG_WAR3_MAP) ? MPQ_FILE_VALID_FLAGS_W3X : MPQ_FILE_VALID_FLAGS;
-
// Defragment the hash table, if needed
if(ha->dwFlags & MPQ_FLAG_HASH_TABLE_CUT)
{
@@ -976,10 +972,12 @@ static DWORD BuildFileTableFromBlockTable( if(pFileEntry->ByteOffset == 0 && pBlock->dwFSize == 0)
pFileEntry->ByteOffset = ha->pHeader->dwHeaderSize;
+ // Clear file flags that are unknown to this type of map.
+ pFileEntry->dwFlags = pBlock->dwFlags & ha->dwValidFileFlags;
+
// Fill the rest of the file entry
- pFileEntry->dwFileSize = pBlock->dwFSize;
- pFileEntry->dwCmpSize = pBlock->dwCSize;
- pFileEntry->dwFlags = pBlock->dwFlags & dwFlagMask;
+ pFileEntry->dwFileSize = pBlock->dwFSize;
+ pFileEntry->dwCmpSize = pBlock->dwCSize;
}
}
diff --git a/src/SBaseSubTypes.cpp b/src/SBaseSubTypes.cpp index 6ab4a99..9808ef3 100644 --- a/src/SBaseSubTypes.cpp +++ b/src/SBaseSubTypes.cpp @@ -201,6 +201,9 @@ TMPQHash * LoadSqpHashTable(TMPQArchive * ha) // Ignore free entries if(pSqpHash->dwBlockIndex != HASH_ENTRY_FREE) { + // Store the hash entry to a temporary variable + TSQPHash TempEntry = *pSqpHash; + // Check block index against the size of the block table if(pHeader->dwBlockTableSize <= MPQ_BLOCK_INDEX(pSqpHash) && pSqpHash->dwBlockIndex < HASH_ENTRY_DELETED) dwErrCode = ERROR_FILE_CORRUPT; @@ -209,15 +212,13 @@ TMPQHash * LoadSqpHashTable(TMPQArchive * ha) if(pSqpHash->dwAlwaysZero != 0 && pSqpHash->dwAlwaysZero != HASH_ENTRY_FREE) dwErrCode = ERROR_FILE_CORRUPT; - // Store the file name hash - pMpqHash->dwName1 = pSqpHash->dwName1; - pMpqHash->dwName2 = pSqpHash->dwName2; - - // Store the rest. Note that this must be done last, - // because block index corresponds to pMpqHash->dwName2 - pMpqHash->dwBlockIndex = MPQ_BLOCK_INDEX(pSqpHash); + // Copy the entry to the MPQ hash entry + pMpqHash->dwName1 = TempEntry.dwName1; + pMpqHash->dwName2 = TempEntry.dwName2; + pMpqHash->dwBlockIndex = MPQ_BLOCK_INDEX(&TempEntry); pMpqHash->Platform = 0; pMpqHash->lcLocale = 0; + pMpqHash->Reserved = 0; } } @@ -241,7 +242,6 @@ TMPQBlock * LoadSqpBlockTable(TMPQArchive * ha) TSQPBlock * pSqpBlockEnd; TSQPBlock * pSqpBlock; TMPQBlock * pMpqBlock; - DWORD dwFlags; DWORD dwErrCode = ERROR_SUCCESS; // Load the hash table @@ -253,15 +253,18 @@ TMPQBlock * LoadSqpBlockTable(TMPQArchive * ha) pMpqBlock = (TMPQBlock *)pSqpBlockTable; for(pSqpBlock = pSqpBlockTable; pSqpBlock < pSqpBlockEnd; pSqpBlock++, pMpqBlock++) { + // Store the block entry to a temporary variable + TSQPBlock TempEntry = *pSqpBlock; + // Check for valid flags if(pSqpBlock->dwFlags & ~MPQ_FILE_VALID_FLAGS) dwErrCode = ERROR_FILE_CORRUPT; // Convert SQP block table entry to MPQ block table entry - dwFlags = pSqpBlock->dwFlags; - pMpqBlock->dwCSize = pSqpBlock->dwCSize; - pMpqBlock->dwFSize = pSqpBlock->dwFSize; - pMpqBlock->dwFlags = dwFlags; + pMpqBlock->dwFilePos = TempEntry.dwFilePos; + pMpqBlock->dwCSize = TempEntry.dwCSize; + pMpqBlock->dwFSize = TempEntry.dwFSize; + pMpqBlock->dwFlags = TempEntry.dwFlags; } // If an error occured, we need to free the hash table diff --git a/src/SFileAddFile.cpp b/src/SFileAddFile.cpp index 7b88c12..9c7331b 100644 --- a/src/SFileAddFile.cpp +++ b/src/SFileAddFile.cpp @@ -795,7 +795,7 @@ bool WINAPI SFileCreateFile( if(dwErrCode == ERROR_SUCCESS)
{
// Mask all unsupported flags out
- dwFlags &= (ha->dwFlags & MPQ_FLAG_WAR3_MAP) ? MPQ_FILE_VALID_FLAGS_W3X : MPQ_FILE_VALID_FLAGS;
+ dwFlags &= ha->dwValidFileFlags;
// Check for valid flag combinations
if((dwFlags & (MPQ_FILE_IMPLODE | MPQ_FILE_COMPRESS)) == (MPQ_FILE_IMPLODE | MPQ_FILE_COMPRESS))
diff --git a/src/SFileCreateArchive.cpp b/src/SFileCreateArchive.cpp index 742b829..4266070 100644 --- a/src/SFileCreateArchive.cpp +++ b/src/SFileCreateArchive.cpp @@ -202,20 +202,21 @@ bool WINAPI SFileCreateArchive2(const TCHAR * szMpqName, PSFILE_CREATE_MPQ pCrea if(dwErrCode == ERROR_SUCCESS) { memset(ha, 0, sizeof(TMPQArchive)); - ha->pfnHashString = HashStringSlash; - ha->pStream = pStream; - ha->dwSectorSize = pCreateInfo->dwSectorSize; - ha->UserDataPos = MpqPos; - ha->MpqPos = MpqPos; - ha->pHeader = pHeader = (TMPQHeader *)ha->HeaderData; - ha->dwMaxFileCount = dwHashTableSize; - ha->dwFileTableSize = 0; - ha->dwReservedFiles = dwReservedFiles; - ha->dwFileFlags1 = pCreateInfo->dwFileFlags1; - ha->dwFileFlags2 = pCreateInfo->dwFileFlags2; - ha->dwFileFlags3 = pCreateInfo->dwFileFlags3 ? MPQ_FILE_EXISTS : 0; - ha->dwAttrFlags = pCreateInfo->dwAttrFlags; - ha->dwFlags = dwMpqFlags | MPQ_FLAG_CHANGED; + ha->pfnHashString = HashStringSlash; + ha->pStream = pStream; + ha->dwSectorSize = pCreateInfo->dwSectorSize; + ha->UserDataPos = MpqPos; + ha->MpqPos = MpqPos; + ha->pHeader = pHeader = (TMPQHeader *)ha->HeaderData; + ha->dwMaxFileCount = dwHashTableSize; + ha->dwFileTableSize = 0; + ha->dwReservedFiles = dwReservedFiles; + ha->dwValidFileFlags = (pCreateInfo->dwMpqVersion > 1) ? MPQ_FILE_VALID_FLAGS : MPQ_FILE_VALID_FLAGS_W3X; + ha->dwFileFlags1 = pCreateInfo->dwFileFlags1; + ha->dwFileFlags2 = pCreateInfo->dwFileFlags2; + ha->dwFileFlags3 = pCreateInfo->dwFileFlags3 ? MPQ_FILE_EXISTS : 0; + ha->dwAttrFlags = pCreateInfo->dwAttrFlags; + ha->dwFlags = dwMpqFlags | MPQ_FLAG_CHANGED; pStream = NULL; // Fill the MPQ header diff --git a/src/SFileFindFile.cpp b/src/SFileFindFile.cpp index ef8b834..223e194 100644 --- a/src/SFileFindFile.cpp +++ b/src/SFileFindFile.cpp @@ -221,7 +221,7 @@ static bool DoMPQSearch_FileEntry( if((pFileEntry->dwFlags & hs->dwFlagMask) == MPQ_FILE_EXISTS)
{
// Ignore fake files which are not compressed but have size higher than the archive
- if ((pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) == 0 && (pFileEntry->dwFileSize > ha->FileSize))
+ if((pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) == 0 && (pFileEntry->dwFileSize > ha->FileSize))
return false;
// Now we have to check if this file was not enumerated before
@@ -236,8 +236,6 @@ static bool DoMPQSearch_FileEntry( // Prepare the block index
dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable);
- if(dwBlockIndex == 569)
- szNameBuff[0] = 'F';
// Get the file name. If it's not known, we will create pseudo-name
szFileName = pFileEntry->szFileName;
diff --git a/src/SFileOpenArchive.cpp b/src/SFileOpenArchive.cpp index ea29850..52e1a39 100644 --- a/src/SFileOpenArchive.cpp +++ b/src/SFileOpenArchive.cpp @@ -35,21 +35,28 @@ static MTYPE CheckMapType(LPCTSTR szFileName, LPBYTE pbHeaderBuffer, size_t cbHe DWORD DwordValue2 = BSWAP_INT32_UNSIGNED(HeaderInt32[2]); DWORD DwordValue3 = BSWAP_INT32_UNSIGNED(HeaderInt32[3]); - // Test for AVI files (Warcraft III cinematics) - 'RIFF', 'AVI ' or 'LIST' - if(DwordValue0 == 0x46464952 && DwordValue2 == 0x20495641 && DwordValue3 == 0x5453494C) - return MapTypeAviFile; - - // Check for Starcraft II maps + // Check maps by extension (Starcraft, Starcraft II). We must do this before + // checking actual data, because the "NP_Protect" protector places + // fake Warcraft III header into the Starcraft II maps if((szExtension = _tcsrchr(szFileName, _T('.'))) != NULL) { - // The "NP_Protect" protector places fake Warcraft III header - // into the Starcraft II maps, whilst SC2 maps have no other header but MPQ v4 + // Check for Starcraft II maps by extension if(!_tcsicmp(szExtension, _T(".s2ma")) || !_tcsicmp(szExtension, _T(".SC2Map")) || !_tcsicmp(szExtension, _T(".SC2Mod"))) { return MapTypeStarcraft2; } + + // Check for Starcraft I maps by extension + if(!_tcsicmp(szExtension, _T(".scm")) || !_tcsicmp(szExtension, _T(".scx"))) + { + return MapTypeStarcraft; + } } + // Test for AVI files (Warcraft III cinematics) - 'RIFF', 'AVI ' or 'LIST' + if(DwordValue0 == 0x46464952 && DwordValue2 == 0x20495641 && DwordValue3 == 0x5453494C) + return MapTypeAviFile; + // Check for Warcraft III maps if(DwordValue0 == 0x57334D48 && DwordValue1 == 0x00000000) return MapTypeWarcraft3; @@ -271,6 +278,7 @@ bool WINAPI SFileOpenArchive( bool bSearchComplete = false; memset(ha, 0, sizeof(TMPQArchive)); + ha->dwValidFileFlags = MPQ_FILE_VALID_FLAGS; ha->pfnHashString = HashStringSlash; ha->pStream = pStream; pStream = NULL; @@ -288,6 +296,8 @@ bool WINAPI SFileOpenArchive( // Limit the header searching to about 130 MB of data if(EndOfSearch > 0x08000000) EndOfSearch = 0x08000000; + if(FileSize < HEADER_SEARCH_BUFFER_SIZE) + memset(pbHeaderBuffer, 0, HEADER_SEARCH_BUFFER_SIZE); // Find the offset of MPQ header within the file while(bSearchComplete == false && ByteOffset < EndOfSearch) @@ -438,7 +448,14 @@ bool WINAPI SFileOpenArchive( // Remember whether whis is a map for Warcraft III if(MapType == MapTypeWarcraft3) + { + ha->dwValidFileFlags = MPQ_FILE_VALID_FLAGS_W3X; ha->dwFlags |= MPQ_FLAG_WAR3_MAP; + } + + // If this is starcraft map, set the flag mask + if(MapType == MapTypeStarcraft) + ha->dwValidFileFlags = MPQ_FILE_VALID_FLAGS_SCX; // Set the size of file sector ha->dwSectorSize = (0x200 << ha->pHeader->wSectorSize); diff --git a/src/SFileReadFile.cpp b/src/SFileReadFile.cpp index 34edc06..1703748 100644 --- a/src/SFileReadFile.cpp +++ b/src/SFileReadFile.cpp @@ -663,7 +663,8 @@ static DWORD ReadMpqFileLocalFile(TMPQFile * hf, void * pvBuffer, DWORD dwFilePo bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD pdwRead, LPOVERLAPPED lpOverlapped) { - TMPQFile * hf = (TMPQFile *)hFile; + TFileEntry * pFileEntry; + TMPQFile * hf; DWORD dwBytesRead = 0; // Number of bytes read DWORD dwErrCode = ERROR_SUCCESS; @@ -673,7 +674,7 @@ bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD lpOverlapped = lpOverlapped; // Check valid parameters - if(!IsValidFileHandle(hFile)) + if((hf = IsValidFileHandle(hFile)) == NULL) { SetLastError(ERROR_INVALID_HANDLE); return false; @@ -697,6 +698,7 @@ bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD } // Clear the last used compression + pFileEntry = hf->pFileEntry; hf->dwCompression0 = 0; // If the file is local file, read the data directly from the stream @@ -706,7 +708,7 @@ bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD } // If the file is a patch file, we have to read it special way - else if(hf->hfPatch != NULL && (hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0) + else if(hf->hfPatch != NULL && (pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0) { dwErrCode = ReadMpqFilePatchFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); } @@ -718,7 +720,7 @@ bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD } // If the file is single unit file, redirect it to read file - else if(hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) + else if(pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) { dwErrCode = ReadMpqFileSingleUnit(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); } diff --git a/src/StormCommon.h b/src/StormCommon.h index e9187f9..f452112 100644 --- a/src/StormCommon.h +++ b/src/StormCommon.h @@ -81,6 +81,7 @@ typedef enum _MTYPE MapTypeNotChecked, // The map type was not checked yet
MapTypeNotRecognized, // The file does not seems to be a map
MapTypeAviFile, // The file is actually an AVI file (Warcraft III cinematics)
+ MapTypeStarcraft, // The file is a Starcraft map
MapTypeWarcraft3, // The file is a Warcraft III map
MapTypeStarcraft2 // The file is a Starcraft II map
} MTYPE, *PMTYPE;
diff --git a/src/StormLib.h b/src/StormLib.h index 0e4c411..1335f0e 100644 --- a/src/StormLib.h +++ b/src/StormLib.h @@ -25,7 +25,7 @@ /* hash table */ /* 08.12.03 4.11 DCH Fixed bug in reading file sector larger than 0x1000 */ /* on certain files. */ -/* Fixed bug in AddFile with MPQ_FILE_REPLACE_EXISTING */ +/* Fixed bug in AddFile with MPQ_FILE_REPLACEEXISTING */ /* (Thanx Daniel Chiamarello, dchiamarello@madvawes.com)*/ /* 21.12.03 4.50 Lad Completed port for Mac */ /* Fixed bug in compacting (if fsize is mul of 0x1000) */ @@ -193,7 +193,7 @@ extern "C" { #define MPQ_FLAG_CHECK_SECTOR_CRC 0x00000020 // Checking sector CRC when reading files #define MPQ_FLAG_SAVING_TABLES 0x00000040 // If set, we are saving MPQ internal files and MPQ tables #define MPQ_FLAG_PATCH 0x00000080 // If set, this MPQ is a patch archive -#define MPQ_FLAG_WAR3_MAP 0x00000100 // If set, this MPQ is a map for Warcraft III +#define MPQ_FLAG_WAR3_MAP 0x00000100 // If set, this MPQ is a Warcraft III map #define MPQ_FLAG_LISTFILE_NONE 0x00000200 // Set when no (listfile) was found in InvalidateInternalFiles #define MPQ_FLAG_LISTFILE_NEW 0x00000400 // Set when (listfile) invalidated by InvalidateInternalFiles #define MPQ_FLAG_LISTFILE_FORCE 0x00000800 // Save updated listfile on exit @@ -250,12 +250,18 @@ extern "C" { MPQ_FILE_SIGNATURE | \ MPQ_FILE_EXISTS) +#define MPQ_FILE_VALID_FLAGS_SCX (MPQ_FILE_IMPLODE | \ + MPQ_FILE_COMPRESS | \ + MPQ_FILE_ENCRYPTED | \ + MPQ_FILE_FIX_KEY | \ + MPQ_FILE_EXISTS) + // 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 << 0x04 // Malformed MPQ maps may contain block indexes like 0x40000001 or 0xF0000023 #define BLOCK_INDEX_MASK 0x0FFFFFFF -#define MPQ_BLOCK_INDEX(pHash) (pHash->dwBlockIndex & BLOCK_INDEX_MASK) +#define MPQ_BLOCK_INDEX(pHash) ((pHash)->dwBlockIndex & BLOCK_INDEX_MASK) // Compression types for multiple compressions #define MPQ_COMPRESSION_HUFFMANN 0x01 // Huffmann compression (used on WAVE files only) @@ -839,6 +845,7 @@ typedef struct _TMPQArchive DWORD dwFileFlags2; // Flags for (attributes) DWORD dwFileFlags3; // Flags for (signature) DWORD dwAttrFlags; // Flags for the (attributes) file, see MPQ_ATTRIBUTE_XXX + DWORD dwValidFileFlags; // Valid flags for the current MPQ DWORD dwFlags; // See MPQ_FLAG_XXXXX DWORD dwSubType; // See MPQ_SUBTYPE_XXX |