diff options
author | Ladislav Zezula <ladislav.zezula@avg.com> | 2014-12-02 09:38:34 +0100 |
---|---|---|
committer | Ladislav Zezula <ladislav.zezula@avg.com> | 2014-12-02 09:38:34 +0100 |
commit | 3e594190e4a89252755907a313914a96b6abb1c8 (patch) | |
tree | dcfd8cb1b143d8728a627b92f0fa71472f3b88ef | |
parent | 495b2ab3d42db3f0d484e76eba15c7da9148d53a (diff) |
+ Files with zero size are now processed properly during archive compacting
+ Fixed few memory leaks
-rw-r--r-- | src/SFileAddFile.cpp | 9 | ||||
-rw-r--r-- | src/SFileCompactArchive.cpp | 91 | ||||
-rw-r--r-- | src/SFileReadFile.cpp | 173 | ||||
-rw-r--r-- | test/StormTest.cpp | 56 | ||||
-rw-r--r-- | test/TLogHelper.cpp | 38 |
5 files changed, 204 insertions, 163 deletions
diff --git a/src/SFileAddFile.cpp b/src/SFileAddFile.cpp index f941141..5997c1b 100644 --- a/src/SFileAddFile.cpp +++ b/src/SFileAddFile.cpp @@ -479,11 +479,14 @@ int SFileAddFile_Init( // Call the callback, if needed if(ha->pfnAddFileCB != NULL) ha->pfnAddFileCB(ha->pvAddFileUserData, 0, hf->dwDataSize, false); + hf->nAddFileError = ERROR_SUCCESS; } - // Store the error code from Add File operation - if(hf != NULL) - hf->nAddFileError = nError; + // Fre the file handle if failed + if(nError != ERROR_SUCCESS && hf != NULL) + FreeFileHandle(hf); + + // Give the handle to the caller *phf = hf; return nError; } diff --git a/src/SFileCompactArchive.cpp b/src/SFileCompactArchive.cpp index 3b2ba83..238873c 100644 --- a/src/SFileCompactArchive.cpp +++ b/src/SFileCompactArchive.cpp @@ -173,11 +173,11 @@ static int CopyNonMpqData( static int CopyMpqFileSectors( TMPQArchive * ha, TMPQFile * hf, - TFileStream * pNewStream) + TFileStream * pNewStream, + ULONGLONG MpqFilePos) // MPQ file position in the new archive { TFileEntry * pFileEntry = hf->pFileEntry; ULONGLONG RawFilePos; // Used for calculating sector offset in the old MPQ archive - ULONGLONG MpqFilePos; // MPQ file position in the new archive DWORD dwBytesToCopy = pFileEntry->dwCmpSize; DWORD dwPatchSize = 0; // Size of patch header DWORD dwFileKey1 = 0; // File key used for decryption @@ -185,10 +185,6 @@ static int CopyMpqFileSectors( DWORD dwCmpSize = 0; // Compressed file size, including patch header int nError = ERROR_SUCCESS; - // Remember the position in the destination file - FileStream_GetPos(pNewStream, &MpqFilePos); - MpqFilePos -= ha->MpqPos; - // Resolve decryption keys. Note that the file key given // in the TMPQFile structure also includes the key adjustment if(nError == ERROR_SUCCESS && (pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)) @@ -374,7 +370,7 @@ static int CopyMpqFileSectors( ha->pHeader->dwRawChunkSize); } - // Update file position in the block table + // Verify the number of bytes written if(nError == ERROR_SUCCESS) { // At this point, number of bytes written should be exactly @@ -391,12 +387,7 @@ static int CopyMpqFileSectors( // into compressed size // - if(dwCmpSize <= pFileEntry->dwCmpSize && pFileEntry->dwCmpSize <= dwCmpSize + dwPatchSize) - { - // Note: DO NOT update the compressed size in the file entry, no matter how bad it is. - pFileEntry->ByteOffset = MpqFilePos; - } - else + if(!(dwCmpSize <= pFileEntry->dwCmpSize && pFileEntry->dwCmpSize <= dwCmpSize + dwPatchSize)) { nError = ERROR_FILE_CORRUPT; assert(false); @@ -411,6 +402,7 @@ static int CopyMpqFiles(TMPQArchive * ha, LPDWORD pFileKeys, TFileStream * pNewS TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; TFileEntry * pFileEntry; TMPQFile * hf = NULL; + ULONGLONG MpqFilePos; int nError = ERROR_SUCCESS; // Walk through all files and write them to the destination MPQ archive @@ -418,49 +410,60 @@ static int CopyMpqFiles(TMPQArchive * ha, LPDWORD pFileKeys, TFileStream * pNewS { // Copy all the file sectors // Only do that when the file has nonzero size - if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) && pFileEntry->dwFileSize != 0) + if((pFileEntry->dwFlags & MPQ_FILE_EXISTS)) { - // Allocate structure for the MPQ file - hf = CreateFileHandle(ha, pFileEntry); - if(hf == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - // Set the file decryption key - hf->dwFileKey = pFileKeys[pFileEntry - ha->pFileTable]; + // Query the position where the destination file will be + FileStream_GetPos(pNewStream, &MpqFilePos); + MpqFilePos = MpqFilePos - ha->MpqPos; - // If the file is a patch file, load the patch header - if(pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) + // Perform file copy ONLY if the file has nonzero size + if(pFileEntry->dwFileSize != 0) { - nError = AllocatePatchInfo(hf, true); + // Allocate structure for the MPQ file + hf = CreateFileHandle(ha, pFileEntry); + if(hf == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Set the file decryption key + hf->dwFileKey = pFileKeys[pFileEntry - ha->pFileTable]; + + // If the file is a patch file, load the patch header + if(pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) + { + nError = AllocatePatchInfo(hf, true); + if(nError != ERROR_SUCCESS) + break; + } + + // Allocate buffers for file sector and sector offset table + nError = AllocateSectorBuffer(hf); if(nError != ERROR_SUCCESS) break; - } - // Allocate buffers for file sector and sector offset table - nError = AllocateSectorBuffer(hf); - if(nError != ERROR_SUCCESS) - break; + // Also allocate sector offset table and sector checksum table + nError = AllocateSectorOffsets(hf, true); + if(nError != ERROR_SUCCESS) + break; - // Also allocate sector offset table and sector checksum table - nError = AllocateSectorOffsets(hf, true); - if(nError != ERROR_SUCCESS) - break; + // Also load sector checksums, if any + if(pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC) + { + nError = AllocateSectorChecksums(hf, false); + if(nError != ERROR_SUCCESS) + break; + } - // Also load sector checksums, if any - if(pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC) - { - nError = AllocateSectorChecksums(hf, false); + // Copy all file sectors + nError = CopyMpqFileSectors(ha, hf, pNewStream, MpqFilePos); if(nError != ERROR_SUCCESS) break; - } - // Copy all file sectors - nError = CopyMpqFileSectors(ha, hf, pNewStream); - if(nError != ERROR_SUCCESS) - break; + // Free buffers. This also sets "hf" to NULL. + FreeFileHandle(hf); + } - // Free buffers. This also sets "hf" to NULL. - FreeFileHandle(hf); + // Note: DO NOT update the compressed size in the file entry, no matter how bad it is. + pFileEntry->ByteOffset = MpqFilePos; } } diff --git a/src/SFileReadFile.cpp b/src/SFileReadFile.cpp index 124f0b3..6884f55 100644 --- a/src/SFileReadFile.cpp +++ b/src/SFileReadFile.cpp @@ -95,111 +95,114 @@ static int ReadMpqSectors(TMPQFile * hf, LPBYTE pbBuffer, DWORD dwByteOffset, DW CalculateRawSectorOffset(RawFilePos, hf, dwRawSectorOffset); // Set file pointer and read all required sectors - if(!FileStream_Read(ha->pStream, &RawFilePos, pbInSector, dwRawBytesToRead)) - return GetLastError(); - dwBytesRead = 0; - - // Now we have to decrypt and decompress all file sectors that have been loaded - for(DWORD i = 0; i < dwSectorsToRead; i++) + if(FileStream_Read(ha->pStream, &RawFilePos, pbInSector, dwRawBytesToRead)) { - DWORD dwRawBytesInThisSector = ha->dwSectorSize; - DWORD dwBytesInThisSector = ha->dwSectorSize; - DWORD dwIndex = dwSectorIndex + i; - - // If there is not enough bytes in the last sector, - // cut the number of bytes in this sector - if(dwRawBytesInThisSector > dwBytesToRead) - dwRawBytesInThisSector = dwBytesToRead; - if(dwBytesInThisSector > dwBytesToRead) - dwBytesInThisSector = dwBytesToRead; - - // If the file is compressed, we have to adjust the raw sector size - if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) - dwRawBytesInThisSector = hf->SectorOffsets[dwIndex + 1] - hf->SectorOffsets[dwIndex]; - - // If the file is encrypted, we have to decrypt the sector - if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) + // Now we have to decrypt and decompress all file sectors that have been loaded + for(DWORD i = 0; i < dwSectorsToRead; i++) { - BSWAP_ARRAY32_UNSIGNED(pbInSector, dwRawBytesInThisSector); - - // If we don't know the key, try to detect it by file content - if(hf->dwFileKey == 0) + DWORD dwRawBytesInThisSector = ha->dwSectorSize; + DWORD dwBytesInThisSector = ha->dwSectorSize; + DWORD dwIndex = dwSectorIndex + i; + + // If there is not enough bytes in the last sector, + // cut the number of bytes in this sector + if(dwRawBytesInThisSector > dwBytesToRead) + dwRawBytesInThisSector = dwBytesToRead; + if(dwBytesInThisSector > dwBytesToRead) + dwBytesInThisSector = dwBytesToRead; + + // If the file is compressed, we have to adjust the raw sector size + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) + dwRawBytesInThisSector = hf->SectorOffsets[dwIndex + 1] - hf->SectorOffsets[dwIndex]; + + // If the file is encrypted, we have to decrypt the sector + if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) { - hf->dwFileKey = DetectFileKeyByContent(pbInSector, dwBytesInThisSector, hf->dwDataSize); + BSWAP_ARRAY32_UNSIGNED(pbInSector, dwRawBytesInThisSector); + + // If we don't know the key, try to detect it by file content if(hf->dwFileKey == 0) { - nError = ERROR_UNKNOWN_FILE_KEY; - break; + hf->dwFileKey = DetectFileKeyByContent(pbInSector, dwBytesInThisSector, hf->dwDataSize); + if(hf->dwFileKey == 0) + { + nError = ERROR_UNKNOWN_FILE_KEY; + break; + } } + + DecryptMpqBlock(pbInSector, dwRawBytesInThisSector, hf->dwFileKey + dwIndex); + BSWAP_ARRAY32_UNSIGNED(pbInSector, dwRawBytesInThisSector); } - DecryptMpqBlock(pbInSector, dwRawBytesInThisSector, hf->dwFileKey + dwIndex); - BSWAP_ARRAY32_UNSIGNED(pbInSector, dwRawBytesInThisSector); - } + // If the file has sector CRC check turned on, perform it + if(hf->bCheckSectorCRCs && hf->SectorChksums != NULL) + { + DWORD dwAdlerExpected = hf->SectorChksums[dwIndex]; + DWORD dwAdlerValue = 0; - // If the file has sector CRC check turned on, perform it - if(hf->bCheckSectorCRCs && hf->SectorChksums != NULL) - { - DWORD dwAdlerExpected = hf->SectorChksums[dwIndex]; - DWORD dwAdlerValue = 0; + // We can only check sector CRC when it's not zero + // Neither can we check it if it's 0xFFFFFFFF. + if(dwAdlerExpected != 0 && dwAdlerExpected != 0xFFFFFFFF) + { + dwAdlerValue = adler32(0, pbInSector, dwRawBytesInThisSector); + if(dwAdlerValue != dwAdlerExpected) + { + nError = ERROR_CHECKSUM_ERROR; + break; + } + } + } - // We can only check sector CRC when it's not zero - // Neither can we check it if it's 0xFFFFFFFF. - if(dwAdlerExpected != 0 && dwAdlerExpected != 0xFFFFFFFF) + // If the sector is really compressed, decompress it. + // WARNING : Some sectors may not be compressed, it can be determined only + // by comparing uncompressed and compressed size !!! + if(dwRawBytesInThisSector < dwBytesInThisSector) { - dwAdlerValue = adler32(0, pbInSector, dwRawBytesInThisSector); - if(dwAdlerValue != dwAdlerExpected) + int cbOutSector = dwBytesInThisSector; + int cbInSector = dwRawBytesInThisSector; + int nResult = 0; + + // Is the file compressed by Blizzard's multiple compression ? + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS) { - nError = ERROR_CHECKSUM_ERROR; - break; + if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2) + nResult = SCompDecompress2(pbOutSector, &cbOutSector, pbInSector, cbInSector); + else + nResult = SCompDecompress(pbOutSector, &cbOutSector, pbInSector, cbInSector); } - } - } - // If the sector is really compressed, decompress it. - // WARNING : Some sectors may not be compressed, it can be determined only - // by comparing uncompressed and compressed size !!! - if(dwRawBytesInThisSector < dwBytesInThisSector) - { - int cbOutSector = dwBytesInThisSector; - int cbInSector = dwRawBytesInThisSector; - int nResult = 0; + // Is the file compressed by PKWARE Data Compression Library ? + else if(pFileEntry->dwFlags & MPQ_FILE_IMPLODE) + { + nResult = SCompExplode(pbOutSector, &cbOutSector, pbInSector, cbInSector); + } - // Is the file compressed by Blizzard's multiple compression ? - if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS) - { - if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2) - nResult = SCompDecompress2(pbOutSector, &cbOutSector, pbInSector, cbInSector); - else - nResult = SCompDecompress(pbOutSector, &cbOutSector, pbInSector, cbInSector); + // Did the decompression fail ? + if(nResult == 0) + { + nError = ERROR_FILE_CORRUPT; + break; + } } - - // Is the file compressed by PKWARE Data Compression Library ? - else if(pFileEntry->dwFlags & MPQ_FILE_IMPLODE) + else { - nResult = SCompExplode(pbOutSector, &cbOutSector, pbInSector, cbInSector); + if(pbOutSector != pbInSector) + memcpy(pbOutSector, pbInSector, dwBytesInThisSector); } - // Did the decompression fail ? - if(nResult == 0) - { - nError = ERROR_FILE_CORRUPT; - break; - } + // Move pointers + dwBytesToRead -= dwBytesInThisSector; + dwByteOffset += dwBytesInThisSector; + dwBytesRead += dwBytesInThisSector; + pbOutSector += dwBytesInThisSector; + pbInSector += dwRawBytesInThisSector; + dwSectorsDone++; } - else - { - if(pbOutSector != pbInSector) - memcpy(pbOutSector, pbInSector, dwBytesInThisSector); - } - - // Move pointers - dwBytesToRead -= dwBytesInThisSector; - dwByteOffset += dwBytesInThisSector; - dwBytesRead += dwBytesInThisSector; - pbOutSector += dwBytesInThisSector; - pbInSector += dwRawBytesInThisSector; - dwSectorsDone++; + } + else + { + nError = GetLastError(); } // Free all used buffers diff --git a/test/StormTest.cpp b/test/StormTest.cpp index a489ecc..c6ae959 100644 --- a/test/StormTest.cpp +++ b/test/StormTest.cpp @@ -2466,7 +2466,7 @@ static int TestOpenArchive_ReadOnly(const char * szPlainName, bool bReadOnly) static int TestOpenArchive_GetFileInfo(const char * szPlainName1, const char * szPlainName4) { - TLogHelper Logger("GetFileInfoTest"); + TLogHelper Logger("GetFileInfoTest", szPlainName1, szPlainName4); HANDLE hFile; HANDLE hMpq4; HANDLE hMpq1; @@ -3342,7 +3342,7 @@ static int TestCreateArchive_IncMaxFileCount(const char * szPlainName) nError = AddFileToMpq(&Logger, hMpq, szFileName, szFileData); if(nError != ERROR_SUCCESS) { - // Increment the ma file count by one + // Increment the max file count by one dwMaxFileCount = SFileGetMaxFileCount(hMpq) + 1; Logger.PrintProgress("Increasing max file count to %u ...", dwMaxFileCount); SFileSetMaxFileCount(hMpq, dwMaxFileCount); @@ -3755,18 +3755,17 @@ static int TestCreateArchive_BigArchive(const char * szPlainName) } // "MPQ_2014_v4_Heroes_Replay.MPQ", "AddFile-replay.message.events" -static int TestModifyArchive_ReplaceFile(const char * szPlainName, const char * szFileName) +static int TestModifyArchive_ReplaceFile(const char * szMpqPlainName, const char * szFileName) { TLogHelper Logger("ModifyTest"); HANDLE hMpq = NULL; - HANDLE hFile = NULL; const char * szArchivedName; char szLocalFileName[MAX_PATH]; size_t nOffset = 0; int nError; // Open an existing archive - nError = OpenExistingArchiveWithCopy(&Logger, szPlainName, szPlainName, &hMpq); + nError = OpenExistingArchiveWithCopy(&Logger, szMpqPlainName, szMpqPlainName, &hMpq); // Add the given file if(nError == ERROR_SUCCESS) @@ -3776,10 +3775,6 @@ static int TestModifyArchive_ReplaceFile(const char * szPlainName, const char * nOffset = 8; szArchivedName = szFileName + nOffset; - // Just for test - try to open the file in the archive - if(SFileOpenFileEx(hMpq, szArchivedName, 0, &hFile)) - SFileCloseFile(hFile); - // Create the local file name CreateFullPathName(szLocalFileName, szMpqSubDir, szFileName); @@ -3792,9 +3787,29 @@ static int TestModifyArchive_ReplaceFile(const char * szPlainName, const char * true); } - // Close the MPQ - if(hMpq != NULL) + // Reopen the MPQ and compact it + if(nError == ERROR_SUCCESS) + { + // Compact the archive + Logger.PrintProgress("Compacting archive %s ...", szMpqPlainName); + if(!SFileSetCompactCallback(hMpq, CompactCallback, &Logger)) + nError = Logger.PrintError("Failed to compact archive %s", szMpqPlainName); + + if(!SFileCompactArchive(hMpq, NULL, 0)) + nError = GetLastError(); + SFileCloseArchive(hMpq); + } + + // Try to open the archive again + if(nError == ERROR_SUCCESS) + { + CreateFullPathName(szLocalFileName, NULL, szMpqPlainName); + nError = OpenExistingArchive(&Logger, szLocalFileName, 0, &hMpq); + if(nError == ERROR_SUCCESS) + SFileCloseArchive(hMpq); + } + return nError; } @@ -3881,9 +3896,9 @@ int main(int argc, char * argv[]) // nError = FindFilePairs(ForEachFile_CreateArchiveLink, "2004 - WoW\\06080", "2004 - WoW\\06299"); // Search all testing archives and verify their SHA1 hash -// if(nError == ERROR_SUCCESS) -// nError = FindFiles(ForEachFile_VerifyFileChecksum, szMpqSubDir); -/* + if(nError == ERROR_SUCCESS) + nError = FindFiles(ForEachFile_VerifyFileChecksum, szMpqSubDir); + // Test reading linear file without bitmap if(nError == ERROR_SUCCESS) nError = TestFileStreamOperations("MPQ_2013_v4_alternate-original.MPQ", 0); @@ -4109,11 +4124,10 @@ int main(int argc, char * argv[]) if(nError == ERROR_SUCCESS) nError = TestAddFile_ListFileTest("MPQ_2013_v4_SC2_EmptyMap.SC2Map", true, true); - // Test archive compacting // Create an empty archive v2 if(nError == ERROR_SUCCESS) nError = TestCreateArchive_EmptyMpq("StormLibTest_EmptyMpq_v2.mpq", MPQ_CREATE_ARCHIVE_V2 | MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES); - + // Create an empty archive v4 if(nError == ERROR_SUCCESS) nError = TestCreateArchive_EmptyMpq("StormLibTest_EmptyMpq_v4.mpq", MPQ_CREATE_ARCHIVE_V4 | MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES); @@ -4188,10 +4202,14 @@ int main(int argc, char * argv[]) // Open a MPQ (add custom user data to it) if(nError == ERROR_SUCCESS) nError = TestCreateArchive_BigArchive("StormLibTest_BigArchive_v4.mpq"); -*/ - // Test modifying a replay file from Heroes of the Storm + + // Test replacing a file with zero size file if(nError == ERROR_SUCCESS) - nError = TestModifyArchive_ReplaceFile("MPQ_2014_v4_Heroes_Replay.MPQ", "AddFile-replay.message.events"); + nError = TestModifyArchive_ReplaceFile("MPQ_2014_v4_Base.StormReplay", "AddFile-replay.message.events"); + +#ifdef _MSC_VER + _CrtDumpMemoryLeaks(); +#endif // _MSC_VER return nError; } diff --git a/test/TLogHelper.cpp b/test/TLogHelper.cpp index fb8505d..511bcc9 100644 --- a/test/TLogHelper.cpp +++ b/test/TLogHelper.cpp @@ -16,7 +16,7 @@ class TLogHelper { public: - TLogHelper(const char * szNewMainTitle = NULL, const char * szNewSubTitle = NULL); + TLogHelper(const char * szNewMainTitle = NULL, const char * szNewSubTitle1 = NULL, const char * szNewSubTitle2 = NULL); ~TLogHelper(); #if defined(UNICODE) || defined(UNICODE) @@ -49,7 +49,8 @@ class TLogHelper int GetConsoleWidth(); const char * szMainTitle; // Title of the text (usually name) - const char * szSubTitle; // Title of the text (can be name of the tested file) + const char * szSubTitle1; // Title of the text (can be name of the tested file) + const char * szSubTitle2; // Title of the text (can be name of the tested file) size_t nTextLength; // Length of the previous progress message bool bMessagePrinted; }; @@ -71,16 +72,18 @@ class TLogHelper //----------------------------------------------------------------------------- // Constructor and destructor + -TLogHelper::TLogHelper(const char * szNewTestTitle, const char * szNewSubTitle) +TLogHelper::TLogHelper(const char * szNewMainTitle, const char * szNewSubTitle1, const char * szNewSubTitle2) { UserString = ""; UserCount = 1; UserTotal = 1; // Fill the test line structure - szMainTitle = szNewTestTitle; - szSubTitle = szNewSubTitle; + szMainTitle = szNewMainTitle; + szSubTitle1 = szNewSubTitle1; + szSubTitle2 = szNewSubTitle2; nTextLength = 0; bMessagePrinted = false; bDontPrintResult = false; @@ -88,8 +91,10 @@ TLogHelper::TLogHelper(const char * szNewTestTitle, const char * szNewSubTitle) // Print the initial information if(szMainTitle != NULL) { - if(szSubTitle != NULL) - printf("Running %s (%s) ...", szMainTitle, szSubTitle); + if(szSubTitle1 != NULL && szSubTitle2 != NULL) + printf("Running %s (%s+%s) ...", szMainTitle, szSubTitle1, szSubTitle2); + else if(szSubTitle1 != NULL) + printf("Running %s (%s) ...", szMainTitle, szSubTitle1); else printf("Running %s ...", szMainTitle); } @@ -98,19 +103,21 @@ TLogHelper::TLogHelper(const char * szNewTestTitle, const char * szNewSubTitle) TLogHelper::~TLogHelper() { const char * szSaveMainTitle = szMainTitle; - const char * szSaveSubTitle = szSubTitle; + const char * szSaveSubTitle1 = szSubTitle1; + const char * szSaveSubTitle2 = szSubTitle2; // Set both to NULL so the won't be printed - szMainTitle = NULL; - szSubTitle = NULL; + szMainTitle = szSubTitle1 = szSubTitle2 = NULL; // Print the final information if(szSaveMainTitle != NULL && bMessagePrinted == false) { if(bDontPrintResult == false) { - if(szSaveSubTitle != NULL) - PrintMessage("%s (%s) succeeded.", szSaveMainTitle, szSaveSubTitle); + if(szSaveSubTitle1 != NULL && szSaveSubTitle2 != NULL) + PrintMessage("%s (%s+%s) succeeded.", szSaveMainTitle, szSaveSubTitle1, szSaveSubTitle2); + else if(szSaveSubTitle1 != NULL) + PrintMessage("%s (%s) succeeded.", szSaveMainTitle, szSaveSubTitle1); else PrintMessage("%s succeeded.", szSaveMainTitle); } @@ -120,6 +127,13 @@ TLogHelper::~TLogHelper() printf("\r"); } } + +#ifdef _MSC_VER + if(_CrtDumpMemoryLeaks()) + { + PrintMessage("Memory leak detected after %s\n.", szSaveMainTitle); + } +#endif // _MSC_VER } //----------------------------------------------------------------------------- |