From afd304b180607a68edc1613074eeaca5e8805153 Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Tue, 6 Jun 2023 09:50:16 +0200 Subject: Fixed loading of corrupt MPQ version 2 --- src/SBaseFileTable.cpp | 58 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp index 43202d0..20d7cc4 100644 --- a/src/SBaseFileTable.cpp +++ b/src/SBaseFileTable.cpp @@ -317,29 +317,54 @@ static ULONGLONG DetermineArchiveSize_V2( ULONGLONG MpqOffset, ULONGLONG FileSize) { - ULONGLONG EndOfMpq = FileSize; - DWORD dwArchiveSize32; + ULONGLONG TableOffset; + ULONGLONG TableSize; + ULONGLONG MaxOffset = 0; // This could only be called for MPQs version 2.0 assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_2); - // Check if we can rely on the archive size in the header - if((FileSize >> 0x20) == 0) + // 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(pHeader->dwBlockTablePos < pHeader->dwArchiveSize) - { - if((pHeader->dwArchiveSize - pHeader->dwBlockTablePos) <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock))) - return pHeader->dwArchiveSize; + TableSize = (ULONGLONG)pHeader->dwBlockTableSize * sizeof(USHORT); + if((TableOffset + TableSize) > MaxOffset) + MaxOffset = TableOffset + TableSize; + } + + // 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); - // If the archive size in the header is less than real file size - dwArchiveSize32 = (DWORD)(FileSize - MpqOffset); - if(pHeader->dwArchiveSize <= dwArchiveSize32) - return pHeader->dwArchiveSize; + // Subtract the offset of the hi-block table + if((TableOffset = pHeader->HiBlockTablePos64) != 0) + { + if(TableOffset > BlockTableOffset) + { + TableSize = TableOffset - BlockTableOffset; } } - - // Return the calculated archive size - return (EndOfMpq - MpqOffset); + return TableSize; } static ULONGLONG DetermineArchiveSize_V4( @@ -564,9 +589,10 @@ DWORD ConvertMpqHeaderToFormat4( { // Determine real archive size pHeader->ArchiveSize64 = DetermineArchiveSize_V2(pHeader, ByteOffset, FileSize); + pHeader->dwArchiveSize = (DWORD)(pHeader->ArchiveSize64); // Calculate size of the block table - pHeader->BlockTableSize64 = pHeader->ArchiveSize64 - BlockTablePos64; + pHeader->BlockTableSize64 = DetermineBlockTableSize_V2(pHeader); assert(pHeader->BlockTableSize64 <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock))); } } -- cgit v1.2.3