diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/FileStream.cpp | 10 | ||||
-rw-r--r-- | src/SBaseCommon.cpp | 42 | ||||
-rw-r--r-- | src/SBaseDumpData.cpp | 4 | ||||
-rw-r--r-- | src/SBaseFileTable.cpp | 131 | ||||
-rw-r--r-- | src/SBaseSubTypes.cpp | 14 | ||||
-rw-r--r-- | src/SFileCompactArchive.cpp | 2 | ||||
-rw-r--r-- | src/SFileCreateArchive.cpp | 4 | ||||
-rw-r--r-- | src/SFileFindFile.cpp | 4 | ||||
-rw-r--r-- | src/SFileGetFileInfo.cpp | 11 | ||||
-rw-r--r-- | src/SFileListFile.cpp | 2 | ||||
-rw-r--r-- | src/SFileOpenArchive.cpp | 17 | ||||
-rw-r--r-- | src/SFileOpenFileEx.cpp | 8 | ||||
-rw-r--r-- | src/SFilePatchArchives.cpp | 324 | ||||
-rw-r--r-- | src/SFileReadFile.cpp | 98 | ||||
-rw-r--r-- | src/StormCommon.h | 2 | ||||
-rw-r--r-- | src/StormLib.h | 30 | ||||
-rw-r--r-- | src/StormPort.h | 581 | ||||
-rw-r--r-- | src/adpcm/adpcm.cpp | 3 | ||||
-rw-r--r-- | src/adpcm/adpcm_old.h | 2 | ||||
-rw-r--r-- | src/huffman/huff.cpp | 1 | ||||
-rw-r--r-- | src/libtomcrypt/src/headers/tomcrypt.h | 4 | ||||
-rw-r--r-- | src/libtomcrypt/src/misc/crypt_ltc_mp_descriptor.c | 2 | ||||
-rw-r--r-- | src/libtomcrypt/src/pk/asn1/der_encode_setof.c | 2 | ||||
-rw-r--r-- | src/pklib/pklib.h | 2 | ||||
-rw-r--r-- | src/sparse/sparse.h | 2 |
25 files changed, 823 insertions, 479 deletions
diff --git a/src/FileStream.cpp b/src/FileStream.cpp index 29a4d33..2aeada1 100644 --- a/src/FileStream.cpp +++ b/src/FileStream.cpp @@ -34,14 +34,14 @@ // Local functions - platform-specific functions
#ifndef PLATFORM_WINDOWS
-static int nLastError = ERROR_SUCCESS;
+static DWORD nLastError = ERROR_SUCCESS;
-int GetLastError()
+DWORD GetLastError()
{
return nLastError;
}
-void SetLastError(int nError)
+void SetLastError(DWORD nError)
{
nLastError = nError;
}
@@ -2821,11 +2821,11 @@ void FileStream_Close(TFileStream * pStream) FileStream_Close(pStream->pMaster);
pStream->pMaster = NULL;
- // Close the stream provider.
+ // Close the stream provider ...
if(pStream->StreamClose != NULL)
pStream->StreamClose(pStream);
- // Also close base stream, if any
+ // ... or close base stream, if any
else if(pStream->BaseClose != NULL)
pStream->BaseClose(pStream);
diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp index 54fc6d0..aa891df 100644 --- a/src/SBaseCommon.cpp +++ b/src/SBaseCommon.cpp @@ -147,7 +147,6 @@ void StringCatT(TCHAR * dest, const TCHAR * src, size_t nMaxChars) // Storm hashing functions
#define STORM_BUFFER_SIZE 0x500
-
#define HASH_INDEX_MASK(ha) (ha->pHeader->dwHashTableSize ? (ha->pHeader->dwHashTableSize - 1) : 0)
static DWORD StormBuffer[STORM_BUFFER_SIZE]; // Buffer for the decryption engine
@@ -192,6 +191,22 @@ void InitializeMpqCryptography() }
}
+//
+// Note: Implementation of this function in WorldEdit.exe and storm.dll
+// incorrectly treats the character as signed, which leads to the
+// a buffer underflow if the character in the file name >= 0x80:
+// The following steps happen when *pbKey == 0xBF and dwHashType == 0x0000
+// (calculating hash index)
+//
+// 1) Result of AsciiToUpperTable_Slash[*pbKey++] is sign-extended to 0xffffffbf
+// 2) The "ch" is added to dwHashType (0xffffffbf + 0x0000 => 0xffffffbf)
+// 3) The result is used as index to the StormBuffer table,
+// thus dereferences a random value BEFORE the begin of StormBuffer.
+//
+// As result, MPQs containing files with non-ANSI characters will not work between
+// various game versions and localizations. Even WorldEdit, after importing a file
+// with Korean characters in the name, cannot open the file back.
+//
DWORD HashString(const char * szFileName, DWORD dwHashType)
{
LPBYTE pbKey = (BYTE *)szFileName;
@@ -255,7 +270,22 @@ DWORD HashStringLower(const char * szFileName, DWORD dwHashType) //-----------------------------------------------------------------------------
// Calculates the hash table size for a given amount of files
-DWORD GetHashTableSizeForFileCount(DWORD dwFileCount)
+// Returns the nearest higher power of two.
+// If the value is already a power of two, returns the same value
+DWORD GetNearestPowerOfTwo(DWORD dwFileCount)
+{
+ dwFileCount --;
+
+ dwFileCount |= dwFileCount >> 1;
+ dwFileCount |= dwFileCount >> 2;
+ dwFileCount |= dwFileCount >> 4;
+ dwFileCount |= dwFileCount >> 8;
+ dwFileCount |= dwFileCount >> 16;
+
+ return dwFileCount + 1;
+}
+/*
+DWORD GetNearestPowerOfTwo(DWORD dwFileCount)
{
DWORD dwPowerOfTwo = HASH_TABLE_SIZE_MIN;
@@ -269,7 +299,7 @@ DWORD GetHashTableSizeForFileCount(DWORD dwFileCount) dwPowerOfTwo <<= 1;
return dwPowerOfTwo;
}
-
+*/
//-----------------------------------------------------------------------------
// Calculates a Jenkin's Encrypting and decrypting MPQ file data
@@ -628,7 +658,7 @@ TMPQHash * GetFirstHashEntry(TMPQArchive * ha, const char * szFileName) TMPQHash * pHash = ha->pHashTable + dwIndex;
// If the entry matches, we found it.
- if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && pHash->dwBlockIndex < ha->dwFileTableSize)
+ if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize)
return pHash;
// If that hash entry is a free entry, it means we haven't found the file
@@ -663,7 +693,7 @@ TMPQHash * GetNextHashEntry(TMPQArchive * ha, TMPQHash * pFirstHash, TMPQHash * pHash = ha->pHashTable + dwIndex;
// If the entry matches, we found it.
- if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && pHash->dwBlockIndex < ha->dwFileTableSize)
+ if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize)
return pHash;
// If that hash entry is a free entry, it means we haven't found the file
@@ -691,7 +721,7 @@ TMPQHash * AllocateHashEntry( pHash->dwName1 = dwName1;
pHash->dwName2 = dwName2;
pHash->lcLocale = (USHORT)lcLocale;
- pHash->wPlatform = 0;
+ pHash->Platform = 0;
pHash->dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable);
}
diff --git a/src/SBaseDumpData.cpp b/src/SBaseDumpData.cpp index d156030..334561b 100644 --- a/src/SBaseDumpData.cpp +++ b/src/SBaseDumpData.cpp @@ -51,11 +51,11 @@ void DumpHashTable(TMPQHash * pHashTable, DWORD dwHashTableSize) printf("== Hash Table =================================\n"); for(i = 0; i < dwHashTableSize; i++) { - printf("[%08x] %08X %08X %04X %04X %08X\n", i, + printf("[%08x] %08X %08X %04X %02X %08X\n", i, pHashTable[i].dwName1, pHashTable[i].dwName2, pHashTable[i].lcLocale, - pHashTable[i].wPlatform, + pHashTable[i].Platform, pHashTable[i].dwBlockIndex); } printf("-----------------------------------------------\n\n"); diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp index ed0748d..c7a26aa 100644 --- a/src/SBaseFileTable.cpp +++ b/src/SBaseFileTable.cpp @@ -581,21 +581,23 @@ int ConvertMpqHeaderToFormat4( // Hash entry verification when the file table does not exist yet
bool IsValidHashEntry(TMPQArchive * ha, TMPQHash * pHash)
{
- TFileEntry * pFileEntry = ha->pFileTable + pHash->dwBlockIndex;
- return ((pHash->dwBlockIndex < ha->dwFileTableSize) && (pFileEntry->dwFlags & MPQ_FILE_EXISTS)) ? true : false;
+ TFileEntry * pFileEntry = ha->pFileTable + MPQ_BLOCK_INDEX(pHash);
+
+ return ((MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) && (pFileEntry->dwFlags & MPQ_FILE_EXISTS)) ? true : false;
}
// Hash entry verification when the file table does not exist yet
static bool IsValidHashEntry1(TMPQArchive * ha, TMPQHash * pHash, TMPQBlock * pBlockTable)
{
ULONGLONG ByteOffset;
- TMPQBlock * pBlock = pBlockTable + pHash->dwBlockIndex;
+ TMPQBlock * pBlock;
- // Storm.dll does not perform this check. However, if there will
- // be an entry with (dwBlockIndex > dwBlockTableSize), the game would crash
- // Hence we assume that dwBlockIndex must be less than dwBlockTableSize
- if(pHash->dwBlockIndex < ha->pHeader->dwBlockTableSize)
+ // The block index is considered valid if it's less than block table size
+ if(MPQ_BLOCK_INDEX(pHash) < ha->pHeader->dwBlockTableSize)
{
+ // Calculate the block table position
+ pBlock = pBlockTable + MPQ_BLOCK_INDEX(pHash);
+
// Check whether this is an existing file
// Also we do not allow to be file size greater than 2GB
if((pBlock->dwFlags & MPQ_FILE_EXISTS) && (pBlock->dwFSize & 0x8000000) == 0)
@@ -610,32 +612,42 @@ static bool IsValidHashEntry1(TMPQArchive * ha, TMPQHash * pHash, TMPQBlock * pB }
// Returns a hash table entry in the following order:
-// 1) A hash table entry with the preferred locale
-// 2) A hash table entry with the neutral locale
+// 1) A hash table entry with the preferred locale and platform
+// 2) A hash table entry with the neutral|matching locale and neutral|matching platform
// 3) NULL
-static TMPQHash * GetHashEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale)
+// Storm_2016.dll: 15020940
+static TMPQHash * GetHashEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale, BYTE Platform)
{
- TMPQHash * pHashNeutral = NULL;
TMPQHash * pFirstHash = GetFirstHashEntry(ha, szFileName);
+ TMPQHash * pBestEntry = NULL;
TMPQHash * pHash = pFirstHash;
// Parse the found hashes
while(pHash != NULL)
{
- // If the locales match, return it
- if(lcLocale == pHash->lcLocale)
+ // Storm_2016.dll: 150209CB
+ // If the hash entry matches both locale and platform, return it immediately
+ // Note: We only succeed this check if the locale is non-neutral, because
+ // some Warcraft III maps have several items with neutral locale&platform, which leads
+ // to wrong item being returned
+ if((lcLocale || Platform) && pHash->lcLocale == lcLocale && pHash->Platform == Platform)
return pHash;
-
- // If we found neutral hash, remember it
- if(pHash->lcLocale == 0)
- pHashNeutral = pHash;
+
+ // Storm_2016.dll: 150209D9
+ // If (locale matches or is neutral) OR (platform matches or is neutral)
+ // remember this as the best entry
+ if(pHash->lcLocale == 0 || pHash->lcLocale == lcLocale)
+ {
+ if(pHash->Platform == 0 || pHash->Platform == Platform)
+ pBestEntry = pHash;
+ }
// Get the next hash entry for that file
pHash = GetNextHashEntry(ha, pFirstHash, pHash);
}
// At the end, return neutral hash (if found), otherwise NULL
- return pHashNeutral;
+ return pBestEntry;
}
// Returns a hash table entry in the following order:
@@ -699,7 +711,7 @@ static TMPQHash * DefragmentHashTable( // Calculate how many entries in the hash table we really need
dwFirstFreeEntry = (DWORD)(pTarget - pHashTable);
- dwNewTableSize = GetHashTableSizeForFileCount(dwFirstFreeEntry);
+ dwNewTableSize = GetNearestPowerOfTwo(dwFirstFreeEntry);
// Fill the rest with entries that look like deleted
pHashTableEnd = pHashTable + dwNewTableSize;
@@ -732,11 +744,15 @@ static int 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_SINGLE_UNIT | MPQ_FILE_PATCH_FILE) : 0xFFFFFFFF;
+
// Defragment the hash table, if needed
if(ha->dwFlags & MPQ_FLAG_HASH_TABLE_CUT)
{
@@ -765,33 +781,34 @@ static int BuildFileTableFromBlockTable( pHashTableEnd = ha->pHashTable + pHeader->dwHashTableSize;
for(pHash = ha->pHashTable; pHash < pHashTableEnd; pHash++)
{
- DWORD dwBlockIndex = pHash->dwBlockIndex;
- DWORD dwNewIndex = pHash->dwBlockIndex;
-
//
// We need to properly handle these cases:
// - Multiple hash entries (same file name) point to the same block entry
// - Multiple hash entries (different file name) point to the same block entry
//
// Ignore all hash table entries where:
- // - dwBlockIndex >= BlockTableSize
+ // - Block Index >= BlockTableSize
// - Flags of the appropriate block table entry
+ //
if(IsValidHashEntry1(ha, pHash, pBlockTable))
{
+ DWORD dwOldIndex = MPQ_BLOCK_INDEX(pHash);
+ DWORD dwNewIndex = MPQ_BLOCK_INDEX(pHash);
+
// Determine the new block index
if(DefragmentTable != NULL)
{
- // Need to handle case when multile hash
+ // Need to handle case when multiple hash
// entries point to the same block entry
- if(DefragmentTable[dwBlockIndex] == HASH_ENTRY_FREE)
+ if(DefragmentTable[dwOldIndex] == HASH_ENTRY_FREE)
{
- DefragmentTable[dwBlockIndex] = dwItemCount;
+ DefragmentTable[dwOldIndex] = dwItemCount;
dwNewIndex = dwItemCount++;
}
else
{
- dwNewIndex = DefragmentTable[dwBlockIndex];
+ dwNewIndex = DefragmentTable[dwOldIndex];
}
// Fix the pointer in the hash entry
@@ -803,7 +820,7 @@ static int BuildFileTableFromBlockTable( // Get the pointer to the file entry and the block entry
pFileEntry = ha->pFileTable + dwNewIndex;
- pBlock = pBlockTable + dwBlockIndex;
+ pBlock = pBlockTable + dwOldIndex;
// ByteOffset is only valid if file size is not zero
pFileEntry->ByteOffset = pBlock->dwFilePos;
@@ -813,7 +830,7 @@ static int BuildFileTableFromBlockTable( // Fill the rest of the file entry
pFileEntry->dwFileSize = pBlock->dwFSize;
pFileEntry->dwCmpSize = pBlock->dwCSize;
- pFileEntry->dwFlags = pBlock->dwFlags;
+ pFileEntry->dwFlags = pBlock->dwFlags & dwFlagMask;
}
}
@@ -1796,12 +1813,12 @@ TFileEntry * GetFileEntryLocale2(TMPQArchive * ha, const char * szFileName, LCID // we will need the pointer to hash table entry
if(ha->pHashTable != NULL)
{
- pHash = GetHashEntryLocale(ha, szFileName, lcLocale);
- if(pHash != NULL && pHash->dwBlockIndex < ha->dwFileTableSize)
+ pHash = GetHashEntryLocale(ha, szFileName, lcLocale, 0);
+ if(pHash != NULL && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize)
{
if(PtrHashIndex != NULL)
PtrHashIndex[0] = (DWORD)(pHash - ha->pHashTable);
- return ha->pFileTable + pHash->dwBlockIndex;
+ return ha->pFileTable + MPQ_BLOCK_INDEX(pHash);
}
}
@@ -1831,11 +1848,11 @@ TFileEntry * GetFileEntryExact(TMPQArchive * ha, const char * szFileName, LCID l if(ha->pHashTable != NULL)
{
pHash = GetHashEntryExact(ha, szFileName, lcLocale);
- if(pHash != NULL && pHash->dwBlockIndex < ha->dwFileTableSize)
+ if(pHash != NULL && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize)
{
if(PtrHashIndex != NULL)
PtrHashIndex[0] = (DWORD)(pHash - ha->pHashTable);
- return ha->pFileTable + pHash->dwBlockIndex;
+ return ha->pFileTable + MPQ_BLOCK_INDEX(pHash);
}
}
@@ -1980,7 +1997,8 @@ int RenameFileEntry( pHashEntry->dwName1 = 0xFFFFFFFF;
pHashEntry->dwName2 = 0xFFFFFFFF;
pHashEntry->lcLocale = 0xFFFF;
- pHashEntry->wPlatform = 0xFFFF;
+ pHashEntry->Platform = 0xFF;
+ pHashEntry->Reserved = 0xFF;
pHashEntry->dwBlockIndex = HASH_ENTRY_DELETED;
}
@@ -2020,7 +2038,8 @@ int DeleteFileEntry(TMPQArchive * ha, TMPQFile * hf) pHashEntry->dwName1 = 0xFFFFFFFF;
pHashEntry->dwName2 = 0xFFFFFFFF;
pHashEntry->lcLocale = 0xFFFF;
- pHashEntry->wPlatform = 0xFFFF;
+ pHashEntry->Platform = 0xFF;
+ pHashEntry->Reserved = 0xFF;
pHashEntry->dwBlockIndex = HASH_ENTRY_DELETED;
}
@@ -2141,9 +2160,10 @@ static TMPQHash * LoadHashTable(TMPQArchive * ha) DWORD dwCmpSize;
bool bHashTableIsCut = false;
- // If the MPQ has no hash table, do nothing
- if(pHeader->dwHashTablePos == 0 && pHeader->wHashTablePosHi == 0)
- return NULL;
+ // Note: It is allowed to load hash table if it is at offset 0.
+ // Example: MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x
+// if(pHeader->dwHashTablePos == 0 && pHeader->wHashTablePosHi == 0)
+// return NULL;
// If the hash table size is zero, do nothing
if(pHeader->dwHashTableSize == 0)
@@ -2201,9 +2221,10 @@ TMPQBlock * LoadBlockTable(TMPQArchive * ha, bool /* bDontFixEntries */) DWORD dwCmpSize;
bool bBlockTableIsCut = false;
- // Do nothing if the block table position is zero
- if(pHeader->dwBlockTablePos == 0 && pHeader->wBlockTablePosHi == 0)
- return NULL;
+ // Note: It is possible that the block table starts at offset 0
+ // Example: MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x
+// if(pHeader->dwBlockTablePos == 0 && pHeader->wBlockTablePosHi == 0)
+// return NULL;
// Do nothing if the block table size is zero
if(pHeader->dwBlockTableSize == 0)
@@ -2298,8 +2319,8 @@ int LoadAnyHashTable(TMPQArchive * ha) if(pHeader->HetTablePos64 != 0)
ha->pHetTable = LoadHetTable(ha);
- // Try to load the hash table
- if(pHeader->wHashTablePosHi || pHeader->dwHashTablePos)
+ // Try to load classic hash table
+ if(pHeader->dwHashTableSize)
ha->pHashTable = LoadHashTable(ha);
// At least one of the tables must be present
@@ -2597,6 +2618,13 @@ int DefragmentFileTable(TMPQArchive * ha) // Update the block table size
dwBlockTableSize = (DWORD)(pSource - ha->pFileTable) + 1;
}
+ else
+ {
+ // If there is file name left, free it
+ if(pSource->szFileName != NULL)
+ STORM_FREE(pSource->szFileName);
+ pSource->szFileName = NULL;
+ }
}
// Did we defragment something?
@@ -2610,14 +2638,17 @@ int DefragmentFileTable(TMPQArchive * ha) {
TMPQHash * pHashTableEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
TMPQHash * pHash;
+ DWORD dwNewBlockIndex;
for(pHash = ha->pHashTable; pHash < pHashTableEnd; pHash++)
{
- if(pHash->dwBlockIndex < ha->dwFileTableSize)
- {
- assert(DefragmentTable[pHash->dwBlockIndex] != HASH_ENTRY_FREE);
- pHash->dwBlockIndex = DefragmentTable[pHash->dwBlockIndex];
- }
+ if(MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize)
+ {
+ // If that block entry is there, set it to the hash entry
+ // If not, set it as DELETED
+ dwNewBlockIndex = DefragmentTable[MPQ_BLOCK_INDEX(pHash)];
+ pHash->dwBlockIndex = (dwNewBlockIndex != HASH_ENTRY_FREE) ? dwNewBlockIndex : HASH_ENTRY_DELETED;
+ }
}
}
}
@@ -2724,7 +2755,7 @@ int RebuildFileTable(TMPQArchive * ha, DWORD dwNewHashTableSize) {
if(IsValidHashEntry(ha, pHash))
{
- pFileEntry = ha->pFileTable + pHash->dwBlockIndex;
+ pFileEntry = ha->pFileTable + MPQ_BLOCK_INDEX(pHash);
AllocateHashEntry(ha, pFileEntry, pHash->lcLocale);
}
}
diff --git a/src/SBaseSubTypes.cpp b/src/SBaseSubTypes.cpp index 9807701..47c205e 100644 --- a/src/SBaseSubTypes.cpp +++ b/src/SBaseSubTypes.cpp @@ -187,7 +187,6 @@ TMPQHash * LoadSqpHashTable(TMPQArchive * ha) TSQPHash * pSqpHashEnd; TSQPHash * pSqpHash; TMPQHash * pMpqHash; - DWORD dwBlockIndex; int nError = ERROR_SUCCESS; // Load the hash table @@ -203,8 +202,7 @@ TMPQHash * LoadSqpHashTable(TMPQArchive * ha) if(pSqpHash->dwBlockIndex != HASH_ENTRY_FREE) { // Check block index against the size of the block table - dwBlockIndex = pSqpHash->dwBlockIndex; - if(pHeader->dwBlockTableSize <= dwBlockIndex && dwBlockIndex < HASH_ENTRY_DELETED) + if(pHeader->dwBlockTableSize <= MPQ_BLOCK_INDEX(pSqpHash) && pSqpHash->dwBlockIndex < HASH_ENTRY_DELETED) nError = ERROR_FILE_CORRUPT; // We do not support nonzero locale and platform ID @@ -216,9 +214,9 @@ TMPQHash * LoadSqpHashTable(TMPQArchive * ha) pMpqHash->dwName2 = pSqpHash->dwName2; // Store the rest. Note that this must be done last, - // because pSqpHash->dwBlockIndex corresponds to pMpqHash->dwName2 - pMpqHash->dwBlockIndex = dwBlockIndex; - pMpqHash->wPlatform = 0; + // because block index corresponds to pMpqHash->dwName2 + pMpqHash->dwBlockIndex = MPQ_BLOCK_INDEX(pSqpHash); + pMpqHash->Platform = 0; pMpqHash->lcLocale = 0; } } @@ -525,7 +523,7 @@ TMPQHash * LoadMpkHashTable(TMPQArchive * ha) if(pMpkHash != NULL) { // Calculate the hash table size as if it was real MPQ hash table - pHeader->dwHashTableSize = GetHashTableSizeForFileCount(pHeader->dwHashTableSize); + pHeader->dwHashTableSize = GetNearestPowerOfTwo(pHeader->dwHashTableSize); pHeader->HashTableSize64 = pHeader->dwHashTableSize * sizeof(TMPQHash); // Now allocate table that will serve like a true MPQ hash table, @@ -546,7 +544,7 @@ TMPQHash * LoadMpkHashTable(TMPQArchive * ha) // Copy the MPK hash entry to the hash table pHash->dwBlockIndex = pMpkHash[i].dwBlockIndex; - pHash->wPlatform = 0; + pHash->Platform = 0; pHash->lcLocale = 0; pHash->dwName1 = pMpkHash[i].dwName2; pHash->dwName2 = pMpkHash[i].dwName3; diff --git a/src/SFileCompactArchive.cpp b/src/SFileCompactArchive.cpp index 57c8839..2895baa 100644 --- a/src/SFileCompactArchive.cpp +++ b/src/SFileCompactArchive.cpp @@ -481,7 +481,7 @@ bool WINAPI SFileSetMaxFileCount(HANDLE hMpq, DWORD dwMaxFileCount) if(nError == ERROR_SUCCESS)
{
// Calculate the hash table size for the new file limit
- dwNewHashTableSize = GetHashTableSizeForFileCount(dwMaxFileCount);
+ dwNewHashTableSize = GetNearestPowerOfTwo(dwMaxFileCount);
// Rebuild both file tables
nError = RebuildFileTable(ha, dwNewHashTableSize);
diff --git a/src/SFileCreateArchive.cpp b/src/SFileCreateArchive.cpp index fb9ed60..47354fe 100644 --- a/src/SFileCreateArchive.cpp +++ b/src/SFileCreateArchive.cpp @@ -178,7 +178,7 @@ bool WINAPI SFileCreateArchive2(const TCHAR * szMpqName, PSFILE_CREATE_MPQ pCrea } // If file count is not zero, initialize the hash table size - dwHashTableSize = GetHashTableSizeForFileCount(pCreateInfo->dwMaxFileCount + dwReservedFiles); + dwHashTableSize = GetNearestPowerOfTwo(pCreateInfo->dwMaxFileCount + dwReservedFiles); // Retrieve the file size and round it up to 0x200 bytes FileStream_GetSize(pStream, &MpqPos); @@ -202,7 +202,7 @@ bool WINAPI SFileCreateArchive2(const TCHAR * szMpqName, PSFILE_CREATE_MPQ pCrea if(nError == ERROR_SUCCESS) { memset(ha, 0, sizeof(TMPQArchive)); - ha->pfnHashString = HashString; + ha->pfnHashString = HashStringSlash; ha->pStream = pStream; ha->dwSectorSize = pCreateInfo->dwSectorSize; ha->UserDataPos = MpqPos; diff --git a/src/SFileFindFile.cpp b/src/SFileFindFile.cpp index aacba12..18bf4d5 100644 --- a/src/SFileFindFile.cpp +++ b/src/SFileFindFile.cpp @@ -138,7 +138,7 @@ static bool FileWasFoundBefore( }
// Calculate the hash to the table
- dwNameHash = HashString(szRealFileName, MPQ_HASH_NAME_A);
+ dwNameHash = ha->pfnHashString(szRealFileName, MPQ_HASH_NAME_A);
dwStartIndex = dwIndex = (dwNameHash % hs->dwSearchTableItems);
// The file might have been found before
@@ -299,7 +299,7 @@ static int DoMPQSearch_HashTable(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileDa if(IsValidHashEntry(ha, pHash))
{
// Check if this file entry should be included in the search result
- if(DoMPQSearch_FileEntry(hs, lpFindFileData, ha, pHash, ha->pFileTable + pHash->dwBlockIndex))
+ if(DoMPQSearch_FileEntry(hs, lpFindFileData, ha, pHash, ha->pFileTable + MPQ_BLOCK_INDEX(pHash)))
return ERROR_SUCCESS;
}
}
diff --git a/src/SFileGetFileInfo.cpp b/src/SFileGetFileInfo.cpp index 9874793..365dce5 100644 --- a/src/SFileGetFileInfo.cpp +++ b/src/SFileGetFileInfo.cpp @@ -773,6 +773,17 @@ bool WINAPI SFileGetFileInfo( }
break;
+ case SFileInfoCRC32:
+ hf = IsValidFileHandle(hMpqOrFile);
+ if(hf != NULL && hf->pFileEntry != NULL)
+ {
+ dwInt32Value = hf->pFileEntry->dwCrc32;
+ pvSrcFileInfo = &dwInt32Value;
+ cbSrcFileInfo = sizeof(DWORD);
+ nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER;
+ }
+ break;
+
default: // Invalid info class
SetLastError(ERROR_INVALID_PARAMETER);
return false;
diff --git a/src/SFileListFile.cpp b/src/SFileListFile.cpp index 62b8f11..3918bd9 100644 --- a/src/SFileListFile.cpp +++ b/src/SFileListFile.cpp @@ -350,7 +350,7 @@ static int SListFileCreateNodeForAllLocales(TMPQArchive * ha, const char * szFil while(pHash != NULL)
{
// Allocate file name for the file entry
- AllocateFileName(ha, ha->pFileTable + pHash->dwBlockIndex, szFileName);
+ AllocateFileName(ha, ha->pFileTable + MPQ_BLOCK_INDEX(pHash), szFileName);
// Now find the next language version of the file
pHash = GetNextHashEntry(ha, pFirstHash, pHash);
diff --git a/src/SFileOpenArchive.cpp b/src/SFileOpenArchive.cpp index d62b98f..62effe7 100644 --- a/src/SFileOpenArchive.cpp +++ b/src/SFileOpenArchive.cpp @@ -209,19 +209,19 @@ bool WINAPI SFileOpenArchive( { ULONGLONG SearchOffset = 0; ULONGLONG EndOfSearch = FileSize; - DWORD dwStreamFlags = 0; + DWORD dwStrmFlags = 0; DWORD dwHeaderSize; DWORD dwHeaderID; bool bSearchComplete = false; memset(ha, 0, sizeof(TMPQArchive)); - ha->pfnHashString = HashString; + ha->pfnHashString = HashStringSlash; ha->pStream = pStream; pStream = NULL; // Set the archive read only if the stream is read-only - FileStream_GetFlags(ha->pStream, &dwStreamFlags); - ha->dwFlags |= (dwStreamFlags & STREAM_FLAG_READ_ONLY) ? MPQ_FLAG_READ_ONLY : 0; + FileStream_GetFlags(ha->pStream, &dwStrmFlags); + ha->dwFlags |= (dwStrmFlags & STREAM_FLAG_READ_ONLY) ? MPQ_FLAG_READ_ONLY : 0; // Also remember if we shall check sector CRCs when reading file ha->dwFlags |= (dwFlags & MPQ_OPEN_CHECK_SECTOR_CRC) ? MPQ_FLAG_CHECK_SECTOR_CRC : 0; @@ -365,6 +365,13 @@ bool WINAPI SFileOpenArchive( ha->pUserData = NULL; } + // Anti-overflow. If the hash table size in the header is + // higher than 0x10000000, it would overflow in 32-bit version + // Observed in the malformed Warcraft III maps + // Example map: MPQ_2016_v1_ProtectedMap_TableSizeOverflow.w3x + ha->pHeader->dwBlockTableSize = (ha->pHeader->dwBlockTableSize & BLOCK_INDEX_MASK); + ha->pHeader->dwHashTableSize = (ha->pHeader->dwHashTableSize & BLOCK_INDEX_MASK); + // Both MPQ_OPEN_NO_LISTFILE or MPQ_OPEN_NO_ATTRIBUTES trigger read only mode if(dwFlags & (MPQ_OPEN_NO_LISTFILE | MPQ_OPEN_NO_ATTRIBUTES)) ha->dwFlags |= MPQ_FLAG_READ_ONLY; @@ -428,7 +435,7 @@ bool WINAPI SFileOpenArchive( if(pFileEntry != NULL) { // Just remember that the archive is weak-signed - assert(pFileEntry->dwFlags == MPQ_FILE_EXISTS); + assert((pFileEntry->dwFlags & MPQ_FILE_EXISTS) != 0); ha->dwFileFlags3 = pFileEntry->dwFlags; } diff --git a/src/SFileOpenFileEx.cpp b/src/SFileOpenFileEx.cpp index 3794680..9ce0ae2 100644 --- a/src/SFileOpenFileEx.cpp +++ b/src/SFileOpenFileEx.cpp @@ -30,7 +30,7 @@ static DWORD FindHashIndex(TMPQArchive * ha, DWORD dwFileIndex) pHashTableEnd = ha->pHashTable + ha->pHeader->dwHashTableSize; for(pHash = ha->pHashTable; pHash < pHashTableEnd; pHash++) { - if(pHash->dwBlockIndex == dwFileIndex) + if(MPQ_BLOCK_INDEX(pHash) == dwFileIndex) { // Duplicate hash entry found if(dwFirstIndex != HASH_ENTRY_FREE) @@ -309,8 +309,10 @@ bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearch { if(pFileEntry == NULL || (pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0) nError = ERROR_FILE_NOT_FOUND; - if(pFileEntry != NULL && pFileEntry->dwFlags & ~MPQ_FILE_VALID_FLAGS) - nError = ERROR_NOT_SUPPORTED; + + // Ignore unknown loading flags (example: MPQ_2016_v1_WME4_4.w3x) +// if(pFileEntry != NULL && pFileEntry->dwFlags & ~MPQ_FILE_VALID_FLAGS) +// nError = ERROR_NOT_SUPPORTED; } // Did the caller just wanted to know if the file exists? diff --git a/src/SFilePatchArchives.cpp b/src/SFilePatchArchives.cpp index d01aaf2..37b4612 100644 --- a/src/SFilePatchArchives.cpp +++ b/src/SFilePatchArchives.cpp @@ -15,6 +15,8 @@ //-----------------------------------------------------------------------------
// Local structures
+#define MAX_SC2_PATCH_PREFIX 0x80
+
#define PATCH_SIGNATURE_HEADER 0x48435450
#define PATCH_SIGNATURE_MD5 0x5f35444d
#define PATCH_SIGNATURE_XFRM 0x4d524658
@@ -277,6 +279,8 @@ static int ApplyFilePatch_BSD0( // Get the longest block that we can combine
dwCombineSize = ((dwOldOffset + dwAddDataLength) >= dwOldSize) ? (dwOldSize - dwOldOffset) : dwAddDataLength;
+ if((dwNewOffset + dwCombineSize) > dwNewSize || (dwNewOffset + dwCombineSize) < dwNewOffset)
+ return ERROR_FILE_CORRUPT;
// Now combine the patch data with the original file
for(i = 0; i < dwCombineSize; i++)
@@ -410,30 +414,52 @@ static bool CreatePatchPrefix(TMPQArchive * ha, const char * szFileName, size_t {
TMPQNamePrefix * pNewPrefix;
- // If the end of the patch prefix was not entered, find it
+ // If the length of the patch prefix was not entered, find it
+ // Not that the patch prefix must always begin with backslash
if(szFileName != NULL && nLength == 0)
nLength = strlen(szFileName);
// Create the patch prefix
- pNewPrefix = (TMPQNamePrefix *)STORM_ALLOC(BYTE, sizeof(TMPQNamePrefix) + nLength);
+ pNewPrefix = (TMPQNamePrefix *)STORM_ALLOC(BYTE, sizeof(TMPQNamePrefix) + nLength + 1);
if(pNewPrefix != NULL)
{
- // Fill the name prefix
- pNewPrefix->nLength = nLength;
- pNewPrefix->szPatchPrefix[0] = 0;
-
// Fill the name prefix. Also add the backslash
if(szFileName && nLength)
{
memcpy(pNewPrefix->szPatchPrefix, szFileName, nLength);
- pNewPrefix->szPatchPrefix[nLength] = 0;
+ if(pNewPrefix->szPatchPrefix[nLength - 1] != '\\')
+ pNewPrefix->szPatchPrefix[nLength++] = '\\';
}
+
+ // Terminate the string and fill the length
+ pNewPrefix->szPatchPrefix[nLength] = 0;
+ pNewPrefix->nLength = nLength;
}
ha->pPatchPrefix = pNewPrefix;
return (pNewPrefix != NULL);
}
+static bool CheckAndCreatePatchPrefix(TMPQArchive * ha, const char * szPatchPrefix, size_t nLength)
+{
+ char szTempName[MAX_SC2_PATCH_PREFIX + 0x41];
+ bool bResult = false;
+
+ // Prepare the patch file name
+ if(nLength > MAX_SC2_PATCH_PREFIX)
+ return false;
+
+ // Prepare the patched file name
+ memcpy(szTempName, szPatchPrefix, nLength);
+ memcpy(&szTempName[nLength], "\\(patch_metadata)", 18);
+
+ // Verifywhether that file exists
+ if(GetFileEntryLocale(ha, szTempName, 0) != NULL)
+ bResult = CreatePatchPrefix(ha, szPatchPrefix, nLength);
+
+ return bResult;
+}
+
static bool IsMatchingPatchFile(
TMPQArchive * ha,
const char * szFileName,
@@ -512,6 +538,9 @@ static const char * FindArchiveLanguage(TMPQArchive * ha, PLOCALIZED_MPQ_INFO pM return NULL;
}
+//-----------------------------------------------------------------------------
+// Finding ratch prefix for an temporary build of WoW (Pre-Cataclysm)
+
static bool FindPatchPrefix_WoW_13164_13623(TMPQArchive * haBase, TMPQArchive * haPatch)
{
const char * szPatchPrefix;
@@ -532,27 +561,213 @@ static bool FindPatchPrefix_WoW_13164_13623(TMPQArchive * haBase, TMPQArchive * return CreatePatchPrefix(haPatch, szNamePrefix, 5);
}
+//-----------------------------------------------------------------------------
+// Finding patch prefix for Starcraft II (Pre-Legacy of the Void)
+
+//
+// This method tries to match the patch by placement of the archive (in the game subdirectory)
+//
+// Archive Path: %GAME_DIR%\Mods\SwarmMulti.SC2Mod\Base.SC2Data
+// Patch Prefix: Mods\SwarmMulti.SC2Mod\Base.SC2Data
+//
+// Archive Path: %ANY_DIR%\MPQ_2013_v4_Mods#Liberty.SC2Mod#enGB.SC2Data
+// Patch Prefix: Mods\Liberty.SC2Mod\enGB.SC2Data
+//
+
+static bool CheckPatchPrefix_SC2_ArchiveName(
+ TMPQArchive * haPatch,
+ const TCHAR * szPathPtr,
+ const TCHAR * szSeparator,
+ const TCHAR * szPathEnd,
+ const TCHAR * szExpectedString,
+ size_t cchExpectedString)
+{
+ char szPatchPrefix[MAX_SC2_PATCH_PREFIX+0x41];
+ size_t nLength = 0;
+ bool bResult = false;
+
+ // Check whether the length is equal to the length of the expected string
+ if((size_t)(szSeparator - szPathPtr) == cchExpectedString)
+ {
+ // Now check the string itself
+ if(!_tcsnicmp(szPathPtr, szExpectedString, szSeparator - szPathPtr))
+ {
+ // Copy the name string
+ for(; szPathPtr < szPathEnd; szPathPtr++)
+ {
+ if(szPathPtr[0] != _T('/') && szPathPtr[0] != _T('#'))
+ szPatchPrefix[nLength++] = (char)szPathPtr[0];
+ else
+ szPatchPrefix[nLength++] = '\\';
+ }
+
+ // Check and create the patch prefix
+ bResult = CheckAndCreatePatchPrefix(haPatch, szPatchPrefix, nLength);
+ }
+ }
+
+ return bResult;
+}
+
+static bool FindPatchPrefix_SC2_ArchiveName(TMPQArchive * haBase, TMPQArchive * haPatch)
+{
+ const TCHAR * szPathBegin = FileStream_GetFileName(haBase->pStream);
+ const TCHAR * szSeparator = NULL;
+ const TCHAR * szPathEnd = szPathBegin + _tcslen(szPathBegin);
+ const TCHAR * szPathPtr;
+ int nSlashCount = 0;
+ int nDotCount = 0;
+
+ // Skip the part where the patch prefix would be too long
+ if((szPathEnd - szPathBegin) > MAX_SC2_PATCH_PREFIX)
+ szPathBegin = szPathEnd - MAX_SC2_PATCH_PREFIX;
+
+ // Search for the file extension
+ for(szPathPtr = szPathEnd; szPathPtr > szPathBegin; szPathPtr--)
+ {
+ if(szPathPtr[0] == _T('.'))
+ {
+ nDotCount++;
+ break;
+ }
+ }
+
+ // Search for the possible begin of the prefix name
+ for(/* NOTHING */; szPathPtr > szPathBegin; szPathPtr--)
+ {
+ // Check the slashes, backslashes and hashes
+ if(szPathPtr[0] == _T('\\') || szPathPtr[0] == _T('/') || szPathPtr[0] == _T('#'))
+ {
+ if(nDotCount == 0)
+ return false;
+ szSeparator = szPathPtr;
+ nSlashCount++;
+ }
+
+ // Check the path parts
+ if(szSeparator != NULL && nSlashCount >= nDotCount)
+ {
+ if(CheckPatchPrefix_SC2_ArchiveName(haPatch, szPathPtr, szSeparator, szPathEnd, _T("Battle.net"), 10))
+ return true;
+ if(CheckPatchPrefix_SC2_ArchiveName(haPatch, szPathPtr, szSeparator, szPathEnd, _T("Campaigns"), 9))
+ return true;
+ if(CheckPatchPrefix_SC2_ArchiveName(haPatch, szPathPtr, szSeparator, szPathEnd, _T("Mods"), 4))
+ return true;
+ }
+ }
+
+ // Not matched, sorry
+ return false;
+}
+
+//
+// This method tries to read the patch prefix from a helper file
+//
+// Example
+// =========================================================
+// MPQ File Name: MPQ_2013_v4_Base1.SC2Data
+// Helper File : MPQ_2013_v4_Base1.SC2Data-PATCH
+// File Contains: PatchPrefix=Mods\Core.SC2Mod\Base.SC2Data
+// Patch Prefix : Mods\Core.SC2Mod\Base.SC2Data
+//
+
+static bool ExtractPatchPrefixFromFile(const TCHAR * szHelperFile, char * szPatchPrefix, size_t nMaxChars, size_t * PtrLength)
+{
+ TFileStream * pStream;
+ ULONGLONG FileSize = 0;
+ size_t nLength;
+ char szFileData[MAX_PATH+1];
+ bool bResult = false;
+
+ pStream = FileStream_OpenFile(szHelperFile, STREAM_FLAG_READ_ONLY);
+ if(pStream != NULL)
+ {
+ // Retrieve and check the file size
+ FileStream_GetSize(pStream, &FileSize);
+ if(12 <= FileSize && FileSize < MAX_PATH)
+ {
+ // Read the entire file to memory
+ if(FileStream_Read(pStream, NULL, szFileData, (DWORD)FileSize))
+ {
+ // Terminate the buffer with zero
+ szFileData[(DWORD)FileSize] = 0;
+
+ // The file data must begin with the "PatchPrefix" variable
+ if(!_strnicmp(szFileData, "PatchPrefix", 11))
+ {
+ char * szLinePtr = szFileData + 11;
+ char * szLineEnd;
+
+ // Skip spaces or '='
+ while(szLinePtr[0] == ' ' || szLinePtr[0] == '=')
+ szLinePtr++;
+ szLineEnd = szLinePtr;
+
+ // Find the end
+ while(szLineEnd[0] != 0 && szLineEnd[0] != 0x0A && szLineEnd[0] != 0x0D)
+ szLineEnd++;
+ nLength = (size_t)(szLineEnd - szLinePtr);
+
+ // Copy the variable
+ if(szLineEnd > szLinePtr && nLength <= nMaxChars)
+ {
+ memcpy(szPatchPrefix, szLinePtr, nLength);
+ szPatchPrefix[nLength] = 0;
+ PtrLength[0] = nLength;
+ bResult = true;
+ }
+ }
+ }
+ }
+
+ // Close the stream
+ FileStream_Close(pStream);
+ }
+
+ return bResult;
+}
+
+
+static bool FindPatchPrefix_SC2_HelperFile(TMPQArchive * haBase, TMPQArchive * haPatch)
+{
+ TCHAR szHelperFile[MAX_PATH+1];
+ char szPatchPrefix[MAX_SC2_PATCH_PREFIX+0x41];
+ size_t nLength = 0;
+ bool bResult = false;
+
+ // Create the name of the patch helper file
+ _tcscpy(szHelperFile, FileStream_GetFileName(haBase->pStream));
+ if(_tcslen(szHelperFile) + 6 > MAX_PATH)
+ return false;
+ _tcscat(szHelperFile, _T("-PATCH"));
+
+ // Open the patch helper file and read the line
+ if(ExtractPatchPrefixFromFile(szHelperFile, szPatchPrefix, MAX_SC2_PATCH_PREFIX, &nLength))
+ bResult = CheckAndCreatePatchPrefix(haPatch, szPatchPrefix, nLength);
+
+ return bResult;
+}
+
//
// Find match in Starcraft II patch MPQs
// Match a LST file in the root directory if the MPQ with any of the file in subdirectories
//
// The problem:
-// Base: enGB-md5.lst
-// Patch: Campaigns\Liberty.SC2Campaign\enGB.SC2Assets\enGB-md5.lst
-// Campaigns\Liberty.SC2Campaign\enGB.SC2Data\enGB-md5.lst
-// Campaigns\LibertyStory.SC2Campaign\enGB.SC2Data\enGB-md5.lst
-// Campaigns\LibertyStory.SC2Campaign\enGB.SC2Data\enGB-md5.lst Mods\Core.SC2Mod\enGB.SC2Assets\enGB-md5.lst
-// Mods\Core.SC2Mod\enGB.SC2Data\enGB-md5.lst
-// Mods\Liberty.SC2Mod\enGB.SC2Assets\enGB-md5.lst
-// Mods\Liberty.SC2Mod\enGB.SC2Data\enGB-md5.lst
-// Mods\LibertyMulti.SC2Mod\enGB.SC2Data\enGB-md5.lst
+// File in the base MPQ: enGB-md5.lst
+// File in the patch MPQ: Campaigns\Liberty.SC2Campaign\enGB.SC2Assets\enGB-md5.lst
+// Campaigns\Liberty.SC2Campaign\enGB.SC2Data\enGB-md5.lst
+// Campaigns\LibertyStory.SC2Campaign\enGB.SC2Data\enGB-md5.lst
+// Campaigns\LibertyStory.SC2Campaign\enGB.SC2Data\enGB-md5.lst Mods\Core.SC2Mod\enGB.SC2Assets\enGB-md5.lst
+// Mods\Core.SC2Mod\enGB.SC2Data\enGB-md5.lst
+// Mods\Liberty.SC2Mod\enGB.SC2Assets\enGB-md5.lst
+// Mods\Liberty.SC2Mod\enGB.SC2Data\enGB-md5.lst
+// Mods\LibertyMulti.SC2Mod\enGB.SC2Data\enGB-md5.lst
//
// Solution:
// We need to match the file by its MD5
//
-// Note: pBaseEntry is the file entry of the base version of "StreamingBuckets.txt"
-static bool FindPatchPrefix_SC2(TMPQArchive * haBase, TMPQArchive * haPatch, TFileEntry * pBaseEntry)
+static bool FindPatchPrefix_SC2_MatchFiles(TMPQArchive * haBase, TMPQArchive * haPatch, TFileEntry * pBaseEntry)
{
TMPQNamePrefix * pPatchPrefix;
char * szPatchFileName;
@@ -612,6 +827,59 @@ static bool FindPatchPrefix_SC2(TMPQArchive * haBase, TMPQArchive * haPatch, TFi return bResult;
}
+// Note: pBaseEntry is the file entry of the base version of "StreamingBuckets.txt"
+static bool FindPatchPrefix_SC2(TMPQArchive * haBase, TMPQArchive * haPatch, TFileEntry * pBaseEntry)
+{
+ // Method 1: Try it by the placement of the archive.
+ // Works when someone is opening an archive in the game (sub)directory
+ if(FindPatchPrefix_SC2_ArchiveName(haBase, haPatch))
+ return true;
+
+ // Method 2: Try to locate the Name.Ext-PATCH file and read the patch prefix from it
+ if(FindPatchPrefix_SC2_HelperFile(haBase, haPatch))
+ return true;
+
+ // Method 3: Try to pair any version of "StreamingBuckets.txt" from the patch MPQ
+ // with the "StreamingBuckets.txt" in the base MPQ. Does not always work
+ if(FindPatchPrefix_SC2_MatchFiles(haBase, haPatch, pBaseEntry))
+ return true;
+
+ return false;
+}
+
+//
+// Patch prefix is the path subdirectory where the patched files are within MPQ.
+//
+// Example 1:
+// Main MPQ: locale-enGB.MPQ
+// Patch MPQ: wow-update-12694.MPQ
+// File in main MPQ: DBFilesClient\Achievement.dbc
+// File in patch MPQ: enGB\DBFilesClient\Achievement.dbc
+// Path prefix: enGB
+//
+// Example 2:
+// Main MPQ: expansion1.MPQ
+// Patch MPQ: wow-update-12694.MPQ
+// File in main MPQ: DBFilesClient\Achievement.dbc
+// File in patch MPQ: Base\DBFilesClient\Achievement.dbc
+// Path prefix: Base
+//
+// Example 3:
+// Main MPQ: %GAME%\Battle.net\Battle.net.MPQ
+// Patch MPQ: s2-update-base-26147.MPQ
+// File in main MPQ: Battle.net\i18n\deDE\String\CLIENT_ACHIEVEMENTS.xml
+// File in patch MPQ: Battle.net\Battle.net.MPQ\Battle.net\i18n\deDE\String\CLIENT_ACHIEVEMENTS.xml
+// Path prefix: Battle.net\Battle.net.MPQ
+//
+// Example 4:
+// Main MPQ: %GAME%\Campaigns\Liberty.SC2Campaign\enGB.SC2Data
+// *OR* %ANY_DIR%\%ANY_NAME%Campaigns#Liberty.SC2Campaign#enGB.SC2Data
+// Patch MPQ: s2-update-enGB-23258.MPQ
+// File in main MPQ: LocalizedData\GameHotkeys.txt
+// File in patch MPQ: Campaigns\Liberty.SC2Campaign\enGB.SC2Data\LocalizedData\GameHotkeys.txt
+// Patch Prefix: Campaigns\Liberty.SC2Campaign\enGB.SC2Data
+//
+
static bool FindPatchPrefix(TMPQArchive * haBase, TMPQArchive * haPatch, const char * szPatchPathPrefix)
{
TFileEntry * pFileEntry;
@@ -671,7 +939,7 @@ int Patch_InitPatcher(TMPQPatcher * pPatcher, TMPQFile * hf) DWORD cbMaxFileData = 0;
// Overflow check
- if((sizeof(MPQ_PATCH_HEADER) + cbMaxFileData) < cbMaxFileData)
+ if((cbMaxFileData + (DWORD)sizeof(MPQ_PATCH_HEADER)) < cbMaxFileData)
return ERROR_NOT_ENOUGH_MEMORY;
if(hf->hfPatch == NULL)
return ERROR_INVALID_PARAMETER;
@@ -817,24 +1085,6 @@ void Patch_Finalize(TMPQPatcher * pPatcher) //-----------------------------------------------------------------------------
// Public functions
-//
-// Patch prefix is the path subdirectory where the patched files are within MPQ.
-//
-// Example 1:
-// Main MPQ: locale-enGB.MPQ
-// Patch MPQ: wow-update-12694.MPQ
-// File in main MPQ: DBFilesClient\Achievement.dbc
-// File in patch MPQ: enGB\DBFilesClient\Achievement.dbc
-// Path prefix: enGB
-//
-// Example 2:
-// Main MPQ: expansion1.MPQ
-// Patch MPQ: wow-update-12694.MPQ
-// File in main MPQ: DBFilesClient\Achievement.dbc
-// File in patch MPQ: Base\DBFilesClient\Achievement.dbc
-// Path prefix: Base
-//
-
bool WINAPI SFileOpenPatchArchive(
HANDLE hMpq,
const TCHAR * szPatchMpqName,
diff --git a/src/SFileReadFile.cpp b/src/SFileReadFile.cpp index 30dc587..485b361 100644 --- a/src/SFileReadFile.cpp +++ b/src/SFileReadFile.cpp @@ -801,9 +801,10 @@ DWORD WINAPI SFileGetFileSize(HANDLE hFile, LPDWORD pdwFileSizeHigh) DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * plFilePosHigh, DWORD dwMoveMethod) { TMPQFile * hf = (TMPQFile *)hFile; - ULONGLONG FilePosition; - ULONGLONG MoveOffset; - DWORD dwFilePosHi; + ULONGLONG OldPosition; + ULONGLONG NewPosition; + ULONGLONG FileSize; + ULONGLONG DeltaPos; // If the hFile is not a valid file handle, return an error. if(!IsValidFileHandle(hFile)) @@ -812,33 +813,47 @@ DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * plFilePosHi return SFILE_INVALID_POS; } + // Retrieve the file size for handling the limits + if(hf->pStream != NULL) + { + FileStream_GetSize(hf->pStream, &FileSize); + } + else + { + FileSize = SFileGetFileSize(hFile, NULL); + } + + // Handle the NULL and non-NULL values of plFilePosHigh + // Non-NULL: The DeltaPos is combined from lFilePos and *lpFilePosHigh + // NULL: The DeltaPos is sign-extended value of lFilePos + DeltaPos = (plFilePosHigh != NULL) ? MAKE_OFFSET64(plFilePosHigh[0], lFilePos) : (ULONGLONG)(LONGLONG)lFilePos; + // Get the relative point where to move from switch(dwMoveMethod) { case FILE_BEGIN: - FilePosition = 0; + + // Move relative to the file begin. + OldPosition = 0; break; case FILE_CURRENT: + + // Retrieve the current file position if(hf->pStream != NULL) { - FileStream_GetPos(hf->pStream, &FilePosition); + FileStream_GetPos(hf->pStream, &OldPosition); } else { - FilePosition = hf->dwFilePos; + OldPosition = hf->dwFilePos; } break; case FILE_END: - if(hf->pStream != NULL) - { - FileStream_GetSize(hf->pStream, &FilePosition); - } - else - { - FilePosition = SFileGetFileSize(hFile, NULL); - } + + // Move relative to the end of the file + OldPosition = FileSize; break; default: @@ -846,47 +861,36 @@ DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * plFilePosHi return SFILE_INVALID_POS; } - // Now get the move offset. Note that both values form - // a signed 64-bit value (a file pointer can be moved backwards) - if(plFilePosHigh != NULL) - dwFilePosHi = *plFilePosHigh; - else - dwFilePosHi = (lFilePos & 0x80000000) ? 0xFFFFFFFF : 0; - MoveOffset = MAKE_OFFSET64(dwFilePosHi, lFilePos); + // Calculate the new position + NewPosition = OldPosition + DeltaPos; - // Now calculate the new file pointer - // Do not allow the file pointer to overflow - FilePosition = ((FilePosition + MoveOffset) >= FilePosition) ? (FilePosition + MoveOffset) : 0; + // If moving backward, don't allow the new position go negative + if((LONGLONG)DeltaPos < 0) + { + if(NewPosition > FileSize) + NewPosition = 0; + } + + // If moving forward, don't allow the new position go past the end of the file + else + { + if(NewPosition > FileSize) + NewPosition = FileSize; + } // Now apply the file pointer to the file if(hf->pStream != NULL) { - // Apply the new file position - if(!FileStream_Read(hf->pStream, &FilePosition, NULL, 0)) + if(!FileStream_Read(hf->pStream, &NewPosition, NULL, 0)) return SFILE_INVALID_POS; - - // Return the new file position - if(plFilePosHigh != NULL) - *plFilePosHigh = (LONG)(FilePosition >> 32); - return (DWORD)FilePosition; } else { - // Files in MPQ can't be bigger than 4 GB. - // We don't allow to go past 4 GB - if(FilePosition >> 32) - { - SetLastError(ERROR_INVALID_PARAMETER); - return SFILE_INVALID_POS; - } - - // Change the file position - hf->dwFilePos = (DWORD)FilePosition; - - // Return the new file position - if(plFilePosHigh != NULL) - *plFilePosHigh = 0; - return (DWORD)FilePosition; + hf->dwFilePos = (DWORD)NewPosition; } -} + // Return the new file position + if(plFilePosHigh != NULL) + *plFilePosHigh = (LONG)(NewPosition >> 32); + return (DWORD)NewPosition; +} diff --git a/src/StormCommon.h b/src/StormCommon.h index 3c2148e..27ba45f 100644 --- a/src/StormCommon.h +++ b/src/StormCommon.h @@ -154,7 +154,7 @@ DWORD HashStringLower(const char * szFileName, DWORD dwHashType); void InitializeMpqCryptography();
-DWORD GetHashTableSizeForFileCount(DWORD dwFileCount);
+DWORD GetNearestPowerOfTwo(DWORD dwFileCount);
bool IsPseudoFileName(const char * szFileName, LPDWORD pdwFileIndex);
ULONGLONG HashStringJenkins(const char * szFileName);
diff --git a/src/StormLib.h b/src/StormLib.h index 0f0f2a5..dfa31f9 100644 --- a/src/StormLib.h +++ b/src/StormLib.h @@ -71,6 +71,7 @@ /* 27.08.14 9.10 Lad Signing archives with weak digital signature */ /* 25.11.14 9.11 Lad Fixed bug reading & creating HET table */ /* 18.09.15 9.20 Lad Release 9.20 */ +/* 12.12.16 9.20 Lad Release 9.21 */ /*****************************************************************************/ #ifndef __STORMLIB_H__ @@ -135,8 +136,8 @@ extern "C" { //----------------------------------------------------------------------------- // Defines -#define STORMLIB_VERSION 0x0914 // Current version of StormLib (9.20) -#define STORMLIB_VERSION_STRING "9.20" // String version of StormLib version +#define STORMLIB_VERSION 0x0915 // Current version of StormLib (9.21) +#define STORMLIB_VERSION_STRING "9.21" // String version of StormLib version #define ID_MPQ 0x1A51504D // MPQ archive header ID ('MPQ\x1A') #define ID_MPQ_USERDATA 0x1B51504D // MPQ userdata entry ('MPQ\x1B') @@ -213,12 +214,11 @@ extern "C" { #define MPQ_FILE_DELETE_MARKER 0x02000000 // File is a deletion marker. Used in MPQ patches, indicating that the file no longer exists. #define MPQ_FILE_SECTOR_CRC 0x04000000 // File has checksums for each sector. // Ignored if file is not compressed or imploded. - -#define MPQ_FILE_COMPRESS_MASK 0x0000FF00 // Mask for a file being compressed +#define MPQ_FILE_SIGNATURE 0x10000000 // Present on STANDARD.SNP\(signature). The only occurence ever observed #define MPQ_FILE_EXISTS 0x80000000 // Set if file exists, reset when the file was deleted #define MPQ_FILE_REPLACEEXISTING 0x80000000 // Replace when the file exist (SFileAddFile) -#define MPQ_FILE_EXISTS_MASK 0xF00000FF // These must be either zero or MPQ_FILE_EXISTS +#define MPQ_FILE_COMPRESS_MASK 0x0000FF00 // Mask for a file being compressed #define MPQ_FILE_VALID_FLAGS (MPQ_FILE_IMPLODE | \ MPQ_FILE_COMPRESS | \ @@ -228,8 +228,16 @@ extern "C" { MPQ_FILE_SINGLE_UNIT | \ MPQ_FILE_DELETE_MARKER | \ MPQ_FILE_SECTOR_CRC | \ + MPQ_FILE_SIGNATURE | \ 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) + // Compression types for multiple compressions #define MPQ_COMPRESSION_HUFFMANN 0x01 // Huffmann compression (used on WAVE files only) #define MPQ_COMPRESSION_ZLIB 0x02 // ZLIB compression @@ -434,6 +442,7 @@ typedef enum _SFileInfoClass SFileInfoFlags, // File flags from (DWORD) SFileInfoEncryptionKey, // File encryption key SFileInfoEncryptionKeyRaw, // Unfixed value of the file key + SFileInfoCRC32, // CRC32 of the file } SFileInfoClass; //----------------------------------------------------------------------------- @@ -609,12 +618,13 @@ typedef struct _TMPQHash // The platform the file is used for. 0 indicates the default platform. // No other values have been observed. - // Note: wPlatform is actually just BYTE, but since it has never been used, we don't care. - USHORT wPlatform; + BYTE Platform; + BYTE Reserved; #else - USHORT wPlatform; + BYTE Platform; + BYTE Reserved; USHORT lcLocale; #endif @@ -1076,8 +1086,8 @@ int WINAPI SCompDecompress2(void * pvOutBuffer, int * pcbOutBuffer, void * pv #ifndef PLATFORM_WINDOWS -void SetLastError(int err); -int GetLastError(); +void SetLastError(DWORD err); +DWORD GetLastError(); #endif diff --git a/src/StormPort.h b/src/StormPort.h index 154d573..25134b9 100644 --- a/src/StormPort.h +++ b/src/StormPort.h @@ -1,290 +1,291 @@ -/*****************************************************************************/
-/* StormPort.h Copyright (c) Marko Friedemann 2001 */
-/*---------------------------------------------------------------------------*/
-/* Portability module for the StormLib library. Contains a wrapper symbols */
-/* to make the compilation under Linux work */
-/* */
-/* Author: Marko Friedemann <marko.friedemann@bmx-chemnitz.de> */
-/* Created at: Mon Jan 29 18:26:01 CEST 2001 */
-/* Computer: whiplash.flachland-chemnitz.de */
-/* System: Linux 2.4.0 on i686 */
-/* */
-/* Author: Sam Wilkins <swilkins1337@gmail.com> */
-/* System: Mac OS X and port to big endian processor */
-/* */
-/*---------------------------------------------------------------------------*/
-/* Date Ver Who Comment */
-/* -------- ---- --- ------- */
-/* 29.01.01 1.00 Mar Created */
-/* 24.03.03 1.01 Lad Some cosmetic changes */
-/* 12.11.03 1.02 Dan Macintosh compatibility */
-/* 24.07.04 1.03 Sam Mac OS X compatibility */
-/* 22.11.06 1.04 Sam Mac OS X compatibility (for StormLib 6.0) */
-/* 31.12.06 1.05 XPinguin Full GNU/Linux compatibility */
-/* 17.10.12 1.05 Lad Moved error codes so they don't overlap with errno.h */
-/*****************************************************************************/
-
-#ifndef __STORMPORT_H__
-#define __STORMPORT_H__
-
-#ifndef __cplusplus
- #define bool char
- #define true 1
- #define false 0
-#endif
-
-//-----------------------------------------------------------------------------
-// Defines for Windows
-
-#if !defined(PLATFORM_DEFINED) && defined(_WIN32)
-
- // In MSVC 8.0, there are some functions declared as deprecated.
- #if _MSC_VER >= 1400
- #define _CRT_SECURE_NO_DEPRECATE
- #define _CRT_NON_CONFORMING_SWPRINTFS
- #endif
-
- #include <tchar.h>
- #include <assert.h>
- #include <ctype.h>
- #include <stdio.h>
- #include <windows.h>
- #include <wininet.h>
- #define PLATFORM_LITTLE_ENDIAN
-
- #ifdef _WIN64
- #define PLATFORM_64BIT
- #else
- #define PLATFORM_32BIT
- #endif
-
- #define PLATFORM_WINDOWS
- #define PLATFORM_DEFINED // The platform is known now
-
-#endif
-
-//-----------------------------------------------------------------------------
-// Defines for Mac
-
-#if !defined(PLATFORM_DEFINED) && defined(__APPLE__) // Mac BSD API
-
- // Macintosh
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/mman.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <stdlib.h>
- #include <errno.h>
-
- // Support for PowerPC on Max OS X
- #if (__ppc__ == 1) || (__POWERPC__ == 1) || (_ARCH_PPC == 1)
- #include <stdint.h>
- #include <CoreFoundation/CFByteOrder.h>
- #endif
-
- #define PKEXPORT
- #define __SYS_ZLIB
- #define __SYS_BZLIB
-
- #ifndef __BIG_ENDIAN__
- #define PLATFORM_LITTLE_ENDIAN
- #endif
-
- #define PLATFORM_MAC
- #define PLATFORM_DEFINED // The platform is known now
-
-#endif
-
-//-----------------------------------------------------------------------------
-// Assumption: we are not on Windows nor Macintosh, so this must be linux *grin*
-
-#if !defined(PLATFORM_DEFINED)
-
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/mman.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <string.h>
- #include <ctype.h>
- #include <assert.h>
- #include <errno.h>
-
- #define PLATFORM_LITTLE_ENDIAN
- #define PLATFORM_LINUX
- #define PLATFORM_DEFINED
-
-#endif
-
-//-----------------------------------------------------------------------------
-// Definition of Windows-specific types for non-Windows platforms
-
-#ifndef PLATFORM_WINDOWS
- #if __LP64__
- #define PLATFORM_64BIT
- #else
- #define PLATFORM_32BIT
- #endif
-
- // Typedefs for ANSI C
- typedef unsigned char BYTE;
- typedef unsigned short USHORT;
- typedef int LONG;
- typedef unsigned int DWORD;
- typedef unsigned long DWORD_PTR;
- typedef long LONG_PTR;
- typedef long INT_PTR;
- typedef long long LONGLONG;
- typedef unsigned long long ULONGLONG;
- typedef void * HANDLE;
- typedef void * LPOVERLAPPED; // Unsupported on Linux and Mac
- typedef char TCHAR;
- typedef unsigned int LCID;
- typedef LONG * PLONG;
- typedef DWORD * LPDWORD;
- typedef BYTE * LPBYTE;
-
- #ifdef PLATFORM_32BIT
- #define _LZMA_UINT32_IS_ULONG
- #endif
-
- // Some Windows-specific defines
- #ifndef MAX_PATH
- #define MAX_PATH 1024
- #endif
-
- #define WINAPI
-
- #define FILE_BEGIN SEEK_SET
- #define FILE_CURRENT SEEK_CUR
- #define FILE_END SEEK_END
-
- #define _T(x) x
- #define _tcslen strlen
- #define _tcscpy strcpy
- #define _tcscat strcat
- #define _tcschr strchr
- #define _tcsrchr strrchr
- #define _tcsstr strstr
- #define _tprintf printf
- #define _stprintf sprintf
- #define _tremove remove
-
- #define _stricmp strcasecmp
- #define _strnicmp strncasecmp
- #define _tcsicmp strcasecmp
- #define _tcsnicmp strncasecmp
-
-#endif // !PLATFORM_WINDOWS
-
-// 64-bit calls are supplied by "normal" calls on Mac
-#if defined(PLATFORM_MAC)
- #define stat64 stat
- #define fstat64 fstat
- #define lseek64 lseek
- #define ftruncate64 ftruncate
- #define off64_t off_t
- #define O_LARGEFILE 0
-#endif
-
-// Platform-specific error codes for UNIX-based platforms
-#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
- #define ERROR_SUCCESS 0
- #define ERROR_FILE_NOT_FOUND ENOENT
- #define ERROR_ACCESS_DENIED EPERM
- #define ERROR_INVALID_HANDLE EBADF
- #define ERROR_NOT_ENOUGH_MEMORY ENOMEM
- #define ERROR_NOT_SUPPORTED ENOTSUP
- #define ERROR_INVALID_PARAMETER EINVAL
- #define ERROR_DISK_FULL ENOSPC
- #define ERROR_ALREADY_EXISTS EEXIST
- #define ERROR_INSUFFICIENT_BUFFER ENOBUFS
- #define ERROR_BAD_FORMAT 1000 // No such error code under Linux
- #define ERROR_NO_MORE_FILES 1001 // No such error code under Linux
- #define ERROR_HANDLE_EOF 1002 // No such error code under Linux
- #define ERROR_CAN_NOT_COMPLETE 1003 // No such error code under Linux
- #define ERROR_FILE_CORRUPT 1004 // No such error code under Linux
-#endif
-
-//-----------------------------------------------------------------------------
-// Swapping functions
-
-#ifdef PLATFORM_LITTLE_ENDIAN
- #define BSWAP_INT16_UNSIGNED(a) (a)
- #define BSWAP_INT16_SIGNED(a) (a)
- #define BSWAP_INT32_UNSIGNED(a) (a)
- #define BSWAP_INT32_SIGNED(a) (a)
- #define BSWAP_INT64_SIGNED(a) (a)
- #define BSWAP_INT64_UNSIGNED(a) (a)
- #define BSWAP_ARRAY16_UNSIGNED(a,b) {}
- #define BSWAP_ARRAY32_UNSIGNED(a,b) {}
- #define BSWAP_ARRAY64_UNSIGNED(a,b) {}
- #define BSWAP_PART_HEADER(a) {}
- #define BSWAP_TMPQHEADER(a,b) {}
- #define BSWAP_TMPKHEADER(a) {}
-#else
-
-#ifdef __cplusplus
- extern "C" {
-#endif
- int16_t SwapInt16(uint16_t);
- uint16_t SwapUInt16(uint16_t);
- int32_t SwapInt32(uint32_t);
- uint32_t SwapUInt32(uint32_t);
- int64_t SwapInt64(uint64_t);
- uint64_t SwapUInt64(uint64_t);
- void ConvertUInt16Buffer(void * ptr, size_t length);
- void ConvertUInt32Buffer(void * ptr, size_t length);
- void ConvertUInt64Buffer(void * ptr, size_t length);
- void ConvertTMPQUserData(void *userData);
- void ConvertTMPQHeader(void *header, uint16_t wPart);
- void ConvertTMPKHeader(void *header);
-#ifdef __cplusplus
- }
-#endif
- #define BSWAP_INT16_SIGNED(a) SwapInt16((a))
- #define BSWAP_INT16_UNSIGNED(a) SwapUInt16((a))
- #define BSWAP_INT32_SIGNED(a) SwapInt32((a))
- #define BSWAP_INT32_UNSIGNED(a) SwapUInt32((a))
- #define BSWAP_INT64_SIGNED(a) SwapInt64((a))
- #define BSWAP_INT64_UNSIGNED(a) SwapUInt64((a))
- #define BSWAP_ARRAY16_UNSIGNED(a,b) ConvertUInt16Buffer((a),(b))
- #define BSWAP_ARRAY32_UNSIGNED(a,b) ConvertUInt32Buffer((a),(b))
- #define BSWAP_ARRAY64_UNSIGNED(a,b) ConvertUInt64Buffer((a),(b))
- #define BSWAP_TMPQHEADER(a,b) ConvertTMPQHeader((a),(b))
- #define BSWAP_TMPKHEADER(a) ConvertTMPKHeader((a))
-#endif
-
-//-----------------------------------------------------------------------------
-// Macro for deprecated symbols
-
-/*
-#ifdef _MSC_VER
- #if _MSC_FULL_VER >= 140050320
- #define STORMLIB_DEPRECATED(_Text) __declspec(deprecated(_Text))
- #else
- #define STORMLIB_DEPRECATED(_Text) __declspec(deprecated)
- #endif
-#else
- #ifdef __GNUC__
- #define STORMLIB_DEPRECATED(_Text) __attribute__((deprecated))
- #else
- #define STORMLIB_DEPRECATED(_Text) __attribute__((deprecated(_Text)))
- #endif
-#endif
-
-// When a flag is deprecated, use this macro
-#ifndef _STORMLIB_NO_DEPRECATE
- #define STORMLIB_DEPRECATED_FLAG(type, oldflag, newflag) \
- const STORMLIB_DEPRECATED(#oldflag " is deprecated. Use " #newflag ". To supress this warning, define _STORMLIB_NO_DEPRECATE") static type oldflag = (type)newflag;
-#else
-#define STORMLIB_DEPRECATED_FLAG(type, oldflag, newflag) static type oldflag = (type)newflag;
-#endif
-*/
-
-#endif // __STORMPORT_H__
+/*****************************************************************************/ +/* StormPort.h Copyright (c) Marko Friedemann 2001 */ +/*---------------------------------------------------------------------------*/ +/* Portability module for the StormLib library. Contains a wrapper symbols */ +/* to make the compilation under Linux work */ +/* */ +/* Author: Marko Friedemann <marko.friedemann@bmx-chemnitz.de> */ +/* Created at: Mon Jan 29 18:26:01 CEST 2001 */ +/* Computer: whiplash.flachland-chemnitz.de */ +/* System: Linux 2.4.0 on i686 */ +/* */ +/* Author: Sam Wilkins <swilkins1337@gmail.com> */ +/* System: Mac OS X and port to big endian processor */ +/* */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 29.01.01 1.00 Mar Created */ +/* 24.03.03 1.01 Lad Some cosmetic changes */ +/* 12.11.03 1.02 Dan Macintosh compatibility */ +/* 24.07.04 1.03 Sam Mac OS X compatibility */ +/* 22.11.06 1.04 Sam Mac OS X compatibility (for StormLib 6.0) */ +/* 31.12.06 1.05 XPinguin Full GNU/Linux compatibility */ +/* 17.10.12 1.05 Lad Moved error codes so they don't overlap with errno.h */ +/*****************************************************************************/ + +#ifndef __STORMPORT_H__ +#define __STORMPORT_H__ + +#ifndef __cplusplus + #define bool char + #define true 1 + #define false 0 +#endif + +//----------------------------------------------------------------------------- +// Defines for Windows + +#if !defined(PLATFORM_DEFINED) && defined(_WIN32) + + // In MSVC 8.0, there are some functions declared as deprecated. + #if _MSC_VER >= 1400 + #define _CRT_SECURE_NO_DEPRECATE + #define _CRT_NON_CONFORMING_SWPRINTFS + #endif + + #include <tchar.h> + #include <assert.h> + #include <ctype.h> + #include <stdio.h> + #include <windows.h> + #include <wininet.h> + #define PLATFORM_LITTLE_ENDIAN + + #ifdef _WIN64 + #define PLATFORM_64BIT + #else + #define PLATFORM_32BIT + #endif + + #define PLATFORM_WINDOWS + #define PLATFORM_DEFINED // The platform is known now + +#endif + +//----------------------------------------------------------------------------- +// Defines for Mac + +#if !defined(PLATFORM_DEFINED) && defined(__APPLE__) // Mac BSD API + + // Macintosh + #include <sys/types.h> + #include <sys/stat.h> + #include <sys/mman.h> + #include <unistd.h> + #include <fcntl.h> + #include <stdlib.h> + #include <errno.h> + + // Support for PowerPC on Max OS X + #if (__ppc__ == 1) || (__POWERPC__ == 1) || (_ARCH_PPC == 1) + #include <stdint.h> + #include <CoreFoundation/CFByteOrder.h> + #endif + + #define PKEXPORT + #define __SYS_ZLIB + #define __SYS_BZLIB + + #ifndef __BIG_ENDIAN__ + #define PLATFORM_LITTLE_ENDIAN + #endif + + #define PLATFORM_MAC + #define PLATFORM_DEFINED // The platform is known now + +#endif + +//----------------------------------------------------------------------------- +// Assumption: we are not on Windows nor Macintosh, so this must be linux *grin* + +#if !defined(PLATFORM_DEFINED) + + #include <sys/types.h> + #include <sys/stat.h> + #include <sys/mman.h> + #include <fcntl.h> + #include <unistd.h> + #include <stdint.h> + #include <stdlib.h> + #include <stdio.h> + #include <stdarg.h> + #include <string.h> + #include <ctype.h> + #include <assert.h> + #include <errno.h> + + #define PLATFORM_LITTLE_ENDIAN + #define PLATFORM_LINUX + #define PLATFORM_DEFINED + +#endif + +//----------------------------------------------------------------------------- +// Definition of Windows-specific types for non-Windows platforms + +#ifndef PLATFORM_WINDOWS + #if __LP64__ + #define PLATFORM_64BIT + #else + #define PLATFORM_32BIT + #endif + + // Typedefs for ANSI C + typedef unsigned char BYTE; + typedef unsigned short USHORT; + typedef int LONG; + typedef unsigned int DWORD; + typedef unsigned long DWORD_PTR; + typedef long LONG_PTR; + typedef long INT_PTR; + typedef long long LONGLONG; + typedef unsigned long long ULONGLONG; + typedef void * HANDLE; + typedef void * LPOVERLAPPED; // Unsupported on Linux and Mac + typedef char TCHAR; + typedef unsigned int LCID; + typedef LONG * PLONG; + typedef DWORD * LPDWORD; + typedef BYTE * LPBYTE; + + #ifdef PLATFORM_32BIT + #define _LZMA_UINT32_IS_ULONG + #endif + + // Some Windows-specific defines + #ifndef MAX_PATH + #define MAX_PATH 1024 + #endif + + #define WINAPI + + #define FILE_BEGIN SEEK_SET + #define FILE_CURRENT SEEK_CUR + #define FILE_END SEEK_END + + #define _T(x) x + #define _tcslen strlen + #define _tcscpy strcpy + #define _tcscat strcat + #define _tcschr strchr + #define _tcsrchr strrchr + #define _tcsstr strstr + #define _tcsnicmp strncasecmp + #define _tprintf printf + #define _stprintf sprintf + #define _tremove remove + + #define _stricmp strcasecmp + #define _strnicmp strncasecmp + #define _tcsicmp strcasecmp + #define _tcsnicmp strncasecmp + +#endif // !PLATFORM_WINDOWS + +// 64-bit calls are supplied by "normal" calls on Mac +#if defined(PLATFORM_MAC) + #define stat64 stat + #define fstat64 fstat + #define lseek64 lseek + #define ftruncate64 ftruncate + #define off64_t off_t + #define O_LARGEFILE 0 +#endif + +// Platform-specific error codes for UNIX-based platforms +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + #define ERROR_SUCCESS 0 + #define ERROR_FILE_NOT_FOUND ENOENT + #define ERROR_ACCESS_DENIED EPERM + #define ERROR_INVALID_HANDLE EBADF + #define ERROR_NOT_ENOUGH_MEMORY ENOMEM + #define ERROR_NOT_SUPPORTED ENOTSUP + #define ERROR_INVALID_PARAMETER EINVAL + #define ERROR_DISK_FULL ENOSPC + #define ERROR_ALREADY_EXISTS EEXIST + #define ERROR_INSUFFICIENT_BUFFER ENOBUFS + #define ERROR_BAD_FORMAT 1000 // No such error code under Linux + #define ERROR_NO_MORE_FILES 1001 // No such error code under Linux + #define ERROR_HANDLE_EOF 1002 // No such error code under Linux + #define ERROR_CAN_NOT_COMPLETE 1003 // No such error code under Linux + #define ERROR_FILE_CORRUPT 1004 // No such error code under Linux +#endif + +//----------------------------------------------------------------------------- +// Swapping functions + +#ifdef PLATFORM_LITTLE_ENDIAN + #define BSWAP_INT16_UNSIGNED(a) (a) + #define BSWAP_INT16_SIGNED(a) (a) + #define BSWAP_INT32_UNSIGNED(a) (a) + #define BSWAP_INT32_SIGNED(a) (a) + #define BSWAP_INT64_SIGNED(a) (a) + #define BSWAP_INT64_UNSIGNED(a) (a) + #define BSWAP_ARRAY16_UNSIGNED(a,b) {} + #define BSWAP_ARRAY32_UNSIGNED(a,b) {} + #define BSWAP_ARRAY64_UNSIGNED(a,b) {} + #define BSWAP_PART_HEADER(a) {} + #define BSWAP_TMPQHEADER(a,b) {} + #define BSWAP_TMPKHEADER(a) {} +#else + +#ifdef __cplusplus + extern "C" { +#endif + int16_t SwapInt16(uint16_t); + uint16_t SwapUInt16(uint16_t); + int32_t SwapInt32(uint32_t); + uint32_t SwapUInt32(uint32_t); + int64_t SwapInt64(uint64_t); + uint64_t SwapUInt64(uint64_t); + void ConvertUInt16Buffer(void * ptr, size_t length); + void ConvertUInt32Buffer(void * ptr, size_t length); + void ConvertUInt64Buffer(void * ptr, size_t length); + void ConvertTMPQUserData(void *userData); + void ConvertTMPQHeader(void *header, uint16_t wPart); + void ConvertTMPKHeader(void *header); +#ifdef __cplusplus + } +#endif + #define BSWAP_INT16_SIGNED(a) SwapInt16((a)) + #define BSWAP_INT16_UNSIGNED(a) SwapUInt16((a)) + #define BSWAP_INT32_SIGNED(a) SwapInt32((a)) + #define BSWAP_INT32_UNSIGNED(a) SwapUInt32((a)) + #define BSWAP_INT64_SIGNED(a) SwapInt64((a)) + #define BSWAP_INT64_UNSIGNED(a) SwapUInt64((a)) + #define BSWAP_ARRAY16_UNSIGNED(a,b) ConvertUInt16Buffer((a),(b)) + #define BSWAP_ARRAY32_UNSIGNED(a,b) ConvertUInt32Buffer((a),(b)) + #define BSWAP_ARRAY64_UNSIGNED(a,b) ConvertUInt64Buffer((a),(b)) + #define BSWAP_TMPQHEADER(a,b) ConvertTMPQHeader((a),(b)) + #define BSWAP_TMPKHEADER(a) ConvertTMPKHeader((a)) +#endif + +//----------------------------------------------------------------------------- +// Macro for deprecated symbols + +/* +#ifdef _MSC_VER + #if _MSC_FULL_VER >= 140050320 + #define STORMLIB_DEPRECATED(_Text) __declspec(deprecated(_Text)) + #else + #define STORMLIB_DEPRECATED(_Text) __declspec(deprecated) + #endif +#else + #ifdef __GNUC__ + #define STORMLIB_DEPRECATED(_Text) __attribute__((deprecated)) + #else + #define STORMLIB_DEPRECATED(_Text) __attribute__((deprecated(_Text))) + #endif +#endif + +// When a flag is deprecated, use this macro +#ifndef _STORMLIB_NO_DEPRECATE + #define STORMLIB_DEPRECATED_FLAG(type, oldflag, newflag) \ + const STORMLIB_DEPRECATED(#oldflag " is deprecated. Use " #newflag ". To supress this warning, define _STORMLIB_NO_DEPRECATE") static type oldflag = (type)newflag; +#else +#define STORMLIB_DEPRECATED_FLAG(type, oldflag, newflag) static type oldflag = (type)newflag; +#endif +*/ + +#endif // __STORMPORT_H__ diff --git a/src/adpcm/adpcm.cpp b/src/adpcm/adpcm.cpp index e3741b6..e551bda 100644 --- a/src/adpcm/adpcm.cpp +++ b/src/adpcm/adpcm.cpp @@ -13,7 +13,8 @@ /* 10.01.13 3.00 Lad Refactored, beautified, documented :-) */ /*****************************************************************************/ -#include "../StormPort.h" +#include <stddef.h> + #include "adpcm.h" //----------------------------------------------------------------------------- diff --git a/src/adpcm/adpcm_old.h b/src/adpcm/adpcm_old.h index beb9615..7b76aff 100644 --- a/src/adpcm/adpcm_old.h +++ b/src/adpcm/adpcm_old.h @@ -14,7 +14,7 @@ //----------------------------------------------------------------------------- // Functions -#include "../StormPort.h" +#include <StormPort.h> int CompressADPCM (unsigned char * pbOutBuffer, int dwOutLength, short * pwInBuffer, int dwInLength, int nCmpType, int nChannels); int DecompressADPCM(unsigned char * pbOutBuffer, int dwOutLength, unsigned char * pbInBuffer, int dwInLength, int nChannels); diff --git a/src/huffman/huff.cpp b/src/huffman/huff.cpp index 1636a80..877a294 100644 --- a/src/huffman/huff.cpp +++ b/src/huffman/huff.cpp @@ -19,7 +19,6 @@ #include <assert.h> #include <string.h> -#include "../StormPort.h" #include "huff.h" //----------------------------------------------------------------------------- diff --git a/src/libtomcrypt/src/headers/tomcrypt.h b/src/libtomcrypt/src/headers/tomcrypt.h index 74cdff4..7df3f5a 100644 --- a/src/libtomcrypt/src/headers/tomcrypt.h +++ b/src/libtomcrypt/src/headers/tomcrypt.h @@ -25,6 +25,10 @@ extern "C" { /* descriptor table size */ #define TAB_SIZE 32 +#ifdef _MSC_VER +#pragma warning(disable: 4333) // der_encode_utf8_string.c(91) : warning C4333: '>>' : right shift by too large amount, data loss +#endif + /* error codes [will be expanded in future releases] */ enum { CRYPT_OK=0, /* Result OK */ diff --git a/src/libtomcrypt/src/misc/crypt_ltc_mp_descriptor.c b/src/libtomcrypt/src/misc/crypt_ltc_mp_descriptor.c index 91ba9d1..c02a96f 100644 --- a/src/libtomcrypt/src/misc/crypt_ltc_mp_descriptor.c +++ b/src/libtomcrypt/src/misc/crypt_ltc_mp_descriptor.c @@ -10,4 +10,4 @@ */ #include "../headers/tomcrypt.h" -ltc_math_descriptor ltc_mp; +ltc_math_descriptor ltc_mp = {0}; diff --git a/src/libtomcrypt/src/pk/asn1/der_encode_setof.c b/src/libtomcrypt/src/pk/asn1/der_encode_setof.c index ad7b0f6..b4e97b5 100644 --- a/src/libtomcrypt/src/pk/asn1/der_encode_setof.c +++ b/src/libtomcrypt/src/pk/asn1/der_encode_setof.c @@ -102,7 +102,7 @@ int der_encode_setof(ltc_asn1_list *list, unsigned long inlen, } /* get the size of the static header */ - hdrlen = ((unsigned long)ptr) - ((unsigned long)buf); + hdrlen = (unsigned long)((size_t)ptr - (size_t)buf); /* scan for edges */ diff --git a/src/pklib/pklib.h b/src/pklib/pklib.h index f43da15..9eb2915 100644 --- a/src/pklib/pklib.h +++ b/src/pklib/pklib.h @@ -11,8 +11,6 @@ #ifndef __PKLIB_H__ #define __PKLIB_H__ -#include "../StormPort.h" - //----------------------------------------------------------------------------- // Defines diff --git a/src/sparse/sparse.h b/src/sparse/sparse.h index b1cd872..12f62b5 100644 --- a/src/sparse/sparse.h +++ b/src/sparse/sparse.h @@ -11,8 +11,6 @@ #ifndef __SPARSE_H__ #define __SPARSE_H__ -#include "../StormPort.h" - void CompressSparse(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer); int DecompressSparse(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer); |