Skip to content

Commit

Permalink
Merge pull request #265 from ladislav-zezula/LZ_LocaleAndPlatform
Browse files Browse the repository at this point in the history
Locale&platform problems fixed
  • Loading branch information
ladislav-zezula authored Oct 3, 2022
2 parents 88b18d4 + 3055830 commit 3846f0b
Show file tree
Hide file tree
Showing 15 changed files with 160 additions and 118 deletions.
8 changes: 4 additions & 4 deletions make-msvc.bat
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ if exist "%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2019\Professional\VC\Auxil
if exist "%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" set VCVARS_2019=%PROGRAM_FILES_DIR%\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat

:: Build all libraries using Visual Studio 2008 and 2019
call :BuildLibs "%VCVARS_2008%" x86 %LIB_NAME%_vs08.sln \vs2008
call :BuildLibs "%VCVARS_2008%" x64 %LIB_NAME%_vs08.sln \vs2008
call :BuildLibs "%VCVARS_2019%" x86 %LIB_NAME%_vs19.sln
call :BuildLibs "%VCVARS_2019%" x64 %LIB_NAME%_vs19.sln
if not "x%VCVARS_2008%" == "x" call :BuildLibs "%VCVARS_2008%" x86 %LIB_NAME%_vs08.sln \vs2008
if not "x%VCVARS_2008%" == "x" call :BuildLibs "%VCVARS_2008%" x64 %LIB_NAME%_vs08.sln \vs2008
if not "x%VCVARS_2019%" == "x" call :BuildLibs "%VCVARS_2019%" x86 %LIB_NAME%_vs19.sln
if not "x%VCVARS_2019%" == "x" call :BuildLibs "%VCVARS_2019%" x64 %LIB_NAME%_vs19.sln
goto:eof

::-----------------------------------------------------------------------------
Expand Down
17 changes: 9 additions & 8 deletions src/SBaseCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ char StormLibCopyright[] = "StormLib v " STORMLIB_VERSION_STRING " Copyright Lad
DWORD g_dwMpqSignature = ID_MPQ; // Marker for MPQ header
DWORD g_dwHashTableKey = MPQ_KEY_HASH_TABLE; // Key for hash table
DWORD g_dwBlockTableKey = MPQ_KEY_BLOCK_TABLE; // Key for block table
LCID g_lcFileLocale = LANG_NEUTRAL; // File locale
USHORT wPlatform = 0; // File platform
LCID g_lcFileLocale = 0; // Compound of file locale and platform

//-----------------------------------------------------------------------------
// Conversion to uppercase/lowercase
Expand Down Expand Up @@ -737,12 +736,13 @@ TMPQFile * IsValidFileHandle(HANDLE hFile)
// Hash table and block table manipulation

// Attempts to search a free hash entry, or an entry whose names and locale matches
TMPQHash * FindFreeHashEntry(TMPQArchive * ha, DWORD dwStartIndex, DWORD dwName1, DWORD dwName2, LCID lcLocale)
TMPQHash * FindFreeHashEntry(TMPQArchive * ha, DWORD dwStartIndex, DWORD dwName1, DWORD dwName2, LCID lcFileLocale)
{
TMPQHash * pDeletedEntry = NULL; // If a deleted entry was found in the continuous hash range
TMPQHash * pFreeEntry = NULL; // If a free entry was found in the continuous hash range
DWORD dwHashIndexMask = HASH_INDEX_MASK(ha);
DWORD dwIndex;
USHORT Locale = SFILE_LOCALE(lcFileLocale);

// Set the initial index
dwStartIndex = dwIndex = (dwStartIndex & dwHashIndexMask);
Expand All @@ -757,7 +757,7 @@ TMPQHash * FindFreeHashEntry(TMPQArchive * ha, DWORD dwStartIndex, DWORD dwName1
TMPQHash * pHash = ha->pHashTable + dwIndex;

// If we found a matching entry, return that one
if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && pHash->lcLocale == lcLocale)
if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && pHash->Locale == Locale)
return pHash;

