From 809005c7f025bcc55bfa4ede78cb4cc45d3c0e6c Mon Sep 17 00:00:00 2001 From: Ladislav Zezula Date: Sat, 21 Nov 2020 04:27:09 +0100 Subject: * Release 9.23 * Fixed regressions * Fixed test program --- CMakeLists.txt | 6 +- StormLib_vs08_test.vcproj | 2 +- StormLib_vs19_test.vcxproj | 2 +- src/SBaseDumpData.cpp | 50 +- src/SBaseFileTable.cpp | 6 +- src/SFileAddFile.cpp | 20 +- src/SFileFindFile.cpp | 2 + src/SFileGetFileInfo.cpp | 887 ++++++++++------------------------- src/SFileListFile.cpp | 8 +- src/SFileOpenArchive.cpp | 2 +- src/SFileReadFile.cpp | 2 +- src/StormLib.h | 4 +- src/huffman/huff.cpp | 61 ++- src/huffman/huff.h | 2 +- test/StormTest.cpp | 1108 +++++++++++++++++--------------------------- test/TLogHelper.cpp | 30 +- 16 files changed, 761 insertions(+), 1431 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d9ec5a..bd8d336 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -367,8 +367,8 @@ if (NOT STORM_SKIP_INSTALL) endif() if(STORM_BUILD_TESTS) - add_executable(storm_test ${TEST_SRC_FILES}) - target_link_libraries(storm_test ${LIBRARY_NAME}) - install(TARGETS storm_test RUNTIME DESTINATION bin) + add_executable(StormLib_test ${TEST_SRC_FILES}) + target_link_libraries(StormLib_test ${LIBRARY_NAME}) + install(TARGETS StormLib_test RUNTIME DESTINATION bin) endif() diff --git a/StormLib_vs08_test.vcproj b/StormLib_vs08_test.vcproj index 7e9e485..2f03a0b 100644 --- a/StormLib_vs08_test.vcproj +++ b/StormLib_vs08_test.vcproj @@ -50,7 +50,7 @@ Disabled - WIN32;_DEBUG;_CONSOLE;__STORMLIB_TEST__;__STORMLIB_DUMP_DATA__;%(PreprocessorDefinitions) + WIN32;_DEBUG;_CONSOLE;__STORMLIB_TEST__;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug diff --git a/src/SBaseDumpData.cpp b/src/SBaseDumpData.cpp index 334561b..2454f22 100644 --- a/src/SBaseDumpData.cpp +++ b/src/SBaseDumpData.cpp @@ -111,39 +111,33 @@ void DumpHetAndBetTable(TMPQHetTable * pHetTable, TMPQBetTable * pBetTable) DWORD dwFlags = 0; DWORD dwBetIndex = 0; - GetBits(pHetTable->pBetIndexes, i * pHetTable->dwIndexSizeTotal, - pHetTable->dwIndexSize, - &dwBetIndex, - 4); + GetMPQBits(pHetTable->pBetIndexes, i * pHetTable->dwIndexSizeTotal, + pHetTable->dwIndexSize, + &dwBetIndex, 4); if(dwBetIndex < pHetTable->dwTotalCount) { DWORD dwEntryIndex = pBetTable->dwTableEntrySize * dwBetIndex; - GetBits(pBetTable->pNameHashes, dwBetIndex * pBetTable->dwBitTotal_NameHash2, - pBetTable->dwBitCount_NameHash2, - &BetHash, - 8); - - GetBits(pBetTable->pFileTable, dwEntryIndex + pBetTable->dwBitIndex_FilePos, - pBetTable->dwBitCount_FilePos, - &ByteOffset, - 8); - - GetBits(pBetTable->pFileTable, dwEntryIndex + pBetTable->dwBitIndex_FileSize, - pBetTable->dwBitCount_FileSize, - &dwFileSize, - 4); - - GetBits(pBetTable->pFileTable, dwEntryIndex + pBetTable->dwBitIndex_CmpSize, - pBetTable->dwBitCount_CmpSize, - &dwCmpSize, - 4); - - GetBits(pBetTable->pFileTable, dwEntryIndex + pBetTable->dwBitIndex_FlagIndex, - pBetTable->dwBitCount_FlagIndex, - &dwFlagIndex, - 4); + GetMPQBits(pBetTable->pNameHashes, dwBetIndex * pBetTable->dwBitTotal_NameHash2, + pBetTable->dwBitCount_NameHash2, + &BetHash, 8); + + GetMPQBits(pBetTable->pFileTable, dwEntryIndex + pBetTable->dwBitIndex_FilePos, + pBetTable->dwBitCount_FilePos, + &ByteOffset, 8); + + GetMPQBits(pBetTable->pFileTable, dwEntryIndex + pBetTable->dwBitIndex_FileSize, + pBetTable->dwBitCount_FileSize, + &dwFileSize, 4); + + GetMPQBits(pBetTable->pFileTable, dwEntryIndex + pBetTable->dwBitIndex_CmpSize, + pBetTable->dwBitCount_CmpSize, + &dwCmpSize, 4); + + GetMPQBits(pBetTable->pFileTable, dwEntryIndex + pBetTable->dwBitIndex_FlagIndex, + pBetTable->dwBitCount_FlagIndex, + &dwFlagIndex, 4); dwFlags = pBetTable->pFileFlags[dwFlagIndex]; } diff --git a/src/SBaseFileTable.cpp b/src/SBaseFileTable.cpp index af8d290..7fe1042 100644 --- a/src/SBaseFileTable.cpp +++ b/src/SBaseFileTable.cpp @@ -432,9 +432,9 @@ int ConvertMpqHeaderToFormat4( // If version 1.0 is forced, then the format version is forced to be 1.0 // Reason: Storm.dll in Warcraft III ignores format version value - if((dwFlags & MPQ_OPEN_FORCE_MPQ_V1) || (MapType == MapTypeWarcraft3)) + if((MapType == MapTypeWarcraft3) || (dwFlags & MPQ_OPEN_FORCE_MPQ_V1)) wFormatVersion = MPQ_FORMAT_VERSION_1; - if(MapType == MapTypeStarcraft2) + if((MapType == MapTypeStarcraft2) && (pHeader->wFormatVersion > MPQ_FORMAT_VERSION_4)) wFormatVersion = MPQ_FORMAT_VERSION_4; // Format-specific fixes @@ -647,7 +647,7 @@ int ConvertMpqHeaderToFormat4( return ERROR_FAKE_MPQ_HEADER; // Check for malformed MPQs - if(pHeader->wFormatVersion != MPQ_FORMAT_VERSION_4 || (ha->MpqPos + pHeader->ArchiveSize64) != FileSize || (ha->MpqPos + pHeader->HiBlockTablePos64) >= FileSize) + if(pHeader->wFormatVersion != MPQ_FORMAT_VERSION_4 || (MpqOffset + pHeader->ArchiveSize64) != FileSize || (MpqOffset + pHeader->HiBlockTablePos64) >= FileSize) { pHeader->wFormatVersion = MPQ_FORMAT_VERSION_4; pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V4; diff --git a/src/SFileAddFile.cpp b/src/SFileAddFile.cpp index 7dd583f..e756781 100644 --- a/src/SFileAddFile.cpp +++ b/src/SFileAddFile.cpp @@ -236,7 +236,7 @@ static int WriteDataToMpqFile( // We have to calculate sector CRC, if enabled if(hf->SectorChksums != NULL) hf->SectorChksums[dwSectorIndex] = adler32(0, pbCompressed, nOutBuffer); - } + } // Encrypt the sector, if necessary if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) @@ -592,7 +592,7 @@ int SFileAddFile_Write(TMPQFile * hf, const void * pvData, DWORD dwSize, DWORD d if(hf->pPatchInfo == NULL && IsIncrementalPatchFile(pvData, dwSize, &hf->dwPatchedFileSize)) { // Set the MPQ_FILE_PATCH_FILE flag - hf->pFileEntry->dwFlags |= MPQ_FILE_PATCH_FILE; + pFileEntry->dwFlags |= MPQ_FILE_PATCH_FILE; // Allocate the patch info hf->nAddFileError = nError = AllocatePatchInfo(hf, false); @@ -659,10 +659,10 @@ int SFileAddFile_Write(TMPQFile * hf, const void * pvData, DWORD dwSize, DWORD d if(hf->dwFilePos >= pFileEntry->dwFileSize) { // Finish calculating CRC32 - hf->pFileEntry->dwCrc32 = hf->dwCrc32; + pFileEntry->dwCrc32 = hf->dwCrc32; // Finish calculating MD5 - md5_done((hash_state *)hf->hctx, hf->pFileEntry->md5); + md5_done((hash_state *)hf->hctx, pFileEntry->md5); // If we also have sector checksums, write them to the file if(hf->SectorChksums != NULL) @@ -673,9 +673,9 @@ int SFileAddFile_Write(TMPQFile * hf, const void * pvData, DWORD dwSize, DWORD d // Now write patch info if(hf->pPatchInfo != NULL) { - memcpy(hf->pPatchInfo->md5, hf->pFileEntry->md5, MD5_DIGEST_SIZE); - hf->pPatchInfo->dwDataSize = hf->pFileEntry->dwFileSize; - hf->pFileEntry->dwFileSize = hf->dwPatchedFileSize; + memcpy(hf->pPatchInfo->md5, pFileEntry->md5, MD5_DIGEST_SIZE); + hf->pPatchInfo->dwDataSize = pFileEntry->dwFileSize; + pFileEntry->dwFileSize = hf->dwPatchedFileSize; nError = WritePatchInfo(hf); } @@ -689,13 +689,17 @@ int SFileAddFile_Write(TMPQFile * hf, const void * pvData, DWORD dwSize, DWORD d if(ha->pHeader->dwRawChunkSize != 0) { nError = WriteMpqDataMD5(ha->pStream, - ha->MpqPos + hf->pFileEntry->ByteOffset, + ha->MpqPos + pFileEntry->ByteOffset, hf->pFileEntry->dwCmpSize, ha->pHeader->dwRawChunkSize); } } } + // Update the archive size + if((ha->MpqPos + pFileEntry->ByteOffset + pFileEntry->dwCmpSize) > ha->FileSize) + ha->FileSize = ha->MpqPos + pFileEntry->ByteOffset + pFileEntry->dwCmpSize; + // Store the error code from the Write File operation hf->nAddFileError = nError; return nError; diff --git a/src/SFileFindFile.cpp b/src/SFileFindFile.cpp index 7e8502b..6a4cecd 100644 --- a/src/SFileFindFile.cpp +++ b/src/SFileFindFile.cpp @@ -238,6 +238,8 @@ static bool DoMPQSearch_FileEntry( // Prepare the block index dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable); + if(dwBlockIndex == 569) + szNameBuff[0] = 'F'; // Get the file name. If it's not known, we will create pseudo-name szFileName = pFileEntry->szFileName; diff --git a/src/SFileGetFileInfo.cpp b/src/SFileGetFileInfo.cpp index c57b3b7..4ec05e2 100644 --- a/src/SFileGetFileInfo.cpp +++ b/src/SFileGetFileInfo.cpp @@ -12,36 +12,9 @@ #include "StormLib.h" #include "StormCommon.h" -//----------------------------------------------------------------------------- -// Local defines - -// Information types for SFileGetFileInfo -#define SFILE_INFO_TYPE_INVALID_HANDLE 0 -#define SFILE_INFO_TYPE_NOT_FOUND 1 -#define SFILE_INFO_TYPE_DIRECT_POINTER 2 -#define SFILE_INFO_TYPE_ALLOCATED 3 -#define SFILE_INFO_TYPE_READ_FROM_FILE 4 -#define SFILE_INFO_TYPE_TABLE_POINTER 5 -#define SFILE_INFO_TYPE_FILE_ENTRY 6 - //----------------------------------------------------------------------------- // Local functions -static void ConvertFileEntryToSelfRelative(TFileEntry * pFileEntry, TFileEntry * pSrcFileEntry) -{ - // Copy the file entry itself - memcpy(pFileEntry, pSrcFileEntry, sizeof(TFileEntry)); - - // If source is NULL, leave it NULL - if(pSrcFileEntry->szFileName != NULL) - { - // Set the file name pointer after the file entry - pFileEntry->szFileName = (char *)(pFileEntry + 1); - strcpy(pFileEntry->szFileName, pSrcFileEntry->szFileName); - } -} - - static DWORD GetMpqFileCount(TMPQArchive * ha) { TFileEntry * pFileTableEnd; @@ -69,56 +42,138 @@ static DWORD GetMpqFileCount(TMPQArchive * ha) return dwFileCount; } -static bool GetFilePatchChain(TMPQFile * hf, void * pvFileInfo, DWORD cbFileInfo, DWORD * pcbLengthNeeded) +static bool GetInfo_ReturnError(DWORD dwErrCode) +{ + SetLastError(dwErrCode); + return false; +} + +static bool GetInfo_BufferCheck(void * pvFileInfo, DWORD cbFileInfo, DWORD cbData, LPDWORD pcbLengthNeeded) +{ + // Give the length needed to store the info + if(pcbLengthNeeded != NULL) + pcbLengthNeeded[0] = cbData; + + // Check for sufficient buffer + if(cbData > cbFileInfo) + return GetInfo_ReturnError(ERROR_INSUFFICIENT_BUFFER); + + // If the buffer size is sufficient, check for valid user buffer + if(pvFileInfo == NULL) + return GetInfo_ReturnError(ERROR_INVALID_PARAMETER); + + // Buffers and sizes are OK, we are ready to proceed file copying + return true; +} + +static bool GetInfo(void * pvFileInfo, DWORD cbFileInfo, const void * pvData, DWORD cbData, LPDWORD pcbLengthNeeded) +{ + // Verify buffer pointer and buffer size + if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, cbData, pcbLengthNeeded)) + return false; + + // Copy the data to the caller-supplied buffer + memcpy(pvFileInfo, pvData, cbData); + return true; +} + +static bool GetInfo_Allocated(void * pvFileInfo, DWORD cbFileInfo, void * pvData, DWORD cbData, LPDWORD pcbLengthNeeded) +{ + bool bResult; + + // Verify buffer pointer and buffer size + if((bResult = GetInfo_BufferCheck(pvFileInfo, cbFileInfo, cbData, pcbLengthNeeded)) != false) + memcpy(pvFileInfo, pvData, cbData); + + // Copy the data to the user buffer + STORM_FREE(pvData); + return bResult; +} + +static bool GetInfo_TablePointer(void * pvFileInfo, DWORD cbFileInfo, void * pvTablePointer, SFileInfoClass InfoClass, LPDWORD pcbLengthNeeded) +{ + // Verify buffer pointer and buffer size + if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, sizeof(void *), pcbLengthNeeded)) + { + SFileFreeFileInfo(pvTablePointer, InfoClass); + return false; + } + + // The user buffer receives pointer to the table. + // When done, the caller needs to call SFileFreeFileInfo on it + *(void **)pvFileInfo = pvTablePointer; + return true; +} + +static bool GetInfo_ReadFromFile(void * pvFileInfo, DWORD cbFileInfo, TFileStream * pStream, ULONGLONG ByteOffset, DWORD cbData, LPDWORD pcbLengthNeeded) +{ + // Verify buffer pointer and buffer size + if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, cbData, pcbLengthNeeded)) + return false; + + return FileStream_Read(pStream, &ByteOffset, pvFileInfo, cbData); +} + +static bool GetInfo_FileEntry(void * pvFileInfo, DWORD cbFileInfo, TFileEntry * pFileEntry, LPDWORD pcbLengthNeeded) +{ + LPBYTE pbFileInfo = (LPBYTE)pvFileInfo; + DWORD cbSrcFileInfo = sizeof(TFileEntry); + DWORD cbFileName = 1; + + // The file name belongs to the file entry + if(pFileEntry->szFileName) + cbFileName = (DWORD)strlen(pFileEntry->szFileName) + 1; + cbSrcFileInfo += cbFileName; + + // Verify buffer pointer and buffer size + if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, cbSrcFileInfo, pcbLengthNeeded)) + return false; + + // Copy the file entry + memcpy(pbFileInfo, pFileEntry, sizeof(TFileEntry)); + pbFileInfo += sizeof(TFileEntry); + pbFileInfo[0] = 0; + + // Copy the file name + if(pFileEntry->szFileName) + memcpy(pbFileInfo, pFileEntry->szFileName, cbFileName); + return true; +} + +static bool GetInfo_PatchChain(TMPQFile * hf, void * pvFileInfo, DWORD cbFileInfo, LPDWORD pcbLengthNeeded) { TMPQFile * hfTemp; - TCHAR * szFileInfo = (TCHAR *)pvFileInfo; + LPCTSTR szPatchName; + LPTSTR szFileInfo = (LPTSTR)pvFileInfo; size_t cchCharsNeeded = 1; - size_t cchFileInfo = (cbFileInfo / sizeof(TCHAR)); size_t nLength; - // Patch chain is only supported on MPQ files. + // Patch chain is only supported on MPQ files. Local files are not supported. if(hf->pStream != NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - return false; - } + return GetInfo_ReturnError(ERROR_INVALID_PARAMETER); // Calculate the necessary length of the multi-string for(hfTemp = hf; hfTemp != NULL; hfTemp = hfTemp->hfPatch) cchCharsNeeded += _tcslen(FileStream_GetFileName(hfTemp->ha->pStream)) + 1; - // Give the caller the needed length - if(pcbLengthNeeded != NULL) - pcbLengthNeeded[0] = (DWORD)(cchCharsNeeded * sizeof(TCHAR)); + // Verify whether the caller gave us valid buffer with enough size + if(!GetInfo_BufferCheck(pvFileInfo, cbFileInfo, (DWORD)(cchCharsNeeded * sizeof(TCHAR)), pcbLengthNeeded)) + return false; - // If the caller gave both buffer pointer and data length, - // try to copy the patch chain - if(szFileInfo != NULL && cchFileInfo != 0) + // Copy each patch name + for(hfTemp = hf; hfTemp != NULL; hfTemp = hfTemp->hfPatch) { - // If there is enough space in the buffer, copy the patch chain - if(cchCharsNeeded > cchFileInfo) - { - SetLastError(ERROR_INSUFFICIENT_BUFFER); - return false; - } + // Get the file name and its length + szPatchName = FileStream_GetFileName(hfTemp->ha->pStream); + nLength = _tcslen(szPatchName) + 1; - // Copy each patch - for(hfTemp = hf; hfTemp != NULL; hfTemp = hfTemp->hfPatch) - { - // Get the file name and its length - const TCHAR * szFileName = FileStream_GetFileName(hfTemp->ha->pStream); - nLength = _tcslen(szFileName) + 1; - - // Copy the file name - memcpy(szFileInfo, szFileName, nLength * sizeof(TCHAR)); - szFileInfo += nLength; - } - - // Make it multi-string - szFileInfo[0] = 0; + // Copy the file name + memcpy(szFileInfo, szPatchName, nLength * sizeof(TCHAR)); + szFileInfo += nLength; } + // Make it multi-string + szFileInfo[0] = 0; return true; } @@ -139,719 +194,253 @@ bool WINAPI SFileGetFileInfo( LPDWORD pcbLengthNeeded) { MPQ_SIGNATURE_INFO SignatureInfo; + const TCHAR * szSrcFileInfo; TMPQArchive * ha = NULL; TFileEntry * pFileEntry = NULL; + TMPQHeader * pHeader = NULL; ULONGLONG Int64Value = 0; - ULONGLONG ByteOffset = 0; TMPQFile * hf = NULL; void * pvSrcFileInfo = NULL; DWORD cbSrcFileInfo = 0; DWORD dwInt32Value = 0; - int nInfoType = SFILE_INFO_TYPE_INVALID_HANDLE; - int nError = ERROR_SUCCESS; + // Validate archive/file handle + if((int)InfoClass <= (int)SFileMpqFlags) + { + if((ha = IsValidMpqHandle(hMpqOrFile)) == NULL) + return GetInfo_ReturnError(ERROR_INVALID_HANDLE); + pHeader = ha->pHeader; + } + else + { + if((hf = IsValidFileHandle(hMpqOrFile)) == NULL) + return GetInfo_ReturnError(ERROR_INVALID_HANDLE); + pFileEntry = hf->pFileEntry; + } + + // Return info-class-specific data switch(InfoClass) { case SFileMpqFileName: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = (void *)FileStream_GetFileName(ha->pStream); - cbSrcFileInfo = (DWORD)(_tcslen((TCHAR *)pvSrcFileInfo) + 1) * sizeof(TCHAR); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + szSrcFileInfo = FileStream_GetFileName(ha->pStream); + cbSrcFileInfo = (DWORD)((_tcslen(szSrcFileInfo) + 1) * sizeof(TCHAR)); + return GetInfo(pvFileInfo, cbFileInfo, szSrcFileInfo, cbSrcFileInfo, pcbLengthNeeded); case SFileMpqStreamBitmap: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - return FileStream_GetBitmap(ha->pStream, pvFileInfo, cbFileInfo, pcbLengthNeeded); - break; + return FileStream_GetBitmap(ha->pStream, pvFileInfo, cbFileInfo, pcbLengthNeeded); case SFileMpqUserDataOffset: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - nInfoType = SFILE_INFO_TYPE_NOT_FOUND; - if(ha->pUserData != NULL) - { - pvSrcFileInfo = &ha->UserDataPos; - cbSrcFileInfo = sizeof(ULONGLONG); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &ha->UserDataPos, sizeof(ULONGLONG), pcbLengthNeeded); case SFileMpqUserDataHeader: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - nInfoType = SFILE_INFO_TYPE_NOT_FOUND; - if(ha->pUserData != NULL) - { - ByteOffset = ha->UserDataPos; - cbSrcFileInfo = sizeof(TMPQUserData); - nInfoType = SFILE_INFO_TYPE_READ_FROM_FILE; - } - } - break; + return GetInfo_ReadFromFile(pvFileInfo, cbFileInfo, ha->pStream, ha->UserDataPos, sizeof(TMPQUserData), pcbLengthNeeded); case SFileMpqUserData: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - nInfoType = SFILE_INFO_TYPE_NOT_FOUND; - if(ha->pUserData != NULL) - { - ByteOffset = ha->UserDataPos + sizeof(TMPQUserData); - cbSrcFileInfo = ha->pUserData->dwHeaderOffs - sizeof(TMPQUserData); - nInfoType = SFILE_INFO_TYPE_READ_FROM_FILE; - } - } - break; + return GetInfo_ReadFromFile(pvFileInfo, cbFileInfo, ha->pStream, ha->UserDataPos + sizeof(TMPQUserData), ha->pUserData->dwHeaderOffs - sizeof(TMPQUserData), pcbLengthNeeded); case SFileMpqHeaderOffset: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->MpqPos; - cbSrcFileInfo = sizeof(ULONGLONG); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &ha->MpqPos, sizeof(ULONGLONG), pcbLengthNeeded); case SFileMpqHeaderSize: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->pHeader->dwHeaderSize; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->dwHeaderSize, sizeof(DWORD), pcbLengthNeeded); case SFileMpqHeader: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - ByteOffset = ha->MpqPos; - cbSrcFileInfo = ha->pHeader->dwHeaderSize; - nInfoType = SFILE_INFO_TYPE_READ_FROM_FILE; - } - break; + return GetInfo_ReadFromFile(pvFileInfo, cbFileInfo, ha->pStream, ha->MpqPos, pHeader->dwHeaderSize, pcbLengthNeeded); case SFileMpqHetTableOffset: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->pHeader->HetTablePos64; - cbSrcFileInfo = sizeof(ULONGLONG); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->HetTablePos64, sizeof(ULONGLONG), pcbLengthNeeded); case SFileMpqHetTableSize: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->pHeader->HetTableSize64; - cbSrcFileInfo = sizeof(ULONGLONG); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->HetTableSize64, sizeof(ULONGLONG), pcbLengthNeeded); case SFileMpqHetHeader: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - nInfoType = SFILE_INFO_TYPE_NOT_FOUND; - pvSrcFileInfo = LoadExtTable(ha, ha->pHeader->HetTablePos64, (size_t)ha->pHeader->HetTableSize64, HET_TABLE_SIGNATURE, MPQ_KEY_HASH_TABLE); - if(pvSrcFileInfo != NULL) - { - cbSrcFileInfo = sizeof(TMPQHetHeader); - nInfoType = SFILE_INFO_TYPE_ALLOCATED; - } - } - break; + pvSrcFileInfo = LoadExtTable(ha, pHeader->HetTablePos64, (size_t)pHeader->HetTableSize64, HET_TABLE_SIGNATURE, MPQ_KEY_HASH_TABLE); + if(pvSrcFileInfo == NULL) + return GetInfo_ReturnError(ERROR_FILE_NOT_FOUND); + return GetInfo_Allocated(pvFileInfo, cbFileInfo, pvSrcFileInfo, sizeof(TMPQHetHeader), pcbLengthNeeded); case SFileMpqHetTable: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - nInfoType = SFILE_INFO_TYPE_NOT_FOUND; - pvSrcFileInfo = LoadHetTable(ha); - if(pvSrcFileInfo != NULL) - { - cbSrcFileInfo = sizeof(void *); - nInfoType = SFILE_INFO_TYPE_TABLE_POINTER; - } - } - break; + if((pvSrcFileInfo = LoadHetTable(ha)) == NULL) + return GetInfo_ReturnError(ERROR_NOT_ENOUGH_MEMORY); + return GetInfo_TablePointer(pvFileInfo, cbFileInfo, pvSrcFileInfo, InfoClass, pcbLengthNeeded); case SFileMpqBetTableOffset: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->pHeader->BetTablePos64; - cbSrcFileInfo = sizeof(ULONGLONG); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->BetTablePos64, sizeof(ULONGLONG), pcbLengthNeeded); case SFileMpqBetTableSize: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->pHeader->BetTableSize64; - cbSrcFileInfo = sizeof(ULONGLONG); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->BetTableSize64, sizeof(ULONGLONG), pcbLengthNeeded); case SFileMpqBetHeader: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - nInfoType = SFILE_INFO_TYPE_NOT_FOUND; - pvSrcFileInfo = LoadExtTable(ha, ha->pHeader->BetTablePos64, (size_t)ha->pHeader->BetTableSize64, BET_TABLE_SIGNATURE, MPQ_KEY_BLOCK_TABLE); - if(pvSrcFileInfo != NULL) - { - // It is allowed for the caller to only require BET header. - cbSrcFileInfo = sizeof(TMPQBetHeader) + ((TMPQBetHeader *)pvSrcFileInfo)->dwFlagCount * sizeof(DWORD); - if(cbFileInfo == sizeof(TMPQBetHeader)) - cbSrcFileInfo = sizeof(TMPQBetHeader); - nInfoType = SFILE_INFO_TYPE_ALLOCATED; - } - } - break; + + // Retrieve the table and its size + pvSrcFileInfo = LoadExtTable(ha, pHeader->BetTablePos64, (size_t)pHeader->BetTableSize64, BET_TABLE_SIGNATURE, MPQ_KEY_BLOCK_TABLE); + if(pvSrcFileInfo == NULL) + return GetInfo_ReturnError(ERROR_FILE_NOT_FOUND); + cbSrcFileInfo = sizeof(TMPQBetHeader) + ((TMPQBetHeader *)pvSrcFileInfo)->dwFlagCount * sizeof(DWORD); + + // It is allowed for the caller to only require BET header + if(cbFileInfo == sizeof(TMPQBetHeader)) + cbSrcFileInfo = sizeof(TMPQBetHeader); + return GetInfo_Allocated(pvFileInfo, cbFileInfo, pvSrcFileInfo, cbSrcFileInfo, pcbLengthNeeded); case SFileMpqBetTable: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - nInfoType = SFILE_INFO_TYPE_NOT_FOUND; - pvSrcFileInfo = LoadBetTable(ha); - if(pvSrcFileInfo != NULL) - { - cbSrcFileInfo = sizeof(void *); - nInfoType = SFILE_INFO_TYPE_TABLE_POINTER; - } - } - break; + if((pvSrcFileInfo = LoadBetTable(ha)) == NULL) + return GetInfo_ReturnError(ERROR_NOT_ENOUGH_MEMORY); + return GetInfo_TablePointer(pvFileInfo, cbFileInfo, pvSrcFileInfo, InfoClass, pcbLengthNeeded); case SFileMpqHashTableOffset: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - Int64Value = MAKE_OFFSET64(ha->pHeader->wHashTablePosHi, ha->pHeader->dwHashTablePos); - pvSrcFileInfo = &Int64Value; - cbSrcFileInfo = sizeof(ULONGLONG); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + Int64Value = MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos); + return GetInfo(pvFileInfo, cbFileInfo, &Int64Value, sizeof(ULONGLONG), pcbLengthNeeded); case SFileMpqHashTableSize64: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->pHeader->HashTableSize64; - cbSrcFileInfo = sizeof(ULONGLONG); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->HashTableSize64, sizeof(ULONGLONG), pcbLengthNeeded); case SFileMpqHashTableSize: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->pHeader->dwHashTableSize; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->dwHashTableSize, sizeof(DWORD), pcbLengthNeeded); case SFileMpqHashTable: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL && ha->pHashTable != NULL) - { - pvSrcFileInfo = ha->pHashTable; - cbSrcFileInfo = ha->pHeader->dwHashTableSize * sizeof(TMPQHash); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + cbSrcFileInfo = pHeader->dwHashTableSize * sizeof(TMPQHash); + return GetInfo(pvFileInfo, cbFileInfo, ha->pHashTable, cbSrcFileInfo, pcbLengthNeeded); case SFileMpqBlockTableOffset: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - Int64Value = MAKE_OFFSET64(ha->pHeader->wBlockTablePosHi, ha->pHeader->dwBlockTablePos); - pvSrcFileInfo = &Int64Value; - cbSrcFileInfo = sizeof(ULONGLONG); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + Int64Value = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos); + return GetInfo(pvFileInfo, cbFileInfo, &Int64Value, sizeof(ULONGLONG), pcbLengthNeeded); case SFileMpqBlockTableSize64: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->pHeader->BlockTableSize64; - cbSrcFileInfo = sizeof(ULONGLONG); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->BlockTableSize64, sizeof(ULONGLONG), pcbLengthNeeded); case SFileMpqBlockTableSize: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->pHeader->dwBlockTableSize; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->dwBlockTableSize, sizeof(DWORD), pcbLengthNeeded); case SFileMpqBlockTable: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - nInfoType = SFILE_INFO_TYPE_NOT_FOUND; - if(MAKE_OFFSET64(ha->pHeader->wBlockTablePosHi, ha->pHeader->dwBlockTablePos) < ha->FileSize) - { - cbSrcFileInfo = ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock); - if(cbFileInfo >= cbSrcFileInfo) - pvSrcFileInfo = LoadBlockTable(ha, true); - nInfoType = SFILE_INFO_TYPE_ALLOCATED; - } - } - break; + if(MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos) >= ha->FileSize) + return GetInfo_ReturnError(ERROR_FILE_NOT_FOUND); + cbSrcFileInfo = pHeader->dwBlockTableSize * sizeof(TMPQBlock); + pvSrcFileInfo = LoadBlockTable(ha, true); + return GetInfo_Allocated(pvFileInfo, cbFileInfo, pvSrcFileInfo, cbSrcFileInfo, pcbLengthNeeded); case SFileMpqHiBlockTableOffset: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->pHeader->HiBlockTablePos64; - cbSrcFileInfo = sizeof(ULONGLONG); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->HiBlockTablePos64, sizeof(ULONGLONG), pcbLengthNeeded); case SFileMpqHiBlockTableSize64: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->pHeader->HiBlockTableSize64; - cbSrcFileInfo = sizeof(ULONGLONG); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->HiBlockTableSize64, sizeof(ULONGLONG), pcbLengthNeeded); case SFileMpqHiBlockTable: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - nInfoType = SFILE_INFO_TYPE_NOT_FOUND; - if(ha->pHeader->HiBlockTablePos64 && ha->pHeader->HiBlockTableSize64) - { - assert(false); - } - } - break; + return GetInfo_ReturnError(ERROR_FILE_NOT_FOUND); case SFileMpqSignatures: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL && QueryMpqSignatureInfo(ha, &SignatureInfo)) - { - pvSrcFileInfo = &SignatureInfo.SignatureTypes; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + if(!QueryMpqSignatureInfo(ha, &SignatureInfo)) + return GetInfo_ReturnError(ERROR_FILE_NOT_FOUND); + return GetInfo(pvFileInfo, cbFileInfo, &SignatureInfo.SignatureTypes, sizeof(DWORD), pcbLengthNeeded); case SFileMpqStrongSignatureOffset: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - nInfoType = SFILE_INFO_TYPE_NOT_FOUND; - if(QueryMpqSignatureInfo(ha, &SignatureInfo) && (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG)) - { - pvSrcFileInfo = &SignatureInfo.EndMpqData; - cbSrcFileInfo = sizeof(ULONGLONG); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - } - break; + if(QueryMpqSignatureInfo(ha, &SignatureInfo) == false || (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG) == 0) + return GetInfo_ReturnError(ERROR_FILE_NOT_FOUND); + return GetInfo(pvFileInfo, cbFileInfo, &SignatureInfo.EndMpqData, sizeof(ULONGLONG), pcbLengthNeeded); case SFileMpqStrongSignatureSize: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - nInfoType = SFILE_INFO_TYPE_NOT_FOUND; - if(QueryMpqSignatureInfo(ha, &SignatureInfo) && (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG)) - { - dwInt32Value = MPQ_STRONG_SIGNATURE_SIZE + 4; - pvSrcFileInfo = &dwInt32Value; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - } - break; + if(QueryMpqSignatureInfo(ha, &SignatureInfo) == false || (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG) == 0) + return GetInfo_ReturnError(ERROR_FILE_NOT_FOUND); + dwInt32Value = MPQ_STRONG_SIGNATURE_SIZE + 4; + return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded); case SFileMpqStrongSignature: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - nInfoType = SFILE_INFO_TYPE_NOT_FOUND; - if(QueryMpqSignatureInfo(ha, &SignatureInfo) && (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG)) - { - pvSrcFileInfo = SignatureInfo.Signature; - cbSrcFileInfo = MPQ_STRONG_SIGNATURE_SIZE + 4; - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - } - break; + if(QueryMpqSignatureInfo(ha, &SignatureInfo) == false || (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG) == 0) + return GetInfo_ReturnError(ERROR_FILE_NOT_FOUND); + return GetInfo(pvFileInfo, cbFileInfo, SignatureInfo.Signature, MPQ_STRONG_SIGNATURE_SIZE + 4, pcbLengthNeeded); case SFileMpqArchiveSize64: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->pHeader->ArchiveSize64; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->ArchiveSize64, sizeof(ULONGLONG), pcbLengthNeeded); case SFileMpqArchiveSize: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->pHeader->dwArchiveSize; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->dwArchiveSize, sizeof(DWORD), pcbLengthNeeded); case SFileMpqMaxFileCount: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->dwMaxFileCount; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &ha->dwMaxFileCount, sizeof(DWORD), pcbLengthNeeded); case SFileMpqFileTableSize: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->dwFileTableSize; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &ha->dwFileTableSize, sizeof(DWORD), pcbLengthNeeded); case SFileMpqSectorSize: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &ha->dwSectorSize; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &ha->dwSectorSize, sizeof(DWORD), pcbLengthNeeded); case SFileMpqNumberOfFiles: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - pvSrcFileInfo = &dwInt32Value; - cbSrcFileInfo = sizeof(DWORD); - dwInt32Value = GetMpqFileCount(ha); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + dwInt32Value = GetMpqFileCount(ha); + return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded); case SFileMpqRawChunkSize: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - nInfoType = SFILE_INFO_TYPE_NOT_FOUND; - if(ha->pHeader->dwRawChunkSize != 0) - { - pvSrcFileInfo = &ha->pHeader->dwRawChunkSize; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - } - break; + if(pHeader->dwRawChunkSize == 0) + return GetInfo_ReturnError(ERROR_FILE_NOT_FOUND); + return GetInfo(pvFileInfo, cbFileInfo, &pHeader->dwRawChunkSize, sizeof(DWORD), pcbLengthNeeded); case SFileMpqStreamFlags: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - FileStream_GetFlags(ha->pStream, &dwInt32Value); - pvSrcFileInfo = &dwInt32Value; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + FileStream_GetFlags(ha->pStream, &dwInt32Value); + return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded); case SFileMpqFlags: - ha = IsValidMpqHandle(hMpqOrFile); - if(ha != NULL) - { - dwInt32Value = ha->dwFlags; - pvSrcFileInfo = &dwInt32Value; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &ha->dwFlags, sizeof(DWORD), pcbLengthNeeded); case SFileInfoPatchChain: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL) - return GetFilePatchChain(hf, pvFileInfo, cbFileInfo, pcbLengthNeeded); - break; + return GetInfo_PatchChain(hf, pvFileInfo, cbFileInfo, pcbLengthNeeded); case SFileInfoFileEntry: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL && hf->pFileEntry != NULL) - { - pvSrcFileInfo = pFileEntry = hf->pFileEntry; - cbSrcFileInfo = sizeof(TFileEntry); - if(pFileEntry->szFileName != NULL) - cbSrcFileInfo += (DWORD)strlen(pFileEntry->szFileName) + 1; - nInfoType = SFILE_INFO_TYPE_FILE_ENTRY; - } - break; + if(pFileEntry == NULL) + return GetInfo_ReturnError(ERROR_FILE_NOT_FOUND); + return GetInfo_FileEntry(pvFileInfo, cbFileInfo, pFileEntry, pcbLengthNeeded); case SFileInfoHashEntry: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL && hf->pHashEntry != NULL) - { - pvSrcFileInfo = hf->pHashEntry; - cbSrcFileInfo = sizeof(TMPQHash); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, hf->pHashEntry, sizeof(TMPQHash), pcbLengthNeeded); case SFileInfoHashIndex: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL && hf->pHashEntry != NULL) - { - pvSrcFileInfo = &hf->dwHashIndex; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &hf->dwHashIndex, sizeof(DWORD), pcbLengthNeeded); case SFileInfoNameHash1: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL && hf->pHashEntry != NULL) - { - dwInt32Value = hf->pHashEntry->dwName1; - pvSrcFileInfo = &dwInt32Value; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &hf->pHashEntry->dwName1, sizeof(DWORD), pcbLengthNeeded); case SFileInfoNameHash2: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL && hf->pHashEntry != NULL) - { - dwInt32Value = hf->pHashEntry->dwName2; - pvSrcFileInfo = &dwInt32Value; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &hf->pHashEntry->dwName2, sizeof(DWORD), pcbLengthNeeded); case SFileInfoNameHash3: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL && hf->pFileEntry != NULL) - { - pvSrcFileInfo = &hf->pFileEntry->FileNameHash; - cbSrcFileInfo = sizeof(ULONGLONG); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->FileNameHash, sizeof(ULONGLONG), pcbLengthNeeded); case SFileInfoLocale: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL && hf->pHashEntry != NULL) - { - dwInt32Value = hf->pHashEntry->lcLocale; - pvSrcFileInfo = &dwInt32Value; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + dwInt32Value = hf->pHashEntry->lcLocale; + return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded); case SFileInfoFileIndex: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL && hf->ha != NULL && hf->pFileEntry != NULL) - { - dwInt32Value = (DWORD)(hf->pFileEntry - hf->ha->pFileTable); - pvSrcFileInfo = &dwInt32Value; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + dwInt32Value = (DWORD)(pFileEntry - hf->ha->pFileTable); + return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded); case SFileInfoByteOffset: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL && hf->pFileEntry != NULL) - { - pvSrcFileInfo = &hf->pFileEntry->ByteOffset; - cbSrcFileInfo = sizeof(ULONGLONG); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->ByteOffset, sizeof(ULONGLONG), pcbLengthNeeded); case SFileInfoFileTime: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL && hf->pFileEntry != NULL) - { - pvSrcFileInfo = &hf->pFileEntry->FileTime; - cbSrcFileInfo = sizeof(ULONGLONG); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->FileTime, sizeof(ULONGLONG), pcbLengthNeeded); case SFileInfoFileSize: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL && hf->pFileEntry != NULL) - { - pvSrcFileInfo = &hf->pFileEntry->dwFileSize; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->dwFileSize, sizeof(DWORD), pcbLengthNeeded); case SFileInfoCompressedSize: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL && hf->pFileEntry != NULL) - { - pvSrcFileInfo = &hf->pFileEntry->dwCmpSize; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->dwCmpSize, sizeof(DWORD), pcbLengthNeeded); case SFileInfoFlags: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL && hf->pFileEntry != NULL) - { - pvSrcFileInfo = &hf->pFileEntry->dwFlags; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &pFileEntry->dwFlags, sizeof(DWORD), pcbLengthNeeded); case SFileInfoEncryptionKey: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL) - { - pvSrcFileInfo = &hf->dwFileKey; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + return GetInfo(pvFileInfo, cbFileInfo, &hf->dwFileKey, sizeof(DWORD), pcbLengthNeeded); case SFileInfoEncryptionKeyRaw: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL && hf->pFileEntry != NULL) - { - dwInt32Value = hf->dwFileKey; - if(hf->pFileEntry->dwFlags & MPQ_FILE_FIX_KEY) - dwInt32Value = (dwInt32Value ^ hf->pFileEntry->dwFileSize) - (DWORD)hf->MpqFilePos; - pvSrcFileInfo = &dwInt32Value; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; + dwInt32Value = hf->dwFileKey; + if(pFileEntry->dwFlags & MPQ_FILE_FIX_KEY) + dwInt32Value = (dwInt32Value ^ pFileEntry->dwFileSize) - (DWORD)hf->MpqFilePos; + return GetInfo(pvFileInfo, cbFileInfo, &dwInt32Value, sizeof(DWORD), pcbLengthNeeded); case SFileInfoCRC32: - hf = IsValidFileHandle(hMpqOrFile); - if(hf != NULL && hf->pFileEntry != NULL) - { - dwInt32Value = hf->pFileEntry->dwCrc32; - pvSrcFileInfo = &dwInt32Value; - cbSrcFileInfo = sizeof(DWORD); - nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; - } - break; - - default: // Invalid info class - SetLastError(ERROR_INVALID_PARAMETER); - return false; - } - - // If we validated the handle and info class, give as much info as possible - if(nInfoType >= SFILE_INFO_TYPE_DIRECT_POINTER) - { - // Give the length needed, if wanted - if(pcbLengthNeeded != NULL) - pcbLengthNeeded[0] = cbSrcFileInfo; - - // If the caller entered an output buffer, the output size must also be entered - if(pvFileInfo != NULL && cbFileInfo != 0) - { - // Check if there is enough space in the output buffer - if(cbSrcFileInfo <= cbFileInfo) - { - switch(nInfoType) - { - case SFILE_INFO_TYPE_DIRECT_POINTER: - case SFILE_INFO_TYPE_ALLOCATED: - assert(pvSrcFileInfo != NULL); - memcpy(pvFileInfo, pvSrcFileInfo, cbSrcFileInfo); - break; - - case SFILE_INFO_TYPE_READ_FROM_FILE: - if(!FileStream_Read(ha->pStream, &ByteOffset, pvFileInfo, cbSrcFileInfo)) - nError = GetLastError(); - break; - - case SFILE_INFO_TYPE_TABLE_POINTER: - assert(pvSrcFileInfo != NULL); - *(void **)pvFileInfo = pvSrcFileInfo; - pvSrcFileInfo = NULL; - break; - - case SFILE_INFO_TYPE_FILE_ENTRY: - assert(pFileEntry != NULL); - ConvertFileEntryToSelfRelative((TFileEntry *)pvFileInfo, pFileEntry); - break; - } - } - else - { - nError = ERROR_INSUFFICIENT_BUFFER; - } - } - - // Free the file info if needed - if(nInfoType == SFILE_INFO_TYPE_ALLOCATED && pvSrcFileInfo != NULL) - STORM_FREE(pvSrcFileInfo); - if(nInfoType == SFILE_INFO_TYPE_TABLE_POINTER && pvSrcFileInfo != NULL) - SFileFreeFileInfo(pvSrcFileInfo, InfoClass); - } - else - { - // Handle error cases - if(nInfoType == SFILE_INFO_TYPE_INVALID_HANDLE) - nError = ERROR_INVALID_HANDLE; - if(nInfoType == SFILE_INFO_TYPE_NOT_FOUND) - nError = ERROR_FILE_NOT_FOUND; + return GetInfo(pvFileInfo, cbFileInfo, &hf->pFileEntry->dwCrc32, sizeof(DWORD), pcbLengthNeeded); } - // Set the last error value, if needed - if(nError != ERROR_SUCCESS) - SetLastError(nError); - return (nError == ERROR_SUCCESS); + // Invalid info class + return GetInfo_ReturnError(ERROR_INVALID_PARAMETER); } bool WINAPI SFileFreeFileInfo(void * pvFileInfo, SFileInfoClass InfoClass) diff --git a/src/SFileListFile.cpp b/src/SFileListFile.cpp index aa8969c..fe9bc69 100644 --- a/src/SFileListFile.cpp +++ b/src/SFileListFile.cpp @@ -17,7 +17,7 @@ // Listfile entry structure #define CACHE_BUFFER_SIZE 0x1000 // Size of the cache buffer -#define MAX_LISTFILE_SIZE 0x04000000 // Maximum accepted listfile size is about 68 MB +#define MAX_LISTFILE_SIZE 0x8000000 // Maximum accepted listfile size is 128 MB union TListFileHandle { @@ -148,6 +148,10 @@ static TListFileCache * CreateListFileCache( TListFileCache * pCache = NULL; TListFileHandle ListHandle = {NULL}; + // Put default value to dwMaxSize + if(dwMaxSize == 0) + dwMaxSize = MAX_LISTFILE_SIZE; + // Internal listfile: hMPQ must be non NULL and szListFile must be NULL. // We load the MPQ::(listfile) file if(hMpq != NULL && szListFile == NULL) @@ -181,7 +185,7 @@ static TListFileCache * CreateListFileCache( { // Verify the file size FileStream_GetSize(ListHandle.pStream, &FileSize); - if(0 < FileSize && FileSize < MAX_LISTFILE_SIZE) + if(0 < FileSize && FileSize < dwMaxSize) { pCache = CreateListFileCache(LoadListFile_Stream, &ListHandle, szWildCard, (DWORD)FileSize, dwMaxSize, dwFlags); } diff --git a/src/SFileOpenArchive.cpp b/src/SFileOpenArchive.cpp index d1cc4d6..3e333a9 100644 --- a/src/SFileOpenArchive.cpp +++ b/src/SFileOpenArchive.cpp @@ -9,7 +9,7 @@ /*---------------------------------------------------------------------------*/ /* Date Ver Who Comment */ /* -------- ---- --- ------- */ -/* xx.xx.xx 1.00 Lad The first version of SFileOpenArchive.cpp */ +/* xx.xx.xx 1.00 Lad Created */ /* 19.11.03 1.01 Dan Big endian handling */ /*****************************************************************************/ diff --git a/src/SFileReadFile.cpp b/src/SFileReadFile.cpp index a693e70..0320677 100644 --- a/src/SFileReadFile.cpp +++ b/src/SFileReadFile.cpp @@ -725,7 +725,7 @@ bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD // Otherwise read it as sector based MPQ file else - { + { nError = ReadMpqFileSectorFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); } diff --git a/src/StormLib.h b/src/StormLib.h index d913a54..f254290 100644 --- a/src/StormLib.h +++ b/src/StormLib.h @@ -142,8 +142,8 @@ extern "C" { //----------------------------------------------------------------------------- // Defines -#define STORMLIB_VERSION 0x0916 // Current version of StormLib (9.21) -#define STORMLIB_VERSION_STRING "9.22" // String version of StormLib version +#define STORMLIB_VERSION 0x0917 // Current version of StormLib (9.23) +#define STORMLIB_VERSION_STRING "9.23" // String version of StormLib version #define ID_MPQ 0x1A51504D // MPQ archive header ID ('MPQ\x1A') #define ID_MPQ_USERDATA 0x1B51504D // MPQ userdata entry ('MPQ\x1B') diff --git a/src/huffman/huff.cpp b/src/huffman/huff.cpp index 9de5acb..fa0964d 100644 --- a/src/huffman/huff.cpp +++ b/src/huffman/huff.cpp @@ -478,19 +478,24 @@ THTreeItem * THuffmannTree::FindHigherOrEqualItem(THTreeItem * pItem, unsigned i THTreeItem * THuffmannTree::CreateNewItem(unsigned int DecompressedValue, unsigned int Weight, TInsertPoint InsertPoint) { - THTreeItem * pNewItem; + THTreeItem * pNewItem = NULL; - // Allocate new item from the item pool - pNewItem = &ItemBuffer[ItemsUsed++]; + // Don't let the item buffer run out of space + if(ItemsUsed < HUFF_ITEM_COUNT) + { + // Allocate new item from the item pool + pNewItem = &ItemBuffer[ItemsUsed++]; - // Insert this item to the top of the tree - InsertItem(pNewItem, InsertPoint, NULL); + // Insert this item to the top of the tree + InsertItem(pNewItem, InsertPoint, NULL); - // Fill the rest of the item - pNewItem->DecompressedValue = DecompressedValue; - pNewItem->Weight = Weight; - pNewItem->pParent = NULL; - pNewItem->pChildLo = NULL; + // Fill the rest of the item + pNewItem->DecompressedValue = DecompressedValue; + pNewItem->Weight = Weight; + pNewItem->pParent = NULL; + pNewItem->pChildLo = NULL; + } + return pNewItem; } @@ -567,6 +572,8 @@ bool THuffmannTree::BuildTree(unsigned int CompressionType) // Create new parent item for the children pNewItem = CreateNewItem(0, pChildHi->Weight + pChildLo->Weight, InsertAfter); + if(pNewItem == NULL) + return false; // Link both child items to their new parent pChildLo->pParent = pNewItem; @@ -631,7 +638,7 @@ void THuffmannTree::IncWeightsAndRebalance(THTreeItem * pItem) } } -void THuffmannTree::InsertNewBranchAndRebalance(unsigned int Value1, unsigned int Value2) +bool THuffmannTree::InsertNewBranchAndRebalance(unsigned int Value1, unsigned int Value2) { THTreeItem * pLastItem = pLast; THTreeItem * pChildHi; @@ -639,16 +646,26 @@ void THuffmannTree::InsertNewBranchAndRebalance(unsigned int Value1, unsigned in // Create higher-weight child pChildHi = CreateNewItem(Value1, pLastItem->Weight, InsertBefore); - pChildHi->pParent = pLastItem; - ItemsByByte[Value1] = pChildHi; + if(pChildHi != NULL) + { + pChildHi->pParent = pLastItem; + ItemsByByte[Value1] = pChildHi; - // Create lower-weight child - pChildLo = CreateNewItem(Value2, 0, InsertBefore); - pChildLo->pParent = pLastItem; - pLastItem->pChildLo = pChildLo; - ItemsByByte[Value2] = pChildLo; + // Create lower-weight child + pChildLo = CreateNewItem(Value2, 0, InsertBefore); + if(pChildLo != NULL) + { + pChildLo->pParent = pLastItem; + pLastItem->pChildLo = pChildLo; + ItemsByByte[Value2] = pChildLo; + + IncWeightsAndRebalance(pChildLo); + return true; + } + } - IncWeightsAndRebalance(pChildLo); + // No more space in the tree buffer + return false; } void THuffmannTree::EncodeOneByte(TOutputStream * os, THTreeItem * pItem) @@ -789,7 +806,8 @@ unsigned int THuffmannTree::Compress(TOutputStream * os, void * pvInBuffer, int // Store the loaded byte into output stream os->PutBits(InputByte, 8); - InsertNewBranchAndRebalance(pLast->DecompressedValue, InputByte); + if(!InsertNewBranchAndRebalance(pLast->DecompressedValue, InputByte)) + return 0; if(bIsCmp0) { @@ -851,7 +869,8 @@ unsigned int THuffmannTree::Decompress(void * pvOutBuffer, unsigned int cbOutLen // The decompressed byte is stored in the next 8 bits DecompressedValue = is->Get8Bits(); - InsertNewBranchAndRebalance(pLast->DecompressedValue, DecompressedValue); + if(!InsertNewBranchAndRebalance(pLast->DecompressedValue, DecompressedValue)) + return 0; if(bIsCmp0 == 0) IncWeightsAndRebalance(ItemsByByte[DecompressedValue]); diff --git a/src/huffman/huff.h b/src/huffman/huff.h index 89993fd..d2c3e3e 100644 --- a/src/huffman/huff.h +++ b/src/huffman/huff.h @@ -118,7 +118,7 @@ class THuffmannTree bool BuildTree(unsigned int CompressionType); void IncWeightsAndRebalance(THTreeItem * pItem); - void InsertNewBranchAndRebalance(unsigned int Value1, unsigned int Value2); + bool InsertNewBranchAndRebalance(unsigned int Value1, unsigned int Value2); void EncodeOneByte(TOutputStream * os, THTreeItem * pItem); unsigned int DecodeOneByte(TInputStream * is); diff --git a/test/StormTest.cpp b/test/StormTest.cpp index 47a8cb5..8f9cd71 100644 --- a/test/StormTest.cpp +++ b/test/StormTest.cpp @@ -35,12 +35,8 @@ //------------------------------------------------------------------------------ // Local structures -#define TEST_OPEN_MPQ 0x00000000 -#define TEST_LOAD_FILE_CHECK_CRC 0x00010000 -#define TEST_OPEN_COMPARE_TWO_FILES 0x00020000 -#define TEST_MASK 0xFFFF0000 - -#define TEST_SETPOS 0x00000001 +#define TEST_FLAG_PROTECTED 0x01000000 +#define TEST_FLAG_FILE_COUNT 0x00FFFFFF typedef struct _TEST_INFO { @@ -60,7 +56,7 @@ static const TCHAR szListFileDir[] = { '1', '9', '9', '5', ' ', '-', ' ', 'T', ' #endif #ifdef STORMLIB_LINUX -#define WORK_PATH_ROOT "/home/ladik/StormLib/test" +#define WORK_PATH_ROOT "/media/ladik/MPQs" static const TCHAR szListFileDir[] = { '1', '9', '9', '5', ' ', '-', ' ', 'T', 'e', 's', 't', ' ', 'M', 'P', 'Q', 's', '\\', 'l', 'i', 's', 't', 'f', 'i', 'l', 'e', 's', '-', (TCHAR)0xe6, (TCHAR)0x96, (TCHAR)0xB0, (TCHAR)0xE5, (TCHAR)0xBB, (TCHAR)0xBA, (TCHAR)0xE6, (TCHAR)0x96, (TCHAR)0x87, (TCHAR)0xE4, (TCHAR)0xBB, (TCHAR)0xB6, (TCHAR)0xE5, (TCHAR)0xA4, (TCHAR)0xB9, 0 }; #endif @@ -486,62 +482,6 @@ static bool CopyStringAndVerifyConversion( return (_tcsicmp(szBufferT, szFoundFile) == 0) ? true : false; } -static void CalculateRelativePath(LPCSTR szFullPath1, LPCSTR szFullPath2, char * szBuffer) -{ - LPCSTR szPathPart1 = szFullPath1; - LPCSTR szPathPart2 = szFullPath2; - LPCSTR szNextPart1; - LPCSTR szNextPart2; - int nEqualParts = 0; - int nStepsUp = 0; - - // Parse both paths and find all path parts that are equal - for(;;) - { - // Find the next part of the first path - szNextPart1 = FindNextPathPart(szPathPart1, 1); - if(szNextPart1 == szPathPart1) - break; - - szNextPart2 = FindNextPathPart(szPathPart2, 1); - if(szNextPart2 == szPathPart2) - break; - - // Are these equal? - if((szNextPart2 - szPathPart2) != (szNextPart1 - szPathPart1)) - break; - if(_strnicmp(szPathPart1, szPathPart2, (szNextPart1 - szPathPart1 - 1))) - break; - - // Increment the number of path parts that are equal - szPathPart1 = szNextPart1; - szPathPart2 = szNextPart2; - nEqualParts++; - } - - // If we found at least one equal part, we can create relative path - if(nEqualParts != 0) - { - // Calculate how many steps up we need to go - nStepsUp = GetPathSeparatorCount(szPathPart2); - - // Append "../" nStepsUp-times - for(int i = 0; i < nStepsUp; i++) - { - *szBuffer++ = '.'; - *szBuffer++ = '.'; - *szBuffer++ = '/'; - } - - // Append the rest of the path. Also change DOS backslashes to slashes - CopyPathPart(szBuffer, szPathPart1); - return; - } - - // Failed. Just copy the source path as it is - strcpy(szBuffer, szFullPath1); -} - static size_t ConvertSha1ToText(const unsigned char * sha1_digest, TCHAR * szSha1Text) { LPCSTR szTable = "0123456789abcdef"; @@ -864,19 +804,23 @@ static int InitializeMpqDirectory(TCHAR * argv[], int argc) TLogHelper Logger("InitWorkDir"); TFileStream * pStream; TCHAR szFullPath[MAX_PATH]; - LPCTSTR szWhereFrom = NULL; - LPCTSTR szDirName; + LPCTSTR szWhereFrom = _T("default"); + LPCTSTR szDirName = WORK_PATH_ROOT; - // Retrieve the name of the MPQ directory + // Retrieve the first argument if(argc > 1 && argv[1] != NULL) { - szWhereFrom = _T("command line"); - szDirName = argv[1]; - } - else - { - szWhereFrom = _T("default"); - szDirName = WORK_PATH_ROOT; + // Check if it's a directory + pStream = FileStream_OpenFile(argv[1], STREAM_FLAG_READ_ONLY); + if(pStream == NULL) + { + szWhereFrom = _T("command line"); + szDirName = argv[1]; + } + else + { + FileStream_Close(pStream); + } } // Copy the name of the MPQ directory. @@ -912,33 +856,33 @@ static int InitializeMpqDirectory(TCHAR * argv[], int argc) return ERROR_SUCCESS; } -static int GetFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName) +static DWORD GetFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName) { TCHAR * szPatchName; HANDLE hFile; TCHAR szPatchChain[0x400]; + DWORD dwErrCode = ERROR_SUCCESS; int nPatchCount = 0; - int nError = ERROR_SUCCESS; // Open the MPQ file if(SFileOpenFileEx(hMpq, szFileName, 0, &hFile)) { // Notify the user - pLogger->PrintProgress(_T("Verifying patch chain for %s ..."), GetShortPlainName(szFileName)); + pLogger->PrintProgress("Verifying patch chain for %s ...", GetShortPlainName(szFileName)); // Query the patch chain if(!SFileGetFileInfo(hFile, SFileInfoPatchChain, szPatchChain, sizeof(szPatchChain), NULL)) - nError = pLogger->PrintError("Failed to retrieve the patch chain on %s", szFileName); + dwErrCode = pLogger->PrintError("Failed to retrieve the patch chain on %s", szFileName); // Is there anything at all in the patch chain? - if(nError == ERROR_SUCCESS && szPatchChain[0] == 0) + if(dwErrCode == ERROR_SUCCESS && szPatchChain[0] == 0) { pLogger->PrintError("The patch chain for %s is empty", szFileName); - nError = ERROR_FILE_CORRUPT; + dwErrCode = ERROR_FILE_CORRUPT; } // Now calculate the number of patches - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { // Get the pointer to the patch szPatchName = szPatchChain; @@ -966,7 +910,7 @@ static int GetFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileNam return nPatchCount; } -static int VerifyFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName, int nExpectedPatchCount) +static DWORD VerifyFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName, int nExpectedPatchCount) { int nPatchCount = 0; @@ -977,21 +921,21 @@ static int VerifyFilePatchCount(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFile // Check if there are any patches at all if(nExpectedPatchCount != 0 && nPatchCount == 0) { - pLogger->PrintMessage(_T("There are no patches for %s"), szFileName); + pLogger->PrintMessage("There are no patches for %s", szFileName); return ERROR_FILE_CORRUPT; } // Check if the number of patches fits if(nPatchCount != nExpectedPatchCount) { - pLogger->PrintMessage(_T("Unexpected number of patches for %s"), szFileName); + pLogger->PrintMessage("Unexpected number of patches for %s", szFileName); return ERROR_FILE_CORRUPT; } return ERROR_SUCCESS; } -static int CreateEmptyFile(TLogHelper * pLogger, LPCTSTR szPlainName, ULONGLONG FileSize, TCHAR * szBuffer) +static DWORD CreateEmptyFile(TLogHelper * pLogger, LPCTSTR szPlainName, ULONGLONG FileSize, TCHAR * szBuffer) { TFileStream * pStream; TCHAR szFullPath[MAX_PATH]; @@ -1015,13 +959,13 @@ static int CreateEmptyFile(TLogHelper * pLogger, LPCTSTR szPlainName, ULONGLONG return ERROR_SUCCESS; } -static int VerifyFilePosition( +static DWORD VerifyFilePosition( TLogHelper * pLogger, TFileStream * pStream, ULONGLONG ExpectedPosition) { ULONGLONG ByteOffset = 0; - int nError = ERROR_SUCCESS; + DWORD dwErrCode = ERROR_SUCCESS; // Retrieve the file position if(FileStream_GetPos(pStream, &ByteOffset)) @@ -1029,15 +973,15 @@ static int VerifyFilePosition( if(ByteOffset != ExpectedPosition) { pLogger->PrintMessage(_T("The file position is different than expected (expected: ") I64u_t _T(", current: ") I64u_t, ExpectedPosition, ByteOffset); - nError = ERROR_FILE_CORRUPT; + dwErrCode = ERROR_FILE_CORRUPT; } } else { - nError = pLogger->PrintError(_T("Failed to retrieve the file offset")); + dwErrCode = pLogger->PrintError(_T("Failed to retrieve the file offset")); } - return nError; + return dwErrCode; } static int VerifyFileMpqHeader(TLogHelper * pLogger, TFileStream * pStream, ULONGLONG * pByteOffset) @@ -1341,10 +1285,11 @@ static void WINAPI CompactCallback(void * pvUserData, DWORD dwWork, ULONGLONG By //----------------------------------------------------------------------------- // MPQ file utilities -#define TEST_FLAG_LOAD_FILES 0x00000001 // Test function should load all files in the MPQ -#define TEST_FLAG_HASH_FILES 0x00000002 // Test function should load all files in the MPQ -#define TEST_FLAG_PLAY_WAVES 0x00000004 // Play extracted WAVE files -#define TEST_FLAG_MOST_PATCHED 0x00000008 // Find the most patched file +#define SEARCH_FLAG_LOAD_FILES 0x00000001 // Test function should load all files in the MPQ +#define SEARCH_FLAG_HASH_FILES 0x00000002 // Test function should load all files in the MPQ +#define SEARCH_FLAG_PLAY_WAVES 0x00000004 // Play extracted WAVE files +#define SEARCH_FLAG_MOST_PATCHED 0x00000008 // Find the most patched file +#define SEARCH_FLAG_IGNORE_ERRORS 0x00000010 // Ignore files that failed to open struct TFileData { @@ -1496,7 +1441,7 @@ static int CompareTwoLocalFilesRR( return nError; } -static TFileData * LoadMpqFile(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName, LCID lcLocale = 0) +static TFileData * LoadMpqFile(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileName, LCID lcLocale = 0, bool bIgnoreOpenErrors = false) { TFileData * pFileData = NULL; HANDLE hFile; @@ -1518,74 +1463,81 @@ static TFileData * LoadMpqFile(TLogHelper * pLogger, HANDLE hMpq, LPCSTR szFileN SFileSetLocale(lcLocale); // Open the file from MPQ - if(!SFileOpenFileEx(hMpq, szFileName, 0, &hFile)) - dwErrCode = pLogger->PrintError("Open failed: %s", szFileName); + if(SFileOpenFileEx(hMpq, szFileName, 0, &hFile)) + { + // Get the CRC32 of the file + SFileGetFileInfo(hFile, SFileInfoCRC32, &dwCrc32, sizeof(dwCrc32), NULL); - // Get the CRC32 of the file - SFileGetFileInfo(hFile, SFileInfoCRC32, &dwCrc32, sizeof(dwCrc32), NULL); + // Get the size of the file + if(dwErrCode == ERROR_SUCCESS) + { + dwFileSizeLo = SFileGetFileSize(hFile, &dwFileSizeHi); + if(dwFileSizeLo == SFILE_INVALID_SIZE || dwFileSizeHi != 0) + dwErrCode = pLogger->PrintError("Failed to query the file size"); + } - // Get the size of the file - if(dwErrCode == ERROR_SUCCESS) - { - dwFileSizeLo = SFileGetFileSize(hFile, &dwFileSizeHi); - if(dwFileSizeLo == SFILE_INVALID_SIZE || dwFileSizeHi != 0) - dwErrCode = pLogger->PrintError("Failed to query the file size"); - } + // Spazzler protector: Creates fake files with size of 0x7FFFE7CA + if(dwErrCode == ERROR_SUCCESS) + { + if(dwFileSizeLo > 0x1FFFFFFF) + dwErrCode = ERROR_FILE_CORRUPT; + } - // Spazzler protector: Creates fake files with size of 0x7FFFE7CA - if(dwErrCode == ERROR_SUCCESS) - { - if(dwFileSizeLo > 0x1FFFFFFF) - dwErrCode = ERROR_FILE_CORRUPT; - } + // Allocate buffer for the file content + if(dwErrCode == ERROR_SUCCESS) + { + pFileData = (TFileData *)STORM_ALLOC(BYTE, sizeof(TFileData) + dwFileSizeLo); + if(pFileData == NULL) + { + pLogger->PrintError("Failed to allocate buffer for the file content"); + dwErrCode = ERROR_NOT_ENOUGH_MEMORY; + } + } - // Allocate buffer for the file content - if(dwErrCode == ERROR_SUCCESS) - { - pFileData = (TFileData *)STORM_ALLOC(BYTE, sizeof(TFileData) + dwFileSizeLo); - if(pFileData == NULL) + // get the file index of the MPQ file + if(dwErrCode == ERROR_SUCCESS) { - pLogger->PrintError("Failed to allocate buffer for the file content"); - dwErrCode = ERROR_NOT_ENOUGH_MEMORY; + // Store the file size + memset(pFileData, 0, sizeof(TFileData) + dwFileSizeLo); + pFileData->dwFileSize = dwFileSizeLo; + pFileData->dwCrc32 = dwCrc32; + + // Retrieve the block index and file flags + if(!SFileGetFileInfo(hFile, SFileInfoFileIndex, &pFileData->dwBlockIndex, sizeof(DWORD), NULL)) + dwErrCode = pLogger->PrintError("Failed retrieve the file index of %s", szFileName); + if(!SFileGetFileInfo(hFile, SFileInfoFlags, &pFileData->dwFlags, sizeof(DWORD), NULL)) + dwErrCode = pLogger->PrintError("Failed retrieve the file flags of %s", szFileName); } - } - // get the file index of the MPQ file - if(dwErrCode == ERROR_SUCCESS) - { - // Store the file size - memset(pFileData, 0, sizeof(TFileData) + dwFileSizeLo); - pFileData->dwFileSize = dwFileSizeLo; - pFileData->dwCrc32 = dwCrc32; + // Load the entire file + if(dwErrCode == ERROR_SUCCESS) + { + // Read the file data + SFileReadFile(hFile, pFileData->FileData, dwFileSizeLo, &dwBytesRead, NULL); + if(dwBytesRead != dwFileSizeLo) + dwErrCode = ERROR_FILE_CORRUPT; + } - // Retrieve the block index and file flags - if(!SFileGetFileInfo(hFile, SFileInfoFileIndex, &pFileData->dwBlockIndex, sizeof(DWORD), NULL)) - dwErrCode = pLogger->PrintError("Failed retrieve the file index of %s", szFileName); - if(!SFileGetFileInfo(hFile, SFileInfoFlags, &pFileData->dwFlags, sizeof(DWORD), NULL)) - dwErrCode = pLogger->PrintError("Failed retrieve the file flags of %s", szFileName); - } + // If failed, free the buffer + if(dwErrCode != ERROR_SUCCESS) + { + SetLastError(dwErrCode); + if(pFileData != NULL) + STORM_FREE(pFileData); + pFileData = NULL; + } - // Load the entire file - if(dwErrCode == ERROR_SUCCESS) - { - // Read the file data - SFileReadFile(hFile, pFileData->FileData, dwFileSizeLo, &dwBytesRead, NULL); - if(dwBytesRead != dwFileSizeLo) -// dwErrCode = pLogger->PrintError("Read failed: %s", szFileName); - dwErrCode = ERROR_FILE_CORRUPT; + SFileCloseFile(hFile); } - - // If failed, free the buffer - if(dwErrCode != ERROR_SUCCESS) + else { - STORM_FREE(pFileData); - SetLastError(dwErrCode); - pFileData = NULL; + if(bIgnoreOpenErrors == false) + { + dwErrCode = pLogger->PrintError("Open failed: %s", szFileName); + } } - // Close the file and return what we got - if(hFile != NULL) - SFileCloseFile(hFile); + // Return what we got return pFileData; } @@ -1617,7 +1569,7 @@ static bool CompareTwoFiles(TLogHelper * pLogger, TFileData * pFileData1, TFileD static DWORD SearchArchive( TLogHelper * pLogger, HANDLE hMpq, - DWORD dwTestFlags = 0, + DWORD dwSearchFlags = 0, DWORD * pdwFileCount = NULL, LPBYTE pbFileHash = NULL) { @@ -1629,6 +1581,7 @@ static DWORD SearchArchive( TCHAR szListFile[MAX_PATH] = _T(""); char szMostPatched[MAX_PATH] = ""; DWORD dwErrCode = ERROR_SUCCESS; + bool bIgnoreOpenErrors = (dwSearchFlags & SEARCH_FLAG_IGNORE_ERRORS) ? true : false; bool bFound = true; int nMaxPatchCount = 0; int nPatchCount = 0; @@ -1640,7 +1593,7 @@ static DWORD SearchArchive( md5_init(&md5state); // Initiate the MPQ search - pLogger->PrintProgress("Searching the archive ..."); + pLogger->PrintProgress("Searching the archive (initializing) ..."); hFind = SFileFindFirstFile(hMpq, "*", &sf, szListFile); if(hFind == NULL) { @@ -1650,6 +1603,7 @@ static DWORD SearchArchive( } // Perform the search + pLogger->PrintProgress("Searching the archive ..."); while(bFound == true) { // Increment number of files @@ -1658,7 +1612,7 @@ static DWORD SearchArchive( // if(!_stricmp(sf.cFileName, "war3map.j")) // DebugBreak(); - if(dwTestFlags & TEST_FLAG_MOST_PATCHED) + if(dwSearchFlags & SEARCH_FLAG_MOST_PATCHED) { // Load the patch count nPatchCount = GetFilePatchCount(pLogger, hMpq, sf.cFileName); @@ -1672,18 +1626,18 @@ static DWORD SearchArchive( } // Load the file to memory, if required - if(dwTestFlags & TEST_FLAG_LOAD_FILES) + if(dwSearchFlags & SEARCH_FLAG_LOAD_FILES) { // Load the entire file to the MPQ - pFileData = LoadMpqFile(pLogger, hMpq, sf.cFileName, sf.lcLocale); + pFileData = LoadMpqFile(pLogger, hMpq, sf.cFileName, sf.lcLocale, bIgnoreOpenErrors); if(pFileData != NULL) { // Hash the file data, if needed - if((dwTestFlags & TEST_FLAG_HASH_FILES) && !IsInternalMpqFileName(sf.cFileName)) + if((dwSearchFlags & SEARCH_FLAG_HASH_FILES) && !IsInternalMpqFileName(sf.cFileName)) md5_process(&md5state, pFileData->FileData, pFileData->dwFileSize); // Play sound files, if required - if((dwTestFlags & TEST_FLAG_PLAY_WAVES) && strstr(sf.cFileName, ".wav") != NULL) + if((dwSearchFlags & SEARCH_FLAG_PLAY_WAVES) && strstr(sf.cFileName, ".wav") != NULL) { #ifdef _MSC_VER pLogger->PrintProgress("Playing sound %s", sf.cFileName); @@ -1704,7 +1658,7 @@ static DWORD SearchArchive( pdwFileCount[0] = dwFileCount; // Give the hash, if required - if(pbFileHash != NULL && (dwTestFlags & TEST_FLAG_HASH_FILES)) + if(pbFileHash != NULL && (dwSearchFlags & SEARCH_FLAG_HASH_FILES)) md5_done(&md5state, pbFileHash); return dwErrCode; @@ -2132,35 +2086,42 @@ static void TestGetFileInfo( DWORD cbFileInfo, DWORD * pcbLengthNeeded, bool bExpectedResult, - int nExpectedError) + DWORD dwExpectedErrCode) { + DWORD dwErrCode = ERROR_SUCCESS; bool bResult; - int nError = ERROR_SUCCESS; // Call the get file info bResult = SFileGetFileInfo(hMpqOrFile, InfoClass, pvFileInfo, cbFileInfo, pcbLengthNeeded); if(!bResult) - nError = GetLastError(); + dwErrCode = GetLastError(); if(bResult != bExpectedResult) pLogger->PrintMessage("Different result of SFileGetFileInfo."); - if(nError != nExpectedError) - pLogger->PrintMessage("Different error from SFileGetFileInfo (expected %u, returned %u)", nExpectedError, nError); + if(dwErrCode != dwExpectedErrCode) + pLogger->PrintMessage("Different error from SFileGetFileInfo (expected %u, returned %u)", dwExpectedErrCode, dwErrCode); } // StormLib is able to open local files (as well as the original Storm.dll) // I want to keep this for occasional use -static int TestOpenLocalFile(LPCTSTR szPlainName) +static DWORD TestOnLocalListFile(LPCTSTR szPlainName) { - TLogHelper Logger("OpenLocalFile", szPlainName); + TLogHelper Logger("LocalListFile", szPlainName); + SFILE_FIND_DATA sf; HANDLE hFile; + HANDLE hFind; DWORD dwFileSizeHi = 0; DWORD dwFileSizeLo = 0; + TCHAR szFullPath[MAX_PATH]; char szFileName1[MAX_PATH]; char szFileName2[MAX_PATH]; - char szFileLine[0x40]; + char szFileLine[0x40] = {0}; + int nFileCount = 0; + // Get the full name of the local file CreateFullPathName(szFileName1, _countof(szFileName1), szMpqSubDir, szPlainName); + + // Test opening the local file if(SFileOpenFileEx(NULL, szFileName1, SFILE_OPEN_LOCAL_FILE, &hFile)) { // Retrieve the file name. It must match the name under which the file was open @@ -2170,30 +2131,23 @@ static int TestOpenLocalFile(LPCTSTR szPlainName) // Retrieve the file size dwFileSizeLo = SFileGetFileSize(hFile, &dwFileSizeHi); - if(dwFileSizeHi != 0 || dwFileSizeLo != 3904784) + if(dwFileSizeHi != 0 || dwFileSizeLo != 0x04385a4e) Logger.PrintMessage("Local file size mismatch"); // Read the first line - memset(szFileLine, 0, sizeof(szFileLine)); SFileReadFile(hFile, szFileLine, 18, NULL, NULL); - if(strcmp(szFileLine, "(1)Enslavers01.scm")) + if(strcmp(szFileLine, "accountbilling.url")) Logger.PrintMessage("Content of the listfile does not match"); SFileCloseFile(hFile); } + else + return Logger.PrintError("Failed to open local listfile"); - return ERROR_SUCCESS; -} + // We need unicode listfile name + StringCopy(szFullPath, _countof(szFullPath), szFileName1); -static int TestSearchListFile(LPCTSTR szPlainName) -{ - SFILE_FIND_DATA sf; - TLogHelper Logger("SearchListFile", szPlainName); - TCHAR szFullPath[MAX_PATH]; - HANDLE hFind; - int nFileCount = 0; - - CreateFullPathName(szFullPath, _countof(szFullPath), szMpqSubDir, szPlainName); + // Start searching in the listfile hFind = SListFileFindFirstFile(NULL, szFullPath, "*", &sf); if(hFind != NULL) { @@ -2206,6 +2160,9 @@ static int TestSearchListFile(LPCTSTR szPlainName) SListFileFindClose(hFind); } + else + return Logger.PrintError("Failed to search local listfile"); + return ERROR_SUCCESS; } @@ -2391,28 +2348,29 @@ static int TestFileStreamOperations(LPCTSTR szPlainName, DWORD dwStreamFlags) return nError; } -static DWORD TestArchive_LoadFiles(TLogHelper * pLogger, HANDLE hMpq, ...) +static DWORD TestArchive_LoadFiles(TLogHelper * pLogger, HANDLE hMpq, bool bIgnoreOpenErrors, ...) { TFileData * pFileData; const char * szFileName; va_list argList; DWORD dwErrCode = ERROR_SUCCESS; - va_start(argList, hMpq); + va_start(argList, bIgnoreOpenErrors); while((szFileName = va_arg(argList, const char *)) != NULL) { if(SFileHasFile(hMpq, szFileName)) { pFileData = LoadMpqFile(pLogger, hMpq, szFileName); - if(pFileData != NULL) + if(pFileData == NULL && bIgnoreOpenErrors == false) { - STORM_FREE(pFileData); - pFileData = NULL; + pLogger->PrintError("Error loading the file %s", szFileName); + dwErrCode = ERROR_FILE_CORRUPT; + break; } else { - dwErrCode = pLogger->PrintError("Error loading the file %s", szFileName); - break; + STORM_FREE(pFileData); + pFileData = NULL; } } } @@ -2445,27 +2403,51 @@ static DWORD TestArchive_SetPos(HANDLE hMpq, const char * szFileName) static DWORD TestArchive( LPCTSTR szPlainName, // Plain name of the MPQ LPCTSTR szListFile, // Listfile name (NULL if none) - DWORD dwWhatToDo, // Flags what to do + DWORD dwFlags, // Flags LPCSTR szFileName1, LPCSTR szFileName2) { + TFileData * pFileData1 = NULL; TFileData * pFileData2 = NULL; - TFileData * pFileData = NULL; TLogHelper Logger("TestMpq", szPlainName); -// HANDLE hFile = NULL; + LPCSTR szExpectedMD5 = NULL; HANDLE hMpq = NULL; DWORD dwFileCount = 0; + DWORD dwSearchFlags = 0; DWORD dwErrCode; DWORD dwCrc32 = 0; + DWORD dwExpectedFileCount = 0; + DWORD dwMpqFlags = 0; TCHAR szFullName[MAX_PATH]; + BYTE ExpectedMD5[MD5_DIGEST_SIZE]; + BYTE OverallMD5[MD5_DIGEST_SIZE]; + bool bIgnoreOpenErrors = false; // If the file is a partial MPQ, don't load all files - bool bIsPartialMpq = (_tcsstr(szPlainName, _T(".MPQ.part")) != NULL); + if(_tcsstr(szPlainName, _T(".MPQ.part")) == NULL) + dwSearchFlags |= SEARCH_FLAG_LOAD_FILES; + + // If the MPQ is a protected MPQ, do different tests + if(dwFlags & TEST_FLAG_PROTECTED) + { + dwExpectedFileCount = (dwFlags & TEST_FLAG_FILE_COUNT); + if((szExpectedMD5 = szFileName1) != NULL) + dwSearchFlags |= SEARCH_FLAG_HASH_FILES; + szFileName2 = szFileName1 = NULL; + } // Copy the archive so we won't fuck up the original one dwErrCode = OpenExistingArchiveWithCopy(&Logger, szPlainName, NULL, &hMpq); - if(dwErrCode == ERROR_SUCCESS) + while(dwErrCode == ERROR_SUCCESS) { + // Check for malformed MPQs + SFileGetFileInfo(hMpq, SFileMpqFlags, &dwMpqFlags, sizeof(dwMpqFlags), NULL); + if(dwMpqFlags & MPQ_FLAG_MALFORMED) + { + dwSearchFlags |= SEARCH_FLAG_IGNORE_ERRORS; + bIgnoreOpenErrors = true; + } + // If the listfile was given, add it to the MPQ if(szListFile && szListFile[0]) { @@ -2475,256 +2457,96 @@ static DWORD TestArchive( Logger.PrintMessage("Failed to add the listfile to the MPQ"); } - // Perform work-specific duty - switch(dwWhatToDo & TEST_MASK) - { - case TEST_LOAD_FILE_CHECK_CRC: - - // Load the entire file - pFileData = LoadMpqFile(&Logger, hMpq, szFileName1); - if(pFileData == NULL) - { - dwErrCode = Logger.PrintError("Failed to load the file %s", szFileName1); - break; - } - - // Compare the CRC32, if available - dwCrc32 = crc32(0, (Bytef *)pFileData->FileData, (uInt)pFileData->dwFileSize); - if(dwCrc32 != pFileData->dwCrc32) - Logger.PrintError("Warning: CRC32 error on %s", szFileName1); - break; - - case TEST_OPEN_COMPARE_TWO_FILES: - - // Load the first file - pFileData = LoadMpqFile(&Logger, hMpq, szFileName1); - if(pFileData == NULL) - { - dwErrCode = Logger.PrintError("Failed to load the file %s", "File00000023.xxx"); - break; - } - - // Load the second file - pFileData2 = LoadMpqFile(&Logger, hMpq, szFileName2); - if(pFileData2 == NULL) - { - dwErrCode = Logger.PrintError("Failed to load the file %s", "music\\dintro.wav"); - break; - } + // Attempt to open the (listfile), (attributes), (signature) + dwErrCode = TestArchive_LoadFiles(&Logger, hMpq, bIgnoreOpenErrors, LISTFILE_NAME, ATTRIBUTES_NAME, SIGNATURE_NAME, NULL); + if(dwErrCode != ERROR_SUCCESS) + break; - // Compare both files - if(!CompareTwoFiles(&Logger, pFileData, pFileData2)) - dwErrCode = Logger.PrintError("The file has different size/content when open without name"); + // If szFileName1 was given, load it and check its CRC + if(szFileName1 && szFileName1[0]) + { + // Test setting position + dwErrCode = TestArchive_SetPos(hMpq, szFileName1); + if(dwErrCode != ERROR_SUCCESS) break; - case TEST_OPEN_MPQ: - - // Attempt to open the (listfile), (attributes), (signature) - dwErrCode = TestArchive_LoadFiles(&Logger, hMpq, LISTFILE_NAME, ATTRIBUTES_NAME, SIGNATURE_NAME, NULL); - if(dwErrCode != ERROR_SUCCESS) - break; - - // Test setting position - if((dwWhatToDo & TEST_SETPOS) && (szFileName1 != NULL)) - { - dwErrCode = TestArchive_SetPos(hMpq, szFileName1); - if(dwErrCode != ERROR_SUCCESS) - break; - } - - // Search the archive - dwErrCode = SearchArchive(&Logger, hMpq, (bIsPartialMpq ? 0 : TEST_FLAG_LOAD_FILES), &dwFileCount); + // Load the entire file 1 + pFileData1 = LoadMpqFile(&Logger, hMpq, szFileName1); + if(pFileData1 == NULL) + { + dwErrCode = Logger.PrintError("Failed to load the file %s", szFileName1); break; - } - } - - // Common cleanup - if(pFileData2 != NULL) - STORM_FREE(pFileData2); - if(pFileData != NULL) - STORM_FREE(pFileData); - if(hMpq != NULL) - SFileCloseArchive(hMpq); - return dwErrCode; -} - -static int TestOpenArchive(LPCTSTR szPlainName, LPCTSTR szListFile = NULL, LPCSTR szFileName = NULL, bool bDontCopyArchive = false) -{ - TLogHelper Logger("OpenMpqTest", szPlainName); - TFileData * pFileData; - LPCTSTR szCopyName = (bDontCopyArchive) ? NULL : szPlainName; - HANDLE hMpq; - HANDLE hFile; - DWORD dwFileCount = 0; - DWORD dwTestFlags; - TCHAR szListFileBuff[MAX_PATH]; - bool bIsPartialMpq = false; - int nError; - - // If the file is a partial MPQ, don't load all files - bIsPartialMpq = (_tcsstr(szPlainName, _T(".MPQ.part")) != NULL); - - // Copy the archive so we won't fuck up the original one - nError = OpenExistingArchiveWithCopy(&Logger, szPlainName, szCopyName, &hMpq); - if(nError == ERROR_SUCCESS) - { - // If the listfile was given, add it to the MPQ - if(szListFile != NULL) - { - Logger.PrintProgress(_T("Adding listfile %s ..."), szListFile); - CreateFullPathName(szListFileBuff, _countof(szListFileBuff), szListFileDir, szListFile); - nError = SFileAddListFile(hMpq, szListFileBuff); - if(nError != ERROR_SUCCESS) - Logger.PrintMessage("Failed to add the listfile to the MPQ"); - } + } - // Attempt to open the (listfile) - if(SFileHasFile(hMpq, LISTFILE_NAME)) - { - pFileData = LoadMpqFile(&Logger, hMpq, LISTFILE_NAME); - if(pFileData != NULL) - STORM_FREE(pFileData); + // Check the CRC of file1, if available + if(pFileData1->dwCrc32) + { + // Compare the CRC32, if available + dwCrc32 = crc32(0, (Bytef *)pFileData1->FileData, (uInt)pFileData1->dwFileSize); + if(dwCrc32 != pFileData1->dwCrc32) + Logger.PrintError("Warning: CRC32 error on %s", szFileName1); + } } - // Attempt to open the (attributes) - if(SFileHasFile(hMpq, ATTRIBUTES_NAME)) + // If szFileName2 was given, load it + if(szFileName2 && szFileName2[0]) { - pFileData = LoadMpqFile(&Logger, hMpq, ATTRIBUTES_NAME); - if(pFileData != NULL) - STORM_FREE(pFileData); + // Load the entire file 2 + pFileData2 = LoadMpqFile(&Logger, hMpq, szFileName2); + if(pFileData2 == NULL) + { + dwErrCode = Logger.PrintError("Failed to load the file %s", szFileName2); + break; + } } - // Attempt to open the (signature) - if(SFileHasFile(hMpq, SIGNATURE_NAME)) + // If two files were given, compare them + if(pFileData1 && pFileData2) { - pFileData = LoadMpqFile(&Logger, hMpq, SIGNATURE_NAME); - if(pFileData != NULL) - STORM_FREE(pFileData); + // Compare both files + if(!CompareTwoFiles(&Logger, pFileData1, pFileData2)) + { + dwErrCode = Logger.PrintError("The file has different size/content of files"); + break; + } } - // Attempt to open an arbitrary file - if(szFileName != NULL && szFileName[0] != 0) + // Search the archive + dwErrCode = SearchArchive(&Logger, hMpq, dwSearchFlags, &dwFileCount, OverallMD5); + + // Shall we check the file count and overall MD5? + if(dwExpectedFileCount != 0) { - if(SFileOpenFileEx(hMpq, "1.blp", 0, &hFile)) + if(dwFileCount != dwExpectedFileCount) { - DWORD dwFileSize; - DWORD dwBytesRead = 0; - BYTE Buffer[0x10]; - - dwFileSize = SFileGetFileSize(hFile, NULL); - if(dwFileSize > sizeof(Buffer)) - { - SFileSetFilePointer(hFile, dwFileSize - sizeof(Buffer), NULL, FILE_BEGIN); - SFileReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead, NULL); - } - - SFileCloseFile(hFile); + Logger.PrintMessage("File count mismatch(expected: %u, found:%u)", dwExpectedFileCount, dwFileCount); + dwErrCode = ERROR_CAN_NOT_COMPLETE; + break; } } - // Search the archive and load every file - dwTestFlags = bIsPartialMpq ? 0 : TEST_FLAG_LOAD_FILES; - nError = SearchArchive(&Logger, hMpq, dwTestFlags, &dwFileCount); - SFileCloseArchive(hMpq); - } - - return nError; -} - -static int TestOpenArchive_SetPos(LPCTSTR szPlainName, LPCSTR szFileName) -{ - TLogHelper Logger("SetPosTest", szPlainName); - HANDLE hFile = NULL; - HANDLE hMpq = NULL; - TCHAR szMpqName[MAX_PATH]; - char szFullPath[MAX_PATH]; - int nError = ERROR_SUCCESS; - - // Create the full path name for the archive - CreateFullPathName(szFullPath, _countof(szFullPath), szMpqSubDir, szPlainName); - StringCopy(szMpqName, _countof(szMpqName), szFullPath); - - // Try to open the archive. It is expected to fail - Logger.PrintProgress("Opening archive %s", szPlainName); - if(SFileOpenArchive(szMpqName, 0, MPQ_OPEN_READ_ONLY, &hMpq)) - { - if(SFileOpenFileEx(hMpq, szFileName, 0, &hFile)) + // Shall we check overall MD5? + if(szExpectedMD5 && szExpectedMD5[0]) { - // First, use the SFileSetFilePointer WITHOUT the high-dword position - if(nError == ERROR_SUCCESS) - nError = TestSetFilePointers(hFile, false); - - // First, use the SFileSetFilePointer WITH the high-dword position - if(nError == ERROR_SUCCESS) - nError = TestSetFilePointers(hFile, true); - - // Close the file - SFileCloseFile(hFile); + BinaryFromString(szExpectedMD5, ExpectedMD5, MD5_DIGEST_SIZE); + if(memcmp(ExpectedMD5, OverallMD5, MD5_DIGEST_SIZE)) + { + Logger.PrintMessage("Extracted files MD5 mismatch"); + dwErrCode = ERROR_CAN_NOT_COMPLETE; + break; + } } - else - nError = GetLastError(); - - // Close the archive - SFileCloseArchive(hMpq); + break; } - else - nError = GetLastError(); - - return nError; -} - -static int TestOpenArchive_ProtectedMap(LPCTSTR szPlainName, LPCTSTR szListFile = NULL, DWORD dwExpectedFileCount = 0, LPCSTR szExpectedMD5 = NULL) -{ - TLogHelper Logger("ProtectedMapTest", szPlainName); - HANDLE hMpq; - DWORD dwTestFlags = TEST_FLAG_LOAD_FILES | TEST_FLAG_HASH_FILES; - DWORD dwFileCount = 0; - BYTE ExpectedMD5[MD5_DIGEST_SIZE]; - BYTE OverallMD5[MD5_DIGEST_SIZE]; - TCHAR szListFileBuff[MAX_PATH]; - int nError; - - // Copy the archive so we won't fuck up the original one - nError = OpenExistingArchiveWithCopy(&Logger, szPlainName, szPlainName, &hMpq); - if(nError == ERROR_SUCCESS) - { - // If the listfile was given, add it to the MPQ - if(szListFile != NULL) - { - Logger.PrintProgress(_T("Adding listfile %s ..."), szListFile); - CreateFullPathName(szListFileBuff, _countof(szListFileBuff), szMpqSubDir, szListFile); - nError = SFileAddListFile(hMpq, szListFileBuff); - if(nError != ERROR_SUCCESS) - Logger.PrintMessage("Failed to add the listfile to the MPQ"); - } - // Search the archive and load every file - nError = SearchArchive(&Logger, hMpq, dwTestFlags, &dwFileCount, OverallMD5); + // Common cleanup + if(pFileData2 != NULL) + STORM_FREE(pFileData2); + if(pFileData1 != NULL) + STORM_FREE(pFileData1); + if(hMpq != NULL) SFileCloseArchive(hMpq); - } - - // Check the file count and hash, if required - if(nError == ERROR_SUCCESS && dwExpectedFileCount != 0) - { - if(dwFileCount != dwExpectedFileCount) - { - Logger.PrintMessage("File count mismatch(expected: %u, found:%u)", dwExpectedFileCount, dwFileCount); - nError = ERROR_CAN_NOT_COMPLETE; - } - } - - // Check the overall hash, if required - if(nError == ERROR_SUCCESS && szExpectedMD5 != NULL && szExpectedMD5[0] != 0) - { - BinaryFromString(szExpectedMD5, ExpectedMD5, MD5_DIGEST_SIZE); - if(memcmp(ExpectedMD5, OverallMD5, MD5_DIGEST_SIZE)) - { - Logger.PrintMessage("Extracted files MD5 mismatch"); - nError = ERROR_CAN_NOT_COMPLETE; - } - } - - return nError; + return dwErrCode; } // Open an empty archive (found in WoW cache - it's just a header) @@ -2769,7 +2591,7 @@ static int TestOpenArchive_Corrupt(LPCTSTR szPlainName) // Opens a patched MPQ archive -static int TestOpenArchive_Patched(LPCTSTR PatchList[], LPCSTR szPatchedFile, int nExpectedPatchCount, bool bExpectedToFail = false) +static DWORD TestOpenArchive_Patched(LPCTSTR PatchList[], LPCSTR szPatchedFile, int nExpectedPatchCount, bool bExpectedToFail = false) { TLogHelper Logger("OpenPatchedMpqTest", PatchList[0]); HANDLE hMpq; @@ -2777,18 +2599,18 @@ static int TestOpenArchive_Patched(LPCTSTR PatchList[], LPCSTR szPatchedFile, in BYTE Buffer[0x100]; DWORD dwFileCount = 0; DWORD BytesRead = 0; - int nError; + DWORD dwErrCode; // Open a patched MPQ archive - nError = OpenPatchedArchive(&Logger, &hMpq, PatchList); - if(nError == ERROR_SUCCESS) + dwErrCode = OpenPatchedArchive(&Logger, &hMpq, PatchList); + if(dwErrCode == ERROR_SUCCESS) { // Check patch count if(szPatchedFile != NULL) - nError = VerifyFilePatchCount(&Logger, hMpq, szPatchedFile, nExpectedPatchCount); + dwErrCode = VerifyFilePatchCount(&Logger, hMpq, szPatchedFile, nExpectedPatchCount); // Try to open and read the file - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { if(SFileOpenFileEx(hMpq, szPatchedFile, 0, &hFile)) { @@ -2798,17 +2620,17 @@ static int TestOpenArchive_Patched(LPCTSTR PatchList[], LPCSTR szPatchedFile, in } // Search the archive and load every file - if(nError == ERROR_SUCCESS) - nError = SearchArchive(&Logger, hMpq, TEST_FLAG_LOAD_FILES, &dwFileCount); + if(dwErrCode == ERROR_SUCCESS) + dwErrCode = SearchArchive(&Logger, hMpq, SEARCH_FLAG_LOAD_FILES | SEARCH_FLAG_IGNORE_ERRORS, &dwFileCount); // Close the archive SFileCloseArchive(hMpq); } // Clear the error if patch prefix was not found - if(nError == ERROR_CANT_FIND_PATCH_PREFIX && bExpectedToFail) - nError = ERROR_SUCCESS; - return nError; + if(dwErrCode == ERROR_CANT_FIND_PATCH_PREFIX && bExpectedToFail) + dwErrCode = ERROR_SUCCESS; + return dwErrCode; } // Open an archive for read-only access @@ -2877,21 +2699,21 @@ static int TestOpenArchive_GetFileInfo(LPCTSTR szPlainName1, LPCTSTR szPlainName TestGetFileInfo(&Logger, NULL, SFileMpqBetHeader, NULL, 0, NULL, false, ERROR_INVALID_HANDLE); // Valid handle but invalid value of file info class (false, ERROR_INVALID_PARAMETER) - TestGetFileInfo(&Logger, NULL, (SFileInfoClass)0xFFF, NULL, 0, NULL, false, ERROR_INVALID_PARAMETER); + TestGetFileInfo(&Logger, NULL, (SFileInfoClass)0xFFF, NULL, 0, NULL, false, ERROR_INVALID_HANDLE); - // Valid archive handle but file info class is for file (false, ERROR_INVALID_HANDLE) + // Invalid archive handle and file info class is for file (false, ERROR_INVALID_HANDLE) TestGetFileInfo(&Logger, NULL, SFileInfoNameHash1, NULL, 0, NULL, false, ERROR_INVALID_HANDLE); // Valid handle and all parameters NULL - // Returns (true, ERROR_SUCCESS), if BET table is present, otherwise (false, ERROR_CAN_NOT_COMPLETE) + // Returns (true, ERROR_SUCCESS), if BET table is present, otherwise (false, ERROR_FILE_NOT_FOUND) TestGetFileInfo(&Logger, hMpq1, SFileMpqBetHeader, NULL, 0, NULL, false, ERROR_FILE_NOT_FOUND); - TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, NULL, 0, NULL, true, ERROR_SUCCESS); + TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, NULL, 0, NULL, false, ERROR_INSUFFICIENT_BUFFER); // Now try to retrieve the required size of the BET table header - TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, NULL, 0, &cbLength, true, ERROR_SUCCESS); + TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, NULL, 0, &cbLength, false, ERROR_INSUFFICIENT_BUFFER); // When we call SFileInfo with buffer = NULL and nonzero buffer size, it is ignored - TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, NULL, 3, &cbLength, true, ERROR_SUCCESS); + TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, NULL, 3, &cbLength, false, ERROR_INSUFFICIENT_BUFFER); // When we call SFileInfo with buffer != NULL and nonzero buffer size, it should return error TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, DataBuff, 3, &cbLength, false, ERROR_INSUFFICIENT_BUFFER); @@ -2903,11 +2725,11 @@ static int TestOpenArchive_GetFileInfo(LPCTSTR szPlainName1, LPCTSTR szPlainName TestGetFileInfo(&Logger, hMpq4, SFileMpqBetHeader, DataBuff, sizeof(DataBuff), &cbLength, true, ERROR_SUCCESS); // Try to retrieve strong signature from the MPQ - TestGetFileInfo(&Logger, hMpq1, SFileMpqStrongSignature, NULL, 0, NULL, true, ERROR_SUCCESS); + TestGetFileInfo(&Logger, hMpq1, SFileMpqStrongSignature, NULL, 0, NULL, false, ERROR_INSUFFICIENT_BUFFER); TestGetFileInfo(&Logger, hMpq4, SFileMpqStrongSignature, NULL, 0, NULL, false, ERROR_FILE_NOT_FOUND); // Strong signature is returned including the signature ID - TestGetFileInfo(&Logger, hMpq1, SFileMpqStrongSignature, NULL, 0, &cbLength, true, ERROR_SUCCESS); + TestGetFileInfo(&Logger, hMpq1, SFileMpqStrongSignature, NULL, 0, &cbLength, false, ERROR_INSUFFICIENT_BUFFER); assert(cbLength == MPQ_STRONG_SIGNATURE_SIZE + 4); // Retrieve the signature @@ -3137,8 +2959,7 @@ static int TestOpenArchive_SignExisting(LPCTSTR szPlainName) return nError; } -// Open an empty archive (found in WoW cache - it's just a header) -static int TestOpenArchive_CompactArchive(LPCTSTR szPlainName, LPCTSTR szCopyName, bool bAddUserData) +static DWORD TestOpenArchive_CompactArchive(LPCTSTR szPlainName, LPCTSTR szCopyName, bool bAddUserData) { TLogHelper Logger("CompactMpqTest", szPlainName); ULONGLONG PreMpqDataSize = (bAddUserData) ? 0x400 : 0; @@ -3149,64 +2970,64 @@ static int TestOpenArchive_CompactArchive(LPCTSTR szPlainName, LPCTSTR szCopyNam TCHAR szFullPath[MAX_PATH]; BYTE FileHash1[MD5_DIGEST_SIZE]; BYTE FileHash2[MD5_DIGEST_SIZE]; - int nError; + DWORD dwErrCode; // Create copy of the archive, with interleaving some user data - nError = CreateFileCopy(&Logger, szPlainName, szCopyName, szFullPath, _countof(szFullPath), PreMpqDataSize, UserDataSize); + dwErrCode = CreateFileCopy(&Logger, szPlainName, szCopyName, szFullPath, _countof(szFullPath), PreMpqDataSize, UserDataSize); // Open the archive and load some files - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { // Open the archive - nError = OpenExistingArchive(&Logger, szFullPath, 0, &hMpq); - if(nError != ERROR_SUCCESS) - return nError; + dwErrCode = OpenExistingArchive(&Logger, szFullPath, 0, &hMpq); + if(dwErrCode != ERROR_SUCCESS) + return dwErrCode; // Verify presence of (listfile) and (attributes) CheckIfFileIsPresent(&Logger, hMpq, LISTFILE_NAME, true); CheckIfFileIsPresent(&Logger, hMpq, ATTRIBUTES_NAME, true); // Search the archive and load every file - nError = SearchArchive(&Logger, hMpq, TEST_FLAG_LOAD_FILES | TEST_FLAG_HASH_FILES, &dwFileCount1, FileHash1); + dwErrCode = SearchArchive(&Logger, hMpq, SEARCH_FLAG_LOAD_FILES | SEARCH_FLAG_HASH_FILES, &dwFileCount1, FileHash1); SFileCloseArchive(hMpq); } // Try to compact the MPQ - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { // Open the archive again - nError = OpenExistingArchive(&Logger, szFullPath, 0, &hMpq); - if(nError != ERROR_SUCCESS) - return nError; + dwErrCode = OpenExistingArchive(&Logger, szFullPath, 0, &hMpq); + if(dwErrCode != ERROR_SUCCESS) + return dwErrCode; // Compact the archive Logger.PrintProgress("Compacting archive %s ...", GetShortPlainName(szFullPath)); if(!SFileSetCompactCallback(hMpq, CompactCallback, &Logger)) - nError = Logger.PrintError(_T("Failed to compact archive %s"), szFullPath); + dwErrCode = Logger.PrintError(_T("Failed to compact archive %s"), szFullPath); SFileCompactArchive(hMpq, NULL, false); SFileCloseArchive(hMpq); } // Open the archive and load some files - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { // Open the archive - nError = OpenExistingArchive(&Logger, szFullPath, 0, &hMpq); - if(nError != ERROR_SUCCESS) - return nError; + dwErrCode = OpenExistingArchive(&Logger, szFullPath, 0, &hMpq); + if(dwErrCode != ERROR_SUCCESS) + return dwErrCode; // Verify presence of (listfile) and (attributes) CheckIfFileIsPresent(&Logger, hMpq, LISTFILE_NAME, true); CheckIfFileIsPresent(&Logger, hMpq, ATTRIBUTES_NAME, true); // Search the archive and load every file - nError = SearchArchive(&Logger, hMpq, TEST_FLAG_LOAD_FILES | TEST_FLAG_HASH_FILES, &dwFileCount2, FileHash2); + dwErrCode = SearchArchive(&Logger, hMpq, SEARCH_FLAG_LOAD_FILES | SEARCH_FLAG_HASH_FILES, &dwFileCount2, FileHash2); SFileCloseArchive(hMpq); } // Compare the file counts and their hashes - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { if(dwFileCount2 != dwFileCount1) Logger.PrintMessage("Different file count after compacting archive: %u vs %u", dwFileCount2, dwFileCount1); @@ -3215,7 +3036,7 @@ static int TestOpenArchive_CompactArchive(LPCTSTR szPlainName, LPCTSTR szCopyNam Logger.PrintMessage("Different file hash after compacting archive"); } - return nError; + return dwErrCode; } static int ForEachFile_VerifyFileChecksum(LPCTSTR szFullPath) @@ -3403,7 +3224,7 @@ static int TestCreateArchive_Deprotect(LPCSTR szPlainName) BYTE FileHash2[MD5_DIGEST_SIZE]; DWORD dwFileCount1 = 0; DWORD dwFileCount2 = 0; - DWORD dwTestFlags = TEST_FLAG_LOAD_FILES | TEST_FLAG_HASH_FILES; + DWORD dwTestFlags = SEARCH_FLAG_LOAD_FILES | SEARCH_FLAG_HASH_FILES; int nError = ERROR_SUCCESS; // First copy: The original (untouched) file @@ -3898,7 +3719,7 @@ static int TestCreateArchive_UnicodeNames() return nError; } -static int TestCreateArchive_FileFlagTest(LPCTSTR szPlainName) +static DWORD TestCreateArchive_FileFlagTest(LPCTSTR szPlainName) { TLogHelper Logger("FileFlagTest", szPlainName); HANDLE hMpq = NULL; // Handle of created archive @@ -3910,29 +3731,28 @@ static int TestCreateArchive_FileFlagTest(LPCTSTR szPlainName) char szArchivedName[MAX_PATH]; DWORD dwMaxFileCount = 0; DWORD dwFileCount = 0; - size_t i; - int nError; + DWORD dwErrCode; // Create paths for local file to be added CreateFullPathName(szFileName1, _countof(szFileName1), szMpqSubDir, _T("AddFile.exe")); CreateFullPathName(szFileName2, _countof(szFileName2), szMpqSubDir, _T("AddFile.bin")); // Create an empty file that will serve as holder for the MPQ - nError = CreateEmptyFile(&Logger, szPlainName, 0x100000, szFullPath); + dwErrCode = CreateEmptyFile(&Logger, szPlainName, 0x100000, szFullPath); // Create new MPQ archive over that file - if(nError == ERROR_SUCCESS) - nError = CreateNewArchive(&Logger, szPlainName, MPQ_CREATE_ARCHIVE_V1 | MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES, 17, &hMpq); + if(dwErrCode == ERROR_SUCCESS) + dwErrCode = CreateNewArchive(&Logger, szPlainName, MPQ_CREATE_ARCHIVE_V1 | MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES, 17, &hMpq); // Add the same file multiple times - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { dwMaxFileCount = SFileGetMaxFileCount(hMpq); - for(i = 0; AddFlags[i] != 0xFFFFFFFF; i++) + for(size_t i = 0; AddFlags[i] != 0xFFFFFFFF; i++) { sprintf(szArchivedName, "FileTest_%02u.exe", (unsigned int)i); - nError = AddLocalFileToMpq(&Logger, hMpq, szArchivedName, szFileName1, AddFlags[i], 0); - if(nError != ERROR_SUCCESS) + dwErrCode = AddLocalFileToMpq(&Logger, hMpq, szArchivedName, szFileName1, AddFlags[i], 0); + if(dwErrCode != ERROR_SUCCESS) break; dwFileCount++; @@ -3940,41 +3760,41 @@ static int TestCreateArchive_FileFlagTest(LPCTSTR szPlainName) } // Delete a file in the middle of the file table - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { Logger.PrintProgress("Removing file %s ...", szMiddleFile); - nError = RemoveMpqFile(&Logger, hMpq, szMiddleFile, ERROR_SUCCESS); + dwErrCode = RemoveMpqFile(&Logger, hMpq, szMiddleFile, ERROR_SUCCESS); dwFileCount--; } // Add one more file - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { - nError = AddLocalFileToMpq(&Logger, hMpq, "FileTest_xx.exe", szFileName1); + dwErrCode = AddLocalFileToMpq(&Logger, hMpq, "FileTest_xx.exe", szFileName1); dwFileCount++; } // Try to decrement max file count. This must succeed - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { Logger.PrintProgress("Attempting to decrement max file count ..."); if(SFileSetMaxFileCount(hMpq, 5)) - nError = Logger.PrintError("Max file count decremented, even if it should fail"); + dwErrCode = Logger.PrintError("Max file count decremented, even if it should fail"); } // Add ZeroSize.txt several times under a different locale - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { - for(i = 0; LocaleIDs[i] != 0xFFFF; i++) + for(size_t i = 0; LocaleIDs[i] != 0xFFFF; i++) { bool bMustSucceed = ((dwFileCount + 2) < dwMaxFileCount); SFileSetLocale(LocaleIDs[i]); - nError = AddLocalFileToMpq(&Logger, hMpq, "ZeroSize_1.txt", szFileName2); - if(nError != ERROR_SUCCESS) + dwErrCode = AddLocalFileToMpq(&Logger, hMpq, "ZeroSize_1.txt", szFileName2); + if(dwErrCode != ERROR_SUCCESS) { if(bMustSucceed == false) - nError = ERROR_SUCCESS; + dwErrCode = ERROR_SUCCESS; break; } @@ -3983,18 +3803,18 @@ static int TestCreateArchive_FileFlagTest(LPCTSTR szPlainName) } // Add ZeroSize.txt again several times under a different locale - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { - for(i = 0; LocaleIDs[i] != 0xFFFF; i++) + for(size_t i = 0; LocaleIDs[i] != 0xFFFF; i++) { bool bMustSucceed = ((dwFileCount + 2) < dwMaxFileCount); SFileSetLocale(LocaleIDs[i]); - nError = AddLocalFileToMpq(&Logger, hMpq, "ZeroSize_2.txt", szFileName2, 0, 0, bMustSucceed); - if(nError != ERROR_SUCCESS) + dwErrCode = AddLocalFileToMpq(&Logger, hMpq, "ZeroSize_2.txt", szFileName2, 0, 0, bMustSucceed); + if(dwErrCode != ERROR_SUCCESS) { if(bMustSucceed == false) - nError = ERROR_SUCCESS; + dwErrCode = ERROR_SUCCESS; break; } @@ -4003,45 +3823,45 @@ static int TestCreateArchive_FileFlagTest(LPCTSTR szPlainName) } // Verify how many files did we add to the MPQ - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { if(dwFileCount + 2 != dwMaxFileCount) { Logger.PrintErrorVa("Number of files added to MPQ was unexpected (expected %u, added %u)", dwFileCount, dwMaxFileCount - 2); - nError = ERROR_FILE_CORRUPT; + dwErrCode = ERROR_FILE_CORRUPT; } } // Test rename function - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { Logger.PrintProgress("Testing rename files ..."); SFileSetLocale(LANG_NEUTRAL); if(!SFileRenameFile(hMpq, "FileTest_08.exe", "FileTest_08a.exe")) - nError = Logger.PrintError("Failed to rename the file"); + dwErrCode = Logger.PrintError("Failed to rename the file"); } - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { if(!SFileRenameFile(hMpq, "FileTest_08a.exe", "FileTest_08.exe")) - nError = Logger.PrintError("Failed to rename the file"); + dwErrCode = Logger.PrintError("Failed to rename the file"); } - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { if(SFileRenameFile(hMpq, "FileTest_10.exe", "FileTest_10a.exe")) { Logger.PrintError("Rename test succeeded even if it shouldn't"); - nError = ERROR_FILE_CORRUPT; + dwErrCode = ERROR_FILE_CORRUPT; } } - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { if(SFileRenameFile(hMpq, "FileTest_10a.exe", "FileTest_10.exe")) { Logger.PrintError("Rename test succeeded even if it shouldn't"); - nError = ERROR_FILE_CORRUPT; + dwErrCode = ERROR_FILE_CORRUPT; } } @@ -4051,9 +3871,9 @@ static int TestCreateArchive_FileFlagTest(LPCTSTR szPlainName) hMpq = NULL; // Try to reopen the archive - if(nError == ERROR_SUCCESS) - nError = OpenExistingArchive(&Logger, szFullPath, 0, NULL); - return nError; + if(dwErrCode == ERROR_SUCCESS) + dwErrCode = OpenExistingArchive(&Logger, szFullPath, 0, NULL); + return dwErrCode; } static int TestCreateArchive_WaveCompressionsTest(LPCTSTR szPlainName, LPCTSTR szWaveFile) @@ -4097,7 +3917,7 @@ static int TestCreateArchive_WaveCompressionsTest(LPCTSTR szPlainName, LPCTSTR s nError = OpenExistingArchiveWithCopy(&Logger, NULL, szPlainName, &hMpq); if(nError == ERROR_SUCCESS) { - SearchArchive(&Logger, hMpq, TEST_FLAG_LOAD_FILES | TEST_FLAG_PLAY_WAVES, &dwFoundFiles, NULL); + SearchArchive(&Logger, hMpq, SEARCH_FLAG_LOAD_FILES | SEARCH_FLAG_PLAY_WAVES, &dwFoundFiles, NULL); SFileCloseArchive(hMpq); } @@ -4263,20 +4083,20 @@ static int TestCreateArchive_BigArchive(LPCTSTR szPlainName) } // "MPQ_2014_v4_Heroes_Replay.MPQ", "AddFile-replay.message.events" -static int TestModifyArchive_ReplaceFile(LPCTSTR szMpqPlainName, LPCTSTR szFileName) +static DWORD TestModifyArchive_ReplaceFile(LPCTSTR szMpqPlainName, LPCTSTR szFileName) { TLogHelper Logger("ModifyTest", szMpqPlainName); HANDLE hMpq = NULL; TCHAR szLocalFileName[MAX_PATH]; char szArchivedName[MAX_PATH]; size_t nOffset = 0; - int nError; + DWORD dwErrCode; // Open an existing archive - nError = OpenExistingArchiveWithCopy(&Logger, szMpqPlainName, szMpqPlainName, &hMpq); + dwErrCode = OpenExistingArchiveWithCopy(&Logger, szMpqPlainName, szMpqPlainName, &hMpq); // Add the given file - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { // Get the name of archived file if(!_tcsnicmp(szFileName, _T("AddFile-"), 8)) @@ -4287,38 +4107,38 @@ static int TestModifyArchive_ReplaceFile(LPCTSTR szMpqPlainName, LPCTSTR szFileN CreateFullPathName(szLocalFileName, _countof(szLocalFileName), szMpqSubDir, szFileName); // Add the file to MPQ - nError = AddLocalFileToMpq(&Logger, hMpq, - szArchivedName, - szLocalFileName, - MPQ_FILE_REPLACEEXISTING | MPQ_FILE_COMPRESS | MPQ_FILE_SINGLE_UNIT, - MPQ_COMPRESSION_ZLIB, - true); + dwErrCode = AddLocalFileToMpq(&Logger, hMpq, + szArchivedName, + szLocalFileName, + MPQ_FILE_REPLACEEXISTING | MPQ_FILE_COMPRESS | MPQ_FILE_SINGLE_UNIT, + MPQ_COMPRESSION_ZLIB, + true); } // Reopen the MPQ and compact it - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { // Compact the archive Logger.PrintProgress("Compacting archive %s ...", szMpqPlainName); if(!SFileSetCompactCallback(hMpq, CompactCallback, &Logger)) - nError = Logger.PrintError(_T("Failed to compact archive %s"), szMpqPlainName); + dwErrCode = Logger.PrintError(_T("Failed to compact archive %s"), szMpqPlainName); if(!SFileCompactArchive(hMpq, NULL, 0)) - nError = GetLastError(); + dwErrCode = GetLastError(); SFileCloseArchive(hMpq); } // Try to open the archive again - if(nError == ERROR_SUCCESS) + if(dwErrCode == ERROR_SUCCESS) { CreateFullPathName(szLocalFileName, _countof(szLocalFileName), NULL, szMpqPlainName); - nError = OpenExistingArchive(&Logger, szLocalFileName, 0, &hMpq); - if(nError == ERROR_SUCCESS) + dwErrCode = OpenExistingArchive(&Logger, szLocalFileName, 0, &hMpq); + if(dwErrCode == ERROR_SUCCESS) SFileCloseArchive(hMpq); } - return nError; + return dwErrCode; } //----------------------------------------------------------------------------- @@ -4349,28 +4169,53 @@ static const TEST_INFO TestList_MasterMirror[] = static const TEST_INFO Test_Mpqs[] = { - {_T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"), NULL, TEST_OPEN_COMPARE_TWO_FILES, "music\\dintro.wav", "File00000023.xxx"}, - {_T("MPQ_2016_v1_D2XP_IX86_1xx_114a.mpq"), NULL, TEST_LOAD_FILE_CHECK_CRC, "waitingroombkgd.dc6" }, // The update MPQ from Diablo II (patch 2016) - {_T("MPQ_2018_v1_icon_error.w3m"), NULL, TEST_LOAD_FILE_CHECK_CRC, "file00000002.blp" }, - - {_T("MPQ_1997_v1_Diablo1_STANDARD.SNP"), _T("ListFile_Blizzard.txt"), TEST_OPEN_MPQ }, // Open a file whose archive's (signature) file has flags = 0x90000000 - {_T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"), NULL, TEST_OPEN_MPQ | TEST_SETPOS, "music\\dtowne.wav" }, // Test the SFileSetFilePointer operations - {_T("MPQ_2012_v2_EmptyMpq.MPQ") }, // Open an empty archive (found in WoW cache - it's just a header) - {_T("MPQ_2013_v4_EmptyMpq.MPQ") }, // Open an empty archive (created artificially - it's just a header) - {_T("MPQ_2013_v4_patch-base-16357.MPQ") }, // Open an empty archive (found in WoW cache - it's just a header) - {_T("MPQ_2011_v4_InvalidHetEntryCount.MPQ") }, // Open an empty archive (A buggy MPQ with invalid HET entry count) - {_T("MPQ_2002_v1_BlockTableCut.MPQ") }, // Open a truncated archive - - // TODO: Doesn't work anymore - //{_T("MPQ_2010_v2_HasUserData.s2ma") }, // Open a MPQ that actually has user data - - {_T("MPQ_2014_v1_AttributesOneEntryLess.w3x") }, // Open an Warcraft III map whose "(attributes)" file has (BlockTableSize-1) entries - {_T("MPQ_2020_v1_AHF04patch.mix") }, // Open a MIX file - {_T("MPQ_2010_v3_expansion-locale-frFR.MPQ") }, // Open a MPQ archive v 3.0 - {_T("mpqe-file://MPQ_2011_v2_EncryptedMpq.MPQE") }, // Open an encrypted archive from Starcraft II installer - {_T("MPx_2013_v1_LongwuOnline.mpk") }, // Open a MPK archive from Longwu online - {_T("MPx_2013_v1_WarOfTheImmortals.sqp"), _T("ListFile_WarOfTheImmortals.txt") }, // Open a SQP archive from War of the Immortals - {_T("part-file://MPQ_2010_v2_HashTableCompressed.MPQ.part") }, // Open a partial MPQ with compressed hash table + // Correct or damaged archives + {_T("MPQ_1997_v1_Diablo1_DIABDAT.MPQ"), NULL, 0, "music\\dintro.wav", "File00000023.xxx"}, + {_T("MPQ_2016_v1_D2XP_IX86_1xx_114a.mpq"), NULL, 0, "waitingroombkgd.dc6"}, // Update MPQ from Diablo II (patch 2016) + {_T("MPQ_2018_v1_icon_error.w3m"), NULL, 0, "file00000002.blp"}, + {_T("MPQ_1997_v1_Diablo1_STANDARD.SNP"), _T("ListFile_Blizzard.txt")}, // File whose archive's (signature) file has flags = 0x90000000 + {_T("MPQ_2012_v2_EmptyMpq.MPQ") }, // Empty archive (found in WoW cache - it's just a header) + {_T("MPQ_2013_v4_EmptyMpq.MPQ") }, // Empty archive (created artificially - it's just a header) + {_T("MPQ_2013_v4_patch-base-16357.MPQ") }, // Empty archive (found in WoW cache - it's just a header) + {_T("MPQ_2011_v4_InvalidHetEntryCount.MPQ") }, // Empty archive (A buggy MPQ with invalid HET entry count) + {_T("MPQ_2002_v1_BlockTableCut.MPQ") }, // Truncated archive + {_T("MPQ_2010_v2_HasUserData.s2ma") }, // MPQ that actually has user data + {_T("MPQ_2014_v1_AttributesOneEntryLess.w3x") }, // Warcraft III map whose "(attributes)" file has (BlockTableSize-1) entries + {_T("MPQ_2020_v1_AHF04patch.mix") }, // MIX file + {_T("MPQ_2010_v3_expansion-locale-frFR.MPQ") }, // MPQ archive v 3.0 + {_T("mpqe-file://MPQ_2011_v2_EncryptedMpq.MPQE") }, // Encrypted archive from Starcraft II installer + {_T("MPx_2013_v1_LongwuOnline.mpk") }, // MPK archive from Longwu online + {_T("MPx_2013_v1_WarOfTheImmortals.sqp"), _T("ListFile_WarOfTheImmortals.txt") }, // SQP archive from War of the Immortals + {_T("part-file://MPQ_2010_v2_HashTableCompressed.MPQ.part") }, // Partial MPQ with compressed hash table + {_T("blk4-file://streaming/model.MPQ.0")}, // Archive that is merged with multiple files + {_T("MPQ_2002_v1_ProtectedMap_InvalidUserData.w3x")}, + {_T("MPQ_2002_v1_ProtectedMap_InvalidMpqFormat.w3x")}, + {_T("MPQ_2002_v1_ProtectedMap_Spazzler.w3x")}, // Warcraft III map locked by the Spazzler protector + {_T("MPQ_2014_v1_ProtectedMap_Spazzler2.w3x")}, // Warcraft III map locked by the Spazzler protector + {_T("MPQ_2014_v1_ProtectedMap_Spazzler3.w3x")}, // Warcraft III map locked by the Spazzler protector + {_T("MPQ_2002_v1_ProtectedMap_BOBA.w3m")}, // Warcraft III map locked by the BOBA protector + {_T("MPQ_2015_v1_ProtectedMap_KangTooJee.w3x")}, + {_T("MPQ_2015_v1_ProtectedMap_Somj2hM16.w3x")}, + {_T("MPQ_2015_v1_ProtectedMap_Spazy.w3x")}, // Warcraft III map locked by Spazy protector + {_T("MPQ_2015_v1_MessListFile.mpq")}, + {_T("MPQ_2016_v1_ProtectedMap_TableSizeOverflow.w3x")}, + {_T("MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x")}, + {_T("MPQ_2016_v1_ProtectedMap_Somj2.w3x")}, // Something like Somj 2.0 + {_T("MPQ_2016_v1_WME4_4.w3x")}, // Protector from China (2016-05-27) + {_T("MPQ_2016_v1_SP_(4)Adrenaline.w3x")}, + {_T("MPQ_2016_v1_ProtectedMap_1.4.w3x")}, + {_T("MPQ_2016_v1_KoreanFile.w3m")}, + {_T("MPQ_2017_v1_Eden_RPG_S2_2.5J.w3x")}, // Load map protected by PG1.11.973 + {_T("MPQ_2017_v1_BigDummyFiles.w3x")}, + {_T("MPQ_2017_v1_TildeInFileName.mpq")}, + {_T("MPQ_2018_v1_EWIX_v8_7.w3x"), NULL, 0, "BlueCrystal.mdx"}, + {_T("MPQ_2020_v4_FakeMpqHeaders.SC2Mod")}, // Archive that has two fake headers before the real one + {_T("MPQ_2020_v4_NP_Protect_1.s2ma")}, // SC2 map that is protected by the NP_Protect + {_T("MPQ_2020_v4_NP_Protect_2.s2ma")}, // SC2 map that is protected by the NP_Protect + + // Protected archives + {_T("MPQ_2015_v1_flem1.w3x"), NULL, TEST_FLAG_PROTECTED | 20, "1c4c13e627658c473e84d94371e31f37"}, + {_T("MPQ_2002_v1_ProtectedMap_HashTable_FakeValid.w3x"), NULL, TEST_FLAG_PROTECTED | 114, "5250975ed917375fc6540d7be436d4de"}, }; //----------------------------------------------------------------------------- @@ -4389,89 +4234,60 @@ int _tmain(int argc, TCHAR * argv[]) dwErrCode = InitializeMpqDirectory(argv, argc); // - // Open all files from the command line + // Tests on a local listfile // - for(int i = 1; i < argc; i++) + if(dwErrCode == ERROR_SUCCESS) { - //SFILE_FIND_DATA sf; - HANDLE hFile = NULL; - HANDLE hMpq = NULL; - BYTE Buffer[0x40]; - - if(SFileOpenArchive(argv[i], 0, 0, &hMpq)) - { - if(SFileOpenFileEx(hMpq, "koKR.SC2Data\\LocalizedData\\ObjectStrings.txt", 0, &hFile)) - { - SFileReadFile(hFile, Buffer, sizeof(Buffer), NULL, NULL); - SFileCloseFile(hFile); - } - - //if((hFind = SFileFindFirstFile(hMpq, "*", &sf, NULL)) != NULL) - //{ - // SFileFindNextFile(hFind, &sf); - // SFileFindClose(hFind); - //} - - SFileCloseArchive(hMpq); - } + dwErrCode = TestOnLocalListFile(_T("ListFile_Blizzard.txt")); } // - // Search all testing archives and verify their SHA1 hash - // - - //if(dwErrCode == ERROR_SUCCESS) - //{ - // dwErrCode = FindFiles(ForEachFile_VerifyFileChecksum, szMpqSubDir); - //} - - // - // Test file stream operations + // Open all files from the command line // - //if(dwErrCode == ERROR_SUCCESS) - //{ - // for(size_t i = 0; i < _countof(TestList_StreamOps); i++) - // { - // dwErrCode = TestFileStreamOperations(TestList_StreamOps[i].szMpqName1, TestList_StreamOps[i].dwFlags); - // if(dwErrCode != ERROR_SUCCESS) - // break; - // } - //} + for(int i = 1; i < argc; i++) + { + ForEachFile_OpenArchive(argv[i]); + } // - // Test master-mirror reading operations + // Search all testing archives and verify their SHA1 hash // - //if(dwErrCode == ERROR_SUCCESS) - //{ - // for(size_t i = 0; i < _countof(TestList_MasterMirror); i++) - // { - // dwErrCode = TestReadFile_MasterMirror(TestList_MasterMirror[i].szMpqName1, - // TestList_MasterMirror[i].szMpqName2, - // TestList_MasterMirror[i].dwFlags != 0); - // if(dwErrCode != ERROR_SUCCESS) - // break; - // } - //} + if(dwErrCode == ERROR_SUCCESS) + { + dwErrCode = FindFiles(ForEachFile_VerifyFileChecksum, szMpqSubDir); + } // - // Search in listfile + // Test file stream operations // if(dwErrCode == ERROR_SUCCESS) { - dwErrCode = TestSearchListFile(_T("ListFile_Blizzard.txt")); + for(size_t i = 0; i < _countof(TestList_StreamOps); i++) + { + dwErrCode = TestFileStreamOperations(TestList_StreamOps[i].szMpqName1, TestList_StreamOps[i].dwFlags); + if(dwErrCode != ERROR_SUCCESS) + break; + } } // - // Test opening local file with SFileOpenFileEx + // Test master-mirror reading operations // if(dwErrCode == ERROR_SUCCESS) { - dwErrCode = TestOpenLocalFile(_T("ListFile_Blizzard.txt")); + for(size_t i = 0; i < _countof(TestList_MasterMirror); i++) + { + dwErrCode = TestReadFile_MasterMirror(TestList_MasterMirror[i].szMpqName1, + TestList_MasterMirror[i].szMpqName2, + TestList_MasterMirror[i].dwFlags != 0); + if(dwErrCode != ERROR_SUCCESS) + break; + } } // @@ -4492,96 +4308,10 @@ int _tmain(int argc, TCHAR * argv[]) } } - // Open an protected map - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive_ProtectedMap(_T("MPQ_2015_v1_flem1.w3x"), NULL, 20, "1c4c13e627658c473e84d94371e31f37"); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive_ProtectedMap(_T("MPQ_2002_v1_ProtectedMap_HashTable_FakeValid.w3x"), NULL, 114, "5250975ed917375fc6540d7be436d4de"); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2002_v1_ProtectedMap_InvalidUserData.w3x")); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2002_v1_ProtectedMap_InvalidMpqFormat.w3x")); - - // Open an Warcraft III map locked by the Spazzler protector - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2002_v1_ProtectedMap_Spazzler.w3x")); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2014_v1_ProtectedMap_Spazzler2.w3x")); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2014_v1_ProtectedMap_Spazzler3.w3x")); - - // Open an Warcraft III map locked by the BOBA protector - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2002_v1_ProtectedMap_BOBA.w3m")); - - // Open an Warcraft III map locked by a protector - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2015_v1_ProtectedMap_KangTooJee.w3x")); - - // Open an Warcraft III map locked by a protector - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2015_v1_ProtectedMap_Somj2hM16.w3x")); - - // Open an Warcraft III map locked by Spazy protector - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2015_v1_ProtectedMap_Spazy.w3x")); - - // Open an Warcraft III map locked by Spazy protector - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2015_v1_MessListFile.mpq")); - - // Open another protected map - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2016_v1_ProtectedMap_TableSizeOverflow.w3x")); - - // Open another protected map - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x")); - - // Something like Somj 2.0 - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2016_v1_ProtectedMap_Somj2.w3x")); - - // Protector from China (2016-05-27) - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2016_v1_WME4_4.w3x")); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2016_v1_SP_(4)Adrenaline.w3x")); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2016_v1_ProtectedMap_1.4.w3x")); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2016_v1_KoreanFile.w3m")); - - // Load map protected by PG1.11.973 - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2017_v1_Eden_RPG_S2_2.5J.w3x")); - - // Load map protected by PG1.11.973 - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2017_v1_BigDummyFiles.w3x"), NULL, "1.blp"); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2017_v1_TildeInFileName.mpq"), NULL, "1.blp"); - - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2018_v1_EWIX_v8_7.w3x"), NULL, "BlueCrystal.mdx"); - // Open the multi-file archive with wrong prefix to see how StormLib deals with it if(dwErrCode == ERROR_SUCCESS) dwErrCode = TestOpenArchive_WillFail(_T("flat-file://streaming/model.MPQ.0")); - // Open an archive that is merged with multiple files - if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("blk4-file://streaming/model.MPQ.0"), NULL, NULL, true); - // Open every MPQ that we have in the storage if(dwErrCode == ERROR_SUCCESS) dwErrCode = FindFiles(ForEachFile_OpenArchive, NULL); @@ -4590,18 +4320,6 @@ int _tmain(int argc, TCHAR * argv[]) if(dwErrCode == ERROR_SUCCESS) dwErrCode = TestOpenArchive_Corrupt(_T("MPQ_2013_vX_Battle.net.MPQ")); - // Test on an archive that has two fake headers before the real one - if (dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2020_v4_FakeMpqHeaders.SC2Mod")); - - // Test on an SC2 map that is protected by the NP_Protect - if (dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2020_v4_NP_Protect_1.s2ma")); - - // Test on an SC2 map that is protected by the NP_Protect - if (dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive(_T("MPQ_2020_v4_NP_Protect_2.s2ma")); - // Open a patched archive if(dwErrCode == ERROR_SUCCESS) dwErrCode = TestOpenArchive_Patched(PatchList_StarCraft, "music\\terran1.wav", 0); @@ -4632,7 +4350,7 @@ int _tmain(int argc, TCHAR * argv[]) // Open a patched archive if(dwErrCode == ERROR_SUCCESS) - dwErrCode = TestOpenArchive_Patched(PatchList_SC2_32283_enGB, "LocalizedData\\GameHotkeys.txt", 0, true); + dwErrCode = TestOpenArchive_Patched(PatchList_SC2_32283_enGB, "Assets\\Textures\\startupimage.dds", 0, true); // Open a patched archive where the "StreamingBuckets.txt" in the patch doesn't contain MPQ_FILE_PATCH_FILE if(dwErrCode == ERROR_SUCCESS) diff --git a/test/TLogHelper.cpp b/test/TLogHelper.cpp index 9bf4f6d..fca85ec 100644 --- a/test/TLogHelper.cpp +++ b/test/TLogHelper.cpp @@ -30,11 +30,11 @@ class TLogHelper #endif // defined(UNICODE) || defined(UNICODE) // ANSI functions - int PrintWithClreol(const char * szFormat, va_list argList, bool bPrintPrefix, bool bPrintLastError, bool bPrintEndOfLine); - void PrintProgress(const char * szFormat, ...); - void PrintMessage(const char * szFormat, ...); - int PrintErrorVa(const char * szFormat, ...); - int PrintError(const char * szFormat, const char * szFileName = NULL); + DWORD PrintWithClreol(const char * szFormat, va_list argList, bool bPrintPrefix, bool bPrintLastError, bool bPrintEndOfLine); + void PrintProgress(const char * szFormat, ...); + void PrintMessage(const char * szFormat, ...); + DWORD PrintErrorVa(const char * szFormat, ...); + DWORD PrintError(const char * szFormat, const char * szFileName = NULL); const char * UserString; unsigned int UserCount; @@ -140,7 +140,7 @@ TLogHelper::~TLogHelper() #if defined(_MSC_VER) && defined(_DEBUG) if(_CrtDumpMemoryLeaks()) { - PrintMessage("Memory leak detected after %s\n.", szSaveMainTitle); + PrintMessage(_T("Memory leak(s) detected after %s.\n"), szSaveMainTitle); } #endif // _MSC_VER } @@ -257,7 +257,7 @@ int TLogHelper::PrintError(const TCHAR * szFormat, const TCHAR * szFileName) //----------------------------------------------------------------------------- // ANSI functions -int TLogHelper::PrintWithClreol(const char * szFormat, va_list argList, bool bPrintPrefix, bool bPrintLastError, bool bPrintEndOfLine) +DWORD TLogHelper::PrintWithClreol(const char * szFormat, va_list argList, bool bPrintPrefix, bool bPrintLastError, bool bPrintEndOfLine) { char szFormatBuff[0x200]; char szMessage[0x200]; @@ -265,7 +265,7 @@ int TLogHelper::PrintWithClreol(const char * szFormat, va_list argList, bool bPr int nRemainingWidth; int nConsoleWidth = GetConsoleWidth(); int nLength = 0; - int nError = GetLastError(); + DWORD dwErrCode = GetLastError(); // Always start the buffer with '\r' *szBuffer++ = '\r'; @@ -292,7 +292,7 @@ int TLogHelper::PrintWithClreol(const char * szFormat, va_list argList, bool bPr // Append the last error if(bPrintLastError) { - nLength = sprintf(szBuffer, " (error code: %u)", nError); + nLength = sprintf(szBuffer, " (error code: %u)", dwErrCode); szBuffer += nLength; } @@ -322,7 +322,7 @@ int TLogHelper::PrintWithClreol(const char * szFormat, va_list argList, bool bPr // Spit out the text in one single printf printf("%s", szMessage); - return nError; + return dwErrCode; } void TLogHelper::PrintProgress(const char * szFormat, ...) @@ -343,19 +343,19 @@ void TLogHelper::PrintMessage(const char * szFormat, ...) va_end(argList); } -int TLogHelper::PrintErrorVa(const char * szFormat, ...) +DWORD TLogHelper::PrintErrorVa(const char * szFormat, ...) { va_list argList; - int nResult; + DWORD dwErrCode; va_start(argList, szFormat); - nResult = PrintWithClreol(szFormat, argList, true, true, true); + dwErrCode = PrintWithClreol(szFormat, argList, true, true, true); va_end(argList); - return nResult; + return dwErrCode; } -int TLogHelper::PrintError(const char * szFormat, const char * szFileName) +DWORD TLogHelper::PrintError(const char * szFormat, const char * szFileName) { return PrintErrorVa(szFormat, szFileName); } -- cgit v1.2.3