diff options
author | unknown <E:\Ladik\Mail> | 2015-05-01 07:06:29 +0200 |
---|---|---|
committer | unknown <E:\Ladik\Mail> | 2015-05-01 07:06:29 +0200 |
commit | 46930855f500c1b494e3b16bb7a3323c07d4d5fb (patch) | |
tree | 6220cc643761137a930841d8ec828db9f3db53cf /src/SFileAttributes.cpp | |
parent | a205159d004871efbedd7cbfb686b8fe82bfb532 (diff) |
+ Removed back reference of FileTable -> HashTable, as it is logically incorrect
+ Optimized patching process so it consimes less memory
+ Added hash table and block table defragmenting for malformed War3 maps
Diffstat (limited to 'src/SFileAttributes.cpp')
-rw-r--r-- | src/SFileAttributes.cpp | 63 |
1 files changed, 29 insertions, 34 deletions
diff --git a/src/SFileAttributes.cpp b/src/SFileAttributes.cpp index 81bf1cf..dacfd3b 100644 --- a/src/SFileAttributes.cpp +++ b/src/SFileAttributes.cpp @@ -34,29 +34,29 @@ typedef struct _MPQ_ATTRIBUTES_HEADER //----------------------------------------------------------------------------- // Local functions -static DWORD GetSizeOfAttributesFile(DWORD dwAttrFlags, DWORD dwFileTableSize) +static DWORD GetSizeOfAttributesFile(DWORD dwAttrFlags, DWORD dwBlockTableSize) { DWORD cbAttrFile = sizeof(MPQ_ATTRIBUTES_HEADER); // Calculate size of the (attributes) file if(dwAttrFlags & MPQ_ATTRIBUTE_CRC32) - cbAttrFile += dwFileTableSize * sizeof(DWORD); + cbAttrFile += dwBlockTableSize * sizeof(DWORD); if(dwAttrFlags & MPQ_ATTRIBUTE_FILETIME) - cbAttrFile += dwFileTableSize * sizeof(ULONGLONG); + cbAttrFile += dwBlockTableSize * sizeof(ULONGLONG); if(dwAttrFlags & MPQ_ATTRIBUTE_MD5) - cbAttrFile += dwFileTableSize * MD5_DIGEST_SIZE; + cbAttrFile += dwBlockTableSize * MD5_DIGEST_SIZE; // The bit array has been created without the last bit belonging to (attributes) // When the number of files is a multiplier of 8 plus one, then the size of (attributes) // if 1 byte less than expected. // Example: wow-update-13164.MPQ: BlockTableSize = 0x62E1, but there's only 0xC5C bytes if(dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT) - cbAttrFile += (dwFileTableSize + 6) / 8; + cbAttrFile += (dwBlockTableSize + 6) / 8; return cbAttrFile; } -static DWORD CheckSizeOfAttributesFile(DWORD cbAttrFile, DWORD dwAttrFlags, DWORD dwFileTableSize) +static DWORD CheckSizeOfAttributesFile(DWORD cbAttrFile, DWORD dwAttrFlags, DWORD dwBlockTableSize) { DWORD cbHeaderSize = sizeof(MPQ_ATTRIBUTES_HEADER); DWORD cbChecksumSize1 = 0; @@ -87,21 +87,21 @@ static DWORD CheckSizeOfAttributesFile(DWORD cbAttrFile, DWORD dwAttrFlags, DWOR // Get the expected size of CRC32 array if(dwAttrFlags & MPQ_ATTRIBUTE_CRC32) { - cbChecksumSize1 += dwFileTableSize * sizeof(DWORD); + cbChecksumSize1 += dwBlockTableSize * sizeof(DWORD); cbChecksumSize2 += cbChecksumSize1 - sizeof(DWORD); } // Get the expected size of FILETIME array if(dwAttrFlags & MPQ_ATTRIBUTE_FILETIME) { - cbFileTimeSize1 += dwFileTableSize * sizeof(ULONGLONG); + cbFileTimeSize1 += dwBlockTableSize * sizeof(ULONGLONG); cbFileTimeSize2 += cbFileTimeSize1 - sizeof(ULONGLONG); } // Get the expected size of MD5 array if(dwAttrFlags & MPQ_ATTRIBUTE_MD5) { - cbFileHashSize1 += dwFileTableSize * MD5_DIGEST_SIZE; + cbFileHashSize1 += dwBlockTableSize * MD5_DIGEST_SIZE; cbFileHashSize2 += cbFileHashSize1 - MD5_DIGEST_SIZE; } @@ -109,26 +109,26 @@ static DWORD CheckSizeOfAttributesFile(DWORD cbAttrFile, DWORD dwAttrFlags, DWOR if(dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT) { cbPatchBitSize1 = - cbPatchBitSize2 = ((dwFileTableSize + 6) / 8); - cbPatchBitSize3 = dwFileTableSize * sizeof(DWORD); + cbPatchBitSize2 = ((dwBlockTableSize + 6) / 8); + cbPatchBitSize3 = dwBlockTableSize * sizeof(DWORD); } // Check if the (attributes) file entry count is equal to our file table size if(cbAttrFile == (cbHeaderSize + cbChecksumSize1 + cbFileTimeSize1 + cbFileHashSize1 + cbPatchBitSize1)) - return dwFileTableSize; + return dwBlockTableSize; // Check if the (attributes) file entry count is equal to our file table size minus one if(cbAttrFile == (cbHeaderSize + cbChecksumSize2 + cbFileTimeSize2 + cbFileHashSize2 + cbPatchBitSize2)) - return dwFileTableSize - 1; + return dwBlockTableSize - 1; // Zenith.SC2MAP has the MPQ_ATTRIBUTE_PATCH_BIT set, but the bit array is missing if(cbAttrFile == (cbHeaderSize + cbChecksumSize1 + cbFileTimeSize1 + cbFileHashSize1)) - return dwFileTableSize; + return dwBlockTableSize; // interface.MPQ.part (WoW build 10958) has the MPQ_ATTRIBUTE_PATCH_BIT set // but there's an array of DWORDs (filled with zeros) instead of array of bits if(cbAttrFile == (cbHeaderSize + cbChecksumSize1 + cbFileTimeSize1 + cbFileHashSize1 + cbPatchBitSize3)) - return dwFileTableSize; + return dwBlockTableSize; #ifdef __STORMLIB_TEST__ // Invalid size of the (attributes) file @@ -246,12 +246,11 @@ static int LoadAttributesFile(TMPQArchive * ha, LPBYTE pbAttrFile, DWORD cbAttrF static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile) { PMPQ_ATTRIBUTES_HEADER pAttrHeader; - TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFileTableEnd = ha->pFileTable + ha->pHeader->dwBlockTableSize; TFileEntry * pFileEntry; LPBYTE pbAttrFile; LPBYTE pbAttrPtr; size_t cbAttrFile; - DWORD dwFinalEntries = ha->dwFileTableSize + ha->dwReservedFiles; // Check if we need patch bits in the (attributes) file for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) @@ -265,7 +264,7 @@ static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile) // Allocate the buffer for holding the entire (attributes) // Allocate 1 byte more (See GetSizeOfAttributesFile for more info) - cbAttrFile = GetSizeOfAttributesFile(ha->dwAttrFlags, dwFinalEntries); + cbAttrFile = GetSizeOfAttributesFile(ha->dwAttrFlags, ha->pHeader->dwBlockTableSize); pbAttrFile = pbAttrPtr = STORM_ALLOC(BYTE, cbAttrFile + 1); if(pbAttrFile != NULL) { @@ -287,8 +286,8 @@ static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile) for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) *pArrayCRC32++ = BSWAP_INT32_UNSIGNED(pFileEntry->dwCrc32); - // Skip the reserved entries - pbAttrPtr = (LPBYTE)(pArrayCRC32 + ha->dwReservedFiles); + // Update pointer + pbAttrPtr = (LPBYTE)pArrayCRC32; } // Write the array of file time @@ -300,8 +299,8 @@ static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile) for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) *pArrayFileTime++ = BSWAP_INT64_UNSIGNED(pFileEntry->FileTime); - // Skip the reserved entries - pbAttrPtr = (LPBYTE)(pArrayFileTime + ha->dwReservedFiles); + // Update pointer + pbAttrPtr = (LPBYTE)pArrayFileTime; } // Write the array of MD5s @@ -316,8 +315,8 @@ static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile) pbArrayMD5 += MD5_DIGEST_SIZE; } - // Skip the reserved items - pbAttrPtr = pbArrayMD5 + (ha->dwReservedFiles * MD5_DIGEST_SIZE); + // Update pointer + pbAttrPtr = pbArrayMD5; } // Write the array of patch bits @@ -339,12 +338,8 @@ static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile) dwBitMask = (dwBitMask << 0x07) | (dwBitMask >> 0x01); } - // Having incremented the bit array just by the number of items in the file table - // will create the bit array one byte less of the number of files is a multiplier of 8). - // Blizzard MPQs have the same feature. - // Move past the bit array - pbAttrPtr = (pbBitArray + dwByteIndex) + ((dwBitMask & 0x7F) ? 1 : 0); + pbAttrPtr += (ha->pHeader->dwBlockTableSize + 6) / 8; } // Now we expect that current position matches the estimated size @@ -419,7 +414,7 @@ int SAttrFileSaveToMpq(TMPQArchive * ha) if(ha->dwFileFlags2 != 0) { // At this point, we expect to have at least one reserved entry in the file table - assert(ha->dwFlags & MPQ_FLAG_ATTRIBUTES_INVALID); + assert(ha->dwFlags & MPQ_FLAG_ATTRIBUTES_NEW); assert(ha->dwReservedFiles > 0); // Create the raw data that is to be written to (attributes) @@ -451,6 +446,10 @@ int SAttrFileSaveToMpq(TMPQArchive * ha) SFileAddFile_Finish(hf); } + // Clear the number of reserved files + ha->dwFlags &= ~(MPQ_FLAG_ATTRIBUTES_NEW | MPQ_FLAG_ATTRIBUTES_NONE); + ha->dwReservedFiles--; + // Free the attributes buffer STORM_FREE(pbAttrFile); } @@ -459,10 +458,6 @@ int SAttrFileSaveToMpq(TMPQArchive * ha) // If the (attributes) file would be empty, its OK nError = (cbAttrFile == 0) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY; } - - // Clear the number of reserved files - ha->dwFlags &= ~MPQ_FLAG_ATTRIBUTES_INVALID; - ha->dwReservedFiles--; } return nError; |