// If we found a deleted entry, remember it but keep searching
Expand Down Expand Up @@ -849,22 +849,23 @@ TMPQHash * GetNextHashEntry(TMPQArchive * ha, TMPQHash * pFirstHash, TMPQHash *
TMPQHash * AllocateHashEntry(
TMPQArchive * ha,
TFileEntry * pFileEntry,
LCID lcLocale)
LCID lcFileLocale)
{
TMPQHash * pHash;
DWORD dwStartIndex = ha->pfnHashString(pFileEntry->szFileName, MPQ_HASH_TABLE_INDEX);
DWORD dwName1 = ha->pfnHashString(pFileEntry->szFileName, MPQ_HASH_NAME_A);
DWORD dwName2 = ha->pfnHashString(pFileEntry->szFileName, MPQ_HASH_NAME_B);

// Attempt to find a free hash entry
pHash = FindFreeHashEntry(ha, dwStartIndex, dwName1, dwName2, lcLocale);
pHash = FindFreeHashEntry(ha, dwStartIndex, dwName1, dwName2, lcFileLocale);
if(pHash != NULL)
{
// Fill the free hash entry
pHash->dwName1 = dwName1;
pHash->dwName2 = dwName2;
pHash->lcLocale = (USHORT)lcLocale;
pHash->Platform = 0;
pHash->Locale = SFILE_LOCALE(lcFileLocale);
pHash->Platform = SFILE_PLATFORM(lcFileLocale);
pHash->Reserved = 0;
pHash->dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable);
}

Expand Down
2 changes: 1 addition & 1 deletion src/SBaseDumpData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ void DumpHashTable(TMPQHash * pHashTable, DWORD dwHashTableSize)
printf("[%08x] %08X %08X %04X %02X %08X\n", i,
pHashTable[i].dwName1,
pHashTable[i].dwName2,
pHashTable[i].lcLocale,
pHashTable[i].Locale,
pHashTable[i].Platform,
pHashTable[i].dwBlockIndex);
}
Expand Down
54 changes: 30 additions & 24 deletions src/SBaseFileTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -765,11 +765,13 @@ static bool IsValidHashEntry1(TMPQArchive * ha, TMPQHash * pHash, TMPQBlock * pB
// 2) A hash table entry with the neutral|matching locale and neutral|matching platform
// 3) NULL
// Storm_2016.dll: 15020940
static TMPQHash * GetHashEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale, BYTE Platform)
static TMPQHash * GetHashEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcFileLocale)
{
TMPQHash * pFirstHash = GetFirstHashEntry(ha, szFileName);
TMPQHash * pBestEntry = NULL;
TMPQHash * pHash = pFirstHash;
USHORT Locale = SFILE_LOCALE(lcFileLocale);
BYTE Platform = SFILE_PLATFORM(lcFileLocale);

// Parse the found hashes
while(pHash != NULL)
Expand All @@ -778,13 +780,13 @@ static TMPQHash * GetHashEntryLocale(TMPQArchive * ha, const char * szFileName,
// If the hash entry matches both locale and platform, return it immediately
// Only do that for non-0 locale&platform, because for loc&plat=0, there's different
// processing in Warcraft III vs. Starcraft, which is abused by some protectors.
if((lcLocale || Platform) && pHash->lcLocale == lcLocale && pHash->Platform == Platform)
if((Locale || Platform) && pHash->Locale == Locale && pHash->Platform == Platform)
return pHash;

// Storm_2016.dll: 150209D9
// If (locale matches or is neutral) AND (platform matches or is neutral), remember this as the best entry
// Also remember the first matching entry for Starcraft maps
if(pHash->lcLocale == 0 || pHash->lcLocale == lcLocale)
if(pHash->Locale == 0 || pHash->Locale == Locale)
{
if(pHash->Platform == 0 || pHash->Platform == Platform)
{
Expand All @@ -801,26 +803,31 @@ static TMPQHash * GetHashEntryLocale(TMPQArchive * ha, const char * szFileName,
}

// Returns a hash table entry in the following order:
// 1) A hash table entry with the preferred locale
// 1) A hash table entry with the preferred locale&platform
// 2) NULL
static TMPQHash * GetHashEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcLocale)
// In case there are multiple items with the same locale&platform,
// we need to return the last one. This is because it must correspond to SFileOpenFileEx
static TMPQHash * GetHashEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcFileLocale)
{
TMPQHash * pFirstHash = GetFirstHashEntry(ha, szFileName);
TMPQHash * pBestHash = NULL;
TMPQHash * pHash = pFirstHash;
USHORT Locale = SFILE_LOCALE(lcFileLocale);
BYTE Platform = SFILE_PLATFORM(lcFileLocale);

// Parse the found hashes
while(pHash != NULL)
{
// If the locales match, return it
if(pHash->lcLocale == lcLocale)
return pHash;
// If the locales match, we remember this one as the best one
if(pHash->Locale == Locale && pHash->Platform == Platform)
pBestHash = pHash;

// Get the next hash entry for that file
pHash = GetNextHashEntry(ha, pFirstHash, pHash);
}

// Not found
return NULL;
// Return the best hash or NULL
return pBestHash;
}

// Defragment the file table so it does not contain any gaps
Expand Down Expand Up @@ -925,7 +932,6 @@ static DWORD BuildFileTableFromBlockTable(
if(ha->dwFlags & (MPQ_FLAG_HASH_TABLE_CUT | MPQ_FLAG_BLOCK_TABLE_CUT))
{
// Sanity checks
assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1);
assert(pHeader->HiBlockTablePos64 == 0);

// Allocate the translation table
Expand Down Expand Up @@ -1967,7 +1973,7 @@ void FreeBetTable(TMPQBetTable * pBetTable)
//-----------------------------------------------------------------------------
// Support for file table

TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex)
TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcFileLocale, LPDWORD PtrHashIndex)
{
TMPQHash * pHash;
DWORD dwFileIndex;
Expand All @@ -1977,7 +1983,7 @@ TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID
// we will need the pointer to hash table entry
if(ha->pHashTable != NULL)
{
pHash = GetHashEntryLocale(ha, szFileName, lcLocale, 0);
pHash = GetHashEntryLocale(ha, szFileName, lcFileLocale);
if(pHash != NULL && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize)
{
if(PtrHashIndex != NULL)
Expand All @@ -1998,15 +2004,15 @@ TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID
return NULL;
}

TFileEntry * GetFileEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex)
TFileEntry * GetFileEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcFileLocale, LPDWORD PtrHashIndex)
{
TMPQHash * pHash;
DWORD dwFileIndex;

// If the hash table is present, find the entry from hash table
if(ha->pHashTable != NULL)
{
pHash = GetHashEntryExact(ha, szFileName, lcLocale);
pHash = GetHashEntryExact(ha, szFileName, lcFileLocale);
if(pHash != NULL && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize)
{
if(PtrHashIndex != NULL)
Expand Down Expand Up @@ -2062,7 +2068,7 @@ void AllocateFileName(TMPQArchive * ha, TFileEntry * pFileEntry, const char * sz
}
}

TFileEntry * AllocateFileEntry(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex)
TFileEntry * AllocateFileEntry(TMPQArchive * ha, const char * szFileName, LCID lcFileLocale, LPDWORD PtrHashIndex)
{
TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize;
TFileEntry * pFreeEntry = NULL;
Expand Down Expand Up @@ -2109,10 +2115,10 @@ TFileEntry * AllocateFileEntry(TMPQArchive * ha, const char * szFileName, LCID l
if(ha->pHashTable != NULL)
{
// Make sure that the entry is not there yet
assert(GetHashEntryExact(ha, szFileName, lcLocale) == NULL);
assert(GetHashEntryExact(ha, szFileName, lcFileLocale) == NULL);

// Find a free hash table entry for the name
pHash = AllocateHashEntry(ha, pFreeEntry, lcLocale);
pHash = AllocateHashEntry(ha, pFreeEntry, lcFileLocale);
if(pHash == NULL)
return NULL;

Expand All @@ -2139,7 +2145,7 @@ DWORD RenameFileEntry(
{
TFileEntry * pFileEntry = hf->pFileEntry;
TMPQHash * pHashEntry = hf->pHashEntry;
LCID lcLocale = 0;
LCID lcFileLocale = 0;

// If the archive hash hash table, we need to free the hash table entry
if(ha->pHashTable != NULL)
Expand All @@ -2150,12 +2156,12 @@ DWORD RenameFileEntry(
return ERROR_NOT_SUPPORTED;

// Save the locale
lcLocale = pHashEntry->lcLocale;
lcFileLocale = SFILE_MAKE_LCID(pHashEntry->Locale, pHashEntry->Platform);

// Mark the hash table entry as deleted
pHashEntry->dwName1 = 0xFFFFFFFF;
pHashEntry->dwName2 = 0xFFFFFFFF;
pHashEntry->lcLocale = 0xFFFF;
pHashEntry->Locale = 0xFFFF;
pHashEntry->Platform = 0xFF;
pHashEntry->Reserved = 0xFF;
pHashEntry->dwBlockIndex = HASH_ENTRY_DELETED;
Expand All @@ -2173,7 +2179,7 @@ DWORD RenameFileEntry(
if(ha->pHashTable != NULL)
{
// Since we freed one hash entry before, this must succeed
hf->pHashEntry = AllocateHashEntry(ha, pFileEntry, lcLocale);
hf->pHashEntry = AllocateHashEntry(ha, pFileEntry, lcFileLocale);
assert(hf->pHashEntry != NULL);
}

Expand All @@ -2196,7 +2202,7 @@ DWORD DeleteFileEntry(TMPQArchive * ha, TMPQFile * hf)
// Mark the hash table entry as deleted
pHashEntry->dwName1 = 0xFFFFFFFF;
pHashEntry->dwName2 = 0xFFFFFFFF;
pHashEntry->lcLocale = 0xFFFF;
pHashEntry->Locale = 0xFFFF;
pHashEntry->Platform = 0xFF;
pHashEntry->Reserved = 0xFF;
pHashEntry->dwBlockIndex = HASH_ENTRY_DELETED;
Expand Down Expand Up @@ -2928,7 +2934,7 @@ DWORD RebuildFileTable(TMPQArchive * ha, DWORD dwNewHashTableSize)
if(IsValidHashEntry(ha, pHash))
{
pFileEntry = ha->pFileTable + MPQ_BLOCK_INDEX(pHash);
AllocateHashEntry(ha, pFileEntry, pHash->lcLocale);
AllocateHashEntry(ha, pFileEntry, SFILE_MAKE_LCID(pHash->Locale, pHash->Platform));
}
}

Expand Down
7 changes: 4 additions & 3 deletions src/SBaseSubTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ typedef struct _TSQPHeader

typedef struct _TSQPHash
{
// Most likely the lcLocale+wPlatform.
// Most likely the Locale + Platform
DWORD dwAlwaysZero;

// If the hash table entry is valid, this is the index into the block table of the file.
Expand Down Expand Up @@ -216,8 +216,8 @@ TMPQHash * LoadSqpHashTable(TMPQArchive * ha)
pMpqHash->dwName1 = TempEntry.dwName1;
pMpqHash->dwName2 = TempEntry.dwName2;
pMpqHash->dwBlockIndex = MPQ_BLOCK_INDEX(&TempEntry);
pMpqHash->Locale = 0;
pMpqHash->Platform = 0;
pMpqHash->lcLocale = 0;
pMpqHash->Reserved = 0;
}
}
Expand Down Expand Up @@ -547,8 +547,9 @@ TMPQHash * LoadMpkHashTable(TMPQArchive * ha)

// Copy the MPK hash entry to the hash table
pHash->dwBlockIndex = pMpkHash[i].dwBlockIndex;
pHash->Locale = 0;
pHash->Platform = 0;
pHash->lcLocale = 0;
pHash->Reserved = 0;
pHash->dwName1 = pMpkHash[i].dwName2;
pHash->dwName2 = pMpkHash[i].dwName3;
}
Expand Down
20 changes: 12 additions & 8 deletions src/SFileAddFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ DWORD SFileAddFile_Init(
const char * szFileName,
ULONGLONG FileTime,
DWORD dwFileSize,
LCID lcLocale,
LCID lcFileLocale,
DWORD dwFlags,
TMPQFile ** phf)
{
Expand Down Expand Up @@ -430,7 +430,7 @@ DWORD SFileAddFile_Init(
// If the MPQ is of version 3.0 or higher, we ignore file locale.
// This is because HET and BET tables have no known support for it
if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_3)
lcLocale = 0;
lcFileLocale = 0;

// Allocate the TMPQFile entry for newly added file
hf = CreateWritableHandle(ha, dwFileSize);
Expand All @@ -441,7 +441,7 @@ DWORD SFileAddFile_Init(
if(dwErrCode == ERROR_SUCCESS)
{
// Check if the file already exists in the archive
pFileEntry = GetFileEntryLocale(ha, szFileName, lcLocale, &dwHashIndex);
pFileEntry = GetFileEntryExact(ha, szFileName, lcFileLocale, &dwHashIndex);
if(pFileEntry != NULL)
{
if(dwFlags & MPQ_FILE_REPLACEEXISTING)
Expand All @@ -452,7 +452,7 @@ DWORD SFileAddFile_Init(
else
{
// Attempt to allocate new file entry
pFileEntry = AllocateFileEntry(ha, szFileName, lcLocale, &dwHashIndex);
pFileEntry = AllocateFileEntry(ha, szFileName, lcFileLocale, &dwHashIndex);
if(pFileEntry != NULL)
InvalidateInternalFiles(ha);
else
Expand All @@ -467,7 +467,9 @@ DWORD SFileAddFile_Init(
if(dwErrCode == ERROR_SUCCESS && ha->pHashTable != NULL && dwHashIndex < ha->pHeader->dwHashTableSize)
{
hf->pHashEntry = ha->pHashTable + dwHashIndex;
hf->pHashEntry->lcLocale = (USHORT)lcLocale;
hf->pHashEntry->Locale = SFILE_LOCALE(lcFileLocale);
hf->pHashEntry->Platform = SFILE_PLATFORM(lcFileLocale);
hf->pHashEntry->Reserved = 0;
}

// Prepare the file key
Expand Down Expand Up @@ -762,7 +764,7 @@ bool WINAPI SFileCreateFile(
const char * szArchivedName,
ULONGLONG FileTime,
DWORD dwFileSize,
LCID lcLocale,
LCID lcFileLocale,
DWORD dwFlags,
HANDLE * phFile)
{
Expand Down Expand Up @@ -805,7 +807,7 @@ bool WINAPI SFileCreateFile(

// Initiate the add file operation
if(dwErrCode == ERROR_SUCCESS)
dwErrCode = SFileAddFile_Init(ha, szArchivedName, FileTime, dwFileSize, lcLocale, dwFlags, (TMPQFile **)phFile);
dwErrCode = SFileAddFile_Init(ha, szArchivedName, FileTime, dwFileSize, lcFileLocale, dwFlags, (TMPQFile **)phFile);

// Deal with the errors
if(dwErrCode != ERROR_SUCCESS)
Expand Down Expand Up @@ -1293,7 +1295,9 @@ bool WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale)
}

// Update the locale in the hash table entry
hf->pHashEntry->lcLocale = (USHORT)lcNewLocale;
hf->pHashEntry->Locale = SFILE_LOCALE(lcNewLocale);
hf->pHashEntry->Platform = SFILE_PLATFORM(lcNewLocale);
hf->pHashEntry->Reserved = 0;
ha->dwFlags |= MPQ_FLAG_CHANGED;
return true;
}
Expand Down
4 changes: 2 additions & 2 deletions src/SFileFindFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ static bool DoMPQSearch_FileEntry(
lpFindFileData->dwFileSize = pPatchEntry->dwFileSize;
lpFindFileData->dwFileFlags = pPatchEntry->dwFlags;
lpFindFileData->dwCompSize = pPatchEntry->dwCmpSize;
lpFindFileData->lcLocale = 0; // pPatchEntry->lcLocale;
lpFindFileData->lcLocale = 0; // pPatchEntry->lcFileLocale;

// Fill the filetime
lpFindFileData->dwFileTimeHi = (DWORD)(pPatchEntry->FileTime >> 32);
Expand All @@ -273,7 +273,7 @@ static bool DoMPQSearch_FileEntry(
if(pHashEntry != NULL)
{
lpFindFileData->dwHashIndex = (DWORD)(pHashEntry - ha->pHashTable);
lpFindFileData->lcLocale = pHashEntry->lcLocale;
lpFindFileData->lcLocale = SFILE_MAKE_LCID(pHashEntry->Locale, pHashEntry->Platform);
}

// Fill the file name and plain file name
Expand Down
Loading

0 comments on commit 3846f0b

Please sign in to comment.