diff options
-rw-r--r-- | src/SBaseCommon.cpp | 2 | ||||
-rw-r--r-- | src/SBaseDumpData.cpp | 4 | ||||
-rw-r--r-- | src/SBaseFileTable.cpp | 40 | ||||
-rw-r--r-- | src/SBaseSubTypes.cpp | 4 | ||||
-rw-r--r-- | src/StormLib.h | 7 | ||||
-rw-r--r-- | storm_dll/storm_test.cpp | 12 | ||||
-rw-r--r-- | test/StormTest.cpp | 80 |
7 files changed, 119 insertions, 30 deletions
diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp index 977664a..aa891df 100644 --- a/src/SBaseCommon.cpp +++ b/src/SBaseCommon.cpp @@ -721,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 fe5eb78..c7a26aa 100644 --- a/src/SBaseFileTable.cpp +++ b/src/SBaseFileTable.cpp @@ -612,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:
@@ -1803,7 +1813,7 @@ 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);
+ pHash = GetHashEntryLocale(ha, szFileName, lcLocale, 0);
if(pHash != NULL && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize)
{
if(PtrHashIndex != NULL)
@@ -1987,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;
}
@@ -2027,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;
}
diff --git a/src/SBaseSubTypes.cpp b/src/SBaseSubTypes.cpp index 333b881..47c205e 100644 --- a/src/SBaseSubTypes.cpp +++ b/src/SBaseSubTypes.cpp @@ -216,7 +216,7 @@ TMPQHash * LoadSqpHashTable(TMPQArchive * ha) // Store the rest. Note that this must be done last, // because block index corresponds to pMpqHash->dwName2 pMpqHash->dwBlockIndex = MPQ_BLOCK_INDEX(pSqpHash); - pMpqHash->wPlatform = 0; + pMpqHash->Platform = 0; pMpqHash->lcLocale = 0; } } @@ -544,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/StormLib.h b/src/StormLib.h index 3621096..b6df481 100644 --- a/src/StormLib.h +++ b/src/StormLib.h @@ -617,12 +617,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 diff --git a/storm_dll/storm_test.cpp b/storm_dll/storm_test.cpp index 5e498b3..2d1e6bc 100644 --- a/storm_dll/storm_test.cpp +++ b/storm_dll/storm_test.cpp @@ -22,22 +22,22 @@ //----------------------------------------------------------------------------- // Main -unsigned char szKoreanFileName[] = {0x77, 0x61, 0x72, 0x33, 0x6D, 0x61, 0x70, 0x49, 0x6D, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x5C, 0xBF, 0xD5, 0xB1, 0xB9, 0x2E, 0x6D, 0x70, 0x33, 0x00}; - int main() { - LPCSTR szArchiveName = "e:\\MPQ_2016_v1_KoreanFile.w3m"; + LPCSTR szArchiveName = "e:\\Multimedia\\MPQs\\1995 - Test MPQs\\MPQ_2016_v1_123.w3x"; HANDLE hMpq = NULL; HANDLE hFile = NULL; - char szFileName[MAX_PATH]; + BYTE Buffer[0x100]; + DWORD dwBytesRead = 0; _asm int 3; if(StormOpenArchive(szArchiveName, 0, 0, &hMpq)) { - memcpy(szFileName, szKoreanFileName, _countof(szKoreanFileName)); - if(StormOpenFileEx(hMpq, szFileName, 0, &hFile)) + if(StormOpenFileEx(hMpq, "war3map.j", 0, &hFile)) { + dwBytesRead = StormGetFileSize(hFile, NULL); + StormReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead, NULL); StormCloseFile(hFile); } diff --git a/test/StormTest.cpp b/test/StormTest.cpp index 410dfd4..0feb003 100644 --- a/test/StormTest.cpp +++ b/test/StormTest.cpp @@ -308,6 +308,25 @@ static bool IsMpqExtension(const char * szFileName) return false;
}
+static void BinaryFromString(const char * szBinary, LPBYTE pbBuffer, DWORD cbBuffer)
+{
+ LPBYTE pbBufferEnd = pbBuffer + cbBuffer;
+ char * szTemp;
+ char szHexaDigit[4];
+
+ while(szBinary[0] != 0 && pbBuffer < pbBufferEnd)
+ {
+ // Get the 2-byte chunk
+ szHexaDigit[0] = szBinary[0];
+ szHexaDigit[1] = szBinary[1];
+ szHexaDigit[2] = 0;
+
+ // Convert to integer
+ *pbBuffer++ = (BYTE)strtoul(szHexaDigit, &szTemp, 16);
+ szBinary += 2;
+ }
+}
+
static void AddStringBeforeExtension(char * szBuffer, const char * szFileName, const char * szExtraString)
{
const char * szExtension;
@@ -1675,7 +1694,7 @@ static int SearchArchive( // Increment number of files
dwFileCount++;
-// if(!_stricmp(sf.cFileName, "Interface\\Glues\\CREDITS\\1024px-Blade3_final2.blp"))
+// if(!_stricmp(sf.cFileName, "war3map.j"))
// DebugBreak();
if(dwTestFlags & TEST_FLAG_MOST_PATCHED)
@@ -2634,6 +2653,60 @@ static int TestOpenArchive_SetPos(const char * szPlainName, const char * szFileN return nError;
}
+static int TestOpenArchive_ProtectedMap(const char * szPlainName, const char * szListFile = NULL, DWORD dwExpectedFileCount = 0, const char * szExpectedMD5 = NULL)
+{
+ TLogHelper Logger("ProtectedMapTest", szPlainName);
+ HANDLE hMpq;
+ DWORD dwTestFlags = TEST_FLAG_LOAD_FILES | TEST_FLAG_HASH_FILES;
+ DWORD dwFileCount = 0;
+ BYTE ExpectedMD5[MD5_DIGEST_SIZE];
+ BYTE OverallMD5[MD5_DIGEST_SIZE];
+ char szListFileBuff[MAX_PATH];
+ int nError;
+
+ // Copy the archive so we won't fuck up the original one
+ nError = OpenExistingArchiveWithCopy(&Logger, szPlainName, szPlainName, &hMpq);
+ if(nError == ERROR_SUCCESS)
+ {
+ // If the listfile was given, add it to the MPQ
+ if(szListFile != NULL)
+ {
+ Logger.PrintProgress("Adding listfile %s ...", szListFile);
+ CreateFullPathName(szListFileBuff, szMpqSubDir, szListFile);
+ nError = SFileAddListFile(hMpq, szListFileBuff);
+ if(nError != ERROR_SUCCESS)
+ Logger.PrintMessage("Failed to add the listfile to the MPQ");
+ }
+
+ // Search the archive and load every file
+ nError = SearchArchive(&Logger, hMpq, dwTestFlags, &dwFileCount, OverallMD5);
+ SFileCloseArchive(hMpq);
+ }
+
+ // Check the file count and hash, if required
+ if(nError == ERROR_SUCCESS && dwExpectedFileCount != 0)
+ {
+ if(dwFileCount != dwExpectedFileCount)
+ {
+ Logger.PrintMessage("File count mismatch(expected: %u, found:%u)", dwExpectedFileCount, dwFileCount);
+ nError = ERROR_CAN_NOT_COMPLETE;
+ }
+ }
+
+ // Check the overall hash, if required
+ if(nError == ERROR_SUCCESS && szExpectedMD5 != NULL && szExpectedMD5[0] != 0)
+ {
+ BinaryFromString(szExpectedMD5, ExpectedMD5, MD5_DIGEST_SIZE);
+ if(memcmp(ExpectedMD5, OverallMD5, MD5_DIGEST_SIZE))
+ {
+ Logger.PrintMessage("Extracted files MD5 mismatch");
+ nError = ERROR_CAN_NOT_COMPLETE;
+ }
+ }
+
+ return nError;
+}
+
// Open an empty archive (found in WoW cache - it's just a header)
static int TestOpenArchive_WillFail(const char * szPlainName)
{
@@ -4470,9 +4543,12 @@ int main(int argc, char * argv[]) if(nError == ERROR_SUCCESS)
nError = TestOpenArchive("MPQ_2016_v1_ProtectedMap_1.4.w3x");
-*/
+
if(nError == ERROR_SUCCESS)
nError = TestOpenArchive("MPQ_2016_v1_KoreanFile.w3m");
+*/
+ if(nError == ERROR_SUCCESS)
+ nError = TestOpenArchive_ProtectedMap("MPQ_2016_v1_123.w3x", NULL, 17, "23b09ad3b8d89ec97df8860447abc7eb");
/*
// Open the multi-file archive with wrong prefix to see how StormLib deals with it
if(nError == ERROR_SUCCESS)
|