diff options
-rw-r--r-- | src/SBaseFileTable.cpp | 100 | ||||
-rw-r--r-- | src/StormLib.h | 4 | ||||
-rwxr-xr-x | test/StormTest.cpp | 2 | ||||
-rw-r--r-- | test/stormlib-test-001.txt | 6 |
4 files changed, 32 insertions, 80 deletions
diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp index 20d7cc4..befe40f 100644 --- a/src/SBaseFileTable.cpp +++ b/src/SBaseFileTable.cpp @@ -312,59 +312,38 @@ static ULONGLONG DetermineArchiveSize_V1( return (EndOfMpq - MpqOffset);
}
-static ULONGLONG DetermineArchiveSize_V2(
- TMPQHeader * pHeader,
- ULONGLONG MpqOffset,
- ULONGLONG FileSize)
+static ULONGLONG DetermineBlockTableSize_V2(TMPQHeader * pHeader, ULONGLONG MpqHeaderPos, ULONGLONG FileSize)
{
- ULONGLONG TableOffset;
- ULONGLONG TableSize;
- ULONGLONG MaxOffset = 0;
-
- // This could only be called for MPQs version 2.0
- assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_2);
+ ULONGLONG BlockTablePos = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
+ ULONGLONG ArchiveSize = FileSize - MpqHeaderPos;
- // Is the hash table end greater than max offset?
- TableOffset = MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos);
- TableSize = (ULONGLONG)pHeader->dwHashTableSize * sizeof(TMPQHash);
- if((TableOffset + TableSize) > MaxOffset)
- MaxOffset = TableOffset + TableSize;
-
- // Is the block table end greater than max offset?
- TableOffset = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
- TableSize = (ULONGLONG)pHeader->dwBlockTableSize * sizeof(TMPQBlock);
- if((TableOffset + TableSize) > MaxOffset)
- MaxOffset = TableOffset + TableSize;
-
- // Is the hi-block table end greater than max offset?
- if((TableOffset = pHeader->HiBlockTablePos64) != 0)
+ // If there is a hi-block table and it is beyond the block table,
+ // we can determine the block table size from it
+ if(pHeader->HiBlockTablePos64 != 0)
{
- TableSize = (ULONGLONG)pHeader->dwBlockTableSize * sizeof(USHORT);
- if((TableOffset + TableSize) > MaxOffset)
- MaxOffset = TableOffset + TableSize;
+ if(pHeader->HiBlockTablePos64 > BlockTablePos)
+ {
+ return (pHeader->HiBlockTablePos64 - BlockTablePos);
+ }
}
- // Cut to the file size
- if(MaxOffset > (FileSize - MpqOffset))
- MaxOffset = FileSize - MpqOffset;
- return MaxOffset;
-}
-
-static ULONGLONG DetermineBlockTableSize_V2(TMPQHeader * pHeader)
-{
- ULONGLONG BlockTableOffset = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos);
- ULONGLONG TableOffset;
- ULONGLONG TableSize = (pHeader->ArchiveSize64 - BlockTableOffset);
-
- // Subtract the offset of the hi-block table
- if((TableOffset = pHeader->HiBlockTablePos64) != 0)
+ // If we have valid archive size, we can determine the block table size from the archive size
+ else
{
- if(TableOffset > BlockTableOffset)
+ if((BlockTablePos >> 0x20) == 0 && (ArchiveSize >> 0x20) == 0)
{
- TableSize = TableOffset - BlockTableOffset;
+ DWORD dwBlockTablePos32 = (DWORD)(BlockTablePos);
+ DWORD dwArchiveSize32 = (DWORD)(ArchiveSize);
+
+ if(pHeader->dwArchiveSize == dwArchiveSize32)
+ {
+ return (dwArchiveSize32 - dwBlockTablePos32);
+ }
}
}
- return TableSize;
+
+ // Default is the block table size from MPQ header
+ return (ULONGLONG)(pHeader->dwBlockTableSize) * sizeof(TMPQBlock);
}
static ULONGLONG DetermineArchiveSize_V4(
@@ -566,35 +545,14 @@ DWORD ConvertMpqHeaderToFormat4( // We require the block table to follow hash table
if(BlockTablePos64 >= HashTablePos64)
{
- // HashTableSize64 may be less than TblSize * sizeof(TMPQHash).
- // That means that the hash table is compressed.
+ // Determine whether the hash table is compressed. This can be detected
+ // by subtracting hash table position from the block table position.
pHeader->HashTableSize64 = BlockTablePos64 - HashTablePos64;
- // Calculate the compressed block table size
- if(pHeader->HiBlockTablePos64 != 0)
- {
- // BlockTableSize64 may be less than TblSize * sizeof(TMPQBlock).
- // That means that the block table is compressed.
- pHeader->BlockTableSize64 = pHeader->HiBlockTablePos64 - BlockTablePos64;
- assert(pHeader->BlockTableSize64 <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock)));
-
- // Determine real archive size
- pHeader->ArchiveSize64 = DetermineArchiveSize_V2(pHeader, ByteOffset, FileSize);
-
- // Calculate the size of the hi-block table
- pHeader->HiBlockTableSize64 = pHeader->ArchiveSize64 - pHeader->HiBlockTablePos64;
- assert(pHeader->HiBlockTableSize64 == (pHeader->dwBlockTableSize * sizeof(USHORT)));
- }
- else
- {
- // Determine real archive size
- pHeader->ArchiveSize64 = DetermineArchiveSize_V2(pHeader, ByteOffset, FileSize);
- pHeader->dwArchiveSize = (DWORD)(pHeader->ArchiveSize64);
-
- // Calculate size of the block table
- pHeader->BlockTableSize64 = DetermineBlockTableSize_V2(pHeader);
- assert(pHeader->BlockTableSize64 <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock)));
- }
+ // Also, block table may be compressed. We check whether the HiBlockTable is there.
+ // If not, we try to use the archive size. Note that ArchiveSize may have
+ // an arbitrary value, because it is not tested by Blizzard games anymore
+ pHeader->BlockTableSize64 = DetermineBlockTableSize_V2(pHeader, ByteOffset, FileSize);
}
else
{
diff --git a/src/StormLib.h b/src/StormLib.h index 94e9813..4aa51c1 100644 --- a/src/StormLib.h +++ b/src/StormLib.h @@ -143,8 +143,8 @@ extern "C" { //----------------------------------------------------------------------------- // Defines -#define STORMLIB_VERSION 0x0918 // Current version of StormLib (9.24) -#define STORMLIB_VERSION_STRING "9.24" // String version of StormLib version +#define STORMLIB_VERSION 0x0919 // Current version of StormLib +#define STORMLIB_VERSION_STRING "9.25" // Current version of StormLib as string #define ID_MPQ 0x1A51504D // MPQ archive header ID ('MPQ\x1A') #define ID_MPQ_USERDATA 0x1B51504D // MPQ userdata entry ('MPQ\x1B') diff --git a/test/StormTest.cpp b/test/StormTest.cpp index 249cc80..a65430d 100755 --- a/test/StormTest.cpp +++ b/test/StormTest.cpp @@ -2655,7 +2655,7 @@ static DWORD TestOpenArchive( }
// Reset error code, if the failure is expected
- if((dwErrCode != ERROR_SUCCESS) && (hMpq == NULL) && (dwFlags & TFLG_WILL_FAIL))
+ if((dwErrCode != ERROR_SUCCESS || hMpq == NULL) && (dwFlags & TFLG_WILL_FAIL))
SetLastError(dwErrCode = ERROR_SUCCESS);
// Cleanup and exit
diff --git a/test/stormlib-test-001.txt b/test/stormlib-test-001.txt index f35c06f..d69a56e 100644 --- a/test/stormlib-test-001.txt +++ b/test/stormlib-test-001.txt @@ -1,7 +1,3 @@ -Microsoft Windows [Version 10.0.19045.2965] -(c) Microsoft Corporation. All rights reserved. - -E:\Ladik\AppDir\StormLib\bin\StormLib_test\x64\Release>StormLib_test.exe ==== Test Suite for StormLib version 9.24 ==== InitWorkFolder: Work directory \Multimedia\MPQs (default) TestLiFiSearch (FLAT-MAP:ListFile_Blizzard.txt) succeeded. @@ -138,5 +134,3 @@ ListFilePos (StormLibTest_ListFilePos.mpq) succeeded. TestBigArchive (StormLibTest_BigArchive_v4.mpq) succeeded. TestModifyMpq (MPQ_2014_v4_Base.StormReplay) succeeded. TestModifyMpq (MPQ_2022_v1_v4.329.w3x) succeeded. - -E:\Ladik\AppDir\StormLib\bin\StormLib_test\x64\Release>
\ No newline at end of file |