From f3112547853a361f9c5419cfb6810b2a54c643e6 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Thu, 14 Jul 2016 14:15:29 +0200 Subject: [PATCH] + Fixed bug in opening SQP archives + More efficient version of GetNearestPowerOfTwo --- src/SBaseCommon.cpp | 28 ++++++++++++++-------------- src/SBaseFileTable.cpp | 2 +- src/SBaseSubTypes.cpp | 4 ++-- src/SFileCompactArchive.cpp | 2 +- src/SFileCreateArchive.cpp | 2 +- src/StormCommon.h | 2 +- test/StormTest.cpp | 8 ++++---- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp index 5483f55..02dc124 100644 --- a/src/SBaseCommon.cpp +++ b/src/SBaseCommon.cpp @@ -257,20 +257,20 @@ DWORD HashStringLower(const char * szFileName, DWORD dwHashType) // Returns the nearest higher power of two. // If the value is already a power of two, returns the same value -//static DWORD GetNearestPowerOfTwo(DWORD dwValue) -//{ -// dwValue --; -// -// dwValue |= dwValue >> 1; -// dwValue |= dwValue >> 2; -// dwValue |= dwValue >> 4; -// dwValue |= dwValue >> 8; -// dwValue |= dwValue >> 16; -// -// return dwValue + 1; -//} +DWORD GetNearestPowerOfTwo(DWORD dwFileCount) +{ + dwFileCount --; -DWORD GetHashTableSizeForFileCount(DWORD 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; @@ -284,7 +284,7 @@ DWORD GetHashTableSizeForFileCount(DWORD dwFileCount) dwPowerOfTwo <<= 1; return dwPowerOfTwo; } - +*/ //----------------------------------------------------------------------------- // Calculates a Jenkin's Encrypting and decrypting MPQ file data diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp index 981328b..fe5eb78 100644 --- a/src/SBaseFileTable.cpp +++ b/src/SBaseFileTable.cpp @@ -701,7 +701,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; diff --git a/src/SBaseSubTypes.cpp b/src/SBaseSubTypes.cpp index 1f72c17..333b881 100644 --- a/src/SBaseSubTypes.cpp +++ b/src/SBaseSubTypes.cpp @@ -202,7 +202,7 @@ TMPQHash * LoadSqpHashTable(TMPQArchive * ha) if(pSqpHash->dwBlockIndex != HASH_ENTRY_FREE) { // Check block index against the size of the block table - if(pHeader->dwBlockTableSize <= MPQ_BLOCK_INDEX(pSqpHash) && MPQ_BLOCK_INDEX(pSqpHash) < 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 @@ -523,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, 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 df32759..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); 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/test/StormTest.cpp b/test/StormTest.cpp index 2d957b0..eb3f665 100644 --- a/test/StormTest.cpp +++ b/test/StormTest.cpp @@ -4397,7 +4397,7 @@ int main(int argc, char * argv[]) // Open a MPK archive from Longwu online if(nError == ERROR_SUCCESS) nError = TestOpenArchive("MPx_2013_v1_LongwuOnline.mpk"); - +*/ // Open a SQP archive from War of the Immortals if(nError == ERROR_SUCCESS) nError = TestOpenArchive("MPx_2013_v1_WarOfTheImmortals.sqp", "ListFile_WarOfTheImmortals.txt"); @@ -4467,10 +4467,10 @@ int main(int argc, char * argv[]) if(nError == ERROR_SUCCESS) nError = TestOpenArchive("MPQ_2016_v1_SP_(4)Adrenaline.w3x"); -*/ + if(nError == ERROR_SUCCESS) nError = TestOpenArchive("MPQ_2016_v1_ProtectedMap_1.4.w3x"); -/* + // Open the multi-file archive with wrong prefix to see how StormLib deals with it if(nError == ERROR_SUCCESS) nError = TestOpenArchive_WillFail("flat-file://streaming/model.MPQ.0"); @@ -4673,7 +4673,7 @@ int main(int argc, char * argv[]) // Test replacing a file with zero size file if(nError == ERROR_SUCCESS) nError = TestModifyArchive_ReplaceFile("MPQ_2014_v4_Base.StormReplay", "AddFile-replay.message.events"); -*/ + #ifdef _MSC_VER _CrtDumpMemoryLeaks(); #endif // _MSC_VER