From 383e1572eecafdfe4f92ddad7a4bece069e12f38 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Sun, 13 Dec 2020 12:32:25 +0100 Subject: Added support for amternative MPQ markers --- src/SBaseCommon.cpp | 7 +++++-- src/SBaseFileTable.cpp | 4 ++-- src/SBaseSubTypes.cpp | 4 ++-- src/SFileAddFile.cpp | 4 ++-- src/SFileCreateArchive.cpp | 2 +- src/SFileListFile.cpp | 2 +- src/SFileOpenArchive.cpp | 42 +++++++++++++++++++++++++++++++++++------- src/SFileOpenFileEx.cpp | 2 +- src/SFileVerify.cpp | 4 ++-- src/StormCommon.h | 5 ++++- src/StormLib.h | 13 +++++++++++++ 11 files changed, 68 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp index 9003960..700c4a7 100644 --- a/src/SBaseCommon.cpp +++ b/src/SBaseCommon.cpp @@ -20,7 +20,10 @@ char StormLibCopyright[] = "StormLib v " STORMLIB_VERSION_STRING " Copyright Lad //----------------------------------------------------------------------------- // Local variables -LCID lcFileLocale = LANG_NEUTRAL; // File locale +DWORD g_dwMpqSignature = ID_MPQ; // Marker for MPQ header +DWORD g_dwHashTableKey = MPQ_KEY_HASH_TABLE; // Key for hash table +DWORD g_dwBlockTableKey = MPQ_KEY_BLOCK_TABLE; // Key for block table +LCID g_lcFileLocale = LANG_NEUTRAL; // File locale USHORT wPlatform = 0; // File platform //----------------------------------------------------------------------------- @@ -630,7 +633,7 @@ TMPQArchive * IsValidMpqHandle(HANDLE hMpq) { TMPQArchive * ha = (TMPQArchive *)hMpq; - return (ha != NULL && ha->pHeader != NULL && ha->pHeader->dwID == ID_MPQ) ? ha : NULL; + return (ha != NULL && ha->pHeader != NULL && ha->pHeader->dwID == g_dwMpqSignature) ? ha : NULL; } TMPQFile * IsValidFileHandle(HANDLE hFile) diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp index f9a86a0..aba5e2c 100644 --- a/src/SBaseFileTable.cpp +++ b/src/SBaseFileTable.cpp @@ -2336,7 +2336,7 @@ static TMPQHash * LoadHashTable(TMPQArchive * ha) dwCmpSize = (DWORD)pHeader->HashTableSize64; // Read, decrypt and uncompress the hash table - pHashTable = (TMPQHash *)LoadMpqTable(ha, ByteOffset, pHeader->MD5_HashTable, dwCmpSize, dwTableSize, MPQ_KEY_HASH_TABLE, &bHashTableIsCut); + pHashTable = (TMPQHash *)LoadMpqTable(ha, ByteOffset, pHeader->MD5_HashTable, dwCmpSize, dwTableSize, g_dwHashTableKey, &bHashTableIsCut); // DumpHashTable(pHashTable, pHeader->dwHashTableSize); // If the hash table was cut, we can/have to defragment it @@ -2397,7 +2397,7 @@ TMPQBlock * LoadBlockTable(TMPQArchive * ha, bool /* bDontFixEntries */) dwCmpSize = (DWORD)pHeader->BlockTableSize64; // Read, decrypt and uncompress the block table - pBlockTable = (TMPQBlock * )LoadMpqTable(ha, ByteOffset, NULL, dwCmpSize, dwTableSize, MPQ_KEY_BLOCK_TABLE, &bBlockTableIsCut); + pBlockTable = (TMPQBlock * )LoadMpqTable(ha, ByteOffset, NULL, dwCmpSize, dwTableSize, g_dwBlockTableKey, &bBlockTableIsCut); // If the block table was cut, we need to remember it if(pBlockTable != NULL && bBlockTableIsCut) diff --git a/src/SBaseSubTypes.cpp b/src/SBaseSubTypes.cpp index 6ac5279..afa7311 100644 --- a/src/SBaseSubTypes.cpp +++ b/src/SBaseSubTypes.cpp @@ -131,7 +131,7 @@ int ConvertSqpHeaderToFormat4( Header.wSectorSize = BSWAP_INT16_UNSIGNED(pSqpHeader->wSectorSize); // Verify the SQP header - if(Header.dwID == ID_MPQ && Header.dwHeaderSize == sizeof(TSQPHeader) && Header.dwArchiveSize == FileSize) + if(Header.dwID == g_dwMpqSignature && Header.dwHeaderSize == sizeof(TSQPHeader) && Header.dwArchiveSize == FileSize) { // Check for fixed values of version and sector size if(Header.wFormatVersion == MPQ_FORMAT_VERSION_1 && Header.wSectorSize == 3) @@ -414,7 +414,7 @@ int ConvertMpkHeaderToFormat4( if(Header.dwID == ID_MPK && Header.dwHeaderSize == sizeof(TMPKHeader) && Header.dwArchiveSize == (DWORD)FileSize) { // The header ID must be ID_MPQ - Header.dwID = ID_MPQ; + Header.dwID = g_dwMpqSignature; Header.wFormatVersion = MPQ_FORMAT_VERSION_1; Header.wSectorSize = 3; diff --git a/src/SFileAddFile.cpp b/src/SFileAddFile.cpp index 31f052a..4599ca4 100644 --- a/src/SFileAddFile.cpp +++ b/src/SFileAddFile.cpp @@ -954,7 +954,7 @@ bool WINAPI SFileAddFileEx( } // Initiate adding file to the MPQ - if(!SFileCreateFile(hMpq, szArchivedName, FileTime, (DWORD)FileSize, lcFileLocale, dwFlags, &hMpqFile)) + if(!SFileCreateFile(hMpq, szArchivedName, FileTime, (DWORD)FileSize, g_lcFileLocale, dwFlags, &hMpqFile)) nError = GetLastError(); } @@ -1165,7 +1165,7 @@ bool WINAPI SFileRenameFile(HANDLE hMpq, const char * szFileName, const char * s // Open the new file. If exists, we don't allow rename operation if(nError == ERROR_SUCCESS) { - if(GetFileEntryLocale(ha, szNewFileName, lcFileLocale) != NULL) + if(GetFileEntryLocale(ha, szNewFileName, g_lcFileLocale) != NULL) nError = ERROR_ALREADY_EXISTS; } diff --git a/src/SFileCreateArchive.cpp b/src/SFileCreateArchive.cpp index 7c24491..4185f3d 100644 --- a/src/SFileCreateArchive.cpp +++ b/src/SFileCreateArchive.cpp @@ -220,7 +220,7 @@ bool WINAPI SFileCreateArchive2(const TCHAR * szMpqName, PSFILE_CREATE_MPQ pCrea // Fill the MPQ header memset(pHeader, 0, sizeof(ha->HeaderData)); - pHeader->dwID = ID_MPQ; + pHeader->dwID = g_dwMpqSignature; pHeader->dwHeaderSize = MpqHeaderSizes[pCreateInfo->dwMpqVersion]; pHeader->dwArchiveSize = pHeader->dwHeaderSize + dwHashTableSize * sizeof(TMPQHash); pHeader->wFormatVersion = (USHORT)pCreateInfo->dwMpqVersion; diff --git a/src/SFileListFile.cpp b/src/SFileListFile.cpp index 6fcd736..f94f955 100644 --- a/src/SFileListFile.cpp +++ b/src/SFileListFile.cpp @@ -536,7 +536,7 @@ static int SFileAddInternalListFile( { TMPQHash * pFirstHash; TMPQHash * pHash; - LCID lcSaveLocale = lcFileLocale; + LCID lcSaveLocale = g_lcFileLocale; DWORD dwMaxSize = MAX_LISTFILE_SIZE; int nError = ERROR_SUCCESS; diff --git a/src/SFileOpenArchive.cpp b/src/SFileOpenArchive.cpp index 500e041..1d2c2f9 100644 --- a/src/SFileOpenArchive.cpp +++ b/src/SFileOpenArchive.cpp @@ -146,9 +146,37 @@ static int VerifyMpqTablePositions(TMPQArchive * ha, ULONGLONG FileSize) return ERROR_SUCCESS; } -/*****************************************************************************/ -/* Public functions */ -/*****************************************************************************/ +//----------------------------------------------------------------------------- +// Support for alternate markers. Call before SFileOpenArchive + +#define SFILE_MARKERS_MIN_SIZE (sizeof(DWORD) + sizeof(DWORD) + sizeof(const char *) + sizeof(const char *)) + +bool WINAPI SFileSetArchiveMarkers(PSFILE_MARKERS pMarkers) +{ + // Check structure minimum size + if(pMarkers == NULL || pMarkers->dwSize < SFILE_MARKERS_MIN_SIZE) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // Make sure that the MPQ cryptography is initialized at this time + InitializeMpqCryptography(); + + // Remember the marker for MPQ header + g_dwMpqSignature = pMarkers->dwSignature; + + // Remember the encryption key for hash table + if(pMarkers->szHashTableKey != NULL) + g_dwHashTableKey = HashString(pMarkers->szHashTableKey, MPQ_HASH_FILE_KEY); + + // Remember the encryption key for block table + if(pMarkers->szBlockTableKey != NULL) + g_dwBlockTableKey = HashString(pMarkers->szBlockTableKey, MPQ_HASH_FILE_KEY); + + // Succeeded + return true; +} //----------------------------------------------------------------------------- // SFileGetLocale and SFileSetLocale @@ -156,13 +184,13 @@ static int VerifyMpqTablePositions(TMPQArchive * ha, ULONGLONG FileSize) LCID WINAPI SFileGetLocale() { - return lcFileLocale; + return g_lcFileLocale; } LCID WINAPI SFileSetLocale(LCID lcNewLocale) { - lcFileLocale = lcNewLocale; - return lcFileLocale; + g_lcFileLocale = lcNewLocale; + return g_lcFileLocale; } //----------------------------------------------------------------------------- @@ -323,7 +351,7 @@ bool WINAPI SFileOpenArchive( // Abused by Spazzler Map protector. Note that the size check is not present // in Storm.dll v 1.00, so Diablo I code would load the MPQ anyway. dwHeaderSize = BSWAP_INT32_UNSIGNED(ha->HeaderData[1]); - if(dwHeaderID == ID_MPQ && dwHeaderSize >= MPQ_HEADER_SIZE_V1) + if(dwHeaderID == g_dwMpqSignature && dwHeaderSize >= MPQ_HEADER_SIZE_V1) { // Now convert the header to version 4 nError = ConvertMpqHeaderToFormat4(ha, ByteOffset, FileSize, dwFlags, MapType); diff --git a/src/SFileOpenFileEx.cpp b/src/SFileOpenFileEx.cpp index 5b7933a..1e02a22 100644 --- a/src/SFileOpenFileEx.cpp +++ b/src/SFileOpenFileEx.cpp @@ -263,7 +263,7 @@ bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearch // If this MPQ has no patches, open the file from this MPQ directly if(ha->haPatch == NULL || dwSearchScope == SFILE_OPEN_BASE_FILE) { - pFileEntry = GetFileEntryLocale2(ha, szFileName, lcFileLocale, &dwHashIndex); + pFileEntry = GetFileEntryLocale2(ha, szFileName, g_lcFileLocale, &dwHashIndex); } // If this MPQ is a patched archive, open the file as patched diff --git a/src/SFileVerify.cpp b/src/SFileVerify.cpp index 7e8848f..1b885b4 100644 --- a/src/SFileVerify.cpp +++ b/src/SFileVerify.cpp @@ -592,7 +592,7 @@ static DWORD VerifyFile( dwVerifyResult |= VERIFY_FILE_HAS_RAW_MD5; // Find file entry for the file - pFileEntry = GetFileEntryLocale(ha, szFileName, lcFileLocale); + pFileEntry = GetFileEntryLocale(ha, szFileName, g_lcFileLocale); if(pFileEntry != NULL) { // If the file's raw MD5 doesn't match, don't bother with more checks @@ -964,7 +964,7 @@ int WINAPI SFileVerifyRawData(HANDLE hMpq, DWORD dwWhatToVerify, const char * sz return ERROR_INVALID_PARAMETER; // Get the offset of a file - pFileEntry = GetFileEntryLocale(ha, szFileName, lcFileLocale); + pFileEntry = GetFileEntryLocale(ha, szFileName, g_lcFileLocale); if(pFileEntry == NULL) return ERROR_FILE_NOT_FOUND; diff --git a/src/StormCommon.h b/src/StormCommon.h index 9f9715f..f8023c4 100644 --- a/src/StormCommon.h +++ b/src/StormCommon.h @@ -134,7 +134,10 @@ typedef struct _MPQ_SIGNATURE_INFO //----------------------------------------------------------------------------- // StormLib internal global variables -extern LCID lcFileLocale; // Preferred file locale +extern DWORD g_dwMpqSignature; // Marker for MPQ header +extern DWORD g_dwHashTableKey; // Key for hash table +extern DWORD g_dwBlockTableKey; // Key for block table +extern LCID g_lcFileLocale; // Preferred file locale //----------------------------------------------------------------------------- // Conversion to uppercase/lowercase (and "/" to "\") diff --git a/src/StormLib.h b/src/StormLib.h index 4d9066d..145cf58 100644 --- a/src/StormLib.h +++ b/src/StormLib.h @@ -924,6 +924,14 @@ typedef struct _SFILE_CREATE_MPQ } SFILE_CREATE_MPQ, *PSFILE_CREATE_MPQ; +typedef struct _SFILE_MARKERS +{ + DWORD dwSize; // Size of this structure, in bytes + DWORD dwSignature; // Alternate MPQ header marker + const char * szHashTableKey; // Replacement for "(hash table)" + const char * szBlockTableKey; // Replacement for "(block table)" +} SFILE_MARKERS, *PSFILE_MARKERS; + //----------------------------------------------------------------------------- // TMPQBits support - functions @@ -979,6 +987,11 @@ typedef bool (WINAPI * SFILEREADFILE)(HANDLE, void *, DWORD, LPDWORD, LPOVERLAP //----------------------------------------------------------------------------- // Functions for manipulation with StormLib global flags +// Alternate marker support. This is for MPQs masked as DLLs (*.asi), which +// patch Storm.dll at runtime. Call before SFileOpenArchive +bool WINAPI SFileSetArchiveMarkers(PSFILE_MARKERS pMarkers); + +// Call before SFileOpenFileEx LCID WINAPI SFileGetLocale(); LCID WINAPI SFileSetLocale(LCID lcNewLocale); -- cgit v1.2.3