diff options
author | Ladislav <Zezula> | 2013-12-27 23:13:28 +0100 |
---|---|---|
committer | Ladislav <Zezula> | 2013-12-27 23:13:28 +0100 |
commit | 3a9a6ec46beaf839cfe4fe8b6a26e1ca5e2d0316 (patch) | |
tree | de92b78a86b403cdf17b1c0bd509d7a3bf10454f /src/SBaseFileTable.cpp | |
parent | 3dd8d1198c46c42a47cd6089e9dd99b9dfdaa798 (diff) |
+ Support for master-mirror pairsv9.00
+ Support for streaming MPQs
+ Bug fixes
Diffstat (limited to 'src/SBaseFileTable.cpp')
-rw-r--r-- | src/SBaseFileTable.cpp | 95 |
1 files changed, 56 insertions, 39 deletions
diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp index fe02931..322211c 100644 --- a/src/SBaseFileTable.cpp +++ b/src/SBaseFileTable.cpp @@ -250,7 +250,7 @@ static DWORD GetMaxFileOffset32(TMPQArchive * ha) return dwMaxFileOffset; } -static ULONGLONG DetermineEndOfArchive_V1_V2( +static ULONGLONG DetermineArchiveSize_V1_V2( TMPQArchive * ha, TMPQHeader * pHeader, ULONGLONG MpqOffset, @@ -264,9 +264,17 @@ static ULONGLONG DetermineEndOfArchive_V1_V2( // Check if we can rely on the archive size in the header if((FileSize >> 0x20) == 0) { - dwArchiveSize32 = (DWORD)(FileSize - MpqOffset); - if(pHeader->dwBlockTablePos < pHeader->dwArchiveSize && pHeader->dwArchiveSize <= dwArchiveSize32) - return pHeader->dwArchiveSize; + if(pHeader->dwBlockTablePos < pHeader->dwArchiveSize) + { + // If the block table end matches the archive size, we trust the archive size + if(pHeader->dwBlockTablePos + (pHeader->dwBlockTableSize * sizeof(TMPQBlock)) == pHeader->dwArchiveSize) + return pHeader->dwArchiveSize; + + // If the archive size in the header is less than real file size + dwArchiveSize32 = (DWORD)(FileSize - MpqOffset); + if(pHeader->dwArchiveSize <= dwArchiveSize32) + return pHeader->dwArchiveSize; + } } // Check if there is a signature header @@ -385,7 +393,7 @@ int ConvertMpqHeaderToFormat4( // Determine the archive size on malformed MPQs if(ha->dwFlags & MPQ_FLAG_MALFORMED) { - pHeader->ArchiveSize64 = DetermineEndOfArchive_V1_V2(ha, pHeader, MpqOffset, FileSize); + pHeader->ArchiveSize64 = DetermineArchiveSize_V1_V2(ha, pHeader, MpqOffset, FileSize); pHeader->dwArchiveSize = (DWORD)pHeader->ArchiveSize64; } break; @@ -423,25 +431,25 @@ int ConvertMpqHeaderToFormat4( if(pHeader->HiBlockTablePos64 != 0) { // BlockTableSize64 may be less than TblSize * sizeof(TMPQBlock). - // That means that the hash table is compressed. + // That means that the hi-block table is compressed. pHeader->BlockTableSize64 = pHeader->HiBlockTablePos64 - BlockTablePos64; assert(pHeader->BlockTableSize64 <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock))); - // Determine the size of the hi-block table - pHeader->HiBlockTableSize64 = DetermineEndOfArchive_V1_V2(ha, pHeader, MpqOffset, FileSize) - pHeader->HiBlockTablePos64; - assert(pHeader->HiBlockTableSize64 == (pHeader->dwBlockTableSize * sizeof(USHORT))); + // Determine real archive size + pHeader->ArchiveSize64 = DetermineArchiveSize_V1_V2(ha, pHeader, MpqOffset, FileSize); - // Recalculate the archive size - pHeader->ArchiveSize64 = pHeader->HiBlockTablePos64 + pHeader->HiBlockTableSize64; + // Calculate the size of the hi-block table + pHeader->HiBlockTableSize64 = pHeader->ArchiveSize64 - pHeader->HiBlockTablePos64; + assert(pHeader->HiBlockTableSize64 == (pHeader->dwBlockTableSize * sizeof(USHORT))); } else { - // Block table size is the end of the archive minus the block table position - pHeader->BlockTableSize64 = DetermineEndOfArchive_V1_V2(ha, pHeader, MpqOffset, FileSize) - BlockTablePos64; - assert(pHeader->BlockTableSize64 <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock))); + // Determine real archive size + pHeader->ArchiveSize64 = DetermineArchiveSize_V1_V2(ha, pHeader, MpqOffset, FileSize); - // dwArchiveSize in the header v 2.0 is 32-bit only - pHeader->ArchiveSize64 = BlockTablePos64 + pHeader->BlockTableSize64; + // Calculate size of the block table + pHeader->BlockTableSize64 = pHeader->ArchiveSize64 - BlockTablePos64; + assert(pHeader->BlockTableSize64 <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock))); } } else @@ -1041,7 +1049,7 @@ static void CreateHetHeader( pHetHeader->dwIndexTableSize; } -TMPQHetTable * CreateHetTable(DWORD dwFileCount, DWORD dwNameHashBitSize, LPBYTE pbSrcData) +TMPQHetTable * CreateHetTable(DWORD dwEntryCount, DWORD dwTotalCount, DWORD dwNameHashBitSize, LPBYTE pbSrcData) { TMPQHetTable * pHetTable; @@ -1058,33 +1066,37 @@ TMPQHetTable * CreateHetTable(DWORD dwFileCount, DWORD dwNameHashBitSize, LPBYTE pHetTable->AndMask64 = ((dwNameHashBitSize != 0x40) ? ((ULONGLONG)1 << dwNameHashBitSize) : 0) - 1; pHetTable->OrMask64 = (ULONGLONG)1 << (dwNameHashBitSize - 1); + // If the total count is not entered, use default + if(dwTotalCount == 0) + dwTotalCount = (dwEntryCount * 4) / 3; + // Store the HET table parameters - pHetTable->dwEntryCount = dwFileCount; - pHetTable->dwTotalCount = (dwFileCount * 4) / 3; + pHetTable->dwEntryCount = dwEntryCount; + pHetTable->dwTotalCount = dwTotalCount; pHetTable->dwNameHashBitSize = dwNameHashBitSize; - pHetTable->dwIndexSizeTotal = GetNecessaryBitCount(dwFileCount); + pHetTable->dwIndexSizeTotal = GetNecessaryBitCount(dwEntryCount); pHetTable->dwIndexSizeExtra = 0; pHetTable->dwIndexSize = pHetTable->dwIndexSizeTotal; // Allocate array of hashes - pHetTable->pNameHashes = STORM_ALLOC(BYTE, pHetTable->dwTotalCount); + pHetTable->pNameHashes = STORM_ALLOC(BYTE, dwTotalCount); if(pHetTable->pNameHashes != NULL) { // Make sure the data are initialized - memset(pHetTable->pNameHashes, 0, pHetTable->dwTotalCount); + memset(pHetTable->pNameHashes, 0, dwTotalCount); // Allocate the bit array for file indexes - pHetTable->pBetIndexes = CreateBitArray(pHetTable->dwTotalCount * pHetTable->dwIndexSizeTotal, 0xFF); + pHetTable->pBetIndexes = CreateBitArray(dwTotalCount * pHetTable->dwIndexSizeTotal, 0xFF); if(pHetTable->pBetIndexes != NULL) { // Initialize the HET table from the source data (if given) if(pbSrcData != NULL) { // Copy the name hashes - memcpy(pHetTable->pNameHashes, pbSrcData, pHetTable->dwTotalCount); + memcpy(pHetTable->pNameHashes, pbSrcData, dwTotalCount); // Copy the file indexes - memcpy(pHetTable->pBetIndexes->Elements, pbSrcData + pHetTable->dwTotalCount, pHetTable->pBetIndexes->NumberOfBytes); + memcpy(pHetTable->pBetIndexes->Elements, pbSrcData + dwTotalCount, pHetTable->pBetIndexes->NumberOfBytes); } // Return the result HET table @@ -1152,7 +1164,7 @@ static TMPQHetTable * TranslateHetTable(TMPQHetHeader * pHetHeader) assert(pHetHeader->ExtHdr.dwVersion == 1); // Verify size of the HET table - if(pHetHeader->ExtHdr.dwDataSize >= sizeof(TMPQHetHeader)) + if(pHetHeader->ExtHdr.dwDataSize >= (sizeof(TMPQHetHeader) - sizeof(TMPQExtHeader))) { // Verify the size of the table in the header if(pHetHeader->dwTableSize == pHetHeader->ExtHdr.dwDataSize) @@ -1161,7 +1173,8 @@ static TMPQHetTable * TranslateHetTable(TMPQHetHeader * pHetHeader) assert((sizeof(TMPQHetHeader) - sizeof(TMPQExtHeader) + pHetHeader->dwTotalCount + pHetHeader->dwIndexTableSize) == pHetHeader->dwTableSize); // So far, all MPQs with HET Table have had total number of entries equal to 4/3 of file count - assert(((pHetHeader->dwEntryCount * 4) / 3) == pHetHeader->dwTotalCount); + // Exception: "2010 - Starcraft II\!maps\Tya's Zerg Defense (unprotected).SC2Map" +// assert(((pHetHeader->dwEntryCount * 4) / 3) == pHetHeader->dwTotalCount); // The size of one index is predictable as well assert(GetNecessaryBitCount(pHetHeader->dwEntryCount) == pHetHeader->dwIndexSizeTotal); @@ -1171,7 +1184,7 @@ static TMPQHetTable * TranslateHetTable(TMPQHetHeader * pHetHeader) assert(((pHetHeader->dwTotalCount * pHetHeader->dwIndexSizeTotal) + 7) / 8 == pHetHeader->dwIndexTableSize); // Create translated table - pHetTable = CreateHetTable(pHetHeader->dwEntryCount, pHetHeader->dwNameHashBitSize, pbSrcData); + pHetTable = CreateHetTable(pHetHeader->dwEntryCount, pHetHeader->dwTotalCount, pHetHeader->dwNameHashBitSize, pbSrcData); if(pHetTable != NULL) { // Now the sizes in the hash table should be already set @@ -1422,7 +1435,7 @@ static TMPQBetTable * TranslateBetTable( ha = ha; // Verify size of the HET table - if(pBetHeader->ExtHdr.dwDataSize >= sizeof(TMPQBetHeader)) + if(pBetHeader->ExtHdr.dwDataSize >= (sizeof(TMPQBetHeader) - sizeof(TMPQExtHeader))) { // Verify the size of the table in the header if(pBetHeader->dwTableSize == pBetHeader->ExtHdr.dwDataSize) @@ -2263,9 +2276,8 @@ TMPQHetTable * LoadHetTable(TMPQArchive * ha) TMPQHetTable * pHetTable = NULL; TMPQHeader * pHeader = ha->pHeader; - // If the HET table position is not NULL, we expect - // both HET and BET tables to be present. - if(pHeader->HetTablePos64 != 0) + // If the HET table position is not 0, we expect the table to be present + if(pHeader->HetTablePos64 != 0 && pHeader->HetTableSize64 != 0) { // Attempt to load the HET table (Hash Extended Table) pExtTable = LoadExtTable(ha, pHeader->HetTablePos64, (size_t)pHeader->HetTableSize64, HET_TABLE_SIGNATURE, MPQ_KEY_HASH_TABLE); @@ -2286,9 +2298,8 @@ TMPQBetTable * LoadBetTable(TMPQArchive * ha) TMPQBetTable * pBetTable = NULL; TMPQHeader * pHeader = ha->pHeader; - // If the HET table position is not NULL, we expect - // both HET and BET tables to be present. - if(pHeader->BetTablePos64 != 0) + // If the BET table position is not 0, we expect the table to be present + if(pHeader->BetTablePos64 != 0 && pHeader->BetTableSize64 != 0) { // Attempt to load the HET table (Hash Extended Table) pExtTable = LoadExtTable(ha, pHeader->BetTablePos64, (size_t)pHeader->BetTableSize64, BET_TABLE_SIGNATURE, MPQ_KEY_BLOCK_TABLE); @@ -2312,9 +2323,15 @@ int LoadAnyHashTable(TMPQArchive * ha) if(pHeader->dwHashTableSize == 0 && pHeader->HetTableSize64 == 0) return CreateHashTable(ha, HASH_TABLE_SIZE_DEFAULT); - // Try to load HET table (the new hash table) and the classic HASH table - ha->pHetTable = LoadHetTable(ha); - ha->pHashTable = LoadHashTable(ha); + // Try to load HET table + if(pHeader->HetTablePos64 != 0) + ha->pHetTable = LoadHetTable(ha); + + // Try to load the hash table + if(pHeader->wHashTablePosHi || pHeader->dwHashTablePos) + ha->pHashTable = LoadHashTable(ha); + + // At least one of the tables must be present if(ha->pHetTable == NULL && ha->pHashTable == NULL) return ERROR_FILE_CORRUPT; @@ -2580,7 +2597,7 @@ int RebuildHetTable(TMPQArchive * ha) // Create new HET table based on the total number of entries in the file table // Note that if we fail to create it, we just stop using HET table - ha->pHetTable = CreateHetTable(ha->dwFileTableSize, 0x40, NULL); + ha->pHetTable = CreateHetTable(ha->dwFileTableSize, 0, 0x40, NULL); if(ha->pHetTable != NULL) { // Go through the file table again and insert all existing files |