summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/FileStream.cpp10
-rw-r--r--src/SBaseCommon.cpp42
-rw-r--r--src/SBaseDumpData.cpp4
-rw-r--r--src/SBaseFileTable.cpp131
-rw-r--r--src/SBaseSubTypes.cpp14
-rw-r--r--src/SFileCompactArchive.cpp2
-rw-r--r--src/SFileCreateArchive.cpp4
-rw-r--r--src/SFileFindFile.cpp4
-rw-r--r--src/SFileGetFileInfo.cpp11
-rw-r--r--src/SFileListFile.cpp2
-rw-r--r--src/SFileOpenArchive.cpp17
-rw-r--r--src/SFileOpenFileEx.cpp8
-rw-r--r--src/SFilePatchArchives.cpp324
-rw-r--r--src/SFileReadFile.cpp98
-rw-r--r--src/StormCommon.h2
-rw-r--r--src/StormLib.h30
-rw-r--r--src/StormPort.h581
-rw-r--r--src/adpcm/adpcm.cpp3
-rw-r--r--src/adpcm/adpcm_old.h2
-rw-r--r--src/huffman/huff.cpp1
-rw-r--r--src/libtomcrypt/src/headers/tomcrypt.h4
-rw-r--r--src/libtomcrypt/src/misc/crypt_ltc_mp_descriptor.c2
-rw-r--r--src/libtomcrypt/src/pk/asn1/der_encode_setof.c2
-rw-r--r--src/pklib/pklib.h2
-rw-r--r--src/sparse/sparse.h2
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);