diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/Test.cpp | 2263 |
1 files changed, 2263 insertions, 0 deletions
diff --git a/test/Test.cpp b/test/Test.cpp new file mode 100644 index 0000000..3edde98 --- /dev/null +++ b/test/Test.cpp @@ -0,0 +1,2263 @@ +/*****************************************************************************/ +/* StormLibTest.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Test module for StormLib */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 25.03.03 1.00 Lad The first version of StormLibTest.cpp */ +/*****************************************************************************/ + +#define _CRT_SECURE_NO_DEPRECATE +#define __INCLUDE_CRYPTOGRAPHY__ +#define __STORMLIB_SELF__ // Don't use StormLib.lib +#include <stdio.h> + +#ifdef _MSC_VER +#include <crtdbg.h> +#endif + +#include "../src/StormLib.h" +#include "../src/StormCommon.h" + +#ifdef _MSC_VER +#pragma warning(disable: 4505) // 'XXX' : unreferenced local function has been removed +#pragma comment(lib, "winmm.lib") +#endif + +#ifndef ERROR_BAD_LENGTH +#define ERROR_INVALID_DATA 13L +#define ERROR_BAD_LENGTH 24L +#endif + +//------------------------------------------------------------------------------ +// Defines + +#ifdef PLATFORM_WINDOWS +#define WORK_PATH_ROOT "E:\\Multimedia\\MPQs\\" +#endif + +#ifdef PLATFORM_LINUX +#define WORK_PATH_ROOT "/home/ladik/MPQs/" +#endif + +#ifdef PLATFORM_MAC +#define WORK_PATH_ROOT "/Users/sam/StormLib/test" +#endif + +#ifndef LANG_CZECH +#define LANG_CZECH 0x0405 +#endif + +#define MPQ_SECTOR_SIZE 0x1000 + +#define MAKE_PATH(path) _T(WORK_PATH_ROOT) _T(path) +#define MAKE_PATHA(path) (WORK_PATH_ROOT path) + +//----------------------------------------------------------------------------- +// Unicode MPQ names + +/* Czech */ static const wchar_t szUnicodeName1[] = {0x010C, 0x0065, 0x0073, 0x006B, 0x00FD, _T('.'), _T('m'), _T('p'), _T('q'), 0}; +/* Russian */ static const wchar_t szUnicodeName2[] = {0x0420, 0x0443, 0x0441, 0x0441, 0x043A, 0x0438, 0x0439, _T('.'), _T('m'), _T('p'), _T('q'), 0}; +/* Greece */ static const wchar_t szUnicodeName3[] = {0x03B5, 0x03BB, 0x03BB, 0x03B7, 0x03BD, 0x03B9, 0x03BA, 0x03AC, _T('.'), _T('m'), _T('p'), _T('q'), 0}; +/* Chinese */ static const wchar_t szUnicodeName4[] = {0x65E5, 0x672C, 0x8A9E, _T('.'), _T('m'), _T('p'), _T('q'), 0}; +/* Japanese */ static const wchar_t szUnicodeName5[] = {0x7B80, 0x4F53, 0x4E2D, 0x6587, _T('.'), _T('m'), _T('p'), _T('q'), 0}; +/* Arabic */ static const wchar_t szUnicodeName6[] = {0x0627, 0x0644, 0x0639, 0x0639, 0x0631, 0x0628, 0x064A, 0x0629, _T('.'), _T('m'), _T('p'), _T('q'), 0}; + +//----------------------------------------------------------------------------- +// Constants + +static const TCHAR * szWorkDir = MAKE_PATH("Work"); + +static unsigned int AddFlags[] = +{ +// Compression Encryption Fixed key Single Unit Sector CRC + 0 | 0 | 0 | 0 | 0, + 0 | MPQ_FILE_ENCRYPTED | 0 | 0 | 0, + 0 | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY | 0 | 0, + 0 | 0 | 0 | MPQ_FILE_SINGLE_UNIT | 0, + 0 | MPQ_FILE_ENCRYPTED | 0 | MPQ_FILE_SINGLE_UNIT | 0, + 0 | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY | MPQ_FILE_SINGLE_UNIT | 0, + MPQ_FILE_IMPLODE | 0 | 0 | 0 | 0, + MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | 0 | 0 | 0, + MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY | 0 | 0, + MPQ_FILE_IMPLODE | 0 | 0 | MPQ_FILE_SINGLE_UNIT | 0, + MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | 0 | MPQ_FILE_SINGLE_UNIT | 0, + MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY | MPQ_FILE_SINGLE_UNIT | 0, + MPQ_FILE_IMPLODE | 0 | 0 | 0 | MPQ_FILE_SECTOR_CRC, + MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | 0 | 0 | MPQ_FILE_SECTOR_CRC, + MPQ_FILE_IMPLODE | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY | 0 | MPQ_FILE_SECTOR_CRC, + MPQ_FILE_COMPRESS | 0 | 0 | 0 | 0, + MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | 0 | 0 | 0, + MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY | 0 | 0, + MPQ_FILE_COMPRESS | 0 | 0 | MPQ_FILE_SINGLE_UNIT | 0, + MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | 0 | MPQ_FILE_SINGLE_UNIT | 0, + MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY | MPQ_FILE_SINGLE_UNIT | 0, + MPQ_FILE_COMPRESS | 0 | 0 | 0 | MPQ_FILE_SECTOR_CRC, + MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | 0 | 0 | MPQ_FILE_SECTOR_CRC, + MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY | 0 | MPQ_FILE_SECTOR_CRC, + 0xFFFFFFFF +}; + +//----------------------------------------------------------------------------- +// Local testing functions + +static void clreol() +{ +#ifdef PLATFORM_WINDOWS + CONSOLE_SCREEN_BUFFER_INFO ScreenInfo; + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + LPTSTR szConsoleLine; + int nConsoleChars; + int i = 0; + + GetConsoleScreenBufferInfo(hConsole, &ScreenInfo); + nConsoleChars = (ScreenInfo.srWindow.Right - ScreenInfo.srWindow.Left); + if(nConsoleChars > 0) + { + szConsoleLine = new TCHAR[nConsoleChars + 3]; + if(szConsoleLine != NULL) + { + szConsoleLine[i++] = '\r'; + for(; i < nConsoleChars; i++) + szConsoleLine[i] = ' '; + szConsoleLine[i++] = '\r'; + szConsoleLine[i] = 0; + + _tprintf(szConsoleLine); + delete [] szConsoleLine; + } + } +#endif // PLATFORM_WINDOWS +} + +static void PrintfTA(const TCHAR * szFormat, const TCHAR * szStrT, const char * szStrA, int lcLocale = 0) +{ + TCHAR * szTemp; + TCHAR szBuffer[MAX_PATH]; + + // Convert ANSI string to TCHAR + for(szTemp = szBuffer; *szStrA != 0; szTemp++, szStrA++) + szTemp[0] = szStrA[0]; + szTemp[0] = 0; + + _tprintf(szFormat, szStrT, szBuffer, lcLocale); +} + +static void MergeLocalPath(TCHAR * szBuffer, const TCHAR * szPart1, const char * szPart2) +{ + // Copy directory name + while(*szPart1 != 0) + *szBuffer++ = *szPart1++; + + // Add separator + *szBuffer++ = _T('/'); + + // Copy file name + while(*szPart2 != 0) + *szBuffer++ = *szPart2++; + + // Terminate the string + *szBuffer = 0; +} + +int GetFirstDiffer(void * ptr1, void * ptr2, int nSize) +{ + char * buff1 = (char *)ptr1; + char * buff2 = (char *)ptr2; + int nDiffer; + + for(nDiffer = 0; nDiffer < nSize; nDiffer++) + { + if(*buff1++ != *buff2++) + return nDiffer; + } + return -1; +} + +static void WINAPI CompactCB(void * /* lpParam */, DWORD dwWork, ULONGLONG BytesDone, ULONGLONG TotalBytes) +{ + clreol(); + + _tprintf(_T("%u of %u "), (DWORD)BytesDone, (DWORD)TotalBytes); + switch(dwWork) + { + case CCB_CHECKING_FILES: + _tprintf(_T("Checking files in archive ...\r")); + break; + + case CCB_CHECKING_HASH_TABLE: + _tprintf(_T("Checking hash table ...\r")); + break; + + case CCB_COPYING_NON_MPQ_DATA: + _tprintf(_T("Copying non-MPQ data ...\r")); + break; + + case CCB_COMPACTING_FILES: + _tprintf(_T("Compacting archive ...\r")); + break; + + case CCB_CLOSING_ARCHIVE: + _tprintf(_T("Closing archive ...\r")); + break; + } +} + +static void GenerateRandomDataBlock(LPBYTE pbBuffer, DWORD cbBuffer) +{ + LPBYTE pbBufferEnd = pbBuffer + cbBuffer; + LPBYTE pbPtr = pbBuffer; + DWORD cbBytesToPut = 0; + BYTE ByteToPut = 0; + bool bRandomData = false; + + while(pbPtr < pbBufferEnd) + { + // If there are no bytes to put, we will generate new byte and length + if(cbBytesToPut == 0) + { + bRandomData = false; + switch(rand() % 10) + { + case 0: // A short sequence of zeros + cbBytesToPut = rand() % 0x08; + ByteToPut = 0; + break; + + case 1: // A long sequence of zeros + cbBytesToPut = rand() % 0x80; + ByteToPut = 0; + break; + + case 2: // A short sequence of non-zeros + cbBytesToPut = rand() % 0x08; + ByteToPut = (BYTE)(rand() % 0x100); + break; + + case 3: // A long sequence of non-zeros + cbBytesToPut = rand() % 0x80; + ByteToPut = (BYTE)(rand() % 0x100); + break; + + case 4: // A short random data + cbBytesToPut = rand() % 0x08; + bRandomData = true; + break; + + case 5: // A long random data + cbBytesToPut = rand() % 0x80; + bRandomData = true; + break; + + default: // A single random byte + cbBytesToPut = 1; + ByteToPut = (BYTE)(rand() % 0x100); + break; + } + } + + // Generate random byte, if needed + if(bRandomData) + ByteToPut = (BYTE)(rand() % 0x100); + + // Put next byte to the output buffer + *pbPtr++ = ByteToPut; + cbBytesToPut--; + } +} + +static bool CompareArchivedFiles(const char * szFileName, HANDLE hFile1, HANDLE hFile2, DWORD dwBlockSize) +{ + LPBYTE pbBuffer1 = NULL; + LPBYTE pbBuffer2 = NULL; + DWORD dwRead1; // Number of bytes read (Storm.dll) + DWORD dwRead2; // Number of bytes read (StormLib) + bool bResult1 = false; // Result from Storm.dll + bool bResult2 = false; // Result from StormLib + bool bResult = true; + int nDiff; + + szFileName = szFileName; + + // Allocate buffers + pbBuffer1 = new BYTE[dwBlockSize]; + pbBuffer2 = new BYTE[dwBlockSize]; + + for(;;) + { + // Read the file's content by both methods and compare the result + memset(pbBuffer1, 0, dwBlockSize); + memset(pbBuffer2, 0, dwBlockSize); + bResult1 = SFileReadFile(hFile1, pbBuffer1, dwBlockSize, &dwRead1, NULL); + bResult2 = SFileReadFile(hFile2, pbBuffer2, dwBlockSize, &dwRead2, NULL); + if(bResult1 != bResult2) + { + _tprintf(_T("Different results from SFileReadFile, Mpq1 %u, Mpq2 %u\n"), bResult1, bResult2); + bResult = false; + break; + } + + // Test the number of bytes read + if(dwRead1 != dwRead2) + { + _tprintf(_T("Different bytes read from SFileReadFile, Mpq1 %u, Mpq2 %u\n"), dwRead1, dwRead2); + bResult = false; + break; + } + + // No more bytes ==> OK + if(dwRead1 == 0) + break; + + // Test the content + if((nDiff = GetFirstDiffer(pbBuffer1, pbBuffer2, dwRead1)) != -1) + { + bResult = false; + break; + } + } + + delete [] pbBuffer2; + delete [] pbBuffer1; + return bResult; +} + +// Random read version +static bool CompareArchivedFilesRR(const char * /* szFileName */, HANDLE hFile1, HANDLE hFile2, DWORD dwBlockSize) +{ + const char * szPositions[3] = {"FILE_BEGIN ", "FILE_CURRENT", "FILE_END "}; + LPBYTE pbBuffer1 = NULL; + LPBYTE pbBuffer2 = NULL; + DWORD dwFileSize1; // File size (Storm.dll) + DWORD dwFileSize2; // File size (StormLib) + DWORD dwRead1; // Number of bytes read (Storm.dll) + DWORD dwRead2; // Number of bytes read (StormLib) + bool bResult1 = false; // Result from Storm.dll + bool bResult2 = false; // Result from StormLib + int nError = ERROR_SUCCESS; + + // Test the file size + dwFileSize1 = SFileGetFileSize(hFile1, NULL); + dwFileSize2 = SFileGetFileSize(hFile2, NULL); + if(dwFileSize1 != dwFileSize2) + { + _tprintf(_T("Different size from SFileGetFileSize (file1: %u, file2: %u)\n"), dwFileSize1, dwFileSize2); + return false; + } + + if(dwFileSize1 != 0) + { + for(int i = 0; i < 10000; i++) + { + DWORD dwRandom = rand() * rand(); + DWORD dwMoveMethod = dwRandom % 3; + DWORD dwPosition = dwRandom % dwFileSize1; + DWORD dwToRead = dwRandom % dwBlockSize; + + // Also test negative seek + if(rand() & 1) + { + int nPosition = (int)dwPosition; + dwPosition = (DWORD)(-nPosition); + } + + // Allocate buffers + pbBuffer1 = new BYTE[dwToRead]; + pbBuffer2 = new BYTE[dwToRead]; + + // Set the file pointer + _tprintf(_T("RndRead (%u): pos %8i from %s, size %u ...\r"), i, dwPosition, szPositions[dwMoveMethod], dwToRead); + dwRead1 = SFileSetFilePointer(hFile1, dwPosition, NULL, dwMoveMethod); + dwRead2 = SFileSetFilePointer(hFile2, dwPosition, NULL, dwMoveMethod); + if(dwRead1 != dwRead2) + { + _tprintf(_T("Difference returned by SFileSetFilePointer (file1: %u, file2: %u)\n"), dwRead1, dwRead2); + nError = ERROR_CAN_NOT_COMPLETE; + break; + } + + // Read the file's content by both methods and compare the result + bResult1 = SFileReadFile(hFile1, pbBuffer1, dwToRead, &dwRead1, NULL); + bResult2 = SFileReadFile(hFile2, pbBuffer2, dwToRead, &dwRead2, NULL); + if(bResult1 != bResult2) + { + _tprintf(_T("Different results from SFileReadFile (file1: %u, file2: %u)\n\n"), bResult1, bResult2); + nError = ERROR_CAN_NOT_COMPLETE; + break; + } + + // Test the number of bytes read + if(dwRead1 != dwRead2) + { + _tprintf(_T("Different bytes read from SFileReadFile (file1: %u, file2: %u)\n\n"), dwRead1, dwRead2); + nError = ERROR_CAN_NOT_COMPLETE; + break; + } + + // Test the content + if(dwRead1 != 0 && memcmp(pbBuffer1, pbBuffer2, dwRead1)) + { + _tprintf(_T("Different data content from SFileReadFile\n")); + nError = ERROR_CAN_NOT_COMPLETE; + break; + } + + delete [] pbBuffer2; + delete [] pbBuffer1; + } + } + clreol(); + return (nError == ERROR_SUCCESS) ? true : false; +} + +//----------------------------------------------------------------------------- +// Opening local file + +static int TestOpenLocalFile(const char * szFileName) +{ + HANDLE hFile; + char szRetrievedName[MAX_PATH]; + + if(SFileOpenFileEx(NULL, szFileName, SFILE_OPEN_LOCAL_FILE, &hFile)) + { + SFileGetFileName(hFile, szRetrievedName); + SFileCloseFile(hFile); + } + + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// Partial file reading + +static int TestPartFileRead(const TCHAR * szFileName) +{ + ULONGLONG ByteOffset; + ULONGLONG FileSize = 0; + TFileStream * pStream; + BYTE BigBuffer[0x7000]; + BYTE Buffer[0x100]; + int nError = ERROR_SUCCESS; + + // Open the partial file + pStream = FileStream_OpenFile(szFileName, false); + if(pStream == NULL) + nError = GetLastError(); + + // Get the size of the stream + if(nError == ERROR_SUCCESS) + { + if(!FileStream_GetSize(pStream, &FileSize)) + nError = GetLastError(); + } + + // Read the last 0x7000 bytes + if(nError == ERROR_SUCCESS) + { + ByteOffset = FileSize - sizeof(BigBuffer); + if(!FileStream_Read(pStream, &ByteOffset, BigBuffer, sizeof(BigBuffer))) + nError = GetLastError(); + } + + // Read the last 0x100 bytes + if(nError == ERROR_SUCCESS) + { + ByteOffset = FileSize - sizeof(Buffer); + if(!FileStream_Read(pStream, &ByteOffset, Buffer, sizeof(Buffer))) + nError = GetLastError(); + } + + // Read 0x100 bytes from position (FileSize - 0xFF) + if(nError == ERROR_SUCCESS) + { + ByteOffset = FileSize - sizeof(Buffer) + 1; + if(!FileStream_Read(pStream, &ByteOffset, Buffer, sizeof(Buffer))) + nError = GetLastError(); + } + + FileStream_Close(pStream); + return nError; +} + +//----------------------------------------------------------------------------- +// Compare Huffmann decompression + +struct TFileData +{ + DWORD dwFileSize; + BYTE FileData[1]; +}; + +static TFileData * ReadFileContent(const TCHAR * szMpqName, const char * szFileName) +{ + TFileData * pFileData = NULL; + HANDLE hMpq = NULL; + HANDLE hFile = NULL; + DWORD dwSearchScope = (szMpqName == NULL) ? SFILE_OPEN_LOCAL_FILE : SFILE_OPEN_FROM_MPQ; + DWORD dwBytesRead = 0; + DWORD dwFileSize = 0; + + // Open the MPQ, if any + if(szMpqName != NULL) + { + if(!SFileOpenArchive(szMpqName, 0, 0, &hMpq)) + return NULL; + } + + // Open the file + if(SFileOpenFileEx(hMpq, szFileName, dwSearchScope, &hFile)) + { + dwFileSize = SFileGetFileSize(hFile, NULL); + pFileData = (TFileData *)(new BYTE[sizeof(TFileData) + dwFileSize]); + if(pFileData != NULL) + { + SFileReadFile(hFile, pFileData->FileData, dwFileSize, &dwBytesRead, NULL); + pFileData->dwFileSize = dwFileSize; + } + SFileCloseFile(hFile); + } + + if(hMpq != NULL) + SFileCloseArchive(hMpq); + return pFileData; +} + +static TFileData * CompressFileContent(TFileData * pDecompressed, BYTE Compression1, BYTE Compression2) +{ + TFileData * pRecompressed; + LPBYTE pbOutBuffer; + LPBYTE pbInBuffer; + DWORD dwBytesRemaining; + int cbOutBuffer; + int cbInBuffer; + + // Allocate buffer for compressed data + pRecompressed = (TFileData *)(new BYTE[sizeof(TFileData) + pDecompressed->dwFileSize]); + if(pRecompressed != NULL) + { + // Set the source and target + dwBytesRemaining = pDecompressed->dwFileSize; + pbInBuffer = pDecompressed->FileData; + pbOutBuffer = pRecompressed->FileData; + + while(dwBytesRemaining != 0) + { + // Perform the compression + cbOutBuffer = cbInBuffer = (int)STORMLIB_MIN(dwBytesRemaining, 0x1000); + SCompCompress((char *)pbOutBuffer, &cbOutBuffer, (char *)pbInBuffer, cbInBuffer, Compression1, 0x00, 0); + assert(cbOutBuffer < cbInBuffer); + + // Move buffers + dwBytesRemaining -= cbInBuffer; + pbOutBuffer += cbOutBuffer; + pbInBuffer += cbInBuffer; + Compression1 = Compression2; + } + + // Put the size of the decompressed part + pRecompressed->dwFileSize = (DWORD)(pbOutBuffer - pRecompressed->FileData); + } + + return pRecompressed; +} + +static int WriteFileContent(const TCHAR * szFileName, TFileData * pFileData) +{ + TFileStream * pLocalFile = NULL; + int nError = ERROR_SUCCESS; + + // Create the local file + if(nError == ERROR_SUCCESS) + { + pLocalFile = FileStream_CreateFile(szFileName, STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE); + if(pLocalFile == NULL) + nError = GetLastError(); + } + + // Write the file data + if(nError == ERROR_SUCCESS) + { + if(!FileStream_Write(pLocalFile, NULL, pFileData->FileData, pFileData->dwFileSize)) + nError = GetLastError(); + } + + // Close handles and return + if(pLocalFile != NULL) + FileStream_Close(pLocalFile); + return nError; +} + +static int CompareHuffmanCompressions7() +{ + TFileData * pDecompressed1 = NULL; + TFileData * pDecompressed2 = NULL; + TFileData * pRecompressed1 = NULL; + TFileData * pRecompressed2 = NULL; + int nDifference; + int nError = ERROR_SUCCESS; + + // Load the decompressed data + if(nError == ERROR_SUCCESS) + { + pDecompressed1 = ReadFileContent(MAKE_PATH("BroodWar.mpq"), "music\\prdyroom.wav"); + pDecompressed2 = ReadFileContent(NULL, MAKE_PATHA("mpq_decompressed.wav")); + if(pDecompressed1 != NULL && pDecompressed2 != NULL) + { + // Compare decompressed size + if(pDecompressed1->dwFileSize == pDecompressed2->dwFileSize) + { + // Compare the data + nDifference = GetFirstDiffer(pDecompressed1->FileData, pDecompressed2->FileData, pDecompressed1->dwFileSize); + if(nDifference != -1) + { + _tprintf(_T("Different decompressed data at offset %08X\n\n"), nDifference); + nError = ERROR_BAD_FORMAT; + } + else + { + _tprintf(_T("Huffmann decompression OK\n")); + } + } + else + { + _tprintf(_T("Different decompressed size: %u <-> %u\n"), pDecompressed1->dwFileSize, pDecompressed2->dwFileSize); + nError = ERROR_BAD_LENGTH; + } + } + else + { + _tprintf(_T("Failed to real one of the compressed files.\n")); + nError = ERROR_CAN_NOT_COMPLETE; + } + } + + // Get the recompressed data + if(nError == ERROR_SUCCESS) + { + pRecompressed1 = CompressFileContent(pDecompressed1, MPQ_COMPRESSION_PKWARE, MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_HUFFMANN); + pRecompressed2 = ReadFileContent(NULL, MAKE_PATHA("mpq_recompressed.bin")); + if(pRecompressed1 != NULL && pRecompressed2 != NULL) + { + // Comprare decompressed size + if(pRecompressed1->dwFileSize == pRecompressed2->dwFileSize) + { + // Compare the data + nDifference = GetFirstDiffer(pRecompressed1->FileData, pRecompressed2->FileData, pRecompressed1->dwFileSize); + if(nDifference != -1) + { + _tprintf(_T("Different recompressed data at offset %08X\n"), nDifference); + nError = ERROR_BAD_FORMAT; + } + else + { + _tprintf(_T("Huffmann recompression OK\n")); + } + } + else + { + _tprintf(_T("Different recompressed size: %u <-> %u\n"), pRecompressed1->dwFileSize, pRecompressed2->dwFileSize); + nError = ERROR_BAD_LENGTH; + } + } + else + { + _tprintf(_T("Failed to compress the file or read the compressed muster.\n")); + nError = ERROR_CAN_NOT_COMPLETE; + } + } + + assert(nError == ERROR_SUCCESS); + + if(pRecompressed1 != NULL) + delete [] pRecompressed1; + if(pRecompressed2 != NULL) + delete [] pRecompressed2; + if(pDecompressed1 != NULL) + delete [] pDecompressed1; + if(pDecompressed2 != NULL) + delete [] pDecompressed2; + return ERROR_SUCCESS; +} + +// Just some binary data +static unsigned char Decompressed[2048] = +{ + 0x2E, 0x56, 0xF8, 0x44, 0xB0, 0xE2, 0x58, 0x20, 0x44, 0xBC, 0xE2, 0x46, 0x00, 0x44, 0x4A, 0x1D, + 0x59, 0x44, 0xC4, 0xE3, 0x00, 0x00, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x34, 0xE2, 0x01, 0x01, + 0x01, 0x6C, 0x44, 0xB4, 0xE2, 0x58, 0x01, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x00, 0xB4, 0xE2, 0x58, + 0x44, 0xB4, 0x02, 0x02, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x00, 0x44, 0xB4, 0xE2, 0x40, 0x58, + 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0x02, 0x02, 0xE2, 0x58, 0x44, 0x04, 0xB4, 0xE0, 0x58, 0x40, + 0x44, 0xC0, 0xC3, 0x58, 0x58, 0x08, 0x8B, 0x8A, 0x4B, 0xDE, 0xF6, 0x80, 0x92, 0x5B, 0xDC, 0x2F, + 0xA1, 0x78, 0x10, 0x10, 0x65, 0x1C, 0x32, 0x8A, 0xA2, 0xF4, 0x02, 0xBC, 0x02, 0x02, 0x9A, 0x7A, + 0x06, 0x9A, 0x9E, 0x01, 0xF4, 0x38, 0x20, 0xB2, 0xA2, 0x5C, 0xA2, 0x01, 0x9C, 0x8E, 0xF4, 0x06, + 0xB2, 0x98, 0x80, 0x80, 0xF4, 0x08, 0x84, 0x8C, 0x7E, 0x40, 0x06, 0x18, 0xEA, 0x66, 0x10, 0x3E, + 0x3E, 0x08, 0x20, 0xAE, 0xF6, 0x10, 0x2A, 0xB4, 0x10, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, + 0x00, 0x00, 0xB4, 0xE2, 0x58, 0x44, 0x04, 0xB4, 0xE2, 0x58, 0x80, 0x44, 0xB4, 0xE2, 0x58, 0x44, + 0x80, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0x10, 0x10, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x40, 0x58, 0x44, + 0x08, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x80, 0x80, 0x58, 0x44, 0xB4, + 0xE2, 0x58, 0x44, 0xB4, 0x02, 0x02, 0xE2, 0x58, 0x00, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, + 0x00, 0x00, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0x00, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, + 0x44, 0xB4, 0x01, 0x01, 0x01, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x01, 0x58, 0x44, 0xB4, 0xE2, 0x58, + 0x44, 0xB4, 0xE2, 0x58, 0x02, 0x02, 0x44, 0xB4, 0xE2, 0x20, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, + 0x01, 0x01, 0xB4, 0xE2, 0x58, 0x44, 0x40, 0xB4, 0xE2, 0x58, 0x44, 0x40, 0xB4, 0xE2, 0x58, 0x08, + 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x08, 0x08, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, + 0x40, 0x40, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x00, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, + 0x01, 0x01, 0x58, 0x44, 0x14, 0x68, 0x58, 0x44, 0x2C, 0xE0, 0x5C, 0x01, 0x01, 0x01, 0x44, 0x20, + 0x85, 0x3B, 0xD3, 0xB4, 0xE2, 0x02, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x20, 0x20, 0x44, 0x75, 0xE3, + 0x44, 0x08, 0x47, 0xA2, 0xE0, 0x5C, 0x76, 0xB4, 0x00, 0xBA, 0x7E, 0x44, 0x40, 0xB4, 0xB2, 0x4B, + 0x44, 0xB4, 0x08, 0x08, 0xE2, 0x58, 0x44, 0xB4, 0xC2, 0x58, 0x01, 0x44, 0xB4, 0xC2, 0x80, 0x58, + 0x44, 0xB4, 0x62, 0x10, 0x7E, 0x44, 0xB4, 0xE2, 0xD8, 0x10, 0x44, 0xB4, 0x20, 0xC2, 0x58, 0x44, + 0xB4, 0xE6, 0x58, 0x80, 0x80, 0x44, 0xBE, 0xE2, 0x58, 0x44, 0x04, 0xB4, 0xE2, 0x58, 0x44, 0xBE, + 0xE2, 0x58, 0x44, 0x10, 0x10, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0x04, 0x82, 0x63, 0x44, 0xB4, 0xEA, + 0x58, 0x80, 0x80, 0x44, 0xAE, 0x6E, 0x42, 0x10, 0x44, 0xB0, 0xE2, 0x58, 0x44, 0x01, 0x01, 0xB4, + 0xE2, 0x78, 0x44, 0xB4, 0x62, 0x58, 0x04, 0x44, 0xB4, 0xE2, 0x78, 0x44, 0xB4, 0x01, 0x01, 0xC2, + 0x58, 0x44, 0xB4, 0xE2, 0x04, 0x58, 0x44, 0x94, 0x02, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, + 0xB4, 0x80, 0x80, 0xE2, 0x58, 0x44, 0x2C, 0xDC, 0x63, 0x44, 0x02, 0x02, 0xDC, 0xE4, 0x58, 0x44, + 0xB4, 0x02, 0x02, 0xE2, 0x63, 0x44, 0x64, 0xD8, 0x58, 0x44, 0xB4, 0xE2, 0x04, 0x04, 0x58, 0x44, + 0xB4, 0xE2, 0x58, 0x00, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0x00, 0x00, 0xE2, 0x58, 0x44, 0x02, + 0xB4, 0xE2, 0x58, 0x00, 0x44, 0xB4, 0xE2, 0x58, 0x10, 0x44, 0xB4, 0xE2, 0x58, 0x20, 0x44, 0xB4, + 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x00, 0x00, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x80, + 0x80, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x2C, 0x01, 0x01, 0xBC, 0x63, 0x44, 0x0C, 0xE2, 0x58, + 0x44, 0x20, 0x20, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x08, 0x08, 0x44, 0xB4, 0xE2, 0x58, + 0x44, 0xB4, 0x20, 0xE2, 0x58, 0x44, 0x01, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0x01, 0xE2, 0x58, 0x44, + 0xB4, 0x00, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x00, 0x00, 0x58, 0x44, 0xB4, 0xE2, 0x01, 0x58, 0x44, + 0xB4, 0xE2, 0x80, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0x08, 0x08, 0xE2, 0x58, 0x44, 0xE8, + 0x0A, 0x92, 0xB4, 0x04, 0x04, 0x5C, 0xE2, 0x58, 0x44, 0xB4, 0x02, 0x62, 0x44, 0xB4, 0xC2, 0x01, + 0x01, 0x58, 0x44, 0xB4, 0xBE, 0x08, 0x41, 0x44, 0xB4, 0xEA, 0x80, 0x80, 0x58, 0x44, 0x14, 0x68, + 0xDE, 0x20, 0x1C, 0x7C, 0x20, 0x20, 0x58, 0x44, 0xB4, 0xE2, 0x40, 0x58, 0x44, 0xF5, 0xE2, 0x01, + 0x58, 0x84, 0xE8, 0x06, 0xBE, 0xA0, 0x72, 0xE2, 0x02, 0x02, 0x58, 0x44, 0xB4, 0x82, 0x58, 0x44, + 0xB4, 0xE2, 0x63, 0x20, 0x20, 0x44, 0xB4, 0x82, 0x58, 0x44, 0xB4, 0x86, 0x02, 0x02, 0x41, 0x44, + 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x01, 0x01, 0x58, 0x40, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xF5, + 0xE2, 0x58, 0x08, 0x08, 0x84, 0xB4, 0xE2, 0x58, 0x08, 0x44, 0xB4, 0xE2, 0x04, 0x58, 0x44, 0xB4, + 0xE2, 0x58, 0x10, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x20, 0x20, 0x44, 0x80, 0xB4, + 0xE2, 0x58, 0x44, 0xB4, 0x40, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0x80, 0x80, 0xE2, + 0x58, 0x44, 0xB4, 0x20, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x20, 0x20, 0xB4, 0xE2, 0x58, + 0x08, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x20, 0xB4, 0xE2, 0x20, 0x58, 0x44, 0xB4, 0x04, 0xE2, 0x58, + 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x80, 0xB4, 0xE2, 0x10, 0x58, 0x44, 0xB4, 0x00, 0xE2, 0x58, 0x44, + 0xB4, 0xE2, 0x58, 0x08, 0x44, 0xB4, 0x40, 0xE2, 0x58, 0x44, 0xB4, 0x08, 0xE2, 0x58, 0x80, 0x44, + 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x80, 0x80, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, + 0x04, 0x04, 0x58, 0x44, 0xB4, 0xE2, 0x08, 0x58, 0x44, 0xB4, 0x04, 0xE2, 0x58, 0x44, 0xB4, 0xE2, + 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x02, 0x02, 0x02, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0x04, 0xE2, + 0x58, 0x44, 0xB4, 0xE2, 0x10, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x10, 0x10, 0xB4, 0xE2, 0x58, + 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x00, 0x00, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x80, 0x80, + 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x40, 0x40, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, + 0x80, 0x80, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x20, 0x44, 0xB4, 0xE2, 0x01, 0x58, 0x44, 0x40, + 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x08, 0x08, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x40, 0xB4, + 0xE2, 0x58, 0x44, 0x01, 0xB4, 0xE2, 0x58, 0x44, 0x80, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, + 0x04, 0x04, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x04, 0x04, 0x58, 0x44, 0xB4, 0x02, 0xE2, + 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x04, 0x04, 0xB4, 0xE2, 0x58, 0x44, 0x20, 0xB4, 0xE2, 0x58, + 0x44, 0x20, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x20, 0x20, 0xB4, 0xE2, 0x58, 0x44, + 0x20, 0xB4, 0xE2, 0x58, 0x44, 0x40, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x08, 0x08, + 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0x02, 0x02, 0x02, 0xE2, 0x58, 0x44, 0xB4, + 0xE2, 0x58, 0x44, 0x01, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x01, 0x01, 0x01, 0xB4, + 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0x10, 0x10, 0xE2, 0x58, 0x44, 0xB4, 0x01, 0xE2, + 0x58, 0x44, 0x10, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0x08, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, + 0xB4, 0x01, 0x01, 0xE2, 0x04, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x01, 0x44, 0xB4, 0xE2, 0x58, 0x44, + 0xB4, 0xE2, 0x58, 0x08, 0x08, 0x44, 0x02, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, + 0xE2, 0x20, 0x20, 0x58, 0x44, 0xB4, 0x08, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x40, 0x58, 0x44, 0x20, + 0xB4, 0xE2, 0x58, 0x20, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x08, 0x08, 0x58, 0x44, 0xB4, + 0xE2, 0x58, 0x01, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0x00, 0x00, 0xE2, 0x58, 0x44, 0xB4, 0xE2, + 0x58, 0x40, 0x44, 0xB4, 0x20, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0x10, 0x10, 0xE2, + 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x10, 0x10, 0xB4, 0xE2, 0x58, 0x44, 0x01, 0xB4, 0xE2, 0x58, + 0x10, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x02, 0x02, 0x02, 0x58, + 0x44, 0xB4, 0xE2, 0x58, 0x02, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x00, 0xB4, 0xE2, 0x58, 0x44, 0xB4, + 0xE2, 0x08, 0x08, 0x58, 0x44, 0x80, 0xB4, 0xE2, 0x58, 0x44, 0xB4, 0xE2, 0x40, 0x58, 0x44, 0xB4, + 0xE2, 0x58, 0x44, 0xB4, 0x20, 0x20, 0xE2, 0x58, 0x04, 0x44, 0xB4, 0xE2, 0x58, 0x44, 0x20, 0xB4, + 0xE2, 0x58, 0x44, 0xC4, 0xEB, 0x05, 0x10, 0x10, 0xFF, 0xB5, 0x42, 0x90, 0xBA, 0xDE, 0x20, 0xE2, + 0x58, 0x44, 0x40, 0xB4, 0x2A, 0x40, 0x4A, 0x0F, 0xB4, 0x80, 0xE2, 0x58, 0x44, 0xD2, 0x40, 0x62, + 0x4B, 0x55, 0x14, 0x68, 0x02, 0xDE, 0x9A, 0x00, 0x6E, 0x02, 0x9A, 0x82, 0x5C, 0x86, 0x00, 0x58, + 0x62, 0x0B, 0xBA, 0x7F, 0xA9, 0x00, 0x00, 0x00, 0xFF, 0xCC, 0x38, 0x71, 0xD8, 0x90, 0x4C, 0x01, + 0x01, 0x27, 0xB2, 0x6B, 0x10, 0x30, 0x43, 0xC4, 0x9B, 0xB1, 0x1E, 0x45, 0x02, 0x02, 0x34, 0xDF, + 0x72, 0x36, 0x00, 0xF5, 0xDC, 0xCE, 0x7A, 0x01, 0x93, 0xEF, 0x4F, 0xB0, 0xDA, 0x22, 0xA4, 0xBB, + 0x01, 0x01, 0xC5, 0x47, 0x27, 0x50, 0x80, 0x23, 0x7B, 0xC1, 0x5F, 0x00, 0x13, 0x47, 0xC1, 0x52, + 0x46, 0xD9, 0xAB, 0xB6, 0x20, 0x20, 0x8F, 0x04, 0xEF, 0xD5, 0x9E, 0x2B, 0x73, 0x5F, 0x91, 0xF4, + 0x40, 0x40, 0x9C, 0xB2, 0x9B, 0x76, 0xDE, 0xDF, 0x90, 0x01, 0x01, 0xFC, 0x27, 0x9C, 0x66, 0x17, + 0x6B, 0xB1, 0x5E, 0x00, 0x00, 0xEC, 0x8E, 0x0A, 0xEF, 0x1B, 0xFA, 0xE3, 0xF8, 0xDF, 0x08, 0x08, + 0x8E, 0x38, 0x77, 0x24, 0x40, 0xCA, 0x10, 0x2B, 0x10, 0x9D, 0xF7, 0x8E, 0x67, 0xD1, 0x20, 0xEF, + 0xF2, 0x94, 0x8F, 0xFC, 0x70, 0xF8, 0x3F, 0x01, 0x01, 0x01, 0xF7, 0xBF, 0x6B, 0xD1, 0x50, 0xA5, + 0x10, 0x66, 0x6A, 0x6F, 0xB0, 0x69, 0x68, 0x21, 0xAA, 0x01, 0x01, 0x17, 0x00, 0x48, 0x85, 0x6A, + 0xBB, 0xAA, 0x51, 0x0F, 0x01, 0xCE, 0xBB, 0x08, 0x08, 0x1C, 0x2D, 0x84, 0x04, 0x4A, 0xBD, 0x01, + 0x7E, 0x88, 0x04, 0x04, 0xE4, 0x29, 0x3E, 0x6C, 0xD0, 0x10, 0x49, 0xA7, 0x93, 0x09, 0xA7, 0x52, + 0x48, 0x01, 0x01, 0x4A, 0x24, 0xA5, 0x5E, 0xBE, 0x04, 0x0C, 0x77, 0x01, 0x23, 0xE0, 0x5D, 0xFB, + 0x02, 0xD0, 0x1F, 0xD2, 0x3A, 0xFC, 0x5F, 0x08, 0x9A, 0xF2, 0x20, 0x77, 0x54, 0x95, 0x22, 0xD2, + 0x32, 0x17, 0x9D, 0x02, 0x02, 0x6B, 0xC0, 0xD6, 0x5B, 0xF4, 0xE5, 0x50, 0x00, 0x00, 0x9A, 0xF7, + 0xC6, 0xD6, 0x02, 0x5F, 0x8D, 0x71, 0x80, 0xD8, 0xD2, 0x87, 0x40, 0x7C, 0xF3, 0xB2, 0xBC, 0x84, + 0x4B, 0x83, 0xCE, 0x80, 0x80, 0xE3, 0x71, 0x89, 0xAF, 0xE2, 0x01, 0xF8, 0x1B, 0x86, 0x66, 0x4F, + 0x40, 0x0F, 0x73, 0x4C, 0x4E, 0xF3, 0x0B, 0x01, 0x01, 0x18, 0x7F, 0x04, 0xBD, 0x7D, 0x51, 0x3C, + 0xEB, 0x5B, 0x04, 0xC6, 0xFE, 0x7B, 0x9B, 0x2F, 0x86, 0x62, 0x02, 0x02, 0x56, 0x35, 0x20, 0x05, + 0xE6, 0x1C, 0x4C, 0x68, 0x01, 0x29, 0xEA, 0xB0, 0xD3, 0xB0, 0xB5, 0xFE, 0x40, 0x40, 0x9D, 0xE0, + 0xC4, 0x6B, 0xF8, 0x6C, 0x00, 0x00, 0xE4, 0x74, 0x6A, 0x95, 0x04, 0x7A, 0xDC, 0x8C, 0x1B, 0x02, + 0xBB, 0x8C, 0x29, 0x1F, 0x01, 0xC6, 0xA7, 0x9C, 0x9C, 0xC7, 0x02, 0xB8, 0xD1, 0x10, 0x73, 0xA5, + 0x95, 0x92, 0xCC, 0xE8, 0x10, 0x67, 0x14, 0x39, 0xB3, 0x22, 0xB2, 0xAB, 0x00, 0x00, 0xF1, 0x5E, + 0x56, 0x90, 0x5F, 0x9D, 0xC5, 0x00, 0x00, 0xA4, 0xA3, 0x36, 0x20, 0xAF, 0x4E, 0x5A, 0xB3, 0x96, + 0x41, 0xDE, 0x04, 0x04, 0x77, 0x92, 0x16, 0x8D, 0x02, 0x2D, 0xB9, 0xCA, 0xC2, 0x40, 0xEF, 0x88, + 0x5D, 0x5F, 0x81, 0x93, 0xF7, 0x5A, 0x08, 0x08, 0xE3, 0xA3, 0x37, 0xE4, 0x10, 0xE1, 0xEA, 0x8B, + 0xDE, 0x02, 0xAC, 0x2D, 0xFE, 0x9C, 0x09, 0x05, 0xBF, 0xA4, 0x40, 0x40, 0xF0, 0x02, 0x92, 0xBB, + 0x5D, 0x42, 0x9D, 0x83, 0xF5, 0x2C, 0x40, 0x40, 0x3A, 0xE4, 0x52, 0x62, 0x36, 0x53, 0x8E, 0x40, + 0x40, 0x71, 0x91, 0xB7, 0x3E, 0xC0, 0x55, 0x88, 0x1C, 0x40, 0x40, 0xEF, 0x3F, 0xB4, 0x70, 0xF8, + 0xE9, 0x2A, 0x7A, 0x4D, 0x02, 0x02, 0xC0, 0x9B, 0x1C, 0x05, 0x08, 0xE2, 0x6C, 0x5E, 0x80, 0xDC, + 0x2A, 0xC0, 0x91, 0x05, 0x10, 0x10, 0x1B, 0x85, 0x09, 0x47, 0xBC, 0x27, 0x38, 0x02, 0x04, 0x04, + 0xCC, 0x7F, 0x55, 0x1A, 0xF0, 0x06, 0x02, 0xDF, 0xC6, 0xF8, 0xB5, 0x18, 0xB5, 0xF1, 0x97, 0x08, + 0x08, 0x08, 0x20, 0xF5, 0x1F, 0xCD, 0x02, 0x20, 0x07, 0xC5, 0x98, 0x44, 0x57, 0x21, 0x00, 0x24, + 0xBC, 0x78, 0x10, 0xD6, 0xA9, 0xCC, 0xD1, 0xC4, 0x20, 0x20, 0x30, 0x61, 0x51, 0xEC, 0x5F, 0x80, + 0x06, 0xAE, 0x5F, 0x6E, 0x32, 0x2E, 0x8B, 0x01, 0x01, 0x8F, 0xC5, 0x9D, 0x4F, 0x5E, 0x00, 0x07, + 0x6A, 0x02, 0xF9, 0xF6, 0x9B, 0xA1, 0x20, 0xF6, 0x8B, 0x19, 0xCA, 0x6D, 0x7E, 0x01, 0xBE, 0x7D, + 0x40, 0x18, 0x2D, 0xC2, 0xD5, 0xF8, 0x14, 0x83, 0x49, 0x80, 0x80, 0x1A, 0x7E, 0xDC, 0x6F, 0x0F, + 0xB1, 0xA4, 0x04, 0x04, 0x13, 0x0A, 0x2E, 0xF0, 0x08, 0x38, 0x74, 0xAB, 0x40, 0x13, 0xBE, 0xC5, + 0x20, 0xFD, 0xFB, 0xC5, 0xDD, 0x37, 0xF3, 0x47, 0xB6, 0x10, 0x10, 0xE0, 0x01, 0x7C, 0xB3, 0xE8, + 0x80, 0x95, 0x91, 0xF7, 0x00, 0x63, 0x01, 0x01, 0xFE, 0xBA, 0x86, 0xBE, 0xF0, 0xA8, 0x20, 0xBE, + 0xA3, 0x20, 0x90, 0x5A, 0x84, 0xB4, 0x9F, 0x63, 0x20, 0xC2, 0x8E, 0x3A, 0x38, 0xFD, 0xB7, 0x1D, + 0x20, 0x20, 0x26, 0x02, 0xDA, 0xDA, 0xA5, 0xFC, 0xA3, 0x65, 0x08, 0x88, 0xF6, 0xCD, 0xAF, 0x81, + 0x98, 0x90, 0x10, 0x10, 0xED, 0x7D, 0x2B, 0x74, 0xF5, 0x0B, 0x08, 0x08, 0xE8, 0xB3, 0x92, 0x04, + 0x7D, 0xE5, 0x7E, 0x36, 0x48, 0x02, 0xC2, 0x0D, 0x93, 0x4C, 0x20, 0x02, 0xC8, 0x73, 0x81, 0xC5 +}; + +static int CompareHuffmanCompressions0() +{ + unsigned char * pbDecompressed = Decompressed; + unsigned char * pbCompressed; + unsigned char * pbUncompressed; + int cbOutLength; + int cbInLength; + int nLength = sizeof(Decompressed); + int nError = ERROR_NOT_ENOUGH_MEMORY; + + // Allocate buffers for compressed buffer + pbCompressed = new unsigned char[nLength]; + if(pbCompressed != NULL) + { + // Perform the compression + cbInLength = + cbOutLength = nLength; + SCompCompress(pbCompressed, &cbOutLength, pbDecompressed, nLength, MPQ_COMPRESSION_HUFFMANN, 0x00, 0); + assert(cbOutLength < cbInLength); + + // Allocate space for decompressed buffer + pbUncompressed = new unsigned char[nLength]; + if(pbUncompressed != NULL) + { + // Perform the decompression + cbInLength = cbOutLength; + cbOutLength = nLength; + SCompDecompress(pbUncompressed, &cbOutLength, pbCompressed, cbInLength); + + // Compare length + if(cbOutLength == nLength) + { + if(!memcmp(pbUncompressed, pbDecompressed, nLength)) + { + _tprintf(_T("Huffmann compression OK\n")); + nError = ERROR_SUCCESS; + } + else + { + _tprintf(_T("Error: Decompressed data are not the same like the compressed ones\n")); + nError = ERROR_INVALID_DATA; + } + } + else + { + _tprintf(_T("Error: Length of the uncompressed data is different from original length\n")); + nError = ERROR_BAD_LENGTH; + } + + delete [] pbUncompressed; + } + + delete [] pbCompressed; + } + + assert(nError == ERROR_SUCCESS); + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// Compare PKLIB decompression + +BYTE pbCompressed1[] = {0x00, 0x04, 0x00, 0x00, 0x04, 0xF0, 0x1F, 0x7B, 0x01, 0xFF}; +BYTE pbCompressed2[] = {0x00, 0x04, 0x00, 0x00, 0x04, 0xF0, 0x1F, 0x00, 0x00, 0x04, 0xFC, 0x03}; + +static int ComparePklibCompressions() +{ + char Decompressed[0x1000]; + char Compressed[0x1000]; + int cbDecompressed = 0x208; + int cbCompressed = sizeof(Compressed); + + memset(Decompressed, 0, cbDecompressed); + SCompImplode(Compressed, &cbCompressed, Decompressed, cbDecompressed); + + cbDecompressed = sizeof(Decompressed); + SCompExplode(Decompressed, &cbDecompressed, Compressed, cbCompressed); + + + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// Compare LZMA decompression + +#ifdef PLATFORM_WINDOWS +typedef void * (*ALLOC_MEMORY)(size_t); +typedef void (*FREE_MEMORY)(void *); +typedef int (GIVE_DATA)(void *); + +extern "C" int starcraft_decompress_lzma(char * pbInBuffer, int cbInBuffer, char * pbOutBuffer, int cbOutBuffer, int * pcbOutBuffer, ALLOC_MEMORY pfnAllocMemory, FREE_MEMORY pfnFreeMemory); +extern "C" int starcraft_compress_lzma(char * pbInBuffer, int cbInBuffer, int dummy1, char * pbOutBuffer, int cbOutBuffer, int dummy2, int * pcbOutBuffer, ALLOC_MEMORY pfnAllocMemory, FREE_MEMORY pfnFreeMemory, GIVE_DATA pfnGiveData); +void Compress_LZMA(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer, int *, int); +int Decompress_LZMA(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer); + +extern "C" void * operator_new(size_t sz) +{ + return malloc(sz); +} + +void * Memory_Allocate(size_t byte_size) +{ + return malloc(byte_size); +} + +void Memory_Free(void * address) +{ + if(address != NULL) + free(address); +} + +int GiveData(void *) +{ + return 0; +} + +static int StarcraftCompress_LZMA(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer) +{ + return starcraft_compress_lzma(pbInBuffer, + cbInBuffer, + 0, + pbOutBuffer, + *pcbOutBuffer, + 0, + pcbOutBuffer, + Memory_Allocate, + Memory_Free, + GiveData); +} + +static int StarcraftDecompress_LZMA(char * pbOutBuffer, int * pcbOutBuffer, char * pbInBuffer, int cbInBuffer) +{ + return starcraft_decompress_lzma(pbInBuffer, + cbInBuffer, + pbOutBuffer, + *pcbOutBuffer, + pcbOutBuffer, + Memory_Allocate, + Memory_Free); +} + +static int CompareLzmaCompressions(int nSectorSize) +{ + LPBYTE pbCompressed1 = NULL; // Compressed by our code + LPBYTE pbCompressed2 = NULL; // Compressed by Blizzard's code + LPBYTE pbDecompressed1 = NULL; // Decompressed by our code + LPBYTE pbDecompressed2 = NULL; // Decompressed by Blizzard's code + LPBYTE pbOriginalData = NULL; + int nError = ERROR_SUCCESS; + + // Allocate buffers + // Must allocate twice blocks due to probable bug in Storm.dll. + // Storm.dll corrupts stack when uncompresses data with PKWARE DCL + // and no compression occurs. + pbDecompressed1 = new BYTE [nSectorSize]; + pbDecompressed2 = new BYTE [nSectorSize]; + pbCompressed1 = new BYTE [nSectorSize]; + pbCompressed2 = new BYTE [nSectorSize]; + pbOriginalData = new BYTE[nSectorSize]; + if(!pbDecompressed1 || !pbDecompressed2 || !pbCompressed1 || !pbCompressed2 || !pbOriginalData) + nError = ERROR_NOT_ENOUGH_MEMORY; + + if(nError == ERROR_SUCCESS) + { + for(int i = 0; i < 100000; i++) + { + int nDcmpLength1; + int nDcmpLength2; + int nCmpLength1; + int nCmpLength2; + int nDiff; + + clreol(); + _tprintf(_T("Testing compression of sector %u\r"), i + 1); + + // Generate random data sector + GenerateRandomDataBlock(pbOriginalData, nSectorSize); + + // Compress the sector by both methods + nCmpLength1 = nCmpLength2 = nSectorSize; +// Compress_LZMA((char *)pbCompressed1, &nCmpLength1, (char *)pbOriginalData, nSectorSize, 0, 0); + StarcraftCompress_LZMA((char *)pbCompressed1, &nCmpLength2, (char *)pbOriginalData, nSectorSize); + +__TryToDecompress: + + // Only test decompression when the compression actually succeeded + if(nCmpLength1 < nSectorSize) + { + // Decompress both data + nDcmpLength2 = nDcmpLength1 = nSectorSize; +// Decompress_LZMA((char *)pbDecompressed1, &nDcmpLength1, (char *)pbCompressed1, nCmpLength1); + StarcraftDecompress_LZMA((char *)pbDecompressed2, &nDcmpLength2, (char *)pbCompressed1, nCmpLength1); + + // Compare the length of the output data + if(nDcmpLength1 != nDcmpLength2) + { + _tprintf(_T("Difference in compressed blocks lengths (%u vs %u)\n"), nDcmpLength1, nDcmpLength2); + goto __TryToDecompress; + } + + // Compare the output + if((nDiff = GetFirstDiffer(pbDecompressed1, pbDecompressed2, nDcmpLength1)) != -1) + { + _tprintf(_T("Difference in decompressed blocks (offset 0x%08X)\n"), nDiff); + goto __TryToDecompress; + } + + // Check for data overflow + if(pbDecompressed1[nSectorSize] != 0xFD || pbDecompressed1[nSectorSize] != 0xFD) + { + _tprintf(_T("Damage after decompressed sector !!!\n")); + goto __TryToDecompress; + } + + // Compare the decompressed data against original data + if((nDiff = GetFirstDiffer(pbDecompressed1, pbOriginalData, nDcmpLength1)) != -1) + { + _tprintf(_T("Difference between original data and decompressed data (offset 0x%08X)\n"), nDiff); + goto __TryToDecompress; + } + } + } + } + + // Cleanup + if(pbOriginalData != NULL) + delete [] pbOriginalData; + if(pbCompressed2 != NULL) + delete [] pbCompressed2; + if(pbCompressed1 != NULL) + delete [] pbCompressed1; + if(pbDecompressed2 != NULL) + delete [] pbDecompressed2; + if(pbDecompressed1 != NULL) + delete [] pbDecompressed1; + clreol(); + return nError; +} +#endif // PLATFORM_WINDOWS + +//----------------------------------------------------------------------------- +// Compression method test + +static int TestSectorCompress(int nSectorSize) +{ + LPBYTE pbDecompressed = NULL; + LPBYTE pbCompressed = NULL; + LPBYTE pbOriginal = NULL; + int nError = ERROR_SUCCESS; + + // Allocate buffers + pbDecompressed = new BYTE[nSectorSize]; + pbCompressed = new BYTE[nSectorSize]; + pbOriginal = new BYTE[nSectorSize]; + if(!pbDecompressed || !pbCompressed || !pbOriginal) + nError = ERROR_NOT_ENOUGH_MEMORY; + + if(nError == ERROR_SUCCESS) + { + for(int i = 0; i < 100000; i++) + { + int nOriginalLength = nSectorSize % (rand() + 1); + int nCompressedLength; + int nDecompressedLength; + int nCmp = MPQ_COMPRESSION_SPARSE | MPQ_COMPRESSION_ZLIB | MPQ_COMPRESSION_BZIP2 | MPQ_COMPRESSION_PKWARE; + int nDiff; + + clreol(); + _tprintf(_T("Testing compression of sector %u\r"), i + 1); + + // Generate random data sector + GenerateRandomDataBlock(pbOriginal, nOriginalLength); + if(nOriginalLength == 0x123) + nOriginalLength = 0; + +__TryAgain: + + // Compress the sector + nCompressedLength = nOriginalLength; + SCompCompress((char *)pbCompressed, &nCompressedLength, (char *)pbOriginal, nOriginalLength, nCmp, 0, -1); +// SCompImplode((char *)pbCompressed, &nCompressedLength, (char *)pbOriginal, nOriginalLength); + + // When the method was unable to compress data, + // the compressed data must be identical to original data + if(nCompressedLength == nOriginalLength) + { + if((nDiff = GetFirstDiffer(pbCompressed, pbOriginal, nOriginalLength)) != -1) + { + _tprintf(_T("Compression error: Fail when unable to compress the data (Offset 0x%08X).\n"), nDiff); + goto __TryAgain; + } + } + + // Uncompress the sector + nDecompressedLength = nOriginalLength; + SCompDecompress((char *)pbDecompressed, &nDecompressedLength, (char *)pbCompressed, nCompressedLength); +// SCompExplode((char *)pbDecompressed, &nDecompressedLength, (char *)pbCompressed, nCompressedLength); + + // Check the decompressed length against original length + if(nDecompressedLength != nOriginalLength) + { + _tprintf(_T("Length of uncompressed data does not agree with original data length !!!\n")); + goto __TryAgain; + } + + // Check decompressed block against original block + if((nDiff = GetFirstDiffer(pbDecompressed, pbOriginal, nOriginalLength)) != -1) + { + _tprintf(_T("Decompressed sector does not agree with the original data !!! (Offset 0x%08X)\n"), nDiff); + goto __TryAgain; + } + } + } + + // Cleanup + delete [] pbOriginal; + delete [] pbCompressed; + delete [] pbDecompressed; + clreol(); + return nError; +} + +static int TestArchiveOpenAndClose(const TCHAR * szMpqName) +{ + const char * szFileName1 = "Sound\\terran\\duran\\TDnPss01.wav"; +// const char * szFileName2 = "items\\map\\mapz_deleted.cel"; + TMPQArchive * ha = NULL; + HANDLE hFile1 = NULL; +// HANDLE hFile2 = NULL; + HANDLE hMpq = NULL; + int nError = ERROR_SUCCESS; + + if(nError == ERROR_SUCCESS) + { + _tprintf(_T("Opening archive %s ...\n"), szMpqName); + if(!SFileOpenArchive(szMpqName, 0, STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE, &hMpq)) + nError = GetLastError(); + ha = (TMPQArchive *)hMpq; + } + + if(nError == ERROR_SUCCESS) + { + SFileAddListFile(hMpq, "c:\\Tools32\\Listfiles\\ListFile.txt"); + } + + // Verify the raw data in the archive + if(nError == ERROR_SUCCESS) + { + // Verify the archive + SFileVerifyRawData(hMpq, SFILE_VERIFY_FILE, szFileName1); + + // Try to open a file + if(!SFileOpenFileEx(hMpq, szFileName1, SFILE_OPEN_FROM_MPQ, &hFile1)) + { + nError = GetLastError(); + printf("%s - file not found in the MPQ\n", szFileName1); + } + } + + // Dummy read from the file + if(nError == ERROR_SUCCESS) + { + DWORD dwBytesRead = 0; + BYTE Buffer[0x1000]; + + SFileSetFilePointer(hFile1, 0x1000, NULL, FILE_BEGIN); + SFileReadFile(hFile1, Buffer, sizeof(Buffer), &dwBytesRead, NULL); + } + + // Verify the MPQ listfile +#ifdef _MSC_VER + if(nError == ERROR_SUCCESS) + { + SFileExtractFile(hMpq, szFileName1, _T("E:\\extracted.wav"), 0); + PlaySound(_T("E:\\extracted.wav"), NULL, SND_FILENAME); + } +#endif + + if(hFile1 != NULL) + SFileCloseFile(hFile1); + if(hMpq != NULL) + SFileCloseArchive(hMpq); + return nError; +} + +static int TestFindFiles(const TCHAR * szMpqName) +{ + TMPQFile * hf; + HANDLE hFile; + HANDLE hMpq = NULL; + BYTE Buffer[100]; + int nError = ERROR_SUCCESS; + int nFiles = 0; + int nFound = 0; + + // Open the archive + if(nError == ERROR_SUCCESS) + { + _tprintf(_T("Opening \"%s\" for finding files ...\n"), szMpqName); + if(!SFileOpenArchive(szMpqName, 0, 0, &hMpq)) + nError = GetLastError(); + } + + // Compact the archive + if(nError == ERROR_SUCCESS) + { + SFILE_FIND_DATA sf; + HANDLE hFind; + DWORD dwExtraDataSize; + bool bFound = true; + + hFind = SFileFindFirstFile(hMpq, "*", &sf, "c:\\Tools32\\ListFiles\\ListFile.txt"); + while(hFind != NULL && bFound != false) + { + if(SFileOpenFileEx(hMpq, sf.cFileName, 0, &hFile)) + { + hf = (TMPQFile *)hFile; + SFileReadFile(hFile, Buffer, sizeof(Buffer), NULL, NULL); + nFiles++; + + if(sf.dwFileFlags & MPQ_FILE_SECTOR_CRC) + { + dwExtraDataSize = hf->SectorOffsets[hf->dwSectorCount + 1] - hf->SectorOffsets[hf->dwSectorCount]; + if(dwExtraDataSize != 0) + nFound++; + } + + SFileCloseFile(hFile); + } + + bFound = SFileFindNextFile(hFind, &sf); + } + } + + if(hMpq != NULL) + SFileCloseArchive(hMpq); + if(nError == ERROR_SUCCESS) + _tprintf(_T("Search complete\n")); + return nError; +} + +static int TestMpqCompacting(const TCHAR * szMpqName) +{ + HANDLE hMpq = NULL; + int nError = ERROR_SUCCESS; + + // Open the archive + if(nError == ERROR_SUCCESS) + { + _tprintf(_T("Opening \"%s\" for compacting ...\n"), szMpqName); + if(!SFileOpenArchive(szMpqName, 0, 0, &hMpq)) + nError = GetLastError(); + } + + if(nError == ERROR_SUCCESS) + { + const char * szFileName = "Shaders\\Effects\\shadowmap.wfx"; + + printf("Deleting file %s ...\r", szFileName); + if(!SFileRemoveFile(hMpq, szFileName, SFILE_OPEN_FROM_MPQ)) + nError = GetLastError(); + } +/* + // Compact the archive + if(nError == ERROR_SUCCESS) + { + _tprintf(_T("Compacting archive ...\r")); + SFileSetCompactCallback(hMpq, CompactCB, NULL); + if(!SFileCompactArchive(hMpq, "c:\\Tools32\\ListFiles\\ListFile.txt")) + nError = GetLastError(); + } +*/ + if(hMpq != NULL) + SFileCloseArchive(hMpq); + if(nError == ERROR_SUCCESS) + _tprintf(_T("Compacting complete (No errors)\n")); + return nError; +} + +static int TestCreateArchive(const TCHAR * szMpqName) +{ + TFileStream * pStream; + const TCHAR * szFileName1 = MAKE_PATH("FileTest.exe"); + const TCHAR * szFileName2 = MAKE_PATH("ZeroSize.txt"); + HANDLE hMpq = NULL; // Handle of created archive + DWORD dwVerifyResult; + DWORD dwFileCount = 0; + LCID LocaleIDs[] = {0x000, 0x405, 0x406, 0x407, 0xFFFF}; + char szMpqFileName[MAX_PATH]; + int nError = ERROR_SUCCESS; + int i; + + // Create the new file + _tprintf(_T("Creating %s ...\n"), szMpqName); + pStream = FileStream_CreateFile(szMpqName, STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE); + if(pStream == NULL) + nError = GetLastError(); + + // Write some data + if(nError == ERROR_SUCCESS) + { + ULONGLONG FileSize = 0x100000; + + FileStream_SetSize(pStream, FileSize); + FileStream_Close(pStream); + } + + // Well, now create the MPQ archive + if(nError == ERROR_SUCCESS) + { + if(!SFileCreateArchive(szMpqName, + MPQ_CREATE_ARCHIVE_V4 | MPQ_CREATE_ATTRIBUTES, + 17, + &hMpq)) + { + nError = GetLastError(); + } + } + + // Add the same file multiple times + if(nError == ERROR_SUCCESS) + { + // Add FileTest.exe + for(i = 0; AddFlags[i] != 0xFFFFFFFF; i++) + { + sprintf(szMpqFileName, "FileTest_%02u.exe", i); + PrintfTA(_T("Adding %s as %s ...\n"), szFileName1, szMpqFileName); + if(SFileAddFileEx(hMpq, szFileName1, szMpqFileName, AddFlags[i], MPQ_COMPRESSION_ZLIB, MPQ_COMPRESSION_NEXT_SAME)) + { + dwVerifyResult = SFileVerifyFile(hMpq, szMpqFileName, MPQ_ATTRIBUTE_CRC32 | MPQ_ATTRIBUTE_MD5); + if(dwVerifyResult & (VERIFY_OPEN_ERROR | VERIFY_READ_ERROR | VERIFY_FILE_SECTOR_CRC_ERROR | VERIFY_FILE_CHECKSUM_ERROR | VERIFY_FILE_MD5_ERROR)) + printf("CRC error on \"%s\"\n", szMpqFileName); + dwFileCount++; + } + else + { + printf("Failed to add the file \"%s\".\n", szMpqFileName); + } + } + + + // Delete a file in the middle of the file table + SFileRemoveFile(hMpq, "FileTest_10.exe", SFILE_OPEN_FROM_MPQ); + SFileAddFileEx(hMpq, szFileName1, "FileTest_xx.exe", MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED, MPQ_COMPRESSION_ZLIB, MPQ_COMPRESSION_NEXT_SAME); + + // Try to decrement max file count + dwFileCount = SFileGetMaxFileCount(hMpq); + SFileSetMaxFileCount(hMpq, dwFileCount - 1); + + // Add ZeroSize.txt (1) + sprintf(szMpqFileName, "ZeroSize_1.txt"); + for(i = 0; LocaleIDs[i] != 0xFFFF; i++) + { + PrintfTA(_T("Adding %s as %s (locale %04x) ...\n"), szFileName2, szMpqFileName, LocaleIDs[i]); + SFileSetLocale(LocaleIDs[i]); + if(!SFileAddFileEx(hMpq, szFileName2, szMpqFileName, MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED, MPQ_COMPRESSION_ZLIB, MPQ_COMPRESSION_NEXT_SAME)) + printf("Cannot add the file\n"); + } + + // Add ZeroSize.txt (1) + sprintf(szMpqFileName, "ZeroSize_2.txt"); + for(int i = 0; LocaleIDs[i] != 0xFFFF; i++) + { + PrintfTA(_T("Adding %s as %s (locale %04x) ...\n"), szFileName2, szMpqFileName, LocaleIDs[i]); + SFileSetLocale(LocaleIDs[i]); + if(!SFileAddFileEx(hMpq, szFileName2, szMpqFileName, MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED, MPQ_COMPRESSION_ZLIB, MPQ_COMPRESSION_NEXT_SAME)) + printf("Cannot add the file\n"); + } + } + + // Test rename function + if(nError == ERROR_SUCCESS) + { + _tprintf(_T("Testing rename files ...\n")); + SFileSetLocale(LANG_NEUTRAL); + if(!SFileRenameFile(hMpq, "FileTest_08.exe", "FileTest_08a.exe")) + { + nError = GetLastError(); + _tprintf(_T("Failed to rename the file\n")); + } + + if(!SFileRenameFile(hMpq, "FileTest_08a.exe", "FileTest_08.exe")) + { + nError = GetLastError(); + _tprintf(_T("Failed to rename the file\n")); + } + + if(!SFileRenameFile(hMpq, "FileTest_10.exe", "FileTest_10a.exe")) + { + nError = GetLastError(); + _tprintf(_T("Failed to rename the file\n")); + } + + if(!SFileRenameFile(hMpq, "FileTest_10a.exe", "FileTest_10.exe")) + { + nError = GetLastError(); + _tprintf(_T("Failed to rename the file\n")); + } + + if(nError == ERROR_SUCCESS) + _tprintf(_T("Rename test succeeded.\n\n")); + else + _tprintf(_T("Rename test failed.\n\n")); + } + + // Compact the archive +// if(nError == ERROR_SUCCESS) +// SFileCompactArchive(hMpq); + + // Test changing hash table size + if(nError == ERROR_SUCCESS) + SFileSetMaxFileCount(hMpq, 0x95); + + if(hMpq != NULL) + SFileCloseArchive(hMpq); + + // Try to reopen the archive + if(SFileOpenArchive(szMpqName, 0, 0, &hMpq)) + SFileCloseArchive(hMpq); + + _tprintf(_T("\n")); + return nError; +} + +static int TestCreateArchive_PaliRoharBug(const TCHAR * szMpqName) +{ + const TCHAR * szFileName = MAKE_PATH("FileTest.exe"); + HANDLE hMpq = NULL; // Handle of created archive + DWORD dwMaxFileCount = 0; + DWORD dwMpqFlags = MPQ_FILE_ENCRYPTED | MPQ_FILE_COMPRESS; + char szMpqFileName[MAX_PATH]; + int nError = ERROR_SUCCESS; + int i; + + _tremove(szMpqName); + if(SFileCreateArchive(szMpqName, + MPQ_CREATE_ARCHIVE_V4 | MPQ_CREATE_ATTRIBUTES, + 1, + &hMpq)) + { + // Add the file there + SFileAddFileEx(hMpq, szFileName, "FileTest_base.exe", dwMpqFlags, MPQ_COMPRESSION_ZLIB, MPQ_COMPRESSION_NEXT_SAME); + SFileFlushArchive(hMpq); + SFileCloseArchive(hMpq); + + // Add the same file 10 times + for(i = 0; i < 10; i++) + { + if(SFileOpenArchive(szMpqName, 0, 0, &hMpq)) + { + dwMaxFileCount = SFileGetMaxFileCount(hMpq) + 1; + _tprintf(_T("Increasing max file count to %u ...\n"), dwMaxFileCount); + SFileSetMaxFileCount(hMpq, dwMaxFileCount); + + sprintf(szMpqFileName, "FileTest_%02u.exe", dwMaxFileCount); + PrintfTA(_T("Adding %s as %s\n"), szFileName, szMpqFileName); + if(!SFileAddFileEx(hMpq, szFileName, szMpqFileName, dwMpqFlags, MPQ_COMPRESSION_ZLIB, MPQ_COMPRESSION_NEXT_SAME)) + { + printf("Failed to add the file \"%s\".\n", szMpqFileName); + break; + } + + SFileFlushArchive(hMpq); + SFileCompactArchive(hMpq, NULL, false); + SFileCloseArchive(hMpq); + } + } + } + + _tprintf(_T("\n")); + return nError; +} + + +static int TestAddFilesToMpq( + const TCHAR * szMpqName, + ... + ) +{ + const TCHAR * szFileName; + const TCHAR * szSrc; + char * szTrg; + HANDLE hMpq; + va_list argList; + char szMpqFileName[MAX_PATH]; + int nError = ERROR_SUCCESS; + + if(!SFileOpenArchive(szMpqName, 0, 0, &hMpq)) + return GetLastError(); + + va_start(argList, szMpqName); + while((szFileName = va_arg(argList, const TCHAR *)) != NULL) + { + // Convert the plain name to ANSI + szSrc = GetPlainFileNameT(szFileName); + szTrg = szMpqFileName; + while(*szSrc != 0) + *szTrg++ = (char)*szSrc++; + *szTrg = 0; + + // Add the file to MPQ + if(!SFileAddFileEx(hMpq, szFileName, + szMpqFileName, + MPQ_FILE_COMPRESS, + MPQ_COMPRESSION_ZLIB, + MPQ_COMPRESSION_NEXT_SAME)) + { + nError = GetLastError(); + printf("Failed to add the file \"%s\"\n", szFileName); + } + } + + SFileCloseArchive(hMpq); + return nError; +} + +static int TestCreateArchiveFromMemory(const TCHAR * szMpqName) +{ +#define FILE_SIZE 65535 + + HANDLE hFile; + HANDLE hMPQ; + char* data = new char [FILE_SIZE]; // random memory data + char szFileName[100]; + int i; + + // Create an mpq file for testing + if(SFileCreateArchive(szMpqName, MPQ_CREATE_ARCHIVE_V2|MPQ_CREATE_ATTRIBUTES, 0x100000, &hMPQ)) + { + for(i = 0; i < 1000; i++) + { + sprintf(szFileName, "File%03u.bin", i); + printf("Adding file %s\r", szFileName); + + if(SFileCreateFile(hMPQ, szFileName, 0, FILE_SIZE, 0, MPQ_FILE_COMPRESS, &hFile)) + { + SFileWriteFile(hFile, data, FILE_SIZE, MPQ_COMPRESSION_ZLIB); + SFileFinishFile(hFile); + } + } + } + SFileCloseArchive(hMPQ); + delete [] data; + return ERROR_SUCCESS; +} + +static int TestFileReadAndWrite( + const TCHAR * szMpqName, + const char * szFileName) +{ + LPBYTE pvFile = NULL; + HANDLE hFile = NULL; + HANDLE hMpq = NULL; + DWORD dwBytesRead; + DWORD dwFileSize = 0; + int nError = ERROR_SUCCESS; + + if(!SFileOpenArchive(szMpqName, 0, 0, &hMpq)) + { + nError = GetLastError(); + _tprintf(_T("Failed to open the archive %s (%u).\n"), szMpqName, nError); + } + + if(nError == ERROR_SUCCESS) + { + if(!SFileOpenFileEx(hMpq, szFileName, 0, &hFile)) + { + nError = GetLastError(); + printf("Failed to open the file %s (%u).\n", szFileName, nError); + } + } + + if(nError == ERROR_SUCCESS) + { + if(!SFileGetFileInfo(hFile, SFILE_INFO_FILE_SIZE, &dwFileSize, sizeof(DWORD), NULL)) + { + nError = GetLastError(); + _tprintf(_T("Failed to get the file size (%u).\n"), nError); + } + } + + if(nError == ERROR_SUCCESS) + { + pvFile = new BYTE[dwFileSize]; + if(pvFile == NULL) + { + nError = ERROR_NOT_ENOUGH_MEMORY; + printf("Failed to allocate buffer for the file (%u).\n", nError); + } + } + + if(nError == ERROR_SUCCESS) + { + if(!SFileReadFile(hFile, pvFile, dwFileSize, &dwBytesRead, NULL)) + { + nError = GetLastError(); + printf("Failed to read file (%u).\n", nError); + } + } + + if(hFile != NULL) + { + SFileCloseFile(hFile); + hFile = NULL; + } + + if(nError == ERROR_SUCCESS) + { + if(!SFileCreateFile(hMpq, szFileName, 0, dwFileSize, 0, MPQ_FILE_REPLACEEXISTING, &hFile)) + { + nError = GetLastError(); + printf("Failed to create %s in the archive (%u).\n", szFileName, nError); + } + } + + if(nError == ERROR_SUCCESS) + { + if(!SFileWriteFile(hFile, pvFile, dwFileSize, 0)) + { + nError = GetLastError(); + printf("Failed to write the data to the MPQ (%u).\n", nError); + } + } + + if(hFile != NULL) + { + if(!SFileFinishFile(hFile)) + { + nError = GetLastError(); + printf("Failed to finalize file creation (%u).\n", nError); + } + } + + if(pvFile != NULL) + delete [] pvFile; + if(hMpq != NULL) + SFileCloseArchive(hMpq); + return nError; +} + +static int TestSignatureVerify(const TCHAR * szMpqName) +{ + HANDLE hMpq; + + if(SFileOpenArchive(szMpqName, 0, 0, &hMpq)) + { + _tprintf(_T("Verifying digital signature in %s:\n"), szMpqName); + switch(SFileVerifyArchive(hMpq)) + { + case ERROR_NO_SIGNATURE: + _tprintf(_T("No digital signature present.\n")); + break; + + case ERROR_VERIFY_FAILED: + _tprintf(_T("Failed to verify signature.\n")); + break; + + case ERROR_WEAK_SIGNATURE_OK: + _tprintf(_T("Weak signature is OK.\n")); + break; + + case ERROR_WEAK_SIGNATURE_ERROR: + _tprintf(_T("Weak signature mismatch.\n")); + break; + + case ERROR_STRONG_SIGNATURE_OK: + _tprintf(_T("Strong signature is OK.\n")); + break; + + case ERROR_STRONG_SIGNATURE_ERROR: + _tprintf(_T("Strong signature mismatch.\n")); + break; + } + + SFileCloseArchive(hMpq); + _tprintf(_T("\n")); + } + + return 0; +} + + +static int TestCreateArchiveCopy(const TCHAR * szMpqName, const TCHAR * szMpqCopyName, const char * szListFile) +{ + TFileStream * pStream; + TCHAR szLocalFile[MAX_PATH]; + HANDLE hMpq1 = NULL; // Handle of existing archive + HANDLE hMpq2 = NULL; // Handle of created archive + DWORD dwHashTableSize = 0; + int nError = ERROR_SUCCESS; + + // If no listfile or an empty one, use NULL + if(szListFile == NULL || *szListFile == 0) + szListFile = NULL; + + // Create the new file + pStream = FileStream_CreateFile(szMpqCopyName, STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE); + if(pStream == NULL) + nError = GetLastError(); + + // Write some data + if(nError == ERROR_SUCCESS) + { + ULONGLONG FileSize = 0x100000; + + FileStream_SetSize(pStream, FileSize); + FileStream_Close(pStream); + } + + // Open the existing MPQ archive + if(nError == ERROR_SUCCESS) + { + _tprintf(_T("Opening %s ...\n"), szMpqName); + if(!SFileOpenArchive(szMpqName, 0, 0, &hMpq1)) + nError = GetLastError(); + } + + // Well, now create the MPQ archive + if(nError == ERROR_SUCCESS) + { + _tprintf(_T("Creating %s ...\n"), szMpqCopyName); + SFileGetFileInfo(hMpq1, SFILE_INFO_HASH_TABLE_SIZE, &dwHashTableSize, 4, NULL); + if(!SFileCreateArchive(szMpqCopyName, 0, dwHashTableSize, &hMpq2)) + nError = GetLastError(); + } + + // Copy all files from one archive to another + if(nError == ERROR_SUCCESS) + { + SFILE_FIND_DATA sf; + HANDLE hFind = SFileFindFirstFile(hMpq1, "*", &sf, szListFile); + bool bResult = true; + + _tprintf(_T("Copying files ...\n")); + + if(hFind != NULL) + { + while(bResult) + { + if(strcmp(sf.cFileName, LISTFILE_NAME) && strcmp(sf.cFileName, ATTRIBUTES_NAME)) + { + SFileSetLocale(sf.lcLocale); + + // Create the local file name + MergeLocalPath(szLocalFile, szWorkDir, sf.szPlainName); + if(SFileExtractFile(hMpq1, sf.cFileName, szLocalFile, SFILE_OPEN_FROM_MPQ)) + { + printf("Extracting %s ... OK\n", sf.cFileName); + if(!SFileAddFile(hMpq2, szLocalFile, sf.cFileName, sf.dwFileFlags)) + { + nError = GetLastError(); + printf("Adding %s ... Failed\n\n", sf.cFileName); + _tremove(szLocalFile); + break; + } + else + { + printf("Adding %s ... OK\n", sf.cFileName); + } + } + else + { + printf("Extracting %s ... Failed\n", sf.cFileName); + } + + // Delete the added file + _tremove(szLocalFile); + } + + // Find the next file + bResult = SFileFindNextFile(hFind, &sf); + } + + // Close the search handle + SFileFindClose(hFind); + printf("\n"); + } + } + + // Close both archives + if(hMpq2 != NULL) + SFileCloseArchive(hMpq2); + if(hMpq1 != NULL) + SFileCloseArchive(hMpq1); + return nError; +} + +static int TestOpenPatchedArchive(const TCHAR * szMpqName, ...) +{ + TFileStream * pStream; + HANDLE hFile = NULL; + HANDLE hMpq = NULL; + va_list argList; + const char * szFileName = "Interface/Cinematics/MOP_BR.mp3"; + TCHAR szLocFileName[MAX_PATH]; + LPBYTE pbFullFile = NULL; + DWORD dwFileSize; + int nError = ERROR_SUCCESS; + + // Open the primary MPQ + _tprintf(_T("Opening %s ...\n"), szMpqName); + if(!SFileOpenArchive(szMpqName, 0, MPQ_OPEN_READ_ONLY, &hMpq)) + { + nError = GetLastError(); + _tprintf(_T("Failed to open the archive %s ...\n"), szMpqName); + } + + // Add all patches + if(nError == ERROR_SUCCESS) + { + va_start(argList, szMpqName); + while((szMpqName = va_arg(argList, const TCHAR *)) != NULL) + { + _tprintf(_T("Adding patch %s ...\n"), szMpqName); + if(!SFileOpenPatchArchive(hMpq, szMpqName, NULL, 0)) + { + nError = GetLastError(); + printf("Failed to add patch %s ...\n", szMpqName); + } + } + va_end(argList); + } +/* + // Now search all files + if(nError == ERROR_SUCCESS) + { + SFILE_FIND_DATA sf; + HANDLE hFind; + bool bResult = true; + + hFind = SFileFindFirstFile(hMpq, "World\\Minimaps\\Azeroth\\noLiquid_map20_44.*", &sf, NULL); + while(hFind && bResult) + { + printf("%s\n", sf.cFileName); + bResult = SFileFindNextFile(hFind, &sf); + } + } + + // Now try to open patched version of a file + if(nError == ERROR_SUCCESS) + { + SFileExtractFile(hMpq, szFileName, _T("E:\\noLiquid_map20_44.blp"), SFILE_OPEN_FROM_MPQ); + } +*/ + // Now try to open patched version of "Achievement.dbc" + if(nError == ERROR_SUCCESS) + { + printf("Opening patched file \"%s\" ...\n", szFileName); + SFileHasFile(hMpq, szFileName); + SFileVerifyFile(hMpq, szFileName, SFILE_VERIFY_RAW_MD5); + if(!SFileOpenFileEx(hMpq, szFileName, 0, &hFile)) + { + nError = GetLastError(); + printf("Failed to open patched file \"%s\"\n", szFileName); + } + } + + // Verify of the patched version is correct + if(nError == ERROR_SUCCESS) + { + TCHAR * szPatchChain = NULL; + DWORD cbPatchChain = 0; + + // Get the patch chain + SFileGetFileInfo(hFile, SFILE_INFO_PATCH_CHAIN, szPatchChain, cbPatchChain, &cbPatchChain); + szPatchChain = (TCHAR *)(new BYTE[cbPatchChain]); + SFileGetFileInfo(hFile, SFILE_INFO_PATCH_CHAIN, szPatchChain, cbPatchChain, &cbPatchChain); + delete [] szPatchChain; + + // Get the size of the full patched file + dwFileSize = SFileGetFileSize(hFile, NULL); + if(dwFileSize != 0) + { + DWORD dwBytesRead = 0; + BYTE TempData[0x100]; + + SFileReadFile(hFile, TempData, sizeof(TempData), &dwBytesRead, NULL); + SFileSetFilePointer(hFile, 0, NULL, FILE_BEGIN); + + // Allocate space for the full file + pbFullFile = new BYTE[dwFileSize]; + if(pbFullFile != NULL) + { + if(!SFileReadFile(hFile, pbFullFile, dwFileSize, NULL, NULL)) + { + nError = GetLastError(); + printf("Failed to read full patched file data \"%s\"\n", szFileName); + } + + if(nError == ERROR_SUCCESS) + { + MergeLocalPath(szLocFileName, MAKE_PATH("Work//"), GetPlainFileNameA(szFileName)); + pStream = FileStream_CreateFile(szLocFileName, STREAM_PROVIDER_LINEAR | BASE_PROVIDER_FILE); + if(pStream != NULL) + { + FileStream_Write(pStream, NULL, pbFullFile, dwFileSize); + FileStream_Close(pStream); + } + } + + delete [] pbFullFile; + } + } + } + + // Close handles + if(hFile != NULL) + SFileCloseFile(hFile); + if(hMpq != NULL) + SFileCloseArchive(hMpq); + return nError; +} + +static int TestCompareTwoArchives( + const TCHAR * szMpqName1, + const TCHAR * szMpqName2, + const char * szListFile, + DWORD dwBlockSize) +{ + TMPQArchive * ha1 = NULL; + TMPQArchive * ha2 = NULL; + HANDLE hMpq1 = NULL; // Handle of the first archive + HANDLE hMpq2 = NULL; // Handle of the second archive + HANDLE hFile1 = NULL; + HANDLE hFile2 = NULL; + int nError = ERROR_SUCCESS; + + // If no listfile or an empty one, use NULL + if(szListFile == NULL || *szListFile == 0) + szListFile = NULL; + + _tprintf(_T("=============== Comparing MPQ archives ===============\n")); + + // Open the first MPQ archive + if(nError == ERROR_SUCCESS && szMpqName1 != NULL) + { + _tprintf(_T("Opening %s ...\n"), szMpqName1); + if(!SFileOpenArchive(szMpqName1, 0, 0, &hMpq1)) + nError = GetLastError(); + ha1 = (TMPQArchive *)hMpq1; + } + + // Open the second MPQ archive + if(nError == ERROR_SUCCESS && szMpqName2 != NULL) + { + _tprintf(_T("Opening %s ...\n"), szMpqName2); + if(!SFileOpenArchive(szMpqName2, 0, 0, &hMpq2)) + nError = GetLastError(); + ha2 = (TMPQArchive *)hMpq2; + } + + // Compare the header + if(nError == ERROR_SUCCESS && (ha1 != NULL && ha2 != NULL)) + { + if(ha1->pHeader->dwHeaderSize != ha2->pHeader->dwHeaderSize) + printf(" - Header size is different\n"); + if(ha1->pHeader->wFormatVersion != ha2->pHeader->wFormatVersion) + printf(" - Format version is different\n"); + if(ha1->pHeader->wSectorSize != ha2->pHeader->wSectorSize) + printf(" - Sector size is different\n"); + if(ha1->pHeader->HetTableSize64 != ha2->pHeader->HetTableSize64) + printf(" - HET table size is different\n"); + if(ha1->pHeader->BetTableSize64 != ha2->pHeader->BetTableSize64) + printf(" - BET table size is different\n"); + if(ha1->pHeader->dwHashTableSize != ha2->pHeader->dwHashTableSize) + printf(" - Hash table size is different\n"); + if(ha1->pHeader->dwBlockTableSize != ha2->pHeader->dwBlockTableSize) + printf(" - Block table size is different\n"); + } + + // Find all files in the first archive and compare them + if(nError == ERROR_SUCCESS) + { + SFILE_FIND_DATA sf; + TMPQFile * hf1; + TMPQFile * hf2; + HANDLE hFind = SFileFindFirstFile(hMpq1, "*", &sf, szListFile); + bool bResult = true; + + while(hFind != NULL && bResult == true) + { +// printf("%s \r", sf.cFileName); + SFileSetLocale(sf.lcLocale); + + // Open the first file + if(!SFileOpenFileEx(hMpq1, sf.cFileName, 0, &hFile1)) + printf("Failed to open the file %s in the first archive\n", sf.cFileName); + + if(!SFileOpenFileEx(hMpq2, sf.cFileName, 0, &hFile2)) + printf("Failed to open the file %s in the second archive\n", sf.cFileName); + + if(hFile1 != NULL && hFile2 != NULL) + { + // Get the TMPQFile pointers + hf1 = (TMPQFile *)hFile1; + hf2 = (TMPQFile *)hFile2; + + // Compare the file sizes + if(hf1->pFileEntry->dwFileSize != hf2->pFileEntry->dwFileSize) + printf("Different file size: %s (%u x %u)\n", sf.cFileName, hf1->pFileEntry->dwFileSize, hf2->pFileEntry->dwFileSize); + + if(hf1->pFileEntry->dwCmpSize != hf2->pFileEntry->dwCmpSize) + printf("Different cmpr size: %s (%u x %u)\n", sf.cFileName, hf1->pFileEntry->dwCmpSize, hf2->pFileEntry->dwCmpSize); + + if(hf1->pFileEntry->dwFlags != hf2->pFileEntry->dwFlags) + printf("Different mpq flags: %s (%08X x %08X)\n", sf.cFileName, hf1->pFileEntry->dwFlags, hf2->pFileEntry->dwFlags); + + if(!CompareArchivedFiles(sf.cFileName, hFile1, hFile2, dwBlockSize)) + printf("Different file data: %s\n", sf.cFileName); + +// if(!CompareArchivedFilesRR(sf.cFileName, hFile1, hFile2, dwBlockSize)) +// printf("Different file data: %s\n", sf.cFileName); + } + + // Close both files + if(hFile2 != NULL) + SFileCloseFile(hFile2); + if(hFile1 != NULL) + SFileCloseFile(hFile1); + hFile2 = hFile1 = NULL; + + // Find the next file + bResult = SFileFindNextFile(hFind, &sf); + } + + // Close the find handle + if(hFind != NULL) + SFileFindClose(hFind); + } + + // Close both archives + clreol(); + printf("================ MPQ compare complete ================\n"); + if(hMpq2 != NULL) + SFileCloseArchive(hMpq2); + if(hMpq1 != NULL) + SFileCloseArchive(hMpq1); + return nError; +} + +//----------------------------------------------------------------------------- +// Searching all known MPQs + +#ifdef _WIN32 +static int TestSearchOneArchive(const TCHAR * szMpqName) +{ + SFILE_FIND_DATA sf; + HANDLE hFind; + HANDLE hMpq; + const TCHAR * szExtension; + bool bFound = true; + + // Get the file extension + szExtension = _tcsrchr(szMpqName, _T('.')); + if(szExtension == NULL) + return ERROR_SUCCESS; + + // Only search defined extensions + if(_tcsicmp(szExtension, _T(".mpq")) && _tcsnicmp(szExtension, _T(".SC2"), 4)) + return ERROR_SUCCESS; + + _tprintf(_T("Searching %s ...\n"), szMpqName); + + // Try to open the MPQ + if(SFileOpenArchive(szMpqName, 0, MPQ_OPEN_READ_ONLY, &hMpq)) + { + hFind = SFileFindFirstFile(hMpq, "*", &sf, NULL); + if(hFind != NULL) + { + while(bFound) + { + if(sf.dwFileFlags & MPQ_FILE_DELETE_MARKER) + _tprintf(_T("Delete marker: %s:%hs\n"), szMpqName, sf.cFileName); + + bFound = SFileFindNextFile(hFind, &sf); + } + } + + SFileCloseArchive(hMpq); + } + + return ERROR_SUCCESS; +} + +static int TestSearchAllArchives(const TCHAR * szSearchMask) +{ + WIN32_FIND_DATA wf; + LPTSTR szFilePart; + HANDLE hFind; + TCHAR szFullPath[MAX_PATH]; + BOOL bFound = TRUE; + + // Initiate search + _tcscpy(szFullPath, szSearchMask); + szFilePart = _tcschr(szFullPath, _T('*')); + assert(szFilePart != NULL); + + // Begin search + hFind = FindFirstFile(szSearchMask, &wf); + if(hFind != INVALID_HANDLE_VALUE) + { + while(bFound) + { + // Eliminate "." and ".." + if(wf.cFileName[0] != _T('.')) + { + // Construct the full path + _tcscpy(szFilePart, wf.cFileName); + + // If it a directory? + if(wf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + _tcscat(szFullPath, _T("\\*")); + TestSearchAllArchives(szFullPath); + } + else + { + TestSearchOneArchive(szFullPath); + } + } + bFound = FindNextFile(hFind, &wf); + } + FindClose(hFind); + } + + return ERROR_SUCCESS; +} +#endif + +//----------------------------------------------------------------------------- +// Main +// + +int main(void) +{ + int nError = ERROR_SUCCESS; + +#if defined(_MSC_VER) && defined(_DEBUG) + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); +#endif // defined(_MSC_VER) && defined(_DEBUG) + + // Mix the random number generator +// srand(GetTickCount()); + +// FileStream_OpenEncrypted(_T("e:\\Multimedia\\MPQs\\2010 - Starcraft II\\Installer UI 2 deDE.MPQE")); + + // Test structure sizes +// if(nError == ERROR_SUCCESS) +// nError = TestStructureSizes(); + +// if(nError == ERROR_SUCCESS) +// nError = TestOpenLocalFile("C:\\autoexec.bat"); + + // Test reading partial file +// if(nError == ERROR_SUCCESS) +// nError = TestPartFileRead(MAKE_PATH("2009 - PartialMPQs/patch.MPQ.part")); + + if(nError == ERROR_SUCCESS) + { + CompareHuffmanCompressions7(); + nError = CompareHuffmanCompressions0(); + } + +// if(nError == ERROR_SUCCESS) +// nError = ComparePklibCompressions(); + + // Test LZMA compression method against the code ripped from Starcraft II +// if(nError == ERROR_SUCCESS) +// nError = CompareLzmaCompressions(MPQ_SECTOR_SIZE); + + // Test compression methods +// if(nError == ERROR_SUCCESS) +// nError = TestSectorCompress(MPQ_SECTOR_SIZE); + + // Test the archive open and close +// if(nError == ERROR_SUCCESS) +// nError = TestArchiveOpenAndClose(MAKE_PATH("BrooDat.mpq")); + +// if(nError == ERROR_SUCCESS) +// nError = TestFindFiles(MAKE_PATH("2002 - Warcraft III/HumanEd.mpq")); + + // Create a big MPQ archive +// if(nError == ERROR_SUCCESS) +// nError = TestCreateArchive_PaliRoharBug(MAKE_PATH("Test.mpq")); +// nError = TestCreateArchive(MAKE_PATH("Test.mpq")); +// nError = TestCreateArchive((const TCHAR*)szUnicodeName1); +// nError = TestCreateArchive((const TCHAR*)szUnicodeName2); +// nError = TestCreateArchive((const TCHAR*)szUnicodeName3); +// nError = TestCreateArchive((const TCHAR*)szUnicodeName4); +// nError = TestCreateArchive((const TCHAR*)szUnicodeName5); +// nError = TestCreateArchive((const TCHAR*)szUnicodeName6); + +// if(nError == ERROR_SUCCESS) +// nError = TestAddFilesToMpq(MAKE_PATH("wow-update-13202.MPQ"), +// "c:\\Tools32\\Arj32.exe", +// "c:\\Tools32\\autoruns.chm", +// "c:\\Tools32\\CPUEater.exe", +// "c:\\Tools32\\dumpbin.exe", +// "c:\\Tools32\\editbin.exe", +// "c:\\Tools32\\fsg.ini", +// "c:\\Tools32\\hiew8.ini", +// "c:\\Tools32\\ida.bat", +// "c:\\Tools32\\mp3.ini", +// NULL); + +// if(nError == ERROR_SUCCESS) +// nError = TestCreateArchiveFromMemory(MAKE_PATH("Test-leak.mpq")); + +// if(nError == ERROR_SUCCESS) +// nError = TestFileReadAndWrite(MAKE_PATH("2002 - Warcraft III/(10)DustwallowKeys.w3m"), "war3map.j"); + + // Verify the archive signature +// if(nError == ERROR_SUCCESS) +// nError = TestSignatureVerify(MAKE_PATH("1998 - Starcraft/BW-1152.exe")); +// nError = TestSignatureVerify(MAKE_PATH("2002 - Warcraft III/(10)DustwallowKeys.w3m")); +// nError = TestSignatureVerify(MAKE_PATH("2002 - Warcraft III/War3TFT_121b_English.exe")); +// nError = TestSignatureVerify(MAKE_PATH("2004 - World of Warcraft/WoW-2.3.3.7799-to-2.4.0.8089-enUS-patch.exe")); +// nError = TestSignatureVerify(MAKE_PATH("2004 - World of Warcraft/standalone.MPQ")); + + // Compact the archive +// if(nError == ERROR_SUCCESS) +// nError = TestMpqCompacting(MAKE_PATH("wow-update-base-14333.MPQ")); + + // Create copy of the archive, appending some bytes before the MPQ header +// if(nError == ERROR_SUCCESS) +// nError = TestCreateArchiveCopy(MAKE_PATH("PartialMPQs/interface.MPQ.part"), MAKE_PATH("PartialMPQs/interface-copy.MPQ.part"), NULL); + + +// if(nError == ERROR_SUCCESS) +// { +// nError = TestOpenPatchedArchive(MAKE_PATH("2012 - WoW\\16057\\enUS\\locale-enUS.MPQ"), +// MAKE_PATH("2012 - WoW\\16057\\enUS\\wow-update-enUS-16016.MPQ"), +// NULL); +// } + +// if(nError == ERROR_SUCCESS) +// { +// nError = TestCompareTwoArchives(MAKE_PATH("Sound-copy.mpq"), +// MAKE_PATH("Sound.mpq"), +// NULL, +// 0x1001); +// } + +// if(nError == ERROR_SUCCESS) +// nError = TestSearchAllArchives(MAKE_PATH("*")); + + return nError; +} |