diff --git a/src/tools/stuffextract/StormLib/Makefile.am b/src/tools/stuffextract/StormLib/Makefile.am index 740f3a9..832b354 100644 --- a/src/tools/stuffextract/StormLib/Makefile.am +++ b/src/tools/stuffextract/StormLib/Makefile.am @@ -5,7 +5,20 @@ AM_CFLAGS = -fPIC noinst_LIBRARIES = libstormlib.a libstormlib_a_SOURCES =huffman/huff.cpp\ wave/wave.cpp\ - StormPortLinux.cpp\ - SFileReadFile.cpp SCommon.cpp SCompression.cpp SFileCompactArchive.cpp SFileCreateArchiveEx.cpp SFileExtractFile.cpp SFileFindFile.cpp SFileOpenArchive.cpp\ - SFileOpenFileEx.cpp SListFile.cpp\ -pklib/crc32_pk.c pklib/explode.c pklib/implode.c + SAttrFile.cpp\ + SCommon.cpp\ + SCompression.cpp\ + SFileCompactArchive.cpp\ + SFileCreateArchiveEx.cpp\ + SFileExtractFile.cpp\ + SFileFindFile.cpp\ + SFileOpenArchive.cpp\ + SFileOpenFileEx.cpp\ + SFileReadFile.cpp\ + SListFile.cpp\ + StormPortLinux.cpp\ + pklib/crc32_pk.c\ + pklib/explode.c\ + pklib/implode.c\ + misc/crc32.cpp\ + misc/md5.cpp diff --git a/src/tools/stuffextract/StormLib/SAttrFile.cpp b/src/tools/stuffextract/StormLib/SAttrFile.cpp new file mode 100644 index 0000000..d7b1cb7 --- /dev/null +++ b/src/tools/stuffextract/StormLib/SAttrFile.cpp @@ -0,0 +1,354 @@ +/*****************************************************************************/ +/* SAttrFile.cpp Copyright (c) Ladislav Zezula 2007 */ +/*---------------------------------------------------------------------------*/ +/* Description: */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 12.06.04 1.00 Lad The first version of SAttrFile.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "SCommon.h" +#include + +#include "misc/crc32.h" +#include "misc/md5.h" + +//----------------------------------------------------------------------------- +// Local functions + +// This function creates the name for the listfile. +// the file will be created under unique name in the temporary directory +static void GetAttributesFileName(TMPQArchive * /* ha */, char * szAttrFile) +{ + char szTemp[MAX_PATH]; + + // Create temporary file name int TEMP directory + GetTempPath(sizeof(szTemp)-1, szTemp); + GetTempFileName(szTemp, ATTRIBUTES_NAME, 0, szAttrFile); +} + +//----------------------------------------------------------------------------- +// Public functions (internal use by StormLib) + +int SAttrFileCreate(TMPQArchive * ha) +{ + TMPQAttr * pNewAttr; + int nError = ERROR_SUCCESS; + + // There should NOW be any attributes + assert(ha->pAttributes == NULL); + + pNewAttr = ALLOCMEM(TMPQAttr, 1); + if(pNewAttr != NULL) + { + // Pre-set the structure + pNewAttr->dwVersion = MPQ_ATTRIBUTES_V1; + pNewAttr->dwFlags = 0; + + // Allocate array for CRC32 + pNewAttr->pCrc32 = ALLOCMEM(TMPQCRC32, ha->pHeader->dwHashTableSize); + if(pNewAttr->pCrc32 != NULL) + { + pNewAttr->dwFlags |= MPQ_ATTRIBUTE_CRC32; + memset(pNewAttr->pCrc32, 0, sizeof(TMPQCRC32) * ha->pHeader->dwHashTableSize); + } + else + nError = ERROR_NOT_ENOUGH_MEMORY; + + // Allocate array for FILETIME + pNewAttr->pFileTime = ALLOCMEM(TMPQFileTime, ha->pHeader->dwHashTableSize); + if(pNewAttr->pFileTime != NULL) + { + pNewAttr->dwFlags |= MPQ_ATTRIBUTE_FILETIME; + memset(pNewAttr->pFileTime, 0, sizeof(TMPQFileTime) * ha->pHeader->dwHashTableSize); + } + else + nError = ERROR_NOT_ENOUGH_MEMORY; + + // Allocate array for MD5 + pNewAttr->pMd5 = ALLOCMEM(TMPQMD5, ha->pHeader->dwHashTableSize); + if(pNewAttr->pMd5 != NULL) + { + pNewAttr->dwFlags |= MPQ_ATTRIBUTE_MD5; + memset(pNewAttr->pMd5, 0, sizeof(TMPQMD5) * ha->pHeader->dwHashTableSize); + } + else + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // If something failed, then free the attributes structure + if(nError != ERROR_SUCCESS) + { + FreeMPQAttributes(pNewAttr); + pNewAttr = NULL; + } + + ha->pAttributes = pNewAttr; + return nError; +} + + +int SAttrFileLoad(TMPQArchive * ha) +{ + TMPQAttr * pAttr = NULL; + HANDLE hFile = NULL; + DWORD dwBytesRead; + DWORD dwToRead; + int nError = ERROR_SUCCESS; + + // Initially, set the attrobutes to NULL + ha->pAttributes = NULL; + + // Attempt to open the "(attributes)" file. + // If it's not there, we don't support attributes + if(!SFileOpenFileEx((HANDLE)ha, ATTRIBUTES_NAME, 0, &hFile)) + nError = GetLastError(); + + // Allocate space for the TMPQAttributes + if(nError == ERROR_SUCCESS) + { + pAttr = ALLOCMEM(TMPQAttr, 1); + if(pAttr == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Load the content of the attributes file + if(nError == ERROR_SUCCESS) + { + memset(pAttr, 0, sizeof(TMPQAttr)); + + dwToRead = sizeof(DWORD) + sizeof(DWORD); + SFileReadFile(hFile, pAttr, dwToRead, &dwBytesRead, NULL); + if(dwBytesRead != dwToRead) + nError = ERROR_FILE_CORRUPT; + } + + // Verify format of the attributes + if(nError == ERROR_SUCCESS) + { + if(pAttr->dwVersion > MPQ_ATTRIBUTES_V1) + nError = ERROR_BAD_FORMAT; + } + + // Load the CRC32 (if any) + if(nError == ERROR_SUCCESS && (pAttr->dwFlags & MPQ_ATTRIBUTE_CRC32)) + { + pAttr->pCrc32 = ALLOCMEM(TMPQCRC32, ha->pHeader->dwHashTableSize); + if(pAttr->pCrc32 != NULL) + { + memset(pAttr->pCrc32, 0, sizeof(TMPQCRC32) * ha->pHeader->dwHashTableSize); + dwToRead = sizeof(TMPQCRC32) * ha->pHeader->dwBlockTableSize; + SFileReadFile(hFile, pAttr->pCrc32, dwToRead, &dwBytesRead, NULL); + if(dwBytesRead != dwToRead) + nError = ERROR_FILE_CORRUPT; + } + else + { + nError = ERROR_NOT_ENOUGH_MEMORY; + } + } + + // Read the FILETIMEs (if any) + if(nError == ERROR_SUCCESS && (pAttr->dwFlags & MPQ_ATTRIBUTE_FILETIME)) + { + pAttr->pFileTime = ALLOCMEM(TMPQFileTime, ha->pHeader->dwHashTableSize); + if(pAttr->pFileTime != NULL) + { + memset(pAttr->pFileTime, 0, sizeof(TMPQFileTime) * ha->pHeader->dwHashTableSize); + dwToRead = sizeof(TMPQFileTime) * ha->pHeader->dwBlockTableSize; + SFileReadFile(hFile, pAttr->pFileTime, dwToRead, &dwBytesRead, NULL); + if(dwBytesRead != dwToRead) + nError = ERROR_FILE_CORRUPT; + } + else + { + nError = ERROR_NOT_ENOUGH_MEMORY; + } + } + + // Read the MD5 (if any) + if(nError == ERROR_SUCCESS && (pAttr->dwFlags & MPQ_ATTRIBUTE_MD5)) + { + pAttr->pMd5 = ALLOCMEM(TMPQMD5, ha->pHeader->dwHashTableSize); + if(pAttr->pMd5 != NULL) + { + memset(pAttr->pMd5, 0, sizeof(TMPQMD5) * ha->pHeader->dwHashTableSize); + dwToRead = sizeof(TMPQMD5) * ha->pHeader->dwBlockTableSize; + SFileReadFile(hFile, pAttr->pMd5, dwToRead, &dwBytesRead, NULL); + if(dwBytesRead != dwToRead) + nError = ERROR_FILE_CORRUPT; + } + else + { + nError = ERROR_NOT_ENOUGH_MEMORY; + } + } + + // Set the attributes into the MPQ archive + if(nError == ERROR_SUCCESS) + { + ha->pAttributes = pAttr; + pAttr = NULL; + } + + // Cleanup & exit + FreeMPQAttributes(pAttr); + SFileCloseFile(hFile); + return nError; +} + +int SAttrFileSaveToMpq(TMPQArchive * ha) +{ + HANDLE hFile = INVALID_HANDLE_VALUE; + DWORD dwToWrite; + DWORD dwWritten; + LCID lcSave = lcLocale; + char szAttrFile[MAX_PATH]; + int nError = ERROR_SUCCESS; + + // If there are no attributes, do nothing + if(ha->pAttributes == NULL) + return ERROR_SUCCESS; + + // Create the local attributes file + if(nError == ERROR_SUCCESS) + { + GetAttributesFileName(ha, szAttrFile); + hFile = CreateFile(szAttrFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + if(hFile == INVALID_HANDLE_VALUE) + nError = GetLastError(); + } + + // Write the content of the attributes to the file + if(nError == ERROR_SUCCESS) + { + // Write the header of the attributes file + dwToWrite = sizeof(DWORD) + sizeof(DWORD); + WriteFile(hFile, ha->pAttributes, dwToWrite, &dwWritten, NULL); + if(dwWritten != dwToWrite) + nError = ERROR_DISK_FULL; + } + + // Write the array of CRC32 + if(nError == ERROR_SUCCESS && ha->pAttributes->pCrc32 != NULL) + { + dwToWrite = sizeof(TMPQCRC32) * ha->pHeader->dwBlockTableSize; + WriteFile(hFile, ha->pAttributes->pCrc32, dwToWrite, &dwWritten, NULL); + if(dwWritten != dwToWrite) + nError = ERROR_DISK_FULL; + } + + // Write the array of FILETIMEs + if(nError == ERROR_SUCCESS && ha->pAttributes->pFileTime != NULL) + { + dwToWrite = sizeof(TMPQFileTime) * ha->pHeader->dwBlockTableSize; + WriteFile(hFile, ha->pAttributes->pFileTime, dwToWrite, &dwWritten, NULL); + if(dwWritten != dwToWrite) + nError = ERROR_DISK_FULL; + } + + // Write the array of MD5s + if(nError == ERROR_SUCCESS && ha->pAttributes->pMd5 != NULL) + { + dwToWrite = sizeof(TMPQMD5) * ha->pHeader->dwBlockTableSize; + WriteFile(hFile, ha->pAttributes->pMd5, dwToWrite, &dwWritten, NULL); + if(dwWritten != dwToWrite) + nError = ERROR_DISK_FULL; + } + + // Add the attributes into MPQ + if(nError == ERROR_SUCCESS) + { + SFileSetLocale(LANG_NEUTRAL); + nError = AddFileToArchive(ha, hFile, ATTRIBUTES_NAME, MPQ_FILE_COMPRESS | MPQ_FILE_REPLACEEXISTING, 0, SFILE_TYPE_DATA, NULL); + lcLocale = lcSave; + } + + // Close the temporary file and delete it. + // There is no FILE_FLAG_DELETE_ON_CLOSE on LINUX. + if(hFile != INVALID_HANDLE_VALUE) + CloseHandle(hFile); + DeleteFile(szAttrFile); + + return nError; +} + +void FreeMPQAttributes(TMPQAttr * pAttr) +{ + if(pAttr != NULL) + { + if(pAttr->pCrc32 != NULL) + FREEMEM(pAttr->pCrc32); + if(pAttr->pFileTime != NULL) + FREEMEM(pAttr->pFileTime); + if(pAttr->pMd5 != NULL) + FREEMEM(pAttr->pMd5); + + FREEMEM(pAttr); + } +} + +//----------------------------------------------------------------------------- +// Public (exported) functions + +BOOL WINAPI SFileVerifyFile(HANDLE hMpq, const char * szFileName, DWORD dwFlags) +{ + crc32_context crc32_ctx; + md5_context md5_ctx; + TMPQFile * hf; + TMPQCRC32 Crc32; + TMPQMD5 Md5; + BYTE Buffer[0x1000]; + HANDLE hFile = NULL; + DWORD dwBytesRead; + BOOL bResult = TRUE; + + // Attempt to open the file + if(SFileOpenFileEx(hMpq, szFileName, 0, &hFile)) + { + // Initialize the CRC32 and MD5 counters + CRC32_Init(&crc32_ctx); + MD5_Init(&md5_ctx); + hf = (TMPQFile *)hFile; + + // Go through entire file and update both CRC32 and MD5 + for(;;) + { + // Read data from file + SFileReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead, NULL); + if(dwBytesRead == 0) + break; + + // Update CRC32 value + if(dwFlags & MPQ_ATTRIBUTE_CRC32) + CRC32_Update(&crc32_ctx, Buffer, (int)dwBytesRead); + + // Update MD5 value + if(dwFlags & MPQ_ATTRIBUTE_MD5) + MD5_Update(&md5_ctx, Buffer, (int)dwBytesRead); + } + + // Check if the CRC32 matches + if((dwFlags & MPQ_ATTRIBUTE_CRC32) && hf->pCrc32 != NULL) + { + CRC32_Finish(&crc32_ctx, (unsigned long *)&Crc32.dwValue); + if(Crc32.dwValue != hf->pCrc32->dwValue) + bResult = FALSE; + } + + // Check if MD5 matches + if((dwFlags & MPQ_ATTRIBUTE_MD5) && hf->pMd5 != NULL) + { + MD5_Finish(&md5_ctx, Md5.Value); + if(memcmp(Md5.Value, hf->pMd5->Value, sizeof(TMPQMD5))) + bResult = FALSE; + } + + SFileCloseFile(hFile); + } + + return bResult; +} diff --git a/src/tools/stuffextract/StormLib/SCommon.cpp b/src/tools/stuffextract/StormLib/SCommon.cpp index 393310f..7936a90 100644 --- a/src/tools/stuffextract/StormLib/SCommon.cpp +++ b/src/tools/stuffextract/StormLib/SCommon.cpp @@ -14,6 +14,9 @@ #include "StormLib.h" #include "SCommon.h" +#include "misc/crc32.h" +#include "misc/md5.h" + char StormLibCopyright[] = "StormLib v 4.50 Copyright Ladislav Zezula 1998-2003"; //----------------------------------------------------------------------------- @@ -427,7 +430,7 @@ TMPQHash * GetHashEntry(TMPQArchive * ha, const char * szFileName) // If filename is given by index, we have to search all hash entries for the right index. if(dwIndex <= ha->pHeader->dwBlockTableSize) { - // Pass all the hash entries and find the + // Pass all the hash entries and find the one with proper block index for(pHash = ha->pHashTable; pHash < pHashEnd; pHash++) { if(pHash->dwBlockIndex == dwIndex) @@ -462,9 +465,9 @@ TMPQHash * GetHashEntry(TMPQArchive * ha, const char * szFileName) // Retrieves the locale-specific hash entry TMPQHash * GetHashEntryEx(TMPQArchive * ha, const char * szFileName, LCID lcLocale) { + TMPQHash * pHashNeutral = NULL; // Language-neutral hash entry + TMPQHash * pHashExact = NULL; // Exact hash entry TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize; - TMPQHash * pHash0 = NULL; // Language-neutral hash entry - TMPQHash * pHashX = NULL; // Language-speficic TMPQHash * pHash = GetHashEntry(ha, szFileName); if(pHash != NULL) @@ -473,38 +476,37 @@ TMPQHash * GetHashEntryEx(TMPQArchive * ha, const char * szFileName, LCID lcLoca DWORD dwName1 = pHash->dwName1; DWORD dwName2 = pHash->dwName2; + // Parse the entire block of equal files (differing by language ID only) while(pHash->dwBlockIndex != HASH_ENTRY_FREE) { - if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2) + // There may be an entry deleted amongst various language versions + if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && pHash->dwBlockIndex != HASH_ENTRY_DELETED) { + // Remember hash entry for neutral file and for lag-exact file if(pHash->lcLocale == LANG_NEUTRAL) - pHash0 = pHash; + pHashNeutral = pHash; if(pHash->lcLocale == lcLocale) - pHashX = pHash; - - // If both found, break the loop - if(pHash0 != NULL && pHashX != NULL) - break; + pHashExact = pHash; } + // Move to th next hash if(++pHash >= pHashEnd) pHash = ha->pHashTable; if(pHash == pHashStart) - return NULL; + break; } - if(lcLocale != LANG_NEUTRAL && pHashX != NULL) - return pHashX; - if(pHash0 != NULL) - return pHash0; - return NULL; + // If we found language-exact hash, return that one + // If not, return language neutral hash + if(pHashExact != NULL) + return pHashExact; } - return pHash; + // Not found + return pHashNeutral; } -// Encrypts file name and gets the hash entry -// Returns the hash pointer, which is always within the allocated array +// Finds the nearest free hash entry for a file TMPQHash * FindFreeHashEntry(TMPQArchive * ha, const char * szFileName) { TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize; @@ -518,7 +520,7 @@ TMPQHash * FindFreeHashEntry(TMPQArchive * ha, const char * szFileName) // Save the starting hash position pHash = pHash0 = ha->pHashTable + dwIndex; - // Look for the first free hash entry. Can be also a deleted entry + // Look for the first free or deleted hash entry. while(pHash->dwBlockIndex < HASH_ENTRY_DELETED) { if(++pHash >= pHashEnd) @@ -577,9 +579,67 @@ BOOL IsValidFileHandle(TMPQFile * hf) return IsValidMpqHandle(hf->ha); } +int AddInternalFile(TMPQArchive * ha, const char * szFileName) +{ + TMPQBlockEx * pBlockEx; + TMPQBlock * pBlockEnd; + TMPQBlock * pBlock; + TMPQHash * pHash; + BOOL bFoundFreeEntry = FALSE; + int nError = ERROR_SUCCESS; + + // Check if the file already exists in the archive + pHash = GetHashEntryEx(ha, szFileName, LANG_NEUTRAL); + if(pHash == NULL) + { + pHash = FindFreeHashEntry(ha, szFileName); + if(pHash != NULL) + { + // Reset the locale ID to neutral, to be independent on current + // locale set by the user. + pHash->lcLocale = LANG_NEUTRAL; + + // Fill the block table + pBlockEnd = ha->pBlockTable + ha->pHeader->dwBlockTableSize; + pBlockEx = ha->pExtBlockTable; + for(pBlock = ha->pBlockTable; pBlock < pBlockEnd; pBlock++, pBlockEx++) + { + if((pBlock->dwFlags & MPQ_FILE_EXISTS) == 0) + { + bFoundFreeEntry = TRUE; + break; + } + } + + // If the block is out of the available entries, return error + if(pBlock >= (ha->pBlockTable + ha->pHeader->dwHashTableSize)) + return ERROR_DISK_FULL; + + // If we had to add the file at the end, increment the block table + if(bFoundFreeEntry == FALSE) + ha->pHeader->dwBlockTableSize++; + + // Fill the block entry + pBlockEx->wFilePosHigh = (USHORT)ha->HashTablePos.HighPart; + pBlock->dwFilePos = ha->HashTablePos.LowPart; + pBlock->dwFSize = 0; + pBlock->dwCSize = 0; + pBlock->dwFlags = MPQ_FILE_EXISTS; + + // Add the node for the file name + return SListFileCreateNode(ha, szFileName, LANG_NEUTRAL); + } + else + { + nError = ERROR_HANDLE_DISK_FULL; + } + } + + return nError; +} + // This function writes a local file into the MPQ archive. // Returns 0 if OK, otherwise error code. -// TODO: Test for archives > 4GB int AddFileToArchive( TMPQArchive * ha, HANDLE hFile, @@ -589,34 +649,28 @@ int AddFileToArchive( int nFileType, BOOL * pbReplaced) { - LARGE_INTEGER RelativePos = {0}; - LARGE_INTEGER FilePos = {0}; - LARGE_INTEGER TempPos; - TMPQBlockEx * pBlockEx = NULL; // Entry in the extended block table - TMPQBlock * pBlock = NULL; // Entry in the block table - TMPQHash * pHash = NULL; // Entry in the hash table - DWORD * pdwBlockPos = NULL; // Block position table (compressed files only) - BYTE * pbFileData = NULL; // Uncompressed (source) data - BYTE * pbCompressed = NULL; // Compressed (target) data - BYTE * pbToWrite = NULL; // Data to write to the file - DWORD dwBlockPosLen = 0; // Length of the block table positions - DWORD dwTransferred = 0; // Number of bytes written into archive file - DWORD dwFileSize = 0; // Size of the file to add - DWORD dwSeed1 = 0; // Encryption seed - DWORD nBlocks = 0; // Number of file blocks - DWORD nBlock = 0; // Index of the currently written block - BOOL bReplaced = FALSE; // TRUE if replaced, FALSE if added - int nCmpFirst = nDataCmp; // Compression for the first data block - int nCmpNext = nDataCmp; // Compression for the next data blocks - int nCmp = nDataCmp; // Current compression - int nCmpLevel = -1; // Compression level - int nError = ERROR_SUCCESS; + LARGE_INTEGER TempPos; // For various file offset calculations + TMPQBlock * pBlockEnd; // Pointer to end of the block table + TMPQFile * hf = NULL; // File structure for newly added file + BYTE * pbCompressed = NULL; // Compressed (target) data + BYTE * pbToWrite = NULL; // Data to write to the file + DWORD dwBlockPosLen = 0; // Length of the file block offset (in bytes) + DWORD dwTransferred = 0; // Number of bytes read or written + DWORD dwFileSizeHigh = 0; // High 32 bits of the file size + DWORD dwFileSize = 0; // Low 32-bits of the file size + BOOL bReplaced = FALSE; // TRUE if replaced, FALSE if added + int nCmpFirst = nDataCmp; // Compression for the first data block + int nCmpNext = nDataCmp; // Compression for the next data blocks + int nCmp = nDataCmp; // Current compression + int nCmpLevel = -1; // Compression level + int nError = ERROR_SUCCESS; // Set the correct compression types - if(dwFlags & MPQ_FILE_COMPRESS_PKWARE) + if(dwFlags & MPQ_FILE_IMPLODE) nCmpFirst = nCmpNext = MPQ_COMPRESSION_PKWARE; + pBlockEnd = ha->pBlockTable + ha->pHeader->dwBlockTableSize; - if(dwFlags & MPQ_FILE_COMPRESS_MULTI) + if(dwFlags & MPQ_FILE_COMPRESS) { if(nFileType == SFILE_TYPE_DATA) nCmpFirst = nCmpNext = nDataCmp; @@ -628,138 +682,176 @@ int AddFileToArchive( } } - // Check if the file already exists in the archive + // Get the size of the file to be added if(nError == ERROR_SUCCESS) { - if((pHash = GetHashEntryEx(ha, szArchivedName, lcLocale)) != NULL) - { - if(pHash->lcLocale == lcLocale) - { - if((dwFlags & MPQ_FILE_REPLACEEXISTING) == 0) - { - nError = ERROR_ALREADY_EXISTS; - pHash = NULL; - } - else - bReplaced = TRUE; - } - else - pHash = NULL; - } - - if(nError == ERROR_SUCCESS && pHash == NULL) - { - pHash = FindFreeHashEntry(ha, szArchivedName); - if(pHash == NULL) - nError = ERROR_HANDLE_DISK_FULL; - } - } - - // Get the block table entry for the file - if(nError == ERROR_SUCCESS) - { - DWORD dwFileSizeHigh = 0; - - // Get the size of the added file dwFileSize = GetFileSize(hFile, &dwFileSizeHigh); - if(dwFileSizeHigh != 0) - nError = ERROR_PARAMETER_QUOTA_EXCEEDED; - // Fix the flags, if the file is too small + // Adjust file flags for too-small files if(dwFileSize < 0x04) dwFlags &= ~(MPQ_FILE_ENCRYPTED | MPQ_FILE_FIXSEED); if(dwFileSize < 0x20) dwFlags &= ~MPQ_FILE_COMPRESSED; - if(pHash->dwBlockIndex == HASH_ENTRY_FREE) - pHash->dwBlockIndex = ha->pHeader->dwBlockTableSize; - - // The block table index cannot be larger than hash table size - if(pHash->dwBlockIndex >= ha->pHeader->dwHashTableSize) - nError = ERROR_HANDLE_DISK_FULL; + // File in MPQ cannot be greater than 4GB + if(dwFileSizeHigh != 0) + nError = ERROR_PARAMETER_QUOTA_EXCEEDED; } - // The file will be stored after the end of the last archived file - // (i.e. at old position of archived file + // Allocate the TMPQFile entry for newly added file if(nError == ERROR_SUCCESS) { - TMPQBlock * pBlockEnd = ha->pBlockTable + ha->pHeader->dwBlockTableSize; - const char * szTemp = strrchr(szArchivedName, '\\'); + hf = (TMPQFile *)ALLOCMEM(BYTE, sizeof(TMPQFile) + strlen(szArchivedName)); + if(hf == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Reset the TMPQFile structure + if(nError == ERROR_SUCCESS) + { + memset(hf, 0, sizeof(TMPQFile)); + strcpy(hf->szFileName, szArchivedName); + hf->hFile = INVALID_HANDLE_VALUE; + hf->ha = ha; + + // Check if the file already exists in the archive + if((hf->pHash = GetHashEntryEx(ha, szArchivedName, lcLocale)) != NULL) + { + if(hf->pHash->lcLocale == lcLocale) + { + if((dwFlags & MPQ_FILE_REPLACEEXISTING) == 0) + { + nError = ERROR_ALREADY_EXISTS; + hf->pHash = NULL; + } + else + { + hf->pBlockEx = ha->pExtBlockTable + hf->pHash->dwBlockIndex; + hf->pBlock = ha->pBlockTable + hf->pHash->dwBlockIndex; + bReplaced = TRUE; + } + } + else + hf->pHash = NULL; + } + + if(nError == ERROR_SUCCESS && hf->pHash == NULL) + { + hf->pHash = FindFreeHashEntry(ha, szArchivedName); + if(hf->pHash == NULL) + nError = ERROR_HANDLE_DISK_FULL; + } + + // Set the hash index + hf->dwHashIndex = (DWORD)(hf->pHash - ha->pHashTable); + } + + // Find a block table entry for the file + if(nError == ERROR_SUCCESS) + { + TMPQBlockEx * pBlockEx = NULL; // Entry in the extended block table + TMPQBlock * pBlock = NULL; // Entry in the block table // Get the position of the first file - RelativePos.QuadPart = ha->pHeader->dwHeaderSize; + hf->MpqFilePos.QuadPart = ha->pHeader->dwHeaderSize; - // Find the position of the last file. It has to be after the last archived file - // (Do not use the dwArchiveSize here, because it may or may not - // include the hash table at the end of the file + // Search the entire block table and find a free block. + // Also find MPQ offset at which the file data will be stored pBlockEx = ha->pExtBlockTable; for(pBlock = ha->pBlockTable; pBlock < pBlockEnd; pBlock++, pBlockEx++) { if(pBlock->dwFlags & MPQ_FILE_EXISTS) { - TempPos.HighPart = pBlockEx->wFilePosHigh; - TempPos.LowPart = pBlock->dwFilePos; + TempPos.HighPart = pBlockEx->wFilePosHigh; + TempPos.LowPart = pBlock->dwFilePos; TempPos.QuadPart += pBlock->dwCSize; - if(TempPos.QuadPart > RelativePos.QuadPart) - RelativePos = TempPos; + if(TempPos.QuadPart > hf->MpqFilePos.QuadPart) + hf->MpqFilePos = TempPos; } + else + { + if(hf->pBlock == NULL) + { + hf->pBlockEx = pBlockEx; + hf->pBlock = pBlock; + } + } + } + + // Calculate the raw file offset + hf->RawFilePos.QuadPart = hf->MpqFilePos.QuadPart + ha->MpqPos.QuadPart; + + // If no free block in the middle of the block table, + // use the one after last used block + if(hf->pBlock == NULL) + { + hf->pBlockEx = pBlockEx; + hf->pBlock = pBlock; } // When format V1, we cannot exceed 4 GB if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1) { - TempPos.QuadPart = ha->MpqPos.QuadPart + RelativePos.QuadPart; + TempPos.QuadPart = hf->RawFilePos.QuadPart + dwFileSize; TempPos.QuadPart += ha->pHeader->dwHashTableSize * sizeof(TMPQHash); TempPos.QuadPart += ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock); - TempPos.QuadPart += dwFileSize; if(TempPos.HighPart != 0) nError = ERROR_DISK_FULL; } - // Get pointers to both block entries of the file - pBlockEx = ha->pExtBlockTable + pHash->dwBlockIndex; - pBlock = ha->pBlockTable + pHash->dwBlockIndex; - - // Save the file size info - pBlockEx->wFilePosHigh = (USHORT)RelativePos.HighPart; - pBlock->dwFilePos = RelativePos.LowPart; - pBlock->dwFSize = GetFileSize(hFile, NULL); - pBlock->dwFlags = dwFlags | MPQ_FILE_EXISTS; + // If the block offset exceeds number of hash entries, + // we cannot add new file to the MPQ + hf->dwBlockIndex = (DWORD)(hf->pBlock - ha->pBlockTable); + if(hf->dwBlockIndex >= ha->pHeader->dwHashTableSize) + nError = ERROR_HANDLE_DISK_FULL; + } + + // Create seed1 for file encryption + if(nError == ERROR_SUCCESS && (dwFlags & MPQ_FILE_ENCRYPTED)) + { + const char * szTemp = strrchr(szArchivedName, '\\'); // Create seed1 for file encryption if(szTemp != NULL) szArchivedName = szTemp + 1; - if(dwFlags & MPQ_FILE_ENCRYPTED) - { - dwSeed1 = DecryptFileSeed(szArchivedName); - - if(dwFlags & MPQ_FILE_FIXSEED) - dwSeed1 = (dwSeed1 + pBlock->dwFilePos) ^ pBlock->dwFSize; - } + hf->dwSeed1 = DecryptFileSeed(szArchivedName); + if(dwFlags & MPQ_FILE_FIXSEED) + hf->dwSeed1 = (hf->dwSeed1 + hf->MpqFilePos.LowPart) ^ dwFileSize; } - // Allocate buffer for the input data - if(nError == ERROR_SUCCESS) + // Resolve CRC32 and MD5 entry for the file + // Only do it when the MPQ archive has attributes + if(nError == ERROR_SUCCESS && ha->pAttributes != NULL) { - nBlocks = (pBlock->dwFSize / ha->dwBlockSize) + 1; - if(pBlock->dwFSize % ha->dwBlockSize) - nBlocks++; - - pBlock->dwCSize = 0; - if((pbFileData = ALLOCMEM(BYTE, ha->dwBlockSize)) == NULL) - nError = ERROR_NOT_ENOUGH_MEMORY; - pbToWrite = pbFileData; + if(ha->pAttributes->pCrc32 != NULL) + hf->pCrc32 = ha->pAttributes->pCrc32 + hf->dwBlockIndex; + if(ha->pAttributes->pFileTime != NULL) + hf->pFileTime = ha->pAttributes->pFileTime + hf->dwBlockIndex; + if(ha->pAttributes->pMd5 != NULL) + hf->pMd5 = ha->pAttributes->pMd5 + hf->dwBlockIndex; } // Allocate buffers for the compressed data + if(nError == ERROR_SUCCESS) + { + hf->nBlocks = (dwFileSize / ha->dwBlockSize) + 1; + if(dwFileSize % ha->dwBlockSize) + hf->nBlocks++; + + if((hf->pbFileBuffer = ALLOCMEM(BYTE, ha->dwBlockSize)) == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + pbToWrite = hf->pbFileBuffer; + } + + // For compressed files, allocate buffer for block positions and for the compressed data if(nError == ERROR_SUCCESS && (dwFlags & MPQ_FILE_COMPRESSED)) { - pdwBlockPos = ALLOCMEM(DWORD, nBlocks + 1); + hf->pdwBlockPos = ALLOCMEM(DWORD, hf->nBlocks + 1); pbCompressed = ALLOCMEM(BYTE, ha->dwBlockSize * 2); - if(pdwBlockPos == NULL || pbCompressed == NULL) + if(hf->pdwBlockPos == NULL || pbCompressed == NULL) nError = ERROR_NOT_ENOUGH_MEMORY; pbToWrite = pbCompressed; } @@ -768,88 +860,104 @@ int AddFileToArchive( if(nError == ERROR_SUCCESS) { // Set the file pointer to file data position - FilePos.QuadPart = ha->MpqPos.QuadPart + RelativePos.QuadPart; - if(FilePos.QuadPart != ha->FilePointer.QuadPart) - { - SetFilePointer(ha->hFile, FilePos.LowPart, &FilePos.HighPart, FILE_BEGIN); - ha->FilePointer = FilePos; - } + SetFilePointer(ha->hFile, hf->RawFilePos.LowPart, &hf->RawFilePos.HighPart, FILE_BEGIN); + + // Initialize the hash entry for the file + hf->pHash->dwBlockIndex = hf->dwBlockIndex; + + // Initialize the block table entry for the file + hf->pBlockEx->wFilePosHigh = (USHORT)hf->MpqFilePos.HighPart; + hf->pBlock->dwFilePos = hf->MpqFilePos.LowPart; + hf->pBlock->dwFSize = dwFileSize; + hf->pBlock->dwCSize = 0; + hf->pBlock->dwFlags = dwFlags | MPQ_FILE_EXISTS; } // Write block positions (if the file will be compressed) if(nError == ERROR_SUCCESS && (dwFlags & MPQ_FILE_COMPRESSED)) { - dwBlockPosLen = nBlocks * sizeof(DWORD); + dwBlockPosLen = hf->nBlocks * sizeof(DWORD); if(dwFlags & MPQ_FILE_HAS_EXTRA) dwBlockPosLen += sizeof(DWORD); - memset(pdwBlockPos, 0, dwBlockPosLen); - pdwBlockPos[0] = dwBlockPosLen; + memset(hf->pdwBlockPos, 0, dwBlockPosLen); + hf->pdwBlockPos[0] = dwBlockPosLen; - // Write the block positions - BSWAP_ARRAY32_UNSIGNED((DWORD *)pdwBlockPos, nBlocks); - WriteFile(ha->hFile, pdwBlockPos, dwBlockPosLen, &dwTransferred, NULL); - BSWAP_ARRAY32_UNSIGNED((DWORD *)pdwBlockPos, nBlocks); + // Write the block positions. Only swap the first item, rest is zeros. + BSWAP_ARRAY32_UNSIGNED(hf->pdwBlockPos, 1); + WriteFile(ha->hFile, hf->pdwBlockPos, dwBlockPosLen, &dwTransferred, NULL); + BSWAP_ARRAY32_UNSIGNED(hf->pdwBlockPos, 1); if(dwTransferred == dwBlockPosLen) - pBlock->dwCSize += dwBlockPosLen; + hf->pBlock->dwCSize += dwBlockPosLen; else nError = GetLastError(); - - // Update the current position in the file - ha->HashTablePos.QuadPart = FilePos.QuadPart + dwTransferred; } // Write all file blocks if(nError == ERROR_SUCCESS) { + crc32_context crc32_ctx; + md5_context md5_ctx; + DWORD nBlock; + + // Initialize CRC32 and MD5 processing + CRC32_Init(&crc32_ctx); + MD5_Init(&md5_ctx); nCmp = nCmpFirst; + // Move the file pointer to the begin of the file SetFilePointer(hFile, 0, NULL, FILE_BEGIN); - for(nBlock = 0; nBlock < nBlocks-1; nBlock++) + for(nBlock = 0; nBlock < hf->nBlocks-1; nBlock++) { DWORD dwInLength = ha->dwBlockSize; DWORD dwOutLength = ha->dwBlockSize; // Load the block from the file - ReadFile(hFile, pbFileData, ha->dwBlockSize, &dwInLength, NULL); + ReadFile(hFile, hf->pbFileBuffer, ha->dwBlockSize, &dwInLength, NULL); if(dwInLength == 0) break; + // Update CRC32 and MD5 for the file + if(hf->pCrc32 != NULL) + CRC32_Update(&crc32_ctx, hf->pbFileBuffer, dwInLength); + if(hf->pMd5 != NULL) + MD5_Update(&md5_ctx, hf->pbFileBuffer, dwInLength); + // Compress the block, if necessary dwOutLength = dwInLength; - if(pBlock->dwFlags & MPQ_FILE_COMPRESSED) + if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESSED) { // Should be enough for compression int nOutLength = ha->dwBlockSize * 2; int nCmpType = 0; - if(pBlock->dwFlags & MPQ_FILE_COMPRESS_PKWARE) - Compress_pklib((char *)pbCompressed, &nOutLength, (char *)pbFileData, dwInLength, &nCmpType, 0); + if(hf->pBlock->dwFlags & MPQ_FILE_IMPLODE) + Compress_pklib((char *)pbCompressed, &nOutLength, (char *)hf->pbFileBuffer, dwInLength, &nCmpType, 0); - if(pBlock->dwFlags & MPQ_FILE_COMPRESS_MULTI) - SCompCompress((char *)pbCompressed, &nOutLength, (char *)pbFileData, dwInLength, nCmp, 0, nCmpLevel); + if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESS) + SCompCompress((char *)pbCompressed, &nOutLength, (char *)hf->pbFileBuffer, dwInLength, nCmp, 0, nCmpLevel); // The compressed block size must NOT be the same or greater like // the original block size. If yes, do not compress the block // and store the data as-is. if(nOutLength >= (int)dwInLength) { - memcpy(pbCompressed, pbFileData, dwInLength); + memcpy(pbCompressed, hf->pbFileBuffer, dwInLength); nOutLength = dwInLength; } // Update block positions dwOutLength = nOutLength; - pdwBlockPos[nBlock+1] = pdwBlockPos[nBlock] + dwOutLength; + hf->pdwBlockPos[nBlock+1] = hf->pdwBlockPos[nBlock] + dwOutLength; nCmp = nCmpNext; } // Encrypt the block, if necessary - if(pBlock->dwFlags & MPQ_FILE_ENCRYPTED) + if(hf->pBlock->dwFlags & MPQ_FILE_ENCRYPTED) { BSWAP_ARRAY32_UNSIGNED((DWORD *)pbToWrite, dwOutLength / sizeof(DWORD)); - EncryptMPQBlock((DWORD *)pbToWrite, dwOutLength, dwSeed1 + nBlock); + EncryptMPQBlock((DWORD *)pbToWrite, dwOutLength, hf->dwSeed1 + nBlock); BSWAP_ARRAY32_UNSIGNED((DWORD *)pbToWrite, dwOutLength / sizeof(DWORD)); } @@ -862,87 +970,93 @@ int AddFileToArchive( } // Update the hash table position and the compressed file size - ha->HashTablePos.QuadPart += dwTransferred; - pBlock->dwCSize += dwOutLength; + hf->pBlock->dwCSize += dwTransferred; } + + // Finish calculating of CRC32 and MD5 + if(hf->pCrc32 != NULL) + CRC32_Finish(&crc32_ctx, (unsigned long *)&hf->pCrc32->dwValue); + if(hf->pMd5 != NULL) + MD5_Finish(&md5_ctx, hf->pMd5->Value); } // Now save the block positions - if(nError == ERROR_SUCCESS && (pBlock->dwFlags & MPQ_FILE_COMPRESSED)) + if(nError == ERROR_SUCCESS && (hf->pBlock->dwFlags & MPQ_FILE_COMPRESSED)) { if(dwFlags & MPQ_FILE_HAS_EXTRA) - pdwBlockPos[nBlocks] = pdwBlockPos[nBlocks-1]; + hf->pdwBlockPos[hf->nBlocks] = hf->pdwBlockPos[hf->nBlocks-1]; // If file is encrypted, block positions are also encrypted if(dwFlags & MPQ_FILE_ENCRYPTED) - EncryptMPQBlock(pdwBlockPos, dwBlockPosLen, dwSeed1 - 1); + EncryptMPQBlock(hf->pdwBlockPos, dwBlockPosLen, hf->dwSeed1 - 1); // Set the position back to the block table - SetFilePointer(ha->hFile, FilePos.LowPart, &FilePos.HighPart, FILE_BEGIN); + SetFilePointer(ha->hFile, hf->RawFilePos.LowPart, &hf->RawFilePos.HighPart, FILE_BEGIN); // Write block positions to the archive - BSWAP_ARRAY32_UNSIGNED((DWORD *)pdwBlockPos, nBlocks); - WriteFile(ha->hFile, pdwBlockPos, dwBlockPosLen, &dwTransferred, NULL); + BSWAP_ARRAY32_UNSIGNED(hf->pdwBlockPos, hf->nBlocks); + WriteFile(ha->hFile, hf->pdwBlockPos, dwBlockPosLen, &dwTransferred, NULL); if(dwTransferred != dwBlockPosLen) nError = ERROR_DISK_FULL; - - ha->FilePointer.QuadPart = ha->FilePointer.QuadPart + dwTransferred; } // If success, we have to change the settings // in MPQ header. If failed, we have to clean hash entry if(nError == ERROR_SUCCESS) { + DWORD dwTableSize; + ha->pLastFile = NULL; ha->dwBlockPos = 0; ha->dwBuffPos = 0; - ha->dwFlags |= MPQ_FLAG_CHANGED; // Add new entry to the block table (if needed) - if(pHash->dwBlockIndex >= ha->pHeader->dwBlockTableSize) + if(hf->dwBlockIndex >= ha->pHeader->dwBlockTableSize) ha->pHeader->dwBlockTableSize++; - // Hash table size in the TMPQArchive is already set at this point - RelativePos.QuadPart = ha->HashTablePos.QuadPart - ha->MpqPos.QuadPart; - ha->pHeader->dwHashTablePos = RelativePos.LowPart; - ha->pHeader->wHashTablePosHigh = (USHORT)RelativePos.HighPart; + // Calculate positions of all tables + ha->HashTablePos.QuadPart = hf->RawFilePos.QuadPart + hf->pBlock->dwCSize; + TempPos.QuadPart = hf->MpqFilePos.QuadPart + hf->pBlock->dwCSize; + + // Set the position of hash table of the archive + ha->pHeader->dwHashTablePos = TempPos.LowPart; + ha->pHeader->wHashTablePosHigh = (USHORT)TempPos.HighPart; + dwTableSize = ha->pHeader->dwHashTableSize * sizeof(TMPQHash); // Update block table pos - RelativePos.QuadPart += (ha->pHeader->dwHashTableSize * sizeof(TMPQHash)); - ha->pHeader->wBlockTablePosHigh = (USHORT)RelativePos.HighPart; - ha->pHeader->dwBlockTablePos = RelativePos.LowPart; - ha->BlockTablePos.QuadPart = RelativePos.QuadPart + ha->MpqPos.QuadPart; + TempPos.QuadPart += dwTableSize; + ha->BlockTablePos.QuadPart = ha->HashTablePos.QuadPart + dwTableSize; + ha->pHeader->wBlockTablePosHigh = (USHORT)TempPos.HighPart; + ha->pHeader->dwBlockTablePos = TempPos.LowPart; + dwTableSize = ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock); - // If the archive size exceeded 4GB, we have to use extended block table pos - RelativePos.QuadPart += (ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock)); - if(RelativePos.HighPart != 0) + // If the archive size exceeded 4GB, we have to use extended block table + TempPos.QuadPart += dwTableSize; + if(TempPos.HighPart != 0 || ha->pHeader->ExtBlockTablePos.QuadPart != 0) { - ha->pHeader->ExtBlockTablePos = RelativePos; - ha->ExtBlockTablePos.QuadPart = RelativePos.QuadPart + ha->MpqPos.QuadPart; - - RelativePos.QuadPart += (ha->pHeader->dwBlockTableSize * sizeof(TMPQBlockEx)); + ha->ExtBlockTablePos.QuadPart = ha->BlockTablePos.QuadPart + dwTableSize; + ha->pHeader->ExtBlockTablePos = TempPos; + TempPos.QuadPart += ha->pHeader->dwBlockTableSize * sizeof(TMPQBlockEx); } // Update archive size (only valid for version V1) - ha->MpqSize = RelativePos; - ha->pHeader->dwArchiveSize = ha->MpqSize.LowPart; + ha->MpqSize = TempPos; + ha->pHeader->dwArchiveSize = TempPos.LowPart; + ha->dwFlags |= MPQ_FLAG_CHANGED; } else { // Clear the hash table entry - if(pHash != NULL) - memset(pHash, 0xFF, sizeof(TMPQHash)); + if(hf != NULL && hf->pHash != NULL) + memset(hf->pHash, 0xFF, sizeof(TMPQHash)); } // Cleanup if(pbCompressed != NULL) FREEMEM(pbCompressed); - if(pdwBlockPos != NULL) - FREEMEM(pdwBlockPos); - if(pbFileData != NULL) - FREEMEM(pbFileData); if(pbReplaced != NULL) *pbReplaced = bReplaced; + FreeMPQFile(hf); return nError; } @@ -953,13 +1067,12 @@ int SetDataCompression(int nDataCompression) } // This method saves MPQ header, hash table and block table. -// TODO: Test for archives > 4GB int SaveMPQTables(TMPQArchive * ha) { BYTE * pbBuffer = NULL; DWORD dwBytes; DWORD dwWritten; - DWORD dwBuffSize = max(ha->pHeader->dwHashTableSize, ha->pHeader->dwBlockTableSize); + DWORD dwBuffSize = STORMLIB_MAX(ha->pHeader->dwHashTableSize, ha->pHeader->dwBlockTableSize); int nError = ERROR_SUCCESS; // Allocate buffer for encrypted tables @@ -1040,7 +1153,6 @@ int SaveMPQTables(TMPQArchive * ha) nError = ERROR_DISK_FULL; } - // Set end of file here if(nError == ERROR_SUCCESS) { @@ -1054,7 +1166,6 @@ int SaveMPQTables(TMPQArchive * ha) } // Frees the MPQ archive -// TODO: Test for archives > 4GB void FreeMPQArchive(TMPQArchive *& ha) { if(ha != NULL) @@ -1065,6 +1176,8 @@ void FreeMPQArchive(TMPQArchive *& ha) FREEMEM(ha->pHashTable); if(ha->pListFile != NULL) SListFileFreeListFile(ha); + if(ha->pAttributes != NULL) + FreeMPQAttributes(ha->pAttributes); if(ha->hFile != INVALID_HANDLE_VALUE) CloseHandle(ha->hFile); diff --git a/src/tools/stuffextract/StormLib/SCommon.h b/src/tools/stuffextract/StormLib/SCommon.h index b53be0a..56a18ba 100644 --- a/src/tools/stuffextract/StormLib/SCommon.h +++ b/src/tools/stuffextract/StormLib/SCommon.h @@ -19,6 +19,14 @@ #define SFILE_TYPE_DATA 0 // Process the file as data file #define SFILE_TYPE_WAVE 1 // Process the file as WAVe file +#define LISTFILE_ENTRY_DELETED (DWORD_PTR)(-2) +#define LISTFILE_ENTRY_FREE (DWORD_PTR)(-1) + +// Prevent problems with CRT "min" and "max" functions, +// as they are not defined on all platforms +#define STORMLIB_MIN(a, b) ((a < b) ? a : b) +#define STORMLIB_MAX(a, b) ((a > b) ? a : b) + //----------------------------------------------------------------------------- // External variables @@ -66,21 +74,30 @@ BOOL IsValidFileHandle(TMPQFile * hf); // Other functions BOOL SFileOpenArchiveEx(const char * szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE * phMPQ, DWORD dwAccessMode = GENERIC_READ); +int AddInternalFile(TMPQArchive * ha, const char * szFileName); int AddFileToArchive(TMPQArchive * ha, HANDLE hFile, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality, int nFileType, BOOL * pbReplaced); int SetDataCompression(int nDataCompression); int SaveMPQTables(TMPQArchive * ha); void FreeMPQArchive(TMPQArchive *& ha); +void FreeMPQFile(TMPQFile *& hf); BOOL CheckWildCard(const char * szString, const char * szWildCard); +//----------------------------------------------------------------------------- +// Attributes support + +int SAttrFileCreate(TMPQArchive * ha); +int SAttrFileLoad(TMPQArchive * ha); +int SAttrFileSaveToMpq(TMPQArchive * ha); +void FreeMPQAttributes(TMPQAttr * pAttr); + //----------------------------------------------------------------------------- // Listfile functions int SListFileCreateListFile(TMPQArchive * ha); -int SListFileAddNode(TMPQArchive * ha, const char * szAddedFile); -int SListFileRemoveNode(TMPQArchive * ha, const char * szFileName); -int SListFileRenameNode(TMPQArchive * ha, const char * szOldFileName, const char * szNewFileName); -int SListFileFreeListFile(TMPQArchive * ha); +int SListFileCreateNode(TMPQArchive * ha, const char * szFileName, LCID lcLocale); +int SListFileRemoveNode(TMPQArchive * ha, const char * szFileName, LCID lcLocale); +void SListFileFreeListFile(TMPQArchive * ha); int SListFileSaveToMpq(TMPQArchive * ha); diff --git a/src/tools/stuffextract/StormLib/SCompression.cpp b/src/tools/stuffextract/StormLib/SCompression.cpp index 612ef2c..06321a2 100644 --- a/src/tools/stuffextract/StormLib/SCompression.cpp +++ b/src/tools/stuffextract/StormLib/SCompression.cpp @@ -228,11 +228,9 @@ int Decompress_huff(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, i TInputStream is; // Initialize input stream -// is.pbInBuffer = (unsigned char *)pbInBuffer; - is.dwBitBuff = BSWAP_INT32_UNSIGNED(*(unsigned long *)pbInBuffer); - pbInBuffer += sizeof(unsigned long); - is.pbInBuffer = (unsigned char *)pbInBuffer; - is.nBits = 32; + is.pbInBuffer = (unsigned char *)pbInBuffer; + is.BitBuffer = 0; + is.BitCount = 0; // Initialize the Huffmann tree for compression ht.InitTree(false); @@ -363,7 +361,7 @@ int Decompress_pklib(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, // Fix: If PKLIB is unable to decompress the data, they are uncompressed if(Info.nOutPos == 0) { - Info.nOutPos = min(*pdwOutLength, dwInLength); + Info.nOutPos = STORMLIB_MIN(*pdwOutLength, dwInLength); memcpy(pbOutBuffer, pbInBuffer, Info.nOutPos); } @@ -422,11 +420,12 @@ int Compress_bzip2(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, in int Decompress_bzip2(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength) { bz_stream strm; + int nResult = BZ_OK; // Initialize the BZLIB decompression strm.bzalloc = NULL; strm.bzfree = NULL; - if(BZ2_bzDecompressInit(&strm, 0, 0) == 0) + if(BZ2_bzDecompressInit(&strm, 0, 0) == BZ_OK) { strm.next_in = pbInBuffer; strm.avail_in = dwInLength; @@ -434,18 +433,28 @@ int Decompress_bzip2(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, strm.avail_out = *pdwOutLength; // Perform the decompression - while(BZ2_bzDecompress(&strm) != BZ_STREAM_END); + while(nResult != BZ_STREAM_END) + { + nResult = BZ2_bzDecompress(&strm); + + // If any error there, break the loop + if(nResult < BZ_OK) + break; + } // Put the stream into idle state BZ2_bzDecompressEnd(&strm); - *pdwOutLength = strm.total_out_lo32; - } - else - { - // Set zero output length - *pdwOutLength = 0; + + // If all succeeded, set the number of output bytes + if(nResult >= BZ_OK) + { + *pdwOutLength = strm.total_out_lo32; + return 1; + } } + // Something failed, so set number of output bytes to zero + *pdwOutLength = 0; return 0; } diff --git a/src/tools/stuffextract/StormLib/SFileCompactArchive.cpp b/src/tools/stuffextract/StormLib/SFileCompactArchive.cpp index 9510b15..546a9e7 100644 --- a/src/tools/stuffextract/StormLib/SFileCompactArchive.cpp +++ b/src/tools/stuffextract/StormLib/SFileCompactArchive.cpp @@ -39,7 +39,6 @@ static TMPQHash * CopyHashTable(TMPQArchive * ha) return pHashTableCopy; } -// TODO: Test for archives > 4GB static int CheckIfAllFilesKnown(TMPQArchive * ha, const char * szListFile, DWORD * pFileSeeds) { TMPQHash * pHashTableCopy = NULL; // Copy of the hash table @@ -129,13 +128,13 @@ static int CheckIfAllFilesKnown(TMPQArchive * ha, const char * szListFile, DWORD { // If there is an unresolved entry, try to detect its seed. If it fails, // we cannot complete the work - if(pHash->dwName1 != (DWORD)-1 && pHash->dwName2 != (DWORD)-1) + if(pHash->dwBlockIndex < ha->pHeader->dwBlockTableSize) { HANDLE hFile = NULL; DWORD dwFlags = 0; DWORD dwSeed = 0; - if(SFileOpenFileEx((HANDLE)ha, (char *)(DWORD_PTR)pHash->dwBlockIndex, 0, &hFile)) + if(SFileOpenFileEx((HANDLE)ha, (char *)(DWORD_PTR)pHash->dwBlockIndex, SFILE_OPEN_BY_INDEX, &hFile)) { TMPQFile * hf = (TMPQFile *)hFile; dwFlags = hf->pBlock->dwFlags; @@ -168,7 +167,6 @@ static int CheckIfAllFilesKnown(TMPQArchive * ha, const char * szListFile, DWORD } // Copies all file blocks into another archive. -// TODO: Test for archives > 4GB static int CopyMpqFileBlocks( HANDLE hFile, TMPQArchive * ha, @@ -290,7 +288,7 @@ static int CopyMpqFileBlocks( } } - // Now we have to copy all file block. We will do it without + // Now we have to copy all file blocks. We will do it without // recompression, because re-compression is not necessary in this case if(nError == ERROR_SUCCESS) { @@ -424,7 +422,6 @@ static int CopyNonMpqData( return ERROR_SUCCESS; } -// TODO: Test for archives > 4GB static int CopyMpqFiles(HANDLE hFile, TMPQArchive * ha, DWORD * pFileSeeds) { TMPQBlockEx * pBlockEx; @@ -444,9 +441,6 @@ static int CopyMpqFiles(HANDLE hFile, TMPQArchive * ha, DWORD * pFileSeeds) if(CompactCB != NULL) CompactCB(lpUserData, CCB_COMPACTING_FILES, dwIndex, ha->pHeader->dwBlockTableSize); -// if(dwIndex == 0x1B9) -// DebugBreak(); - // Copy all the file blocks // Debug: Break at (dwIndex == 5973) if(pBlock->dwFlags & MPQ_FILE_EXISTS) @@ -476,7 +470,6 @@ BOOL WINAPI SFileSetCompactCallback(HANDLE /* hMPQ */, COMPACTCB aCompactCB, voi //----------------------------------------------------------------------------- // Archive compacting (incomplete) -// TODO: Test for archives > 4GB BOOL WINAPI SFileCompactArchive(HANDLE hMPQ, const char * szListFile, BOOL /* bReserved */) { TMPQArchive * ha = (TMPQArchive *)hMPQ; @@ -564,6 +557,10 @@ BOOL WINAPI SFileCompactArchive(HANDLE hMPQ, const char * szListFile, BOOL /* bR // Write the data between the header and between the first file // For this, we have to determine where the first file begins + // Ladik: While this seems to be useful at first sight, + // it makes SFileCompactArchive useless, when there's just one file + // in a MPQ that has been rewritten. +/* if(nError == ERROR_SUCCESS) { LARGE_INTEGER FirstFilePos; @@ -596,7 +593,7 @@ BOOL WINAPI SFileCompactArchive(HANDLE hMPQ, const char * szListFile, BOOL /* bR FirstFilePos.QuadPart -= ha->pHeader->dwHeaderSize; nError = CopyNonMpqData(ha->hFile, hFile, FirstFilePos); } - +*/ // Now write all file blocks. if(nError == ERROR_SUCCESS) nError = CopyMpqFiles(hFile, ha, pFileSeeds); @@ -643,7 +640,6 @@ BOOL WINAPI SFileCompactArchive(HANDLE hMPQ, const char * szListFile, BOOL /* bR if(nError == ERROR_SUCCESS) { CloseHandle(ha->hFile); - ha->FilePointer.QuadPart = 0; ha->hFile = hFile; hFile = INVALID_HANDLE_VALUE; nError = SaveMPQTables(ha); @@ -672,7 +668,6 @@ BOOL WINAPI SFileCompactArchive(HANDLE hMPQ, const char * szListFile, BOOL /* bR // Invalidate the positions of the archive if(nError == ERROR_SUCCESS) { - ha->FilePointer.QuadPart = 0; ha->pLastFile = NULL; ha->dwBlockPos = 0; ha->dwBuffPos = 0; diff --git a/src/tools/stuffextract/StormLib/SFileCreateArchiveEx.cpp b/src/tools/stuffextract/StormLib/SFileCreateArchiveEx.cpp index 2410920..c1c8022 100644 --- a/src/tools/stuffextract/StormLib/SFileCreateArchiveEx.cpp +++ b/src/tools/stuffextract/StormLib/SFileCreateArchiveEx.cpp @@ -19,7 +19,7 @@ //----------------------------------------------------------------------------- // Local tables - + static DWORD PowersOfTwo[] = { 0x0000002, 0x0000004, 0x0000008, @@ -30,6 +30,193 @@ static DWORD PowersOfTwo[] = 0x0000000 }; +//----------------------------------------------------------------------------- +// Local functions + +static int RecryptFileData( + TMPQArchive * ha, + DWORD dwSaveBlockIndex, + const char * szFileName, + const char * szNewFileName) +{ + LARGE_INTEGER BlockFilePos; + LARGE_INTEGER MpqFilePos; + TMPQBlockEx * pBlockEx = ha->pExtBlockTable + dwSaveBlockIndex; + TMPQBlock * pBlock = ha->pBlockTable + dwSaveBlockIndex; + const char * szPlainName; + LPDWORD pdwBlockPos1 = NULL; + LPDWORD pdwBlockPos2 = NULL; + LPBYTE pbFileBlock = NULL; + DWORD dwTransferred; + DWORD dwOldSeed; + DWORD dwNewSeed; + DWORD dwToRead; + int nBlocks; + int nError = ERROR_SUCCESS; + + // The file must be encrypted + assert(pBlock->dwFlags & MPQ_FILE_ENCRYPTED); + + // File decryption seed is calculated from the plain name + szPlainName = strrchr(szFileName, '\\'); + if(szPlainName != NULL) + szFileName = szPlainName + 1; + szPlainName = strrchr(szNewFileName, '\\'); + if(szPlainName != NULL) + szNewFileName = szPlainName + 1; + + // Calculate both file seeds + dwOldSeed = DecryptFileSeed(szFileName); + dwNewSeed = DecryptFileSeed(szNewFileName); + if(pBlock->dwFlags & MPQ_FILE_FIXSEED) + { + dwOldSeed = (dwOldSeed + pBlock->dwFilePos) ^ pBlock->dwFSize; + dwNewSeed = (dwNewSeed + pBlock->dwFilePos) ^ pBlock->dwFSize; + } + + // Incase the seeds are equal, don't recrypt the file + if(dwNewSeed == dwOldSeed) + return ERROR_SUCCESS; + + // Calculate the file position of the archived file + MpqFilePos.LowPart = pBlock->dwFilePos; + MpqFilePos.HighPart = pBlockEx->wFilePosHigh; + MpqFilePos.QuadPart += ha->MpqPos.QuadPart; + + // Calculate the number of file blocks + nBlocks = pBlock->dwFSize / ha->dwBlockSize; + if(pBlock->dwFSize % ha->dwBlockSize) + nBlocks++; + + // If the file is stored as single unit, we recrypt one block only + if(pBlock->dwFlags & MPQ_FILE_SINGLE_UNIT) + { + // Allocate the block + pbFileBlock = ALLOCMEM(BYTE, pBlock->dwCSize); + if(pbFileBlock == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + SetFilePointer(ha->hFile, MpqFilePos.LowPart, &MpqFilePos.HighPart, FILE_BEGIN); + ReadFile(ha->hFile, pbFileBlock, pBlock->dwCSize, &dwTransferred, NULL); + if(dwTransferred == pBlock->dwCSize) + nError = ERROR_FILE_CORRUPT; + + if(nError == ERROR_SUCCESS) + { + // Recrypt the block + DecryptMPQBlock((DWORD *)pbFileBlock, pBlock->dwCSize, dwOldSeed); + EncryptMPQBlock((DWORD *)pbFileBlock, pBlock->dwCSize, dwNewSeed); + + // Write it back + SetFilePointer(ha->hFile, MpqFilePos.LowPart, &MpqFilePos.HighPart, FILE_BEGIN); + WriteFile(ha->hFile, pbFileBlock, pBlock->dwCSize, &dwTransferred, NULL); + if(dwTransferred != pBlock->dwCSize) + nError = ERROR_WRITE_FAULT; + } + FREEMEM(pbFileBlock); + return nError; + } + + // If the file is compressed, we have to re-crypt block table first, + // then all file blocks + if(pBlock->dwFlags & MPQ_FILE_COMPRESSED) + { + // Allocate buffer for both blocks + pdwBlockPos1 = ALLOCMEM(DWORD, nBlocks + 2); + pdwBlockPos2 = ALLOCMEM(DWORD, nBlocks + 2); + if(pdwBlockPos1 == NULL || pdwBlockPos2 == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Calculate number of bytes to be read + dwToRead = (nBlocks + 1) * sizeof(DWORD); + if(pBlock->dwFlags & MPQ_FILE_HAS_EXTRA) + dwToRead += sizeof(DWORD); + + // Read the block positions + SetFilePointer(ha->hFile, MpqFilePos.LowPart, &MpqFilePos.HighPart, FILE_BEGIN); + ReadFile(ha->hFile, pdwBlockPos1, dwToRead, &dwTransferred, NULL); + if(dwTransferred != dwToRead) + nError = ERROR_FILE_CORRUPT; + + // Recrypt the block table + if(nError == ERROR_SUCCESS) + { + BSWAP_ARRAY32_UNSIGNED(pdwBlockPos1, dwToRead / sizeof(DWORD)); + DecryptMPQBlock(pdwBlockPos1, dwToRead, dwOldSeed - 1); + if(pdwBlockPos1[0] != dwToRead) + nError = ERROR_FILE_CORRUPT; + + memcpy(pdwBlockPos2, pdwBlockPos1, dwToRead); + EncryptMPQBlock(pdwBlockPos2, dwToRead, dwNewSeed - 1); + BSWAP_ARRAY32_UNSIGNED(pdwBlockPos2, dwToRead / sizeof(DWORD)); + } + + // Write the recrypted block table back + if(nError == ERROR_SUCCESS) + { + SetFilePointer(ha->hFile, MpqFilePos.LowPart, &MpqFilePos.HighPart, FILE_BEGIN); + WriteFile(ha->hFile, pdwBlockPos2, dwToRead, &dwTransferred, NULL); + if(dwTransferred != dwToRead) + nError = ERROR_WRITE_FAULT; + } + } + + // Allocate the transfer buffer + if(nError == ERROR_SUCCESS) + { + pbFileBlock = ALLOCMEM(BYTE, ha->dwBlockSize); + if(pbFileBlock == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Now we have to recrypt all file blocks + if(nError == ERROR_SUCCESS) + { + for(int nBlock = 0; nBlock < nBlocks; nBlock++) + { + // Calc position and length for uncompressed file + BlockFilePos.QuadPart = MpqFilePos.QuadPart + (ha->dwBlockSize * nBlock); + dwToRead = ha->dwBlockSize; + if(nBlock == nBlocks - 1) + dwToRead = pBlock->dwFSize - (ha->dwBlockSize * (nBlocks - 1)); + + // Fix position and length for compressed file + if(pBlock->dwFlags & MPQ_FILE_COMPRESS) + { + BlockFilePos.QuadPart = MpqFilePos.QuadPart + pdwBlockPos1[nBlock]; + dwToRead = pdwBlockPos1[nBlock+1] - pdwBlockPos1[nBlock]; + } + + // Read the file block + SetFilePointer(ha->hFile, BlockFilePos.LowPart, &BlockFilePos.HighPart, FILE_BEGIN); + ReadFile(ha->hFile, pbFileBlock, dwToRead, &dwTransferred, NULL); + if(dwTransferred != dwToRead) + nError = ERROR_FILE_CORRUPT; + + // Recrypt the file block + BSWAP_ARRAY32_UNSIGNED((DWORD *)pbFileBlock, dwToRead/sizeof(DWORD)); + DecryptMPQBlock((DWORD *)pbFileBlock, dwToRead, dwOldSeed + nBlock); + EncryptMPQBlock((DWORD *)pbFileBlock, dwToRead, dwNewSeed + nBlock); + BSWAP_ARRAY32_UNSIGNED((DWORD *)pbFileBlock, dwToRead/sizeof(DWORD)); + + // Write the block back + SetFilePointer(ha->hFile, BlockFilePos.LowPart, &BlockFilePos.HighPart, FILE_BEGIN); + WriteFile(ha->hFile, pbFileBlock, dwToRead, &dwTransferred, NULL); + if(dwTransferred != dwToRead) + nError = ERROR_WRITE_FAULT; + } + } + + // Free buffers and exit + if(pbFileBlock != NULL) + FREEMEM(pbFileBlock); + if(pdwBlockPos2 != NULL) + FREEMEM(pdwBlockPos2); + if(pdwBlockPos1 != NULL) + FREEMEM(pdwBlockPos1); + return nError; +} + /*****************************************************************************/ /* Public functions */ /*****************************************************************************/ @@ -52,6 +239,7 @@ static DWORD PowersOfTwo[] = // // MPQ_CREATE_ARCHIVE_V1 - Creates MPQ archive version 1 // MPQ_CREATE_ARCHIVE_V2 - Creates MPQ archive version 2 +// MPQ_CREATE_ATTRIBUTES - Will also add (attributes) file with the CRCs // // dwHashTableSize - Size of the hash table (only if creating a new archive). // Must be between 2^4 (= 16) and 2^18 (= 262 144) @@ -59,7 +247,6 @@ static DWORD PowersOfTwo[] = // phMpq - Receives handle to the archive // -// TODO: Test for archives > 4GB BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposition, DWORD dwHashTableSize, HANDLE * phMPQ) { LARGE_INTEGER MpqPos = {0}; // Position of MPQ header in the file @@ -67,6 +254,7 @@ BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposi HANDLE hFile = INVALID_HANDLE_VALUE; // File handle DWORD dwTransferred = 0; // Number of bytes written into the archive USHORT wFormatVersion; + BOOL bCreateAttributes = FALSE; BOOL bFileExists = FALSE; int nIndex = 0; int nError = ERROR_SUCCESS; @@ -86,7 +274,8 @@ BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposi bFileExists = (GetFileAttributes(szMpqName) != 0xFFFFFFFF); // Extract format version from the "dwCreationDisposition" - wFormatVersion = (USHORT)(dwCreationDisposition >> 0x10); + bCreateAttributes = (dwCreationDisposition & MPQ_CREATE_ATTRIBUTES); + wFormatVersion = (USHORT)((dwCreationDisposition >> 0x10) & 0x0000000F); dwCreationDisposition &= 0x0000FFFF; // If the file exists and open required, do it. @@ -96,6 +285,11 @@ BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposi // the file exist, but it is not a MPQ archive. if(SFileOpenArchiveEx(szMpqName, 0, 0, phMPQ, GENERIC_READ | GENERIC_WRITE)) return TRUE; + + // If the caller required to open the existing archive, + // and the file is not MPQ archive, return error + if(dwCreationDisposition == OPEN_EXISTING) + return FALSE; } // Two error cases @@ -190,7 +384,6 @@ BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposi ha->hFile = hFile; ha->dwBlockSize = 0x200 << DEFAULT_BLOCK_SIZE; ha->MpqPos = MpqPos; - ha->FilePointer = MpqPos; ha->pHeader = &ha->Header; ha->pHashTable = ALLOCMEM(TMPQHash, dwHashTableSize); ha->pBlockTable = ALLOCMEM(TMPQBlock, dwHashTableSize); @@ -253,7 +446,6 @@ BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposi if(dwTransferred != ha->pHeader->dwHeaderSize) nError = ERROR_DISK_FULL; - ha->FilePointer.QuadPart = ha->MpqPos.QuadPart + dwTransferred; ha->MpqSize.QuadPart += dwTransferred; } @@ -261,9 +453,20 @@ BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposi if(nError == ERROR_SUCCESS) nError = SListFileCreateListFile(ha); - // Try to add the internal listfile + // Try to add the internal listfile, attributes. + // Also add internal listfile to the search lists if(nError == ERROR_SUCCESS) - SFileAddListFile((HANDLE)ha, NULL); + { + if(SFileAddListFile((HANDLE)ha, NULL) != ERROR_SUCCESS) + AddInternalFile(ha, LISTFILE_NAME); + } + + // Create the file attributes + if(nError == ERROR_SUCCESS && bCreateAttributes) + { + if(SAttrFileCreate(ha) == ERROR_SUCCESS) + AddInternalFile(ha, ATTRIBUTES_NAME); + } // Cleanup : If an error, delete all buffers and return if(nError != ERROR_SUCCESS) @@ -272,6 +475,7 @@ BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposi if(hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); SetLastError(nError); + ha = NULL; } // Return the values @@ -282,7 +486,6 @@ BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposi //----------------------------------------------------------------------------- // Changes locale ID of a file -// TODO: Test for archives > 4GB BOOL WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale) { TMPQFile * hf = (TMPQFile *)hFile; @@ -306,7 +509,6 @@ BOOL WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale) //----------------------------------------------------------------------------- // Adds a file into the archive -// TODO: Test for archives > 4GB BOOL WINAPI SFileAddFileEx(HANDLE hMPQ, const char * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality, int nFileType) { TMPQArchive * ha = (TMPQArchive *)hMPQ; @@ -321,7 +523,7 @@ BOOL WINAPI SFileAddFileEx(HANDLE hMPQ, const char * szFileName, const char * sz nError = ERROR_INVALID_PARAMETER; // Check the values of dwFlags - if((dwFlags & MPQ_FILE_COMPRESS_PKWARE) && (dwFlags & MPQ_FILE_COMPRESS_MULTI)) + if((dwFlags & MPQ_FILE_IMPLODE) && (dwFlags & MPQ_FILE_COMPRESS)) nError = ERROR_INVALID_PARAMETER; } @@ -346,7 +548,7 @@ BOOL WINAPI SFileAddFileEx(HANDLE hMPQ, const char * szFileName, const char * sz // Add the file into listfile also if(nError == ERROR_SUCCESS && bReplaced == FALSE) - nError = SListFileAddNode(ha, szArchivedName); + nError = SListFileCreateNode(ha, szArchivedName, lcLocale); // Cleanup and exit if(hFile != INVALID_HANDLE_VALUE) @@ -357,14 +559,12 @@ BOOL WINAPI SFileAddFileEx(HANDLE hMPQ, const char * szFileName, const char * sz } // Adds a data file into the archive -// TODO: Test for archives > 4GB BOOL WINAPI SFileAddFile(HANDLE hMPQ, const char * szFileName, const char * szArchivedName, DWORD dwFlags) { return SFileAddFileEx(hMPQ, szFileName, szArchivedName, dwFlags, 0, SFILE_TYPE_DATA); } // Adds a WAVE file into the archive -// TODO: Test for archives > 4GB BOOL WINAPI SFileAddWave(HANDLE hMPQ, const char * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality) { return SFileAddFileEx(hMPQ, szFileName, szArchivedName, dwFlags, dwQuality, SFILE_TYPE_WAVE); @@ -377,7 +577,6 @@ BOOL WINAPI SFileAddWave(HANDLE hMPQ, const char * szFileName, const char * szAr // remains there, only the entries in the hash table and in the block // table are updated. -// TODO: Test for archives > 4GB BOOL WINAPI SFileRemoveFile(HANDLE hMPQ, const char * szFileName, DWORD dwSearchScope) { TMPQArchive * ha = (TMPQArchive *)hMPQ; @@ -403,6 +602,10 @@ BOOL WINAPI SFileRemoveFile(HANDLE hMPQ, const char * szFileName, DWORD dwSearch nError = ERROR_ACCESS_DENIED; } + // Remove the file from the list file + if(nError == ERROR_SUCCESS) + nError = SListFileRemoveNode(ha, szFileName, lcLocale); + // Get hash entry belonging to this file if(nError == ERROR_SUCCESS) { @@ -445,10 +648,6 @@ BOOL WINAPI SFileRemoveFile(HANDLE hMPQ, const char * szFileName, DWORD dwSearch ha->dwFlags |= MPQ_FLAG_CHANGED; } - // Remove the file from the list file - if(nError == ERROR_SUCCESS && lcLocale == LANG_NEUTRAL) - nError = SListFileRemoveNode(ha, szFileName); - // Resolve error and exit if(nError != ERROR_SUCCESS) SetLastError(nError); @@ -456,13 +655,14 @@ BOOL WINAPI SFileRemoveFile(HANDLE hMPQ, const char * szFileName, DWORD dwSearch } // Renames the file within the archive. -// TODO: Test for archives > 4GB BOOL WINAPI SFileRenameFile(HANDLE hMPQ, const char * szFileName, const char * szNewFileName) { TMPQArchive * ha = (TMPQArchive *)hMPQ; + TMPQBlock * pBlock; TMPQHash * pOldHash = NULL; // Hash entry for the original file TMPQHash * pNewHash = NULL; // Hash entry for the renamed file - DWORD dwBlockIndex = 0; + DWORD dwSaveBlockIndex = 0; + LCID lcSaveLocale = 0; int nError = ERROR_SUCCESS; // Test the valid parameters @@ -481,13 +681,6 @@ BOOL WINAPI SFileRenameFile(HANDLE hMPQ, const char * szFileName, const char * s nError = ERROR_ACCESS_DENIED; } - // Test if the file already exists in the archive - if(nError == ERROR_SUCCESS) - { - if((pNewHash = GetHashEntryEx(ha, szNewFileName, lcLocale)) != NULL) - nError = ERROR_ALREADY_EXISTS; - } - // Get the hash table entry for the original file if(nError == ERROR_SUCCESS) { @@ -495,11 +688,34 @@ BOOL WINAPI SFileRenameFile(HANDLE hMPQ, const char * szFileName, const char * s nError = ERROR_FILE_NOT_FOUND; } - // Get the hash table entry for the renamed file + // Test if the file already exists in the archive + if(nError == ERROR_SUCCESS) + { + if((pNewHash = GetHashEntryEx(ha, szNewFileName, pOldHash->lcLocale)) != NULL) + nError = ERROR_ALREADY_EXISTS; + } + + // We have to know the decryption seed, otherwise we cannot re-crypt + // the file after renaming if(nError == ERROR_SUCCESS) { // Save block table index and remove the hash table entry - dwBlockIndex = pOldHash->dwBlockIndex; + dwSaveBlockIndex = pOldHash->dwBlockIndex; + lcSaveLocale = pOldHash->lcLocale; + pBlock = ha->pBlockTable + dwSaveBlockIndex; + + // If the file is encrypted, we have to re-crypt the file content + // with the new decryption seed + if(pBlock->dwFlags & MPQ_FILE_ENCRYPTED) + { + nError = RecryptFileData(ha, dwSaveBlockIndex, szFileName, szNewFileName); + } + } + + // Get the hash table entry for the renamed file + if(nError == ERROR_SUCCESS) + { + SListFileRemoveNode(ha, szFileName, lcSaveLocale); pOldHash->dwName1 = 0xFFFFFFFF; pOldHash->dwName2 = 0xFFFFFFFF; pOldHash->lcLocale = 0xFFFF; @@ -514,13 +730,13 @@ BOOL WINAPI SFileRenameFile(HANDLE hMPQ, const char * szFileName, const char * s if(nError == ERROR_SUCCESS) { // Copy the block table index - pNewHash->dwBlockIndex = dwBlockIndex; + pNewHash->dwBlockIndex = dwSaveBlockIndex; + pNewHash->lcLocale = (USHORT)lcSaveLocale; ha->dwFlags |= MPQ_FLAG_CHANGED; - } - // Rename the file in the list file - if(nError == ERROR_SUCCESS) - nError = SListFileRenameNode(ha, szFileName, szNewFileName); + // Create new name node for the listfile + nError = SListFileCreateNode(ha, szNewFileName, lcSaveLocale); + } // Resolve error and return if(nError != ERROR_SUCCESS) diff --git a/src/tools/stuffextract/StormLib/SFileExtractFile.cpp b/src/tools/stuffextract/StormLib/SFileExtractFile.cpp index 7f16cde..832c98e 100644 --- a/src/tools/stuffextract/StormLib/SFileExtractFile.cpp +++ b/src/tools/stuffextract/StormLib/SFileExtractFile.cpp @@ -12,13 +12,23 @@ #include "StormLib.h" #include "SCommon.h" -// TODO: Test for archives > 4GB BOOL WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const char * szExtracted) { HANDLE hLocalFile = INVALID_HANDLE_VALUE; HANDLE hMpqFile = NULL; + DWORD dwSearchScope = 0; int nError = ERROR_SUCCESS; + + // Open the MPQ file + if(nError == ERROR_SUCCESS) + { + if((DWORD_PTR)szToExtract <= 0x10000) + dwSearchScope = SFILE_OPEN_BY_INDEX; + if(!SFileOpenFileEx(hMpq, szToExtract, dwSearchScope, &hMpqFile)) + nError = GetLastError(); + } + // Create the local file if(nError == ERROR_SUCCESS) { @@ -27,28 +37,27 @@ BOOL WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const char * nError = GetLastError(); } - // Open the MPQ file - if(nError == ERROR_SUCCESS) - { - if(!SFileOpenFileEx(hMpq, szToExtract, 0, &hMpqFile)) - nError = GetLastError(); - } - // Copy the file's content if(nError == ERROR_SUCCESS) { char szBuffer[0x1000]; - DWORD dwTransferred = 1; + DWORD dwTransferred; - while(dwTransferred > 0) + for(;;) { - SFileReadFile(hMpqFile, szBuffer, sizeof(szBuffer), &dwTransferred, NULL); + // dwTransferred is only set to nonzero if something has been read. + // nError can be ERROR_SUCCESS or ERROR_HANDLE_EOF + if(!SFileReadFile(hMpqFile, szBuffer, sizeof(szBuffer), &dwTransferred, NULL)) + nError = GetLastError(); + if(nError == ERROR_HANDLE_EOF) + nError = ERROR_SUCCESS; if(dwTransferred == 0) break; + // If something has been actually read, write it WriteFile(hLocalFile, szBuffer, dwTransferred, &dwTransferred, NULL); if(dwTransferred == 0) - break; + nError = ERROR_DISK_FULL; } } diff --git a/src/tools/stuffextract/StormLib/SFileFindFile.cpp b/src/tools/stuffextract/StormLib/SFileFindFile.cpp index 41dbeba..8fb4f83 100644 --- a/src/tools/stuffextract/StormLib/SFileFindFile.cpp +++ b/src/tools/stuffextract/StormLib/SFileFindFile.cpp @@ -134,54 +134,82 @@ BOOL CheckWildCard(const char * szString, const char * szWildCard) } // Performs one MPQ search -// TODO: Test for archives > 4GB static int DoMPQSearch(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData) { TMPQArchive * ha = hs->ha; - TFileNode * pNode; + TFileNode * pNode = NULL; + TMPQBlock * pBlock; + TMPQHash * pFoundHash = NULL; TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize; TMPQHash * pHash = ha->pHashTable + hs->dwNextIndex; + DWORD dwIndex = hs->dwNextIndex; - // Do until some file found or no more files + // Do until a file is found or no more files while(pHash < pHashEnd) { - pNode = ha->pListFile[hs->dwNextIndex++]; + pNode = ha->pListFile[dwIndex++]; - // If this entry is free, do nothing - if(pHash->dwBlockIndex < HASH_ENTRY_FREE && (DWORD_PTR)pNode < HASH_ENTRY_FREE) + // Is this entry occupied ? + if(pHash->dwBlockIndex < HASH_ENTRY_DELETED && (DWORD_PTR)pNode < LISTFILE_ENTRY_DELETED) { // Check the file name. if(CheckWildCard(pNode->szFileName, hs->szSearchMask)) { - TMPQBlock * pBlock = ha->pBlockTable + pHash->dwBlockIndex; - - lpFindFileData->lcLocale = pHash->lcLocale; - lpFindFileData->dwFileSize = pBlock->dwFSize; - lpFindFileData->dwFileFlags = pBlock->dwFlags; - lpFindFileData->dwBlockIndex = pHash->dwBlockIndex; - lpFindFileData->dwCompSize = pBlock->dwCSize; - - // Fill the file name and plain file name - strcpy(lpFindFileData->cFileName, pNode->szFileName); - lpFindFileData->szPlainName = strrchr(lpFindFileData->cFileName, '\\'); - if(lpFindFileData->szPlainName == NULL) - lpFindFileData->szPlainName = lpFindFileData->cFileName; - else - lpFindFileData->szPlainName++; - - // Fill the next entry - return ERROR_SUCCESS; + pFoundHash = pHash; + pHash++; + break; } } + // Move to the next hash pHash++; } + // In case there will be more equal entries in the hash table + if(pFoundHash != NULL) + { + while(pHash < pHashEnd) + { + if(pHash->dwName1 != pFoundHash->dwName1 || + pHash->dwName2 != pFoundHash->dwName2 || + pHash->lcLocale != pFoundHash->lcLocale || + pHash->wPlatform != pFoundHash->wPlatform) + { + break; + } + + // Move to the next hash + pFoundHash = pHash; + pHash++; + } + + // Fill the found entry + pBlock = ha->pBlockTable + pFoundHash->dwBlockIndex; + lpFindFileData->lcLocale = pFoundHash->lcLocale; + lpFindFileData->dwFileSize = pBlock->dwFSize; + lpFindFileData->dwFileFlags = pBlock->dwFlags; + lpFindFileData->dwBlockIndex = pFoundHash->dwBlockIndex; + lpFindFileData->dwCompSize = pBlock->dwCSize; + + // Fill the file name and plain file name + strcpy(lpFindFileData->cFileName, pNode->szFileName); + lpFindFileData->szPlainName = strrchr(lpFindFileData->cFileName, '\\'); + if(lpFindFileData->szPlainName == NULL) + lpFindFileData->szPlainName = lpFindFileData->cFileName; + else + lpFindFileData->szPlainName++; + + // Adjust the next hash index to search + hs->dwNextIndex = (DWORD)(pFoundHash - ha->pHashTable) + 1; + + // Fill the next entry + return ERROR_SUCCESS; + } + // No more files found, return error return ERROR_NO_MORE_FILES; } -// TODO: Test for archives > 4GB static void FreeMPQSearch(TMPQSearch *& hs) { if(hs != NULL) @@ -194,7 +222,6 @@ static void FreeMPQSearch(TMPQSearch *& hs) //----------------------------------------------------------------------------- // Public functions -// TODO: Test for archives > 4GB HANDLE WINAPI SFileFindFirstFile(HANDLE hMPQ, const char * szMask, SFILE_FIND_DATA * lpFindFileData, const char * szListFile) { TMPQArchive * ha = (TMPQArchive *)hMPQ; @@ -218,7 +245,7 @@ HANDLE WINAPI SFileFindFirstFile(HANDLE hMPQ, const char * szMask, SFILE_FIND_DA // Include the listfile into the MPQ's internal listfile // Note that if the listfile name is NULL, do nothing because the // internal listfile is always included. - if(nError == ERROR_SUCCESS && szListFile != NULL) + if(nError == ERROR_SUCCESS && szListFile != NULL && *szListFile != 0) nError = SFileAddListFile((HANDLE)ha, szListFile); // Allocate the structure for MPQ search @@ -250,7 +277,6 @@ HANDLE WINAPI SFileFindFirstFile(HANDLE hMPQ, const char * szMask, SFILE_FIND_DA return (HANDLE)hs; } -// TODO: Test for archives > 4GB BOOL WINAPI SFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData) { TMPQSearch * hs = (TMPQSearch *)hFind; @@ -274,7 +300,6 @@ BOOL WINAPI SFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData) return TRUE; } -// TODO: Test for archives > 4GB BOOL WINAPI SFileFindClose(HANDLE hFind) { TMPQSearch * hs = (TMPQSearch *)hFind; diff --git a/src/tools/stuffextract/StormLib/SFileOpenArchive.cpp b/src/tools/stuffextract/StormLib/SFileOpenArchive.cpp index cadb4e0..4282fb2 100644 --- a/src/tools/stuffextract/StormLib/SFileOpenArchive.cpp +++ b/src/tools/stuffextract/StormLib/SFileOpenArchive.cpp @@ -30,7 +30,6 @@ static BOOL IsAviFile(TMPQHeader * pHeader) } // This function gets the right positions of the hash table and the block table. -// TODO: Test for archives > 4GB static int RelocateMpqTablePositions(TMPQArchive * ha) { TMPQHeader2 * pHeader = ha->pHeader; @@ -194,15 +193,19 @@ BOOL SFileOpenArchiveEx( // If there is the MPQ shunt signature, process it if(dwHeaderID == ID_MPQ_SHUNT && ha->pShunt == NULL) { - // Fill the shunt header - ha->ShuntPos = MpqPos; - ha->pShunt = &ha->Shunt; - memcpy(ha->pShunt, ha->pHeader, sizeof(TMPQShunt)); - BSWAP_TMPQSHUNT(ha->pShunt); + // Ignore the MPQ shunt completely if the caller wants to open the MPQ as V1.0 + if((dwFlags & MPQ_OPEN_FORCE_MPQ_V1) == 0) + { + // Fill the shunt header + ha->ShuntPos = MpqPos; + ha->pShunt = &ha->Shunt; + memcpy(ha->pShunt, ha->pHeader, sizeof(TMPQShunt)); + BSWAP_TMPQSHUNT(ha->pShunt); - // Set the MPQ pos and repeat the search - MpqPos.QuadPart = SearchPos.QuadPart + ha->pShunt->dwHeaderPos; - continue; + // Set the MPQ pos and repeat the search + MpqPos.QuadPart = SearchPos.QuadPart + ha->pShunt->dwHeaderPos; + continue; + } } // There must be MPQ header signature @@ -218,38 +221,35 @@ BOOL SFileOpenArchiveEx( { // W3M Map Protectors set some garbage value into the "dwHeaderSize" // field of MPQ header. This value is apparently ignored by Storm.dll - if(ha->pHeader->dwHeaderSize != sizeof(TMPQHeader) && - ha->pHeader->dwHeaderSize != sizeof(TMPQHeader2)) + if(ha->pHeader->dwHeaderSize != sizeof(TMPQHeader)) { ha->dwFlags |= MPQ_FLAG_PROTECTED; ha->pHeader->dwHeaderSize = sizeof(TMPQHeader); } - - if(ha->pHeader->dwHashTablePos < ha->pHeader->dwArchiveSize && - ha->pHeader->dwBlockTablePos < ha->pHeader->dwArchiveSize) - { - break; - } + break; } if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_2) { - break; + // W3M Map Protectors set some garbage value into the "dwHeaderSize" + // field of MPQ header. This value is apparently ignored by Storm.dll + if(ha->pHeader->dwHeaderSize != sizeof(TMPQHeader2)) + { + ha->dwFlags |= MPQ_FLAG_PROTECTED; + ha->pHeader->dwHeaderSize = sizeof(TMPQHeader2); + } + break; } + // + // Note: the "dwArchiveSize" member in the MPQ header is ignored by Storm.dll + // and can contain garbage value ("w3xmaster" protector) + // + nError = ERROR_NOT_SUPPORTED; break; } - // If a MPQ shunt already has been found, - // and no MPQ header was at potision pointed by the shunt, - // then the archive is corrupt - if(ha->pShunt != NULL) - { - nError = ERROR_BAD_FORMAT; - break; - } - // Move to the next possible offset SearchPos.QuadPart += 0x200; MpqPos = SearchPos; @@ -259,6 +259,17 @@ BOOL SFileOpenArchiveEx( // Relocate tables position if(nError == ERROR_SUCCESS) { + // W3x Map Protectors use the fact that War3's StormLib ignores the file shunt, + // and probably ignores the MPQ format version as well. The trick is to + // fake MPQ format 2, with an improper hi-word position of hash table and block table + // We can overcome such protectors by forcing opening the archive as MPQ v 1.0 + if(dwFlags & MPQ_OPEN_FORCE_MPQ_V1) + { + ha->pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1; + ha->pHeader->dwHeaderSize = sizeof(TMPQHeader); + ha->pShunt = NULL; + } + // Clear the fields not supported in older formats if(ha->pHeader->wFormatVersion < MPQ_FORMAT_VERSION_2) { @@ -281,7 +292,10 @@ BOOL SFileOpenArchiveEx( // I have found a MPQ which has the block table larger than // the hash table. We should avoid buffer overruns caused by that. // - dwBlockTableSize = max(ha->pHeader->dwHashTableSize, ha->pHeader->dwBlockTableSize); + + if(ha->pHeader->dwBlockTableSize > ha->pHeader->dwHashTableSize) + ha->pHeader->dwBlockTableSize = ha->pHeader->dwHashTableSize; + dwBlockTableSize = ha->pHeader->dwHashTableSize; ha->pHashTable = ALLOCMEM(TMPQHash, ha->pHeader->dwHashTableSize); ha->pBlockTable = ALLOCMEM(TMPQBlock, dwBlockTableSize); @@ -306,33 +320,20 @@ BOOL SFileOpenArchiveEx( // Decrypt hash table and check if it is correctly decrypted if(nError == ERROR_SUCCESS) { - TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize; - TMPQHash * pHash; +// TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize; +// TMPQHash * pHash; // We have to convert the hash table from LittleEndian BSWAP_ARRAY32_UNSIGNED((DWORD *)ha->pHashTable, (dwBytes / sizeof(DWORD))); DecryptHashTable((DWORD *)ha->pHashTable, (BYTE *)"(hash table)", (ha->pHeader->dwHashTableSize * 4)); + // // Check hash table if is correctly decrypted - for(pHash = ha->pHashTable; pHash < pHashEnd; pHash++) - { - // Note: Some MPQs from World of Warcraft have wPlatform set to 0x0100. - - // If not free or deleted hash entry, check for valid values - if(pHash->dwBlockIndex < HASH_ENTRY_DELETED) - { - // The block index should not be larger than size of the block table - if(pHash->dwBlockIndex > ha->pHeader->dwBlockTableSize) - { - nError = ERROR_BAD_FORMAT; - break; - } - - // Remember the highest block table entry - if(pHash->dwBlockIndex > dwMaxBlockIndex) - dwMaxBlockIndex = pHash->dwBlockIndex; - } - } + // + // Ladik: Some MPQ protectors corrupt the hash table by rewriting part of it. + // To be able to open these, we will not check the entire hash table, + // but will check it at the moment of file opening. + // } // Now, read the block table @@ -340,23 +341,30 @@ BOOL SFileOpenArchiveEx( { memset(ha->pBlockTable, 0, dwBlockTableSize * sizeof(TMPQBlock)); + // Carefully check the block table size dwBytes = ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock); SetFilePointer(ha->hFile, ha->BlockTablePos.LowPart, &ha->BlockTablePos.HighPart, FILE_BEGIN); ReadFile(ha->hFile, ha->pBlockTable, dwBytes, &dwTransferred, NULL); - // We have to convert every DWORD in ha->block from LittleEndian + // I have found a MPQ which claimed 0x200 entries in the block table, + // but the file was cut and there was only 0x1A0 entries. + // We will handle this case properly, even if that means + // omiting another integrity check of the MPQ + if(dwTransferred < dwBytes) + dwBytes = dwTransferred; BSWAP_ARRAY32_UNSIGNED((DWORD *)ha->pBlockTable, dwBytes / sizeof(DWORD)); - if(dwTransferred != dwBytes) + // If nothing was read, we assume the file is corrupt. + if(dwTransferred == 0) nError = ERROR_FILE_CORRUPT; } // Decrypt block table. - // Some MPQs don't have Decrypted block table, e.g. cracked Diablo version + // Some MPQs don't have the block table decrypted, e.g. cracked Diablo version // We have to check if block table is really encrypted if(nError == ERROR_SUCCESS) { - TMPQBlock * pBlockEnd = ha->pBlockTable + ha->pHeader->dwBlockTableSize; + TMPQBlock * pBlockEnd = ha->pBlockTable + (dwBytes / sizeof(TMPQBlock)); TMPQBlock * pBlock = ha->pBlockTable; BOOL bBlockTableEncrypted = FALSE; @@ -380,14 +388,13 @@ BOOL SFileOpenArchiveEx( { DecryptBlockTable((DWORD *)ha->pBlockTable, (BYTE *)"(block table)", - (ha->pHeader->dwBlockTableSize * 4)); + (dwBytes / sizeof(DWORD))); } } // Now, read the extended block table. // For V1 archives, we still will maintain the extended block table // (it will be filled with zeros) - // TODO: Test with >4GB if(nError == ERROR_SUCCESS) { memset(ha->pExtBlockTable, 0, dwBlockTableSize * sizeof(TMPQBlockEx)); @@ -410,7 +417,7 @@ BOOL SFileOpenArchiveEx( } } - // Verify the both block tables (If the MPQ file is not protected) + // Verify both block tables (If the MPQ file is not protected) if(nError == ERROR_SUCCESS && (ha->dwFlags & MPQ_FLAG_PROTECTED) == 0) { TMPQBlockEx * pBlockEx = ha->pExtBlockTable; @@ -437,16 +444,28 @@ BOOL SFileOpenArchiveEx( } } - // If the user didn't specified otherwise, + // If the caller didn't specified otherwise, // include the internal listfile to the TMPQArchive structure - if((dwFlags & MPQ_OPEN_NO_LISTFILE) == 0) + if(nError == ERROR_SUCCESS) { - if(nError == ERROR_SUCCESS) - SListFileCreateListFile(ha); + if((dwFlags & MPQ_OPEN_NO_LISTFILE) == 0) + { + if(nError == ERROR_SUCCESS) + SListFileCreateListFile(ha); - // Add the internal listfile - if(nError == ERROR_SUCCESS) - SFileAddListFile((HANDLE)ha, NULL); + // Add the internal listfile + if(nError == ERROR_SUCCESS) + SFileAddListFile((HANDLE)ha, NULL); + } + } + + // If the caller didn't specified otherwise, + // load the "(attributes)" file + if(nError == ERROR_SUCCESS && (dwFlags & MPQ_OPEN_NO_ATTRIBUTES) == 0) + { + // Ignore the result here. Attrobutes are not necessary, + // if they are not there, we will just ignore them + SAttrFileLoad(ha); } // Cleanup and exit @@ -456,6 +475,7 @@ BOOL SFileOpenArchiveEx( if(hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); SetLastError(nError); + ha = NULL; } else { @@ -472,25 +492,51 @@ BOOL WINAPI SFileOpenArchive(const char * szMpqName, DWORD dwPriority, DWORD dwF } //----------------------------------------------------------------------------- -// BOOL SFileCloseArchive(HANDLE hMPQ); +// BOOL SFileFlushArchive(HANDLE hMpq) +// +// Saves all dirty data into MPQ archive. +// Has similar effect like SFileCLoseArchive, but the archive is not closed. +// Use on clients who keep MPQ archive open even for write operations, +// and terminating without calling SFileCloseArchive might corrupt the archive. // -// TODO: Test for archives > 4GB -BOOL WINAPI SFileCloseArchive(HANDLE hMPQ) +BOOL WINAPI SFileFlushArchive(HANDLE hMpq) { - TMPQArchive * ha = (TMPQArchive *)hMPQ; + TMPQArchive * ha = (TMPQArchive *)hMpq; + // Do nothing if 'hMpq' is bad parameter if(!IsValidMpqHandle(ha)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } + // If the archive has been changed, update the changes + // on the disk drive. if(ha->dwFlags & MPQ_FLAG_CHANGED) { SListFileSaveToMpq(ha); + SAttrFileSaveToMpq(ha); SaveMPQTables(ha); + ha->dwFlags &= ~MPQ_FLAG_CHANGED; } + + return TRUE; +} + +//----------------------------------------------------------------------------- +// BOOL SFileCloseArchive(HANDLE hMPQ); +// + +BOOL WINAPI SFileCloseArchive(HANDLE hMPQ) +{ + TMPQArchive * ha = (TMPQArchive *)hMPQ; + + // Flush all unsaved data to the storage + if(!SFileFlushArchive(hMPQ)) + return FALSE; + + // Free all memory used by MPQ archive FreeMPQArchive(ha); return TRUE; } diff --git a/src/tools/stuffextract/StormLib/SFileOpenFileEx.cpp b/src/tools/stuffextract/StormLib/SFileOpenFileEx.cpp index 515b119..3317455 100644 --- a/src/tools/stuffextract/StormLib/SFileOpenFileEx.cpp +++ b/src/tools/stuffextract/StormLib/SFileOpenFileEx.cpp @@ -16,11 +16,10 @@ /* Local functions */ /*****************************************************************************/ -// TODO: Test for archives > 4GB static BOOL OpenLocalFile(const char * szFileName, HANDLE * phFile) { TMPQFile * hf = NULL; - HANDLE hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + HANDLE hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if(hFile != INVALID_HANDLE_VALUE) { @@ -41,8 +40,7 @@ static BOOL OpenLocalFile(const char * szFileName, HANDLE * phFile) return FALSE; } -// TODO: Test for archives > 4GB -static void FreeMPQFile(TMPQFile *& hf) +void FreeMPQFile(TMPQFile *& hf) { if(hf != NULL) { @@ -67,7 +65,6 @@ static void FreeMPQFile(TMPQFile *& hf) // pointed by plcLocales. There must be enough entries to copy the localed, // otherwise the function returns ERROR_INSUFFICIENT_BUFFER. -// TODO: Test for archives > 4GB int WINAPI SFileEnumLocales( HANDLE hMPQ, const char * szFileName, @@ -109,11 +106,8 @@ int WINAPI SFileEnumLocales( } else pHash = GetHashEntry(ha, szFileName); - } - // If the file was not found, sorry - if(nError == ERROR_SUCCESS) - { + // If the file was not found, sorry if(pHash == NULL) nError = ERROR_FILE_NOT_FOUND; } @@ -121,22 +115,40 @@ int WINAPI SFileEnumLocales( // Count the entries which correspond to the same file name if(nError == ERROR_SUCCESS) { + TMPQHash * pStartHash = pHash; TMPQHash * pSaveHash = pHash; DWORD dwName1 = pHash->dwName1; DWORD dwName2 = pHash->dwName2; + LCID PrevLocale = 0xFFFFFFFF; - // For nameless access, return 1 locale always - if(dwSearchScope == SFILE_OPEN_BY_INDEX) - dwLocales++; - else + if(dwSearchScope != SFILE_OPEN_BY_INDEX) { - while(pHash < pHashEnd && pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2) + while(pHash->dwBlockIndex != HASH_ENTRY_FREE) { - dwLocales++; - pHash++; + if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && pHash->dwBlockIndex != HASH_ENTRY_DELETED) + { + // If the locale is different from previous one, count it. + if(pHash->lcLocale != PrevLocale) + { + PrevLocale = pHash->lcLocale; + dwLocales++; + } + } + + // Move to the next hash + if(++pHash >= pHashEnd) + pHash = ha->pHashTable; + if(pHash == pStartHash) + break; } } + else + { + // For nameless access, return 1 locale always + dwLocales++; + } + // Restore the has pointer pHash = pSaveHash; } @@ -150,11 +162,40 @@ int WINAPI SFileEnumLocales( nError = ERROR_INSUFFICIENT_BUFFER; } - // Fill all the locales + // Fill all present locales if(nError == ERROR_SUCCESS) { - for(DWORD i = 0; i < dwLocales; i++, pHash++) + TMPQHash * pStartHash = pHash; + DWORD dwName1 = pHash->dwName1; + DWORD dwName2 = pHash->dwName2; + LCID PrevLocale = 0xFFFFFFFF; + + if(dwSearchScope != SFILE_OPEN_BY_INDEX) + { + while(pHash->dwBlockIndex != HASH_ENTRY_FREE) + { + if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && pHash->dwBlockIndex != HASH_ENTRY_DELETED) + { + // If the locale is different from previous one, count it. + if(pHash->lcLocale != PrevLocale) + { + *plcLocales++ = (LCID)pHash->lcLocale; + PrevLocale = pHash->lcLocale; + } + } + + // Move to the next hash + if(++pHash >= pHashEnd) + pHash = ha->pHashTable; + if(pHash == pStartHash) + break; + } + } + else + { + // For nameless access, return 1 locale always *plcLocales++ = (LCID)pHash->lcLocale; + } } return nError; } @@ -165,7 +206,6 @@ int WINAPI SFileEnumLocales( // hMPQ - Handle of opened MPQ archive // szFileName - Name of file to look for -// TODO: Test for archives > 4GB BOOL WINAPI SFileHasFile(HANDLE hMPQ, const char * szFileName) { TMPQArchive * ha = (TMPQArchive *)hMPQ; @@ -206,7 +246,6 @@ BOOL WINAPI SFileHasFile(HANDLE hMPQ, const char * szFileName) // dwSearchScope - Where to search // phFile - Pointer to store opened file handle -// TODO: Test for archives > 4GB BOOL WINAPI SFileOpenFileEx(HANDLE hMPQ, const char * szFileName, DWORD dwSearchScope, HANDLE * phFile) { LARGE_INTEGER FilePos; @@ -282,7 +321,8 @@ BOOL WINAPI SFileOpenFileEx(HANDLE hMPQ, const char * szFileName, DWORD dwSearch if(nError == ERROR_SUCCESS) { // If index was not found, or is greater than number of files, exit. - if(dwBlockIndex == (DWORD)-1 || dwBlockIndex > ha->pHeader->dwBlockTableSize) + // This also covers the deleted files and free entries + if(dwBlockIndex > ha->pHeader->dwBlockTableSize) nError = ERROR_FILE_NOT_FOUND; } @@ -323,11 +363,11 @@ BOOL WINAPI SFileOpenFileEx(HANDLE hMPQ, const char * szFileName, DWORD dwSearch hf->pHash = pHash; hf->MpqFilePos.HighPart = pBlockEx->wFilePosHigh; - hf->MpqFilePos.LowPart = pBlock->dwFilePos; - hf->MpqFilePos.QuadPart += ha->MpqPos.QuadPart; + hf->MpqFilePos.LowPart = pBlock->dwFilePos; + hf->RawFilePos.QuadPart = hf->MpqFilePos.QuadPart + ha->MpqPos.QuadPart; - hf->dwHashIndex = dwHashIndex; - hf->dwFileIndex = dwBlockIndex; + hf->dwHashIndex = dwHashIndex; + hf->dwBlockIndex = dwBlockIndex; // Allocate buffers for decompression. if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESSED) @@ -352,8 +392,8 @@ BOOL WINAPI SFileOpenFileEx(HANDLE hMPQ, const char * szFileName, DWORD dwSearch strcpy(hf->szFileName, szFileName); if(szTemp != NULL) szFileName = szTemp + 1; - hf->dwSeed1 = DecryptFileSeed((char *)szFileName); + hf->dwSeed1 = DecryptFileSeed((char *)szFileName); if(hf->pBlock->dwFlags & MPQ_FILE_FIXSEED) { hf->dwSeed1 = (hf->dwSeed1 + hf->pBlock->dwFilePos) ^ hf->pBlock->dwFSize; @@ -368,6 +408,17 @@ BOOL WINAPI SFileOpenFileEx(HANDLE hMPQ, const char * szFileName, DWORD dwSearch } } + // Resolve pointers to file's attributes + if(nError == ERROR_SUCCESS && ha->pAttributes != NULL) + { + if(ha->pAttributes->pCrc32 != NULL) + hf->pCrc32 = ha->pAttributes->pCrc32 + dwBlockIndex; + if(ha->pAttributes->pFileTime != NULL) + hf->pFileTime = ha->pAttributes->pFileTime + dwBlockIndex; + if(ha->pAttributes->pMd5 != NULL) + hf->pMd5 = ha->pAttributes->pMd5 + dwBlockIndex; + } + // Cleanup if(nError != ERROR_SUCCESS) { @@ -380,9 +431,8 @@ BOOL WINAPI SFileOpenFileEx(HANDLE hMPQ, const char * szFileName, DWORD dwSearch } //----------------------------------------------------------------------------- -// BOOL SFileCloseFile(HANDLE hFile); +// BOOL WINAPI SFileCloseFile(HANDLE hFile); -// TODO: Test for archives > 4GB BOOL WINAPI SFileCloseFile(HANDLE hFile) { TMPQFile * hf = (TMPQFile *)hFile; diff --git a/src/tools/stuffextract/StormLib/SFileReadFile.cpp b/src/tools/stuffextract/StormLib/SFileReadFile.cpp index 6363bbd..4d95400 100644 --- a/src/tools/stuffextract/StormLib/SFileReadFile.cpp +++ b/src/tools/stuffextract/StormLib/SFileReadFile.cpp @@ -25,7 +25,7 @@ struct TID2Ext { DWORD dwID; - const char * szExt; + char * szExt; }; //----------------------------------------------------------------------------- @@ -38,7 +38,6 @@ struct TID2Ext // // Returns number of bytes read. -// TODO: Test for archives > 4GB static DWORD WINAPI ReadMPQBlocks(TMPQFile * hf, DWORD dwBlockPos, BYTE * buffer, DWORD blockBytes) { LARGE_INTEGER FilePos; @@ -70,10 +69,7 @@ static DWORD WINAPI ReadMPQBlocks(TMPQFile * hf, DWORD dwBlockPos, BYTE * buffer if((hf->pBlock->dwFlags & MPQ_FILE_COMPRESSED) && hf->bBlockPosLoaded == FALSE) { // Move file pointer to the begin of the file in the MPQ - if(hf->MpqFilePos.QuadPart != ha->FilePointer.QuadPart) - { - SetFilePointer(ha->hFile, hf->MpqFilePos.LowPart, &hf->MpqFilePos.HighPart, FILE_BEGIN); - } + SetFilePointer(ha->hFile, hf->RawFilePos.LowPart, &hf->RawFilePos.HighPart, FILE_BEGIN); // Read block positions from begin of file. dwToRead = (hf->nBlocks+1) * sizeof(DWORD); @@ -109,13 +105,20 @@ static DWORD WINAPI ReadMPQBlocks(TMPQFile * hf, DWORD dwBlockPos, BYTE * buffer // Decrypt block positions DecryptMPQBlock(hf->pdwBlockPos, dwBytesRead, hf->dwSeed1 - 1); + // // Check if the block positions are correctly decrypted - // I don't know why, but sometimes it will result invalid block positions on some files - if(hf->pdwBlockPos[0] != dwBytesRead) + // Previous versions of StormLib (up to 6.20) had bug in SFileRenameFile. + // Incase the file name changed, Stormlib didn't re-crypt the file with changed seed, + // so the file remained corrupt after the name change. + // + // I saw a protector who puts negative offset into the block table. + // Because there are always at least 2 block positions, we can check their difference + // + + if((hf->pdwBlockPos[1] - hf->pdwBlockPos[0]) > ha->dwBlockSize) { // Try once again to detect file seed and decrypt the blocks - // TODO: Test with >4GB - SetFilePointer(ha->hFile, hf->MpqFilePos.LowPart, &hf->MpqFilePos.HighPart, FILE_BEGIN); + SetFilePointer(ha->hFile, hf->RawFilePos.LowPart, &hf->RawFilePos.HighPart, FILE_BEGIN); ReadFile(ha->hFile, hf->pdwBlockPos, dwToRead, &dwBytesRead, NULL); BSWAP_ARRAY32_UNSIGNED(hf->pdwBlockPos, (hf->nBlocks+1)); @@ -129,7 +132,6 @@ static DWORD WINAPI ReadMPQBlocks(TMPQFile * hf, DWORD dwBlockPos, BYTE * buffer } // Update hf's variables - ha->FilePointer.QuadPart = hf->MpqFilePos.QuadPart + dwBytesRead; hf->bBlockPosLoaded = TRUE; } @@ -141,7 +143,12 @@ static DWORD WINAPI ReadMPQBlocks(TMPQFile * hf, DWORD dwBlockPos, BYTE * buffer dwFilePos = hf->pdwBlockPos[blockNum]; dwToRead = hf->pdwBlockPos[blockNum + nBlocks] - dwFilePos; } - FilePos.QuadPart = hf->MpqFilePos.QuadPart + dwFilePos; + + // Warning: dwFilePos, obtained from the block table, might be negative. + // Incase of format V1, we have to ignore the overflow. + FilePos.QuadPart = hf->RawFilePos.QuadPart + dwFilePos; + if((dwFilePos & 0x80000000) && ha->Header.wFormatVersion == MPQ_FORMAT_VERSION_1) + FilePos.HighPart = 0; // Get work buffer for store read data tempBuffer = buffer; @@ -154,22 +161,16 @@ static DWORD WINAPI ReadMPQBlocks(TMPQFile * hf, DWORD dwBlockPos, BYTE * buffer } } - // Set file pointer, if necessary - if(ha->FilePointer.QuadPart != FilePos.QuadPart) - { - SetFilePointer(ha->hFile, FilePos.LowPart, &FilePos.HighPart, FILE_BEGIN); - } - - // 15018F87 : Read all requested blocks + // Set file pointer, if necessary and read all required blocks + SetFilePointer(ha->hFile, FilePos.LowPart, &FilePos.HighPart, FILE_BEGIN); ReadFile(ha->hFile, tempBuffer, dwToRead, &dwBytesRead, NULL); - ha->FilePointer.QuadPart = FilePos.QuadPart + dwBytesRead; // Block processing part. DWORD blockStart = 0; // Index of block start in work buffer - DWORD blockSize = min(blockBytes, ha->dwBlockSize); + DWORD blockSize = STORMLIB_MIN(blockBytes, ha->dwBlockSize); DWORD index = blockNum; // Current block index - dwBytesRead = 0; // Clear read byte counter + dwBytesRead = 0; // Clear read byte counter // Walk through all blocks for(i = 0; i < nBlocks; i++, index++) @@ -198,7 +199,10 @@ static DWORD WINAPI ReadMPQBlocks(TMPQFile * hf, DWORD dwBlockPos, BYTE * buffer hf->dwSeed1 = DetectFileSeed2((DWORD *)inputBuffer, 2, 0x00905A4D, 0x00000003); if(hf->dwSeed1 == 0) - return 0; + { + dwBytesRead = 0; + break; + } DecryptMPQBlock((DWORD *)inputBuffer, blockSize, hf->dwSeed1 + index); BSWAP_ARRAY32_UNSIGNED((DWORD *)inputBuffer, blockSize / sizeof(DWORD)); @@ -210,14 +214,21 @@ static DWORD WINAPI ReadMPQBlocks(TMPQFile * hf, DWORD dwBlockPos, BYTE * buffer if(blockSize < (DWORD)outLength) { // Is the file compressed with PKWARE Data Compression Library ? - if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESS_PKWARE) + if(hf->pBlock->dwFlags & MPQ_FILE_IMPLODE) Decompress_pklib((char *)buffer, &outLength, (char *)inputBuffer, (int)blockSize); // Is it a file compressed by Blizzard's multiple compression ? // Note that Storm.dll v 1.0.9 distributed with Warcraft III // passes the full path name of the opened archive as the new last parameter - if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESS_MULTI) - SCompDecompress((char *)buffer, &outLength, (char *)inputBuffer, (int)blockSize); + if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESS) + { + if(!SCompDecompress((char *)buffer, &outLength, (char *)inputBuffer, (int)blockSize)) + { + dwBytesRead = 0; + break; + } + } + dwBytesRead += outLength; buffer += outLength; } @@ -242,18 +253,11 @@ static DWORD WINAPI ReadMPQBlocks(TMPQFile * hf, DWORD dwBlockPos, BYTE * buffer // When this function is called, it is already ensured that the parameters are valid // (e.g. the "dwToRead + dwFilePos" is not greater than the file size) -// TODO: Test for archives > 4GB static DWORD WINAPI ReadMPQFileSingleUnit(TMPQFile * hf, DWORD dwFilePos, BYTE * pbBuffer, DWORD dwToRead) { TMPQArchive * ha = hf->ha; DWORD dwBytesRead = 0; - if(ha->FilePointer.QuadPart != hf->MpqFilePos.QuadPart) - { - SetFilePointer(ha->hFile, hf->MpqFilePos.LowPart, &hf->MpqFilePos.HighPart, FILE_BEGIN); - ha->FilePointer = hf->MpqFilePos; - } - // If the file is really compressed, decompress it. // Otherwise, read the data as-is to the caller. if(hf->pBlock->dwCSize < hf->pBlock->dwFSize) @@ -264,51 +268,70 @@ static DWORD WINAPI ReadMPQFileSingleUnit(TMPQFile * hf, DWORD dwFilePos, BYTE * int outputBufferSize = (int)hf->pBlock->dwFSize; int inputBufferSize = (int)hf->pBlock->dwCSize; + // Allocate buffer in the hf hf->pbFileBuffer = ALLOCMEM(BYTE, outputBufferSize); + if(hf->pbFileBuffer == NULL) + return (DWORD)-1; + + // Allocate temporary buffer for reading the file inputBuffer = ALLOCMEM(BYTE, inputBufferSize); - if(inputBuffer != NULL && hf->pbFileBuffer != NULL) + if(inputBuffer != NULL) { + // Move file pointer to the begin of the file, move to inner, modified by PeakGao,2008.10.28 + SetFilePointer(ha->hFile, hf->RawFilePos.LowPart, &hf->RawFilePos.HighPart, FILE_BEGIN); + // Read the compressed file data ReadFile(ha->hFile, inputBuffer, inputBufferSize, &dwBytesRead, NULL); // Is the file compressed with PKWARE Data Compression Library ? - if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESS_PKWARE) + if(hf->pBlock->dwFlags & MPQ_FILE_IMPLODE) Decompress_pklib((char *)hf->pbFileBuffer, &outputBufferSize, (char *)inputBuffer, (int)inputBufferSize); // Is it a file compressed by Blizzard's multiple compression ? // Note that Storm.dll v 1.0.9 distributed with Warcraft III // passes the full path name of the opened archive as the new last parameter - if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESS_MULTI) + if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESS) SCompDecompress((char *)hf->pbFileBuffer, &outputBufferSize, (char *)inputBuffer, (int)inputBufferSize); - } - // Free the temporary buffer - if(inputBuffer != NULL) + // Free the temporary input buffer FREEMEM(inputBuffer); + + // If the decompression failed, don't continue + if(outputBufferSize == 0) + { + FREEMEM(hf->pbFileBuffer); + hf->pbFileBuffer = NULL; + return (DWORD)-1; + } + } } // Copy the file data, if any there if(hf->pbFileBuffer != NULL) { memcpy(pbBuffer, hf->pbFileBuffer + dwFilePos, dwToRead); - dwBytesRead += dwToRead; + dwBytesRead = dwToRead; } } else { + LARGE_INTEGER RawFilePos = hf->RawFilePos; + + // Move file pointer to the dwFilePos of the file, added by PeakGao, 2008.10.28 + RawFilePos.QuadPart += dwFilePos; + SetFilePointer(ha->hFile, RawFilePos.LowPart, &RawFilePos.HighPart, FILE_BEGIN); + // Read the uncompressed file data ReadFile(ha->hFile, pbBuffer, dwToRead, &dwBytesRead, NULL); - dwBytesRead = (int)dwBytesRead; } - return (DWORD)dwBytesRead; + return dwBytesRead; } //----------------------------------------------------------------------------- // ReadMPQFile -// TODO: Test for archives > 4GB static DWORD WINAPI ReadMPQFile(TMPQFile * hf, DWORD dwFilePos, BYTE * pbBuffer, DWORD dwToRead) { TMPQArchive * ha = hf->ha; @@ -427,7 +450,6 @@ static DWORD WINAPI ReadMPQFile(TMPQFile * hf, DWORD dwFilePos, BYTE * pbBuffer, //----------------------------------------------------------------------------- // SFileReadFile -// TODO: Test for archives > 4GB BOOL WINAPI SFileReadFile(HANDLE hFile, VOID * lpBuffer, DWORD dwToRead, DWORD * pdwRead, LPOVERLAPPED lpOverlapped) { TMPQFile * hf = (TMPQFile *)hFile; @@ -494,7 +516,6 @@ BOOL WINAPI SFileReadFile(HANDLE hFile, VOID * lpBuffer, DWORD dwToRead, DWORD * // // Returns position of archive file in the archive (relative to begin of file) -// TODO: Test for archives > 4GB DWORD WINAPI SFileGetFilePos(HANDLE hFile, DWORD * pdwFilePosHigh) { TMPQFile * hf = (TMPQFile *)hFile; @@ -514,14 +535,13 @@ DWORD WINAPI SFileGetFilePos(HANDLE hFile, DWORD * pdwFilePosHigh) // If opened from archive, return file size if(pdwFilePosHigh != NULL) - *pdwFilePosHigh = hf->MpqFilePos.HighPart; - return hf->MpqFilePos.LowPart; + *pdwFilePosHigh = hf->RawFilePos.HighPart; + return hf->RawFilePos.LowPart; } //----------------------------------------------------------------------------- // SFileGetFileSize -// TODO: Test for archives > 4GB DWORD WINAPI SFileGetFileSize(HANDLE hFile, DWORD * pdwFileSizeHigh) { TMPQFile * hf = (TMPQFile *)hFile; @@ -543,7 +563,6 @@ DWORD WINAPI SFileGetFileSize(HANDLE hFile, DWORD * pdwFileSizeHigh) return hf->pBlock->dwFSize; } -// TODO: Test for archives > 4GB DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * pdwFilePosHigh, DWORD dwMethod) { TMPQArchive * ha; @@ -623,14 +642,14 @@ static TID2Ext id2ext[] = {0x3032444D, "m2"}, // WoW ??? .m2 {0x43424457, "dbc"}, // ??? .dbc {0x47585053, "bls"}, // WoW pixel shaders + {0xE0FFD8FF, "jpg"}, // JPEG image {0, NULL} // Terminator }; -// TODO: Test for archives > 4GB BOOL WINAPI SFileGetFileName(HANDLE hFile, char * szFileName) { TMPQFile * hf = (TMPQFile *)hFile; // MPQ File handle - const char * szExt = "xxx"; // Default extension + char * szExt = "xxx"; // Default extension DWORD dwFirstBytes[2]; // The first 4 bytes of the file DWORD dwFilePos; // Saved file position int nError = ERROR_SUCCESS; @@ -657,7 +676,7 @@ BOOL WINAPI SFileGetFileName(HANDLE hFile, char * szFileName) if(nError == ERROR_SUCCESS) { - if(hf->dwFileIndex == (DWORD)-1) + if(hf->dwBlockIndex == (DWORD)-1) nError = ERROR_CAN_NOT_COMPLETE; } @@ -666,8 +685,7 @@ BOOL WINAPI SFileGetFileName(HANDLE hFile, char * szFileName) { dwFirstBytes[0] = dwFirstBytes[1] = 0; dwFilePos = SFileSetFilePointer(hf, 0, NULL, FILE_CURRENT); - if(!SFileReadFile(hFile, &dwFirstBytes, sizeof(dwFirstBytes), NULL)) - nError = GetLastError(); + SFileReadFile(hFile, &dwFirstBytes, sizeof(dwFirstBytes), NULL); BSWAP_ARRAY32_UNSIGNED(dwFirstBytes, sizeof(dwFirstBytes) / sizeof(DWORD)); SFileSetFilePointer(hf, dwFilePos, NULL, FILE_BEGIN); } @@ -691,7 +709,7 @@ BOOL WINAPI SFileGetFileName(HANDLE hFile, char * szFileName) } // Create the file name - sprintf(hf->szFileName, "File%08lu.%s", hf->dwFileIndex, szExt); + sprintf(hf->szFileName, "File%08lu.%s", hf->dwBlockIndex, szExt); if(szFileName != hf->szFileName) strcpy(szFileName, hf->szFileName); } @@ -704,7 +722,6 @@ BOOL WINAPI SFileGetFileName(HANDLE hFile, char * szFileName) // hMpqOrFile - Handle to an MPQ archive or to a file // dwInfoType - Information to obtain -// TODO: Test for archives > 4GB DWORD_PTR WINAPI SFileGetFileInfo(HANDLE hMpqOrFile, DWORD dwInfoType) { TMPQArchive * ha = (TMPQArchive *)hMpqOrFile; @@ -781,7 +798,7 @@ DWORD_PTR WINAPI SFileGetFileInfo(HANDLE hMpqOrFile, DWORD dwInfoType) case SFILE_INFO_BLOCKINDEX: if(IsValidFileHandle(hf)) - return hf->dwFileIndex; + return hf->dwBlockIndex; break; case SFILE_INFO_FILE_SIZE: @@ -814,7 +831,7 @@ DWORD_PTR WINAPI SFileGetFileInfo(HANDLE hMpqOrFile, DWORD dwInfoType) { dwSeed = hf->dwSeed1; if(hf->pBlock->dwFlags & MPQ_FILE_FIXSEED) - dwSeed = (dwSeed ^ hf->pBlock->dwFSize) - (DWORD)(hf->MpqFilePos.QuadPart - hf->ha->MpqPos.QuadPart); + dwSeed = (dwSeed ^ hf->pBlock->dwFSize) - hf->MpqFilePos.LowPart; return dwSeed; } break; diff --git a/src/tools/stuffextract/StormLib/SListFile.cpp b/src/tools/stuffextract/StormLib/SListFile.cpp index c3723d1..40e331e 100644 --- a/src/tools/stuffextract/StormLib/SListFile.cpp +++ b/src/tools/stuffextract/StormLib/SListFile.cpp @@ -20,10 +20,6 @@ #define NO_MORE_CHARACTERS 256 #define HASH_TABLE_SIZE 31 // Initial hash table size (should be a prime number) -// TODO: Check on x64 !!! -#define LISTFILE_ENTRY_DELETED (DWORD_PTR)(-2) -#define LISTFILE_ENTRY_FREE (DWORD_PTR)(-1) - struct TListFileCache { HANDLE hFile; // Stormlib file handle @@ -133,9 +129,10 @@ int SListFileCreateListFile(TMPQArchive * ha) return ERROR_SUCCESS; } -// Adds a filename into the listfile. If the file name is already there, -// does nothing. -int SListFileAddNode(TMPQArchive * ha, const char * szFileName) +// Adds a name into the list of all names. For each locale in the MPQ, +// one entry will be created +// If the file name is already there, does nothing. +int SListFileCreateNodeForAllLocales(TMPQArchive * ha, const char * szFileName) { TFileNode * pNode = NULL; TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize; @@ -150,44 +147,107 @@ int SListFileAddNode(TMPQArchive * ha, const char * szFileName) if(pHash == NULL) return ERROR_SUCCESS; - // If the listfile entry already exists, do nothing - dwHashIndex = (DWORD)(pHash - ha->pHashTable); - dwName1 = pHash->dwName1; - dwName2 = pHash->dwName2; - if((DWORD_PTR)ha->pListFile[dwHashIndex] <= LISTFILE_ENTRY_DELETED) - return ERROR_SUCCESS; - - // Create the listfile node and insert it into the listfile table - nLength = strlen(szFileName); - pNode = (TFileNode *)ALLOCMEM(char, sizeof(TFileNode) + nLength); - pNode->dwRefCount = 0; - pNode->nLength = nLength; - strcpy(pNode->szFileName, szFileName); + // Remember the name + dwName1 = pHash->dwName1; + dwName2 = pHash->dwName2; - // Fill the nodes for all language versions - while(pHash->dwBlockIndex < LISTFILE_ENTRY_DELETED) + // Pass all entries in the hash table + while(pHash->dwBlockIndex != HASH_ENTRY_FREE) { - if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2) + // There may be an entry deleted amongst various language versions + if(pHash->dwBlockIndex != HASH_ENTRY_DELETED) { - pNode->dwRefCount++; - ha->pListFile[pHash - ha->pHashTable] = pNode; + if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2) + { + // Compute the hash index + dwHashIndex = (DWORD)(pHash - ha->pHashTable); + + // Create the lang version, if none + if((DWORD_PTR)ha->pListFile[dwHashIndex] >= LISTFILE_ENTRY_DELETED) + { + // Create the listfile node, if doesn't exist yet + if(pNode == NULL) + { + nLength = strlen(szFileName); + pNode = (TFileNode *)ALLOCMEM(char, sizeof(TFileNode) + nLength); + pNode->dwRefCount = 0; + pNode->nLength = nLength; + strcpy(pNode->szFileName, szFileName); + } + + // Insert the node to the listfile table + ha->pListFile[dwHashIndex] = pNode; + pNode->dwRefCount++; + } + } + } + else + { + dwHashIndex = (DWORD)(pHash - ha->pHashTable); + ha->pListFile[dwHashIndex] = (TFileNode *)LISTFILE_ENTRY_DELETED; } + // Move to the next hash entry if(++pHash >= pHashEnd) pHash = ha->pHashTable; if(pHash == pHash0) break; } + return ERROR_SUCCESS; +} + +// Adds a filename into the listfile. If the file name is already there, +// does nothing. +int SListFileCreateNode(TMPQArchive * ha, const char * szFileName, LCID lcLocale) +{ + TFileNode * pNode = NULL; + TMPQHash * pHash0 = GetHashEntry(ha, szFileName); + TMPQHash * pHash1 = GetHashEntryEx(ha, szFileName, lcLocale); + DWORD dwHashIndex0 = 0; + DWORD dwHashIndex1 = 0; + size_t nLength; // File name lentgth + + // If the file does not exist within the MPQ, do nothing + if(pHash1 == NULL || pHash1->dwBlockIndex >= HASH_ENTRY_DELETED) + return ERROR_SUCCESS; + + // If the locale-cpecific listfile entry already exists, do nothing + dwHashIndex0 = (DWORD)(pHash0 - ha->pHashTable); + dwHashIndex1 = (DWORD)(pHash1 - ha->pHashTable); + if((DWORD_PTR)ha->pListFile[dwHashIndex1] < LISTFILE_ENTRY_DELETED) + return ERROR_SUCCESS; + + // Does the neutral table entry exist ? + if((DWORD_PTR)ha->pListFile[dwHashIndex0] < LISTFILE_ENTRY_DELETED) + pNode = ha->pListFile[dwHashIndex0]; + + // If no node yet, we have to create new one + if(pNode == NULL) + { + nLength = strlen(szFileName); + pNode = (TFileNode *)ALLOCMEM(char, sizeof(TFileNode) + nLength); + pNode->dwRefCount = 1; + pNode->nLength = nLength; + strcpy(pNode->szFileName, szFileName); + ha->pListFile[dwHashIndex0] = pNode; + } + + // Also insert the node in the locale-specific entry + if(dwHashIndex1 != dwHashIndex0) + { + pNode->dwRefCount++; + ha->pListFile[dwHashIndex1] = pNode; + } return ERROR_SUCCESS; } // Removes a filename from the listfile. // If the name is not there, does nothing -int SListFileRemoveNode(TMPQArchive * ha, const char * szFileName) +int SListFileRemoveNode(TMPQArchive * ha, const char * szFileName, LCID lcLocale) { TFileNode * pNode = NULL; - TMPQHash * pHash = GetHashEntry(ha, szFileName); + TMPQHash * pHash = GetHashEntryEx(ha, szFileName, lcLocale); size_t nHashIndex = 0; if(pHash != NULL) @@ -196,25 +256,15 @@ int SListFileRemoveNode(TMPQArchive * ha, const char * szFileName) pNode = ha->pListFile[nHashIndex]; ha->pListFile[nHashIndex] = (TFileNode *)LISTFILE_ENTRY_DELETED; - // If the reference count has reached zero, do nothing - if(--pNode->dwRefCount == 0) + // Free the node + pNode->dwRefCount--; + if(pNode->dwRefCount == 0) FREEMEM(pNode); } return ERROR_SUCCESS; } - -// Renames a node. We will not deal with the renaming, we'll simply -// remove the old node and insert the new one. -// TODO: Test for archives > 4GB -int SListFileRenameNode(TMPQArchive * ha, const char * szOldFileName, const char * szNewFileName) -{ - SListFileRemoveNode(ha, szOldFileName); - return SListFileAddNode(ha, szNewFileName); -} - -// TODO: Test for archives > 4GB -int SListFileFreeListFile(TMPQArchive * ha) +void SListFileFreeListFile(TMPQArchive * ha) { if(ha->pListFile != NULL) { @@ -222,25 +272,22 @@ int SListFileFreeListFile(TMPQArchive * ha) { TFileNode * pNode = ha->pListFile[i]; - if((DWORD_PTR)pNode < LISTFILE_ENTRY_FREE) + if((DWORD_PTR)pNode < LISTFILE_ENTRY_DELETED) { - if(--pNode->dwRefCount == 0) - { + ha->pListFile[i] = (TFileNode *)LISTFILE_ENTRY_FREE; + pNode->dwRefCount--; + + if(pNode->dwRefCount == 0) FREEMEM(pNode); - ha->pListFile[i] = (TFileNode *)LISTFILE_ENTRY_FREE; - } } } FREEMEM(ha->pListFile); ha->pListFile = NULL; } - - return ERROR_SUCCESS; } // Saves the whole listfile into the MPQ. -// TODO: Test for archives > 4GB int SListFileSaveToMpq(TMPQArchive * ha) { TFileNode * pNode = NULL; @@ -265,7 +312,7 @@ int SListFileSaveToMpq(TMPQArchive * ha) if(nError == ERROR_SUCCESS) { GetListFileName(ha, szListFile); - hFile = CreateFile(szListFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); + hFile = CreateFile(szListFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); if(hFile == INVALID_HANDLE_VALUE) nError = GetLastError(); } @@ -281,7 +328,7 @@ int SListFileSaveToMpq(TMPQArchive * ha) { for(;;) { - if(pHash->dwName1 != dwName1 && pHash->dwName2 != dwName2 && pHash->dwBlockIndex < LISTFILE_ENTRY_DELETED) + if(pHash->dwName1 != dwName1 && pHash->dwName2 != dwName2 && pHash->dwBlockIndex < HASH_ENTRY_DELETED) { dwName1 = pHash->dwName1; dwName2 = pHash->dwName2; @@ -314,14 +361,22 @@ int SListFileSaveToMpq(TMPQArchive * ha) // Add the listfile into the archive. SFileSetLocale(LANG_NEUTRAL); - nError = AddFileToArchive(ha, hFile, LISTFILE_NAME, MPQ_FILE_COMPRESS_PKWARE | MPQ_FILE_ENCRYPTED | MPQ_FILE_REPLACEEXISTING, 0, SFILE_TYPE_DATA, NULL); + nError = AddFileToArchive(ha, + hFile, + LISTFILE_NAME, + MPQ_FILE_ENCRYPTED | MPQ_FILE_COMPRESS | MPQ_FILE_REPLACEEXISTING, + 0, + SFILE_TYPE_DATA, + NULL); + lcLocale = lcSave; } - // Close the temporary file. This will delete it too. + // Close the temporary file and delete it. + // There is no FILE_FLAG_DELETE_ON_CLOSE on LINUX. if(hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); + DeleteFile(szListFile); - lcLocale = lcSave; return nError; } @@ -330,7 +385,6 @@ int SListFileSaveToMpq(TMPQArchive * ha) // Adds a listfile into the MPQ archive. // Note that the function does not remove the -// TODO: Test for archives > 4GB int WINAPI SFileAddListFile(HANDLE hMpq, const char * szListFile) { TListFileCache * pCache = NULL; @@ -392,15 +446,15 @@ int WINAPI SFileAddListFile(HANDLE hMpq, const char * szListFile) pCache->pPos = &pCache->Buffer[0]; pCache->pEnd = pCache->pBegin + pCache->dwBuffSize; - // Load the node tree + // Load the node list. Add the node for every locale in the archive while((nLength = ReadLine(pCache, szFileName, sizeof(szFileName) - 1)) > 0) - SListFileAddNode(ha, szFileName); + SListFileCreateNodeForAllLocales(ha, szFileName); - // Add well-known names - // Sometimes, they are not in listfile, but they exist in the archive - SListFileAddNode(ha, LISTFILE_NAME); - SListFileAddNode(ha, SIGNATURE_NAME); - SListFileAddNode(ha, ATTRIBUTES_NAME); + // Also, add three special files to the listfile: + // (listfile) itself, (attributes) and (signature) + SListFileCreateNodeForAllLocales(ha, LISTFILE_NAME); + SListFileCreateNodeForAllLocales(ha, SIGNATURE_NAME); + SListFileCreateNodeForAllLocales(ha, ATTRIBUTES_NAME); } // Cleanup & exit @@ -412,7 +466,6 @@ int WINAPI SFileAddListFile(HANDLE hMpq, const char * szListFile) //----------------------------------------------------------------------------- // Passing through the listfile -// TODO: Test for archives > 4GB HANDLE SListFileFindFirstFile(HANDLE hMpq, const char * szListFile, const char * szMask, SFILE_FIND_DATA * lpFindFileData) { TListFileCache * pCache = NULL; @@ -509,7 +562,6 @@ HANDLE SListFileFindFirstFile(HANDLE hMpq, const char * szListFile, const char * return (HANDLE)pCache; } -// TODO: Test for archives > 4GB BOOL SListFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData) { TListFileCache * pCache = (TListFileCache *)hFind; @@ -540,7 +592,6 @@ BOOL SListFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData) return bResult; } -// TODO: Test for archives > 4GB BOOL SListFileFindClose(HANDLE hFind) { TListFileCache * pCache = (TListFileCache *)hFind; diff --git a/src/tools/stuffextract/StormLib/StormLib.h b/src/tools/stuffextract/StormLib/StormLib.h index 47c1858..0a70288 100644 --- a/src/tools/stuffextract/StormLib/StormLib.h +++ b/src/tools/stuffextract/StormLib/StormLib.h @@ -43,6 +43,18 @@ /* 15.05.06 5.02 Lad Fixed issue with WoW 1.10+ */ /* 07.09.06 5.10 Lad Fixed processing files longer than 2GB */ /* 22.11.06 6.00 Lad Support for MPQ archives V2 */ +/* 12.06.07 6.10 Lad Support for extended file attributes */ +/* 10.09.07 6.12 Lad Support for MPQs protected by corrupting hash table */ +/* 03.12.07 6.13 Lad Support for MPQs with hash tbl size > block tbl size */ +/* 07.04.08 6.20 Lad Added SFileFlushArchive */ +/* 09.04.08 Lad Removed FilePointer variable from TMPQArchive, as */ +/* it caused more problems than benefits */ +/* 12.05.08 6.22 Lad Support for w3xMaster map protector */ +/* 05.10.08 6.23 Lad Support for protectors who set negative values in */ +/* the table of file blocks */ +/* 26.05.09 6.24 Lad Fixed search for multiple lang files with deleted */ +/* entries */ +/* 03.09.09 6.25 Lad Fixed decompression bug in huffmann decompression */ /*****************************************************************************/ #ifndef __STORMLIB_H_ @@ -61,8 +73,6 @@ // Z - S for static C library, D for multithreaded DLL C-library // -#define __STORMLIB_SELF__ - #if defined(_MSC_VER) && !defined (__STORMLIB_SELF__) #ifdef _DEBUG // DEBUG VERSIONS #ifdef _DLL @@ -88,7 +98,7 @@ #define ERROR_AVI_FILE 10000 // No MPQ file, but AVI file. // Values for SFileCreateArchiveEx -#define HASH_TABLE_SIZE_MIN 0x00002 +#define HASH_TABLE_SIZE_MIN 0x00004 #define HASH_TABLE_SIZE_MAX 0x40000 #define HASH_ENTRY_DELETED 0xFFFFFFFE // Block index for deleted hash entry @@ -108,8 +118,10 @@ #define MPQ_FLAG_PROTECTED 0x00000002 // Set on protected MPQs (like W3M maps) // Flags for SFileAddFile -#define MPQ_FILE_COMPRESS_PKWARE 0x00000100 // Compression made by PKWARE Data Compression Library -#define MPQ_FILE_COMPRESS_MULTI 0x00000200 // Multiple compressions +// Note: MPQ_FILE_COMPRESS_PKWARE has been replaced by MPQ_FILE_IMPLODE +// Note: MPQ_FILE_COMPRESS_MULTI has been replaced by MPQ_FILE_COMPRESS +#define MPQ_FILE_IMPLODE 0x00000100 // Implode method (By PKWARE Data Compression Library) +#define MPQ_FILE_COMPRESS 0x00000200 // Compress methods (My various methods) #define MPQ_FILE_COMPRESSED 0x0000FF00 // File is compressed #define MPQ_FILE_ENCRYPTED 0x00010000 // Indicates whether file is encrypted #define MPQ_FILE_FIXSEED 0x00020000 // File decrypt seed has to be fixed @@ -120,13 +132,13 @@ #define MPQ_FILE_EXISTS 0x80000000 // Set if file exists, reset when the file was deleted #define MPQ_FILE_REPLACEEXISTING 0x80000000 // Replace when the file exist (SFileAddFile) -#define MPQ_FILE_VALID_FLAGS (MPQ_FILE_COMPRESS_PKWARE | \ - MPQ_FILE_COMPRESS_MULTI | \ - MPQ_FILE_ENCRYPTED | \ - MPQ_FILE_FIXSEED | \ - MPQ_FILE_SINGLE_UNIT | \ - MPQ_FILE_DUMMY_FILE | \ - MPQ_FILE_HAS_EXTRA | \ +#define MPQ_FILE_VALID_FLAGS (MPQ_FILE_IMPLODE | \ + MPQ_FILE_COMPRESS | \ + MPQ_FILE_ENCRYPTED | \ + MPQ_FILE_FIXSEED | \ + MPQ_FILE_SINGLE_UNIT | \ + MPQ_FILE_DUMMY_FILE | \ + MPQ_FILE_HAS_EXTRA | \ MPQ_FILE_EXISTS) // Compression types for multilpe compressions @@ -175,18 +187,29 @@ #define SIGNATURE_NAME "(signature)" // Name of internal signature #define ATTRIBUTES_NAME "(attributes)" // Name of internal attributes file -#define STORMLIB_VERSION (0x0600) // Current version of StormLib +#define STORMLIB_VERSION (0x0619) // Current version of StormLib #define MPQ_FORMAT_VERSION_1 0 // Up to The Burning Crusade -#define MPQ_FORMAT_VERSION_2 1 // The Burning Crusade and newer, +#define MPQ_FORMAT_VERSION_2 1 // The Burning Crusade and newer // Flags for SFileOpenArchiveEx #define MPQ_OPEN_NO_LISTFILE 0x00000001 // Don't add the internal listfile +#define MPQ_OPEN_NO_ATTRIBUTES 0x00000002 // Don't open the attributes +#define MPQ_OPEN_FORCE_MPQ_V1 0x00000004 // Always open the archive as MPQ v 1.00, ignore the "wFormatVersion" variable in the header -// supports archives with size > 4 GB +// Flags for MPQ attributes +#define MPQ_ATTRIBUTE_CRC32 0x00000001 // The "(attributes)" contain array of CRC32s +#define MPQ_ATTRIBUTE_FILETIME 0x00000002 // The "(attributes)" contain array of FILETIMEs +#define MPQ_ATTRIBUTE_MD5 0x00000004 // The "(attributes)" contain array of MD5s + +// Supports archives with size > 4 GB // Additional flags for SFileCreateArchiveEx #define MPQ_CREATE_ARCHIVE_V1 0x00000000 // Creates archive with size up to 4GB #define MPQ_CREATE_ARCHIVE_V2 0x00010000 // Creates archive larger than 4 GB +#define MPQ_CREATE_ATTRIBUTES 0x00100000 // Also add the (attributes) file + +// Formats of (attributes) file +#define MPQ_ATTRIBUTES_V1 100 // FOrmat version 1.00 //----------------------------------------------------------------------------- // Structures @@ -194,7 +217,7 @@ #if (defined(WIN32) || defined(WIN64)) #include #else -#pragma pack(1) +#pragma pack(push,1) #endif struct TMPQFile; @@ -273,7 +296,7 @@ struct TMPQHash // The hash of the file path, using method B. DWORD dwName2; -#ifdef PLATFORM_LITTLE_ENDIAN +#if PLATFORM_LITTLE_ENDIAN // The language of the file. This is a Windows LANGID data type, and uses the same values. // 0 indicates the default language (American English), or that the file is language-neutral. @@ -342,13 +365,47 @@ struct TFileNode char szFileName[1]; // File name, variable length }; + +// CRC32 present in the (attributes) file +struct TMPQCRC32 +{ + DWORD dwValue; // Value of CRC32 for each block +}; + + +// FILETIME present in the (attributes) file +struct TMPQFileTime +{ + DWORD dwFileTimeLow; // Low DWORD of the FILETIME + DWORD dwFileTimeHigh; // High DWORD of the FILETIME +}; + + +// MD5 presetn in the (attributes) file +struct TMPQMD5 +{ + BYTE Value[0x10]; // 16 bytes of MD5 +}; + + +// Data from (attributes) file +struct TMPQAttr +{ + DWORD dwVersion; // Version of the (attributes) file. Must be 100 (0x64) + DWORD dwFlags; // See MPQ_ATTRIBUTE_XXXX + TMPQCRC32 * pCrc32; // Array of CRC32 (NULL if none) + TMPQFileTime * pFileTime; // Array of FILETIME (NULL if not present) + TMPQMD5 * pMd5; // Array of MD5 (NULL if none) +}; + + #if (defined(WIN32) || defined(WIN64)) #include #else -#pragma options align=reset +#pragma pack(pop) #endif -// Archive handle structure. Note that it does not agree with Storm.dll's structure. +// Archive handle structure struct TMPQArchive { // TMPQArchive * pNext; // Next archive (used by Storm.dll only) @@ -356,13 +413,12 @@ struct TMPQArchive char szFileName[MAX_PATH]; // Opened archive file name HANDLE hFile; // File handle DWORD dwPriority; // Priority of the archive - LARGE_INTEGER ShuntPos; // Position of MPQShunt (only valid if a shunt is present) - LARGE_INTEGER MpqPos; // MPQ position in the file, relative to the begin of the file + LARGE_INTEGER ShuntPos; // MPQShunt offset (only valid if a shunt is present) + LARGE_INTEGER MpqPos; // File header offset (relative to the begin of the file) + LARGE_INTEGER HashTablePos; // Hash table offset (relative to the begin of the file) + LARGE_INTEGER BlockTablePos; // Block table offset (relative to the begin of the file) + LARGE_INTEGER ExtBlockTablePos; // Ext. block table offset (relative to the begin of the file) LARGE_INTEGER MpqSize; // Size of MPQ archive - LARGE_INTEGER HashTablePos; // Offset of the hast table in the MPQ, relative to the begin of the file - LARGE_INTEGER BlockTablePos; // Offset of the hast table in the MPQ, relative to the begin - LARGE_INTEGER ExtBlockTablePos; // Offset of the extended block table, relative to the begin - LARGE_INTEGER FilePointer; // Current position in the file (relative to begin of the file) TMPQFile * pLastFile; // Recently read file DWORD dwBlockPos; // Position of loaded block in the file @@ -378,44 +434,44 @@ struct TMPQArchive TMPQShunt Shunt; // MPQ shunt. Valid only when ID_MPQ_SHUNT has been found TMPQHeader2 Header; // MPQ header - // Non-Storm.dll members + TMPQAttr * pAttributes; // MPQ attributes from "(attributes)" file (NULL if none) TFileNode ** pListFile; // File name array -// HANDLE hListFile; // Handle to temporary listfile (when open with write access) DWORD dwFlags; // See MPQ_FLAG_XXXXX -// BOOL bChanged; // TRUE if the archive was changed since open. -// BOOL bProtected; // TRUE if the archive is protected by somehow }; -// File handle structure. Note that it does not agree with Storm.dll structures +// File handle structure struct TMPQFile { - HANDLE hFile; // File handle - TMPQArchive * ha; // Archive handle - TMPQHash * pHash; // Hash table entry - TMPQBlockEx * pBlockEx; // Pointer to extended file block entry - TMPQBlock * pBlock; // File block pointer - DWORD dwSeed1; // Seed used for file decrypt - DWORD dwFilePos; // Current file position - LARGE_INTEGER MpqFilePos; // Position of the file data in MPQ archive - // (relative to file begin) + HANDLE hFile; // File handle + TMPQArchive * ha; // Archive handle + TMPQHash * pHash; // Hash table entry + TMPQBlockEx * pBlockEx; // Pointer to extended file block entry + TMPQBlock * pBlock; // File block pointer + DWORD dwSeed1; // Seed used for file decrypt + DWORD dwFilePos; // Current file position + LARGE_INTEGER RawFilePos; // Offset in MPQ archive (relative to file begin) + LARGE_INTEGER MpqFilePos; // Offset in MPQ archive (relative to MPQ header) - DWORD * pdwBlockPos; // Position of each file block (only for compressed files) - DWORD nBlocks; // Number of blocks in the file (incl. the last noncomplete one) - BOOL bBlockPosLoaded; // TRUE if block positions loaded - BYTE * pbFileBuffer; // Decompressed file (for single unit files, size is the uncompressed file size) + DWORD * pdwBlockPos; // Position of each file block (only for compressed files) + DWORD nBlocks; // Number of blocks in the file (incl. the last incomplete one) + BOOL bBlockPosLoaded; // TRUE if block positions loaded + BYTE * pbFileBuffer; // Decompressed file (for single unit files, size is the uncompressed file size) - DWORD dwHashIndex; // Index to Hash table - DWORD dwFileIndex; // Index to Block table - char szFileName[1]; // File name (variable length) + TMPQCRC32 * pCrc32; // Pointer to CRC32 (NULL if none) + TMPQFileTime * pFileTime; // Pointer to file's FILETIME (NULL if none) + TMPQMD5 * pMd5; // Pointer to file's MD5 (NULL if none) + + DWORD dwHashIndex; // Index to Hash table + DWORD dwBlockIndex; // Index to Block table + char szFileName[1]; // File name (variable length) }; - // Used by searching in MPQ archives struct TMPQSearch { TMPQArchive * ha; // Handle to MPQ, where the search runs - DWORD dwNextIndex; // The next searched hash index + DWORD dwNextIndex; // Next hash index to be checked DWORD dwName1; // Lastly found Name1 DWORD dwName2; // Lastly found Name2 char szSearchMask[1]; // Search mask (variable length) @@ -457,7 +513,7 @@ __inline void * DebugMalloc(char * szFile, int nLine, int nSize) if(plain == NULL) plain = szFile; -#if _MSC_VER > 0x1300 +#if _MSC_VER > 1300 sprintf_s((char *)ptr, nSize+100, "%s(%u)", plain, nLine); #else sprintf((char *)ptr, "%s(%u)", plain, nLine); @@ -497,11 +553,12 @@ typedef BOOL (WINAPI * SFILEREADFILE)(HANDLE, VOID *, DWORD, DWORD *, LPOVERLAP // Archive opening/closing LCID WINAPI SFileSetLocale(LCID lcNewLocale); LCID WINAPI SFileGetLocale(); -BOOL WINAPI SFileOpenArchive(const char * szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE * phMPQ); -BOOL WINAPI SFileCloseArchive(HANDLE hMPQ); +BOOL WINAPI SFileOpenArchive(const char * szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE * phMpq); +BOOL WINAPI SFileFlushArchive(HANDLE hMpq); +BOOL WINAPI SFileCloseArchive(HANDLE hMpq); // File opening/closing -BOOL WINAPI SFileOpenFileEx(HANDLE hMPQ, const char * szFileName, DWORD dwSearchScope, HANDLE * phFile); +BOOL WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope, HANDLE * phFile); BOOL WINAPI SFileCloseFile(HANDLE hFile); // File I/O @@ -510,8 +567,6 @@ DWORD WINAPI SFileGetFileSize(HANDLE hFile, DWORD * pdwFileSizeHigh = NULL); DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * pdwFilePosHigh, DWORD dwMethod); BOOL WINAPI SFileReadFile(HANDLE hFile, VOID * lpBuffer, DWORD dwToRead, DWORD * pdwRead = NULL, LPOVERLAPPED lpOverlapped = NULL); -BOOL WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const char * szExtracted); - // Adds another listfile into MPQ. The currently added listfile(s) remain, // so you can use this API to combining more listfiles. // Note that this function is internally called by SFileFindFirstFile @@ -521,21 +576,21 @@ int WINAPI SFileAddListFile(HANDLE hMpq, const char * szListFile); // Functions in StormLib - not implemented in Storm.dll // Archive creating and editing -BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposition, DWORD dwHashTableSize, HANDLE * phMPQ); -BOOL WINAPI SFileAddFile(HANDLE hMPQ, const char * szFileName, const char * szArchivedName, DWORD dwFlags); -BOOL WINAPI SFileAddWave(HANDLE hMPQ, const char * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality); -BOOL WINAPI SFileRemoveFile(HANDLE hMPQ, const char * szFileName, DWORD dwSearchScope = SFILE_OPEN_BY_INDEX); -BOOL WINAPI SFileRenameFile(HANDLE hMPQ, const char * szOldFileName, const char * szNewFileName); +BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposition, DWORD dwHashTableSize, HANDLE * phMpq); +BOOL WINAPI SFileAddFile(HANDLE hMpq, const char * szFileName, const char * szArchivedName, DWORD dwFlags); +BOOL WINAPI SFileAddWave(HANDLE hMpq, const char * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality); +BOOL WINAPI SFileRemoveFile(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope = SFILE_OPEN_BY_INDEX); +BOOL WINAPI SFileRenameFile(HANDLE hMpq, const char * szOldFileName, const char * szNewFileName); BOOL WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale); // Retrieving info about the file -BOOL WINAPI SFileHasFile(HANDLE hMPQ, const char * szFileName); +BOOL WINAPI SFileHasFile(HANDLE hMpq, const char * szFileName); BOOL WINAPI SFileGetFileName(HANDLE hFile, char * szFileName); DWORD_PTR WINAPI SFileGetFileInfo(HANDLE hMpqOrFile, DWORD dwInfoType); // File search // Note that the SFileFindFirstFileEx has been removed. Use SListFileFindFirst/Next -HANDLE WINAPI SFileFindFirstFile(HANDLE hMPQ, const char * szMask, SFILE_FIND_DATA * lpFindFileData, const char * szListFile); +HANDLE WINAPI SFileFindFirstFile(HANDLE hMpq, const char * szMask, SFILE_FIND_DATA * lpFindFileData, const char * szListFile); BOOL WINAPI SFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData); BOOL WINAPI SFileFindClose(HANDLE hFind); @@ -546,11 +601,11 @@ BOOL SListFileFindClose(HANDLE hFind); // Archive compacting typedef void (WINAPI * COMPACTCB)(void * lpUserData, DWORD dwWorkType, DWORD dwParam1, DWORD dwParam2); -BOOL WINAPI SFileSetCompactCallback(HANDLE hMPQ, COMPACTCB CompactCB, void * lpData); -BOOL WINAPI SFileCompactArchive(HANDLE hMPQ, const char * szListFile = NULL, BOOL bReserved = 0); +BOOL WINAPI SFileSetCompactCallback(HANDLE hMpq, COMPACTCB CompactCB, void * lpData); +BOOL WINAPI SFileCompactArchive(HANDLE hMpq, const char * szListFile = NULL, BOOL bReserved = 0); // Locale support -int WINAPI SFileEnumLocales(HANDLE hMPQ, const char * szFileName, LCID * plcLocales, DWORD * pdwMaxLocales, DWORD dwSearchScope = SFILE_OPEN_BY_INDEX); +int WINAPI SFileEnumLocales(HANDLE hMpq, const char * szFileName, LCID * plcLocales, DWORD * pdwMaxLocales, DWORD dwSearchScope); // (De)compression int WINAPI SCompCompress (char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength, int uCompressions, int nCmpType, int nCmpLevel); @@ -558,8 +613,16 @@ int WINAPI SCompDecompress (char * pbOutBuffer, int * pdwOutLength, char * pbInB // Sets the default data compression for files added to MPQ, // if MPQ_FILE_COMPRESS_MULTI has been specified in call to SFileAddFile +// Use one of the MPQ_COMPRESSION_XXX values int WINAPI SCompSetDataCompression(int nDataCompression); +// Verifies file against its extended attributes (depending on dwFlags). +// For dwFlags, use one or more of MPQ_ATTRIBUTE_MD5 +BOOL WINAPI SFileVerifyFile(HANDLE hMpq, const char * szFileName, DWORD dwFlags); + +// High-level extract function +BOOL WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const char * szExtracted); + //----------------------------------------------------------------------------- // Functions from Storm.dll. They use slightly different names for keeping // possibility to use them together with StormLib (StormXXX instead of SFileXXX) diff --git a/src/tools/stuffextract/StormLib/StormPort.h b/src/tools/stuffextract/StormLib/StormPort.h index 4d7d92d..8ee6ff8 100644 --- a/src/tools/stuffextract/StormLib/StormPort.h +++ b/src/tools/stuffextract/StormLib/StormPort.h @@ -55,14 +55,6 @@ // Macintosh using Carbon #include // Mac OS X - #define _stricmp strcasecmp // Case insensitive strcmp has a different name on this platform. - #define _strnicmp strncasecmp - - typedef void * LPCSTR; - typedef unsigned long * LPDWORD; - typedef long * PLONG; - typedef void * LPVOID; - typedef unsigned int UINT; #define PKEXPORT #define __SYS_ZLIB @@ -74,6 +66,13 @@ #else #define PLATFORM_LITTLE_ENDIAN 1 // Apple is now making Macs with Intel CPUs #endif + + #ifdef __LP64__ + #define PLATFORM_64BIT + #else + #define PLATFORM_32BIT + #endif + #define PLATFORM_DEFINED // The platform is known now #endif @@ -105,14 +104,15 @@ // Typedefs for ANSI C typedef unsigned char BYTE; - typedef short SHORT; - typedef unsigned short WORD; - typedef unsigned short USHORT; - typedef long LONG; - typedef unsigned long DWORD; - typedef unsigned long DWORD_PTR; - typedef long LONG_PTR; - typedef long long LONGLONG; + typedef int16_t SHORT; + typedef uint16_t WORD; + typedef uint16_t USHORT; + typedef int32_t LONG; + typedef uint32_t DWORD; + typedef intptr_t DWORD_PTR; + typedef intptr_t LONG_PTR; + typedef intptr_t INT_PTR; + typedef int64_t LONGLONG; #ifndef __OBJC__ #ifdef __cplusplus #define BOOL bool @@ -121,15 +121,13 @@ #endif #endif typedef void * HANDLE; - typedef void * LPOVERLAPPED; // Unsupported on Linux + typedef void * LPOVERLAPPED; // Unsupported on Linux and Mac typedef char TCHAR; - typedef unsigned long LCID; - - typedef void * LPCSTR; - typedef unsigned long * LPDWORD; - typedef long * PLONG; - typedef void * LPVOID; - typedef unsigned int UINT; + typedef uint32_t LCID; + typedef unsigned int UINT; + typedef LONG * PLONG; + typedef DWORD * LPDWORD; + typedef BYTE * LPBYTE; typedef struct _FILETIME { @@ -186,9 +184,6 @@ #define GENERIC_WRITE 0x40000000 #define GENERIC_READ 0x80000000 - #define FILE_FLAG_DELETE_ON_CLOSE 1 // Sam: Added these two defines so it would compile. - #define FILE_FLAG_SEQUENTIAL_SCAN 2 - #define ERROR_SUCCESS 0 #define ERROR_INVALID_FUNCTION 1 #define ERROR_FILE_NOT_FOUND 2 @@ -196,6 +191,7 @@ #define ERROR_NOT_ENOUGH_MEMORY 8 #define ERROR_BAD_FORMAT 11 #define ERROR_NO_MORE_FILES 18 + #define ERROR_WRITE_FAULT 29 #define ERROR_GEN_FAILURE 31 #define ERROR_HANDLE_EOF 38 #define ERROR_HANDLE_DISK_FULL 39 @@ -211,14 +207,6 @@ #define INVALID_HANDLE_VALUE ((HANDLE) -1) - #ifndef min - #define min(a, b) ((a < b) ? a : b) - #endif - - #ifndef max - #define max(a, b) ((a > b) ? a : b) - #endif - #define _stricmp strcasecmp #define _strnicmp strncasecmp @@ -226,7 +214,7 @@ void SetLastError(int err); int GetLastError(); - const char *ErrString(int err); + char *ErrString(int err); // Emulation of functions for file I/O available in Win32 HANDLE CreateFile(const char * lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, void * lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); @@ -261,12 +249,12 @@ #define BSWAP_TMPQSHUNT(a) {} #define BSWAP_TMPQHEADER(a) {} #else - extern unsigned short SwapUShort(unsigned short); - extern unsigned long SwapULong(unsigned long); - extern short SwapShort(unsigned short); - extern long SwapLong(unsigned long); - extern void ConvertUnsignedLongBuffer(unsigned long *buffer, unsigned long nbLongs); - extern void ConvertUnsignedShortBuffer(unsigned short *buffer, unsigned long nbShorts); + extern uint16_t SwapUShort(uint16_t); + extern uint32_t SwapULong(uint32_t); + extern int16_t SwapShort(uint16_t); + extern int32_t SwapLong(uint32_t); + extern void ConvertUnsignedLongBuffer(uint32_t *buffer, uint32_t nbLongs); + extern void ConvertUnsignedShortBuffer(uint16_t *buffer, uint32_t nbShorts); extern void ConvertTMPQShunt(void *shunt); extern void ConvertTMPQHeader(void *header); #define BSWAP_INT16_UNSIGNED(a) SwapUShort((a)) diff --git a/src/tools/stuffextract/StormLib/StormPortLinux.cpp b/src/tools/stuffextract/StormLib/StormPortLinux.cpp index f446be0..3a7c565 100644 --- a/src/tools/stuffextract/StormLib/StormPortLinux.cpp +++ b/src/tools/stuffextract/StormLib/StormPortLinux.cpp @@ -23,8 +23,8 @@ * Copyright (c) 2001 BMX-Chemnitz.DE All rights reserved. * ********************************************************************/ -#include -#if defined(__linux) || defined(linux) + +#ifndef _WIN32 #include "StormPort.h" int globalerr; @@ -39,47 +39,52 @@ int GetLastError() return(globalerr); } -const char *ErrString(int err) +char *ErrString(int err) { - switch (err) - { - case ERROR_INVALID_FUNCTION: - return "function not implemented"; - case ERROR_FILE_NOT_FOUND: - return "file not found"; - case ERROR_ACCESS_DENIED: - return "access denied"; - case ERROR_NOT_ENOUGH_MEMORY: - return "not enough memory"; - case ERROR_BAD_FORMAT: - return "bad format"; - case ERROR_NO_MORE_FILES: - return "no more files"; - case ERROR_HANDLE_EOF: - return "access beyond EOF"; - case ERROR_INVALID_PARAMETER: - return "invalid parameter"; - case ERROR_HANDLE_DISK_FULL: - case ERROR_DISK_FULL: - return "no space left on device"; - case ERROR_ALREADY_EXISTS: - return "file exists"; - case ERROR_CAN_NOT_COMPLETE: - return "operation cannot be completed"; - default: - return "unknown error"; + switch (err) { + case ERROR_INVALID_FUNCTION: + return "function not implemented"; + case ERROR_FILE_NOT_FOUND: + return "file not found"; + case ERROR_ACCESS_DENIED: + return "access denied"; + case ERROR_NOT_ENOUGH_MEMORY: + return "not enough memory"; + case ERROR_BAD_FORMAT: + return "bad format"; + case ERROR_NO_MORE_FILES: + return "no more files"; + case ERROR_HANDLE_EOF: + return "access beyound EOF"; + case ERROR_HANDLE_DISK_FULL: + return "no space left on device"; + case ERROR_INVALID_PARAMETER: + return "invalid parameter"; + case ERROR_DISK_FULL: + return "no space left on device"; + case ERROR_ALREADY_EXISTS: + return "file exists"; + case ERROR_CAN_NOT_COMPLETE: + return "operation cannot be completed"; + default: + return "unknown error"; } } HANDLE CreateFile(const char *sFileName, DWORD ulMode, DWORD ulSharing, void *pSecAttrib, DWORD ulCreation, DWORD ulFlags, HANDLE hFile) { - switch (ulCreation) { + switch (ulCreation) + { case OPEN_EXISTING: return (HANDLE)open(sFileName, O_RDONLY | O_LARGEFILE); + case OPEN_ALWAYS: - return (HANDLE)open(sFileName, O_RDWR | O_CREAT, 0666); + return (HANDLE)open(sFileName, O_RDWR | O_CREAT, 0); + + case CREATE_ALWAYS: case CREATE_NEW: - return (HANDLE)open(sFileName, O_RDWR | O_CREAT | O_TRUNC, 0666); + return (HANDLE)open(sFileName, O_RDWR | O_CREAT | O_TRUNC, 0); + default: return INVALID_HANDLE_VALUE; } @@ -87,34 +92,49 @@ HANDLE CreateFile(const char *sFileName, DWORD ulMode, DWORD ulSharing, void *pS BOOL CloseHandle(HANDLE hFile) { - return (close((unsigned long long)hFile) == 0); + return (close((intptr_t)hFile) == 0); } DWORD GetFileSize(HANDLE hFile, DWORD *ulOffSetHigh) { - if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE)) + // Fix by Taiche : removed the hFile == NULL test because the CreateFile function above + // can return a HANDLE equal to 0 WHICH IS A LEGAL VALUE and does not mean the handle is NULL. + if (hFile == INVALID_HANDLE_VALUE) + { return 0xffffffff; + } - struct stat fileinfo; - fstat((unsigned long long)hFile, &fileinfo); + struct stat64 fileinfo; + fstat64((intptr_t)hFile, &fileinfo); - return fileinfo.st_size; + // Fix by Ladik: If "ulOffSetHigh" is not NULL, it needs to be set + // to higher 32 bits of a file size. + // TODO: Could some Linux programmer verify this ? + if(ulOffSetHigh != NULL) + *ulOffSetHigh = (fileinfo.st_size >> 32); + + return (DWORD)fileinfo.st_size; } DWORD SetFilePointer(HANDLE hFile, LONG lOffSetLow, LONG *pOffSetHigh, DWORD ulMethod) { - return lseek64((unsigned long long)hFile, (off64_t)(*pOffSetHigh) << 32 | (DWORD)lOffSetLow, ulMethod); + off64_t nFileOffset = (DWORD)lOffSetLow; + + if(pOffSetHigh != NULL) + nFileOffset |= (*(off64_t *)pOffSetHigh) << 32; + + return lseek64((intptr_t)hFile, nFileOffset, ulMethod); } BOOL SetEndOfFile(HANDLE hFile) { - return (ftruncate((unsigned long long)(hFile), lseek((unsigned long long)hFile, 0, SEEK_CUR)) == 0); + return (ftruncate((intptr_t)hFile, lseek((intptr_t)hFile, 0, SEEK_CUR)) == 0); } BOOL ReadFile(HANDLE hFile, void *pBuffer, DWORD ulLen, DWORD *ulRead, void *pOverLapped) { ssize_t count; - if ((count = read((unsigned long long)hFile, pBuffer, ulLen)) == -1) { + if ((count = read((intptr_t)hFile, pBuffer, ulLen)) == -1) { *ulRead = 0; return false; } @@ -125,7 +145,7 @@ BOOL ReadFile(HANDLE hFile, void *pBuffer, DWORD ulLen, DWORD *ulRead, void *pOv BOOL WriteFile(HANDLE hFile, const void *pBuffer, DWORD ulLen, DWORD *ulWritten, void *pOverLapped) { ssize_t count; - if ((count = write((unsigned long long)hFile, pBuffer, ulLen)) == -1) { + if ((count = write((intptr_t)hFile, pBuffer, ulLen)) == -1) { *ulWritten = 0; return false; } @@ -152,7 +172,15 @@ void GetTempPath(DWORD szTempLength, char * szTemp) void GetTempFileName(const char * lpTempFolderPath, const char * lpFileName, DWORD something, char * szLFName) { - strcpy(szLFName, tempnam(lpTempFolderPath, lpFileName)); + //strcpy(szLFName, tempnam(lpTempFolderPath, lpFileName)); + char tempName[15] = "/tmp/sl.XXXXXX"; + int sfp = mkstemp(tempName); + + if(sfp != -1) + { + close(sfp); + strcpy(szLFName, tempName); + } } BOOL DeleteFile(const char *lpFileName) diff --git a/src/tools/stuffextract/StormLib/StormPortMac.cpp b/src/tools/stuffextract/StormLib/StormPortMac.cpp index 476ab60..4c35594 100644 --- a/src/tools/stuffextract/StormLib/StormPortMac.cpp +++ b/src/tools/stuffextract/StormLib/StormPortMac.cpp @@ -1,10 +1,10 @@ /******************************************************************** * -* Description: implementation for StormLib - Macintosh port -* -* these are function wraps to execute Windows API calls -* as native Macintosh file calls (open/close/read/write/...) -* requires Mac OS X +* Description: implementation for StormLib - Macintosh port +* +* these are function wraps to execute Windows API calls +* as native Macintosh file calls (open/close/read/write/...) +* requires Mac OS X * * Derived from Marko Friedemann * StormPort.cpp for Linux @@ -15,8 +15,7 @@ * ********************************************************************/ -#if defined(__APPLE__) & defined( __MACH__) - +#if (!defined(_WIN32) && !defined(_WIN64)) #include "StormPort.h" #include "StormLib.h" @@ -27,72 +26,34 @@ * BEGIN OF MOREFILES COPY-PASTE *****************************************************************************/ -#ifdef __USEPRAGMAINTERNAL - #ifdef __MWERKS__ - #pragma internal on - #endif +#ifdef __USEPRAGMAINTERNAL + #ifdef __MWERKS__ + #pragma internal on + #endif #endif -union TLongAnd4Bytes -{ - unsigned char bytes[4]; - unsigned long uvalue; - signed long svalue; -}; - - -static OSErr FSGetFullPath(const FSRef *ref, UInt8 *fullPath, UInt32 fullPathLength) -{ - OSErr result; - - result = FSRefMakePath(ref, fullPath, fullPathLength); - - return result; -} - -static OSErr FSLocationFromFullPath(const void *fullPath, FSRef *ref) -{ - OSErr result; - - result = FSPathMakeRef((UInt8 *)fullPath, ref, NULL); // Create an FSRef from the path - return result; -} - -/*****************************************************************************/ - -/*****************************************************************************/ - -static OSErr FSCreateCompat(const FSRef *parentRef, OSType creator, OSType fileType, const UniChar *fileName, - UniCharCount nameLength, FSRef *ref) -{ - FSCatalogInfo theCatInfo; - OSErr theErr; - ((FileInfo *)&theCatInfo.finderInfo)->fileCreator = creator; - ((FileInfo *)&theCatInfo.finderInfo)->fileType = fileType; - ((FileInfo *)&theCatInfo.finderInfo)->finderFlags = 0; - SetPt(&((FileInfo *)&theCatInfo.finderInfo)->location, 0, 0); - ((FileInfo *)&theCatInfo.finderInfo)->reservedField = 0; - - theErr = FSCreateFileUnicode(parentRef, nameLength, fileName, kFSCatInfoFinderInfo, &theCatInfo, ref, NULL); - return theErr; -} - /*****************************************************************************/ static OSErr FSOpenDFCompat(FSRef *ref, char permission, short *refNum) { - HFSUniStr255 forkName; - OSErr theErr; - Boolean isFolder, wasChanged; - - theErr = FSResolveAliasFile(ref, TRUE, &isFolder, &wasChanged); - if (theErr != noErr) - return theErr; - - FSGetDataForkName(&forkName); - theErr = FSOpenFork(ref, forkName.length, forkName.unicode, permission, refNum); - return theErr; + HFSUniStr255 forkName; + OSErr theErr; + Boolean isFolder, wasChanged; + + theErr = FSResolveAliasFile(ref, TRUE, &isFolder, &wasChanged); + if (theErr != noErr) + { + return theErr; + } + + FSGetDataForkName(&forkName); +#ifdef PLATFORM_64BIT + theErr = FSOpenFork(ref, forkName.length, forkName.unicode, permission, (FSIORefNum *)refNum); +#else + theErr = FSOpenFork(ref, forkName.length, forkName.unicode, permission, refNum); +#endif + return theErr; } /***************************************************************************** @@ -104,660 +65,646 @@ static OSErr FSOpenDFCompat(FSRef *ref, char permission, short *refNum) int globalerr; /******************************************************************** -* SwapLong +* SwapLong ********************************************************************/ -unsigned long SwapULong(unsigned long data) +uint32_t SwapULong(uint32_t data) { - // Apple provided function - uint32_t result; - - __asm__("lwbrx %0,0,%1" : "=r" (result) : "r" (&data), "m" (data)); - return result; - -/* - TLongAnd4Bytes Work; - unsigned char * value_as_4bytes = (unsigned char *)&value; - - Work.bytes[0] = value_as_4bytes[3]; - Work.bytes[1] = value_as_4bytes[2]; - Work.bytes[2] = value_as_4bytes[1]; - Work.bytes[3] = value_as_4bytes[0]; - - return Work.uvalue; -*/ + return CFSwapInt32(data); } -long SwapLong(unsigned long data) +int32_t SwapLong(uint32_t data) { - // Apple provided function - uint32_t result; - - __asm__("lwbrx %0,0,%1" : "=r" (result) : "r" (&data), "m" (data)); - return (long)result; - -/* - TLongAnd4Bytes Work; - unsigned char * value_as_4bytes = (unsigned char *)&value; - - Work.bytes[0] = value_as_4bytes[3]; - Work.bytes[1] = value_as_4bytes[2]; - Work.bytes[2] = value_as_4bytes[1]; - Work.bytes[3] = value_as_4bytes[0]; - - return Work.svalue; -*/ + return (int32_t)CFSwapInt32(data); } /******************************************************************** -* SwapShort +* SwapShort ********************************************************************/ -unsigned short SwapUShort(unsigned short data) +uint16_t SwapUShort(uint16_t data) { - // Apple provided function - uint16_t result; - __asm__("lhbrx %0,0,%1" : "=r" (result) : "r" (&data), "m" (data)); - return result; + return CFSwapInt16(data); } -short SwapShort(unsigned short data) +int16_t SwapShort(uint16_t data) { - // Apple provided function - uint16_t result; - __asm__("lhbrx %0,0,%1" : "=r" (result) : "r" (&data), "m" (data)); - return (short)result; + return (int16_t)CFSwapInt16(data); } /******************************************************************** -* ConvertUnsignedLongBuffer +* ConvertUnsignedLongBuffer ********************************************************************/ -void ConvertUnsignedLongBuffer(unsigned long *buffer, unsigned long nbLongs) +void ConvertUnsignedLongBuffer(uint32_t *buffer, uint32_t nbLongs) { - while (nbLongs-- > 0) - { - *buffer = SwapLong(*buffer); - buffer++; - } + while (nbLongs-- > 0) + { + *buffer = SwapLong(*buffer); + buffer++; + } } /******************************************************************** -* ConvertUnsignedShortBuffer +* ConvertUnsignedShortBuffer ********************************************************************/ -void ConvertUnsignedShortBuffer(unsigned short *buffer, unsigned long nbShorts) +void ConvertUnsignedShortBuffer(uint16_t *buffer, uint32_t nbShorts) { - while (nbShorts-- > 0) - { - *buffer = SwapShort(*buffer); - buffer++; - } + while (nbShorts-- > 0) + { + *buffer = SwapShort(*buffer); + buffer++; + } } /******************************************************************** -* ConvertTMPQShunt +* ConvertTMPQShunt ********************************************************************/ void ConvertTMPQShunt(void *shunt) { - TMPQShunt * theShunt = (TMPQShunt *)shunt; + TMPQShunt * theShunt = (TMPQShunt *)shunt; - theShunt->dwID = SwapULong(theShunt->dwID); - theShunt->dwUnknown = SwapULong(theShunt->dwUnknown); - theShunt->dwHeaderPos = SwapULong(theShunt->dwHeaderPos); + theShunt->dwID = SwapULong(theShunt->dwID); + theShunt->dwUnknown = SwapULong(theShunt->dwUnknown); + theShunt->dwHeaderPos = SwapULong(theShunt->dwHeaderPos); } /******************************************************************** -* ConvertTMPQHeader +* ConvertTMPQHeader ********************************************************************/ void ConvertTMPQHeader(void *header) { - TMPQHeader2 * theHeader = (TMPQHeader2 *)header; - - theHeader->dwID = SwapULong(theHeader->dwID); - theHeader->dwHeaderSize = SwapULong(theHeader->dwHeaderSize); - theHeader->dwArchiveSize = SwapULong(theHeader->dwArchiveSize); - theHeader->wFormatVersion = SwapUShort(theHeader->wFormatVersion); - theHeader->wBlockSize = SwapUShort(theHeader->wBlockSize); - theHeader->dwHashTablePos = SwapULong(theHeader->dwHashTablePos); - theHeader->dwBlockTablePos = SwapULong(theHeader->dwBlockTablePos); - theHeader->dwHashTableSize = SwapULong(theHeader->dwHashTableSize); - theHeader->dwBlockTableSize = SwapULong(theHeader->dwBlockTableSize); + TMPQHeader2 * theHeader = (TMPQHeader2 *)header; + + theHeader->dwID = SwapULong(theHeader->dwID); + theHeader->dwHeaderSize = SwapULong(theHeader->dwHeaderSize); + theHeader->dwArchiveSize = SwapULong(theHeader->dwArchiveSize); + theHeader->wFormatVersion = SwapUShort(theHeader->wFormatVersion); + theHeader->wBlockSize = SwapUShort(theHeader->wBlockSize); + theHeader->dwHashTablePos = SwapULong(theHeader->dwHashTablePos); + theHeader->dwBlockTablePos = SwapULong(theHeader->dwBlockTablePos); + theHeader->dwHashTableSize = SwapULong(theHeader->dwHashTableSize); + theHeader->dwBlockTableSize = SwapULong(theHeader->dwBlockTableSize); - if(theHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2) - { - DWORD dwTemp = theHeader->ExtBlockTablePos.LowPart; - theHeader->ExtBlockTablePos.LowPart = theHeader->ExtBlockTablePos.HighPart; - theHeader->ExtBlockTablePos.HighPart = dwTemp; - theHeader->ExtBlockTablePos.LowPart = SwapULong(theHeader->ExtBlockTablePos.LowPart); - theHeader->ExtBlockTablePos.HighPart = SwapULong(theHeader->ExtBlockTablePos.HighPart); - theHeader->wHashTablePosHigh = SwapUShort(theHeader->wHashTablePosHigh); - theHeader->wBlockTablePosHigh = SwapUShort(theHeader->wBlockTablePosHigh); - } -} - -/******************************************************************** -* ConvertTMPQHash -********************************************************************/ -void ConvertHashTable(void *hashtable, DWORD nHashEntries) -{ - TMPQHash * theHash = (TMPQHash *)hashtable; - USHORT lcLocale; - - for(DWORD i = 0; i < nHashEntries; i++, theHash++) - { - lcLocale = theHash->lcLocale; - theHash->lcLocale = theHash->wPlatform; - theHash->wPlatform = lcLocale; - } + if(theHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2) + { + DWORD dwTemp = theHeader->ExtBlockTablePos.LowPart; + theHeader->ExtBlockTablePos.LowPart = theHeader->ExtBlockTablePos.HighPart; + theHeader->ExtBlockTablePos.HighPart = dwTemp; + theHeader->ExtBlockTablePos.LowPart = SwapULong(theHeader->ExtBlockTablePos.LowPart); + theHeader->ExtBlockTablePos.HighPart = SwapULong(theHeader->ExtBlockTablePos.HighPart); + theHeader->wHashTablePosHigh = SwapUShort(theHeader->wHashTablePosHigh); + theHeader->wBlockTablePosHigh = SwapUShort(theHeader->wBlockTablePosHigh); + } } #pragma mark - /******************************************************************** -* SetLastError +* SetLastError ********************************************************************/ void SetLastError(int err) { - globalerr = err; + globalerr = err; } /******************************************************************** -* GetLastError +* GetLastError ********************************************************************/ int GetLastError() { - return globalerr; + return globalerr; } /******************************************************************** -* ErrString +* ErrString ********************************************************************/ -const char *ErrString(int err) +char *ErrString(int err) { - switch (err) - { - case ERROR_INVALID_FUNCTION: - return "function not implemented"; - case ERROR_FILE_NOT_FOUND: - return "file not found"; - case ERROR_ACCESS_DENIED: - return "access denied"; - case ERROR_NOT_ENOUGH_MEMORY: - return "not enough memory"; - case ERROR_BAD_FORMAT: - return "bad format"; - case ERROR_NO_MORE_FILES: - return "no more files"; - case ERROR_HANDLE_EOF: - return "access beyound EOF"; - case ERROR_HANDLE_DISK_FULL: - return "no space left on device"; - case ERROR_INVALID_PARAMETER: - return "invalid parameter"; - case ERROR_DISK_FULL: - return "no space left on device"; - case ERROR_ALREADY_EXISTS: - return "file exists"; - case ERROR_CAN_NOT_COMPLETE: - return "operation cannot be completed"; - case ERROR_INSUFFICIENT_BUFFER: - return "insufficient buffer"; - default: - return "unknown error"; - } + switch (err) + { + case ERROR_INVALID_FUNCTION: + return "function not implemented"; + case ERROR_FILE_NOT_FOUND: + return "file not found"; + case ERROR_ACCESS_DENIED: + return "access denied"; + case ERROR_NOT_ENOUGH_MEMORY: + return "not enough memory"; + case ERROR_BAD_FORMAT: + return "bad format"; + case ERROR_NO_MORE_FILES: + return "no more files"; + case ERROR_HANDLE_EOF: + return "access beyond EOF"; + case ERROR_HANDLE_DISK_FULL: + return "no space left on device"; + case ERROR_INVALID_PARAMETER: + return "invalid parameter"; + case ERROR_DISK_FULL: + return "no space left on device"; + case ERROR_ALREADY_EXISTS: + return "file exists"; + case ERROR_CAN_NOT_COMPLETE: + return "operation cannot be completed"; + case ERROR_INSUFFICIENT_BUFFER: + return "insufficient buffer"; + case ERROR_WRITE_FAULT: + return "unable to write to device"; + default: + return "unknown error"; + } } #pragma mark - /******************************************************************** -* GetTempPath - returns a '/' or ':'-terminated path -* szTempLength: length for path -* szTemp: file path +* GetTempPath - returns a '/' or ':'-terminated path +* szTempLength: length for path +* szTemp: file path ********************************************************************/ -void GetTempPath(DWORD szTempLength, char * szTemp) // I think I'll change this to use FSRefs. +void GetTempPath(DWORD szTempLength, char * szTemp) { - FSRef theFSRef; - OSErr theErr = FSFindFolder(kOnAppropriateDisk, kTemporaryFolderType, kCreateFolder, &theFSRef); - if (theErr == noErr) - { - theErr = FSGetFullPath(&theFSRef, (UInt8 *)szTemp, MAX_PATH); - if (theErr != noErr) - szTemp[0] = '\0'; - } - else - szTemp[0] = '\0'; - strcat(szTemp, "/"); - - SetLastError(theErr); + FSRef theFSRef; + OSErr theErr = FSFindFolder(kOnAppropriateDisk, kTemporaryFolderType, kCreateFolder, &theFSRef); + if (theErr == noErr) + { + theErr = FSRefMakePath(&theFSRef, (UInt8 *)szTemp, szTempLength); + if (theErr != noErr) + { + szTemp[0] = '\0'; + } + } + else + { + szTemp[0] = '\0'; + } + strcat(szTemp, "/"); + + SetLastError(theErr); } /******************************************************************** -* GetTempFileName -* lpTempFolderPath: the temporary folder path, terminated by "/" -* lpFileName: a file name base -* something: unknown -* szLFName: the final path, built from the path, the file name and a random pattern +* GetTempFileName +* lpTempFolderPath: the temporary folder path, terminated by "/" +* lpFileName: a file name base +* something: unknown +* szLFName: the final path, built from the path, the file name and a random pattern ********************************************************************/ void GetTempFileName(const char * lpTempFolderPath, const char * lpFileName, DWORD something, char * szLFName) { #pragma unused (something) - char tmp[2] = "A"; + char tmp[2] = "A"; - while (true) - { - HANDLE fHandle; + while (true) + { + HANDLE fHandle; - strcpy(szLFName, lpTempFolderPath); - strcat(szLFName, lpFileName); - strcat(szLFName, tmp); - - if ((fHandle = CreateFile(szLFName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) - // OK we found it! - break; - CloseHandle(fHandle); - tmp[0]++; - } + strcpy(szLFName, lpTempFolderPath); + strcat(szLFName, lpFileName); + strcat(szLFName, tmp); + + if ((fHandle = CreateFile(szLFName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) + { + // OK we found it! + break; + } + CloseHandle(fHandle); + tmp[0]++; + } } /******************************************************************** -* DeleteFile -* lpFileName: file path +* DeleteFile +* lpFileName: file path ********************************************************************/ BOOL DeleteFile(const char * lpFileName) { - OSErr theErr; - FSRef theFileRef; - - theErr = FSLocationFromFullPath(lpFileName, &theFileRef); - if (theErr != noErr) - { - SetLastError(theErr); - return FALSE; - } - - theErr = FSDeleteObject(&theFileRef); - - SetLastError(theErr); + OSErr theErr; + FSRef theFileRef; + + theErr = FSPathMakeRef((const UInt8 *)lpFileName, &theFileRef, NULL); + if (theErr != noErr) + { + SetLastError(theErr); + return FALSE; + } + + theErr = FSDeleteObject(&theFileRef); + + SetLastError(theErr); - return theErr == noErr; + return theErr == noErr; } /******************************************************************** -* MoveFile -* lpFromFileName: old file path -* lpToFileName: new file path +* MoveFile +* lpFromFileName: old file path +* lpToFileName: new file path ********************************************************************/ BOOL MoveFile(const char * lpFromFileName, const char * lpToFileName) { - OSErr theErr; - FSRef fromFileRef; - FSRef toFileRef; - FSRef parentFolderRef; - - // Get the path to the old file - theErr = FSLocationFromFullPath(lpFromFileName, &fromFileRef); - if (theErr != noErr) - { - SetLastError(theErr); - return false; - } - - // Get the path to the new folder for the file - char folderName[strlen(lpToFileName)]; - CFStringRef folderPathCFString = CFStringCreateWithCString(NULL, lpToFileName, kCFStringEncodingUTF8); - CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, folderPathCFString, kCFURLPOSIXPathStyle, FALSE); - CFURLRef folderURL = CFURLCreateCopyDeletingLastPathComponent(NULL, fileURL); - CFURLGetFileSystemRepresentation(folderURL, TRUE, (UInt8 *)folderName, strlen(lpToFileName)); - theErr = FSLocationFromFullPath(folderName, &parentFolderRef); - CFRelease(fileURL); - CFRelease(folderURL); - CFRelease(folderPathCFString); - - // Move the old file - theErr = FSMoveObject(&fromFileRef, &parentFolderRef, &toFileRef); - if (theErr != noErr) - { - SetLastError(theErr); - return false; - } - - // Get a CFString for the new file name - CFStringRef newFileNameCFString = CFStringCreateWithCString(NULL, lpToFileName, kCFStringEncodingUTF8); - fileURL = CFURLCreateWithFileSystemPath(NULL, newFileNameCFString, kCFURLPOSIXPathStyle, FALSE); - CFRelease(newFileNameCFString); - newFileNameCFString = CFURLCopyLastPathComponent(fileURL); - CFRelease(fileURL); - - // Convert CFString to Unicode and rename the file - UniChar unicodeFileName[256]; - CFStringGetCharacters(newFileNameCFString, CFRangeMake(0, CFStringGetLength(newFileNameCFString)), - unicodeFileName); - theErr = FSRenameUnicode(&toFileRef, CFStringGetLength(newFileNameCFString), unicodeFileName, - kTextEncodingUnknown, NULL); - if (theErr != noErr) - { - SetLastError(theErr); - CFRelease(newFileNameCFString); - return false; - } - - CFRelease(newFileNameCFString); - - SetLastError(theErr); - return true; + OSErr theErr; + FSRef fromFileRef; + FSRef toFileRef; + FSRef parentFolderRef; + + // Get the path to the old file + theErr = FSPathMakeRef((const UInt8 *)lpFromFileName, &fromFileRef, NULL); + if (theErr != noErr) + { + SetLastError(theErr); + return false; + } + + // Get the path to the new folder for the file + char folderName[strlen(lpToFileName)]; + CFStringRef folderPathCFString = CFStringCreateWithCString(NULL, lpToFileName, kCFStringEncodingUTF8); + CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, folderPathCFString, kCFURLPOSIXPathStyle, FALSE); + CFURLRef folderURL = CFURLCreateCopyDeletingLastPathComponent(NULL, fileURL); + CFURLGetFileSystemRepresentation(folderURL, TRUE, (UInt8 *)folderName, strlen(lpToFileName)); + theErr = FSPathMakeRef((UInt8 *)folderName, &parentFolderRef, NULL); + CFRelease(fileURL); + CFRelease(folderURL); + CFRelease(folderPathCFString); + + // Move the old file + theErr = FSMoveObject(&fromFileRef, &parentFolderRef, &toFileRef); + if (theErr != noErr) + { + SetLastError(theErr); + return false; + } + + // Get a CFString for the new file name + CFStringRef newFileNameCFString = CFStringCreateWithCString(NULL, lpToFileName, kCFStringEncodingUTF8); + fileURL = CFURLCreateWithFileSystemPath(NULL, newFileNameCFString, kCFURLPOSIXPathStyle, FALSE); + CFRelease(newFileNameCFString); + newFileNameCFString = CFURLCopyLastPathComponent(fileURL); + CFRelease(fileURL); + + // Convert CFString to Unicode and rename the file + UniChar unicodeFileName[256]; + CFStringGetCharacters(newFileNameCFString, CFRangeMake(0, CFStringGetLength(newFileNameCFString)), + unicodeFileName); + theErr = FSRenameUnicode(&toFileRef, CFStringGetLength(newFileNameCFString), unicodeFileName, + kTextEncodingUnknown, NULL); + if (theErr != noErr) + { + SetLastError(theErr); + CFRelease(newFileNameCFString); + return false; + } + + CFRelease(newFileNameCFString); + + SetLastError(theErr); + return true; } /******************************************************************** -* CreateFile -* ulMode: GENERIC_READ | GENERIC_WRITE -* ulSharing: FILE_SHARE_READ -* pSecAttrib: NULL -* ulCreation: OPEN_EXISTING, OPEN_ALWAYS, CREATE_NEW -* ulFlags: 0 -* hFile: NULL +* CreateFile +* ulMode: GENERIC_READ | GENERIC_WRITE +* ulSharing: FILE_SHARE_READ +* pSecAttrib: NULL +* ulCreation: OPEN_EXISTING, OPEN_ALWAYS, CREATE_NEW +* ulFlags: 0 +* hFile: NULL ********************************************************************/ -HANDLE CreateFile( const char *sFileName, /* file name */ - DWORD ulMode, /* access mode */ - DWORD ulSharing, /* share mode */ - void *pSecAttrib, /* SD */ - DWORD ulCreation, /* how to create */ - DWORD ulFlags, /* file attributes */ - HANDLE hFile ) /* handle to template file */ +HANDLE CreateFile( const char *sFileName, /* file name */ + DWORD ulMode, /* access mode */ + DWORD ulSharing, /* share mode */ + void *pSecAttrib, /* SD */ + DWORD ulCreation, /* how to create */ + DWORD ulFlags, /* file attributes */ + HANDLE hFile ) /* handle to template file */ { #pragma unused (ulSharing, pSecAttrib, ulFlags, hFile) - OSErr theErr; - FSRef theFileRef; - FSRef theParentRef; - short fileRef; - char permission; - static OSType gCreator; - static OSType gType; - - theErr = FSLocationFromFullPath(sFileName, &theFileRef); - if (theErr == fnfErr) - { // Create the FSRef for the parent directory. - memset(&theFileRef, 0, sizeof(FSRef)); - UInt8 folderName[MAX_PATH]; - CFStringRef folderPathCFString = CFStringCreateWithCString(NULL, sFileName, kCFStringEncodingUTF8); - CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, folderPathCFString, kCFURLPOSIXPathStyle, FALSE); - CFURLRef folderURL = CFURLCreateCopyDeletingLastPathComponent(NULL, fileURL); - CFURLGetFileSystemRepresentation(folderURL, TRUE, folderName, MAX_PATH); - theErr = FSLocationFromFullPath(folderName, &theParentRef); - CFRelease(fileURL); - CFRelease(folderURL); - CFRelease(folderPathCFString); - } - if (theErr != noErr) - { - SetLastError(theErr); - if (ulCreation == OPEN_EXISTING || theErr != fnfErr) - return INVALID_HANDLE_VALUE; - } - - if (ulCreation != OPEN_EXISTING) - { /* We create the file */ - UniChar unicodeFileName[256]; - CFStringRef filePathCFString = CFStringCreateWithCString(NULL, sFileName, kCFStringEncodingUTF8); - CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, filePathCFString, kCFURLPOSIXPathStyle, FALSE); - CFStringRef fileNameCFString = CFURLCopyLastPathComponent(fileURL); - CFStringGetCharacters(fileNameCFString, CFRangeMake(0, CFStringGetLength(fileNameCFString)), - unicodeFileName); - theErr = FSCreateCompat(&theParentRef, gCreator, gType, unicodeFileName, - CFStringGetLength(fileNameCFString), &theFileRef); - CFRelease(fileNameCFString); - CFRelease(filePathCFString); - CFRelease(fileURL); - if (theErr != noErr) - { - SetLastError(theErr); - return INVALID_HANDLE_VALUE; - } - } + OSErr theErr; + FSRef theFileRef; + FSRef theParentRef; + short fileRef; + char permission; + + theErr = FSPathMakeRef((const UInt8 *)sFileName, &theFileRef, NULL); + if (theErr == fnfErr) + { // Create the FSRef for the parent directory. + memset(&theFileRef, 0, sizeof(FSRef)); + UInt8 folderName[MAX_PATH]; + CFStringRef folderPathCFString = CFStringCreateWithCString(NULL, sFileName, kCFStringEncodingUTF8); + CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, folderPathCFString, kCFURLPOSIXPathStyle, FALSE); + CFURLRef folderURL = CFURLCreateCopyDeletingLastPathComponent(NULL, fileURL); + CFURLGetFileSystemRepresentation(folderURL, TRUE, folderName, MAX_PATH); + theErr = FSPathMakeRef(folderName, &theParentRef, NULL); + CFRelease(fileURL); + CFRelease(folderURL); + CFRelease(folderPathCFString); + } + if (theErr != noErr) + { + SetLastError(theErr); + if (ulCreation == OPEN_EXISTING || theErr != fnfErr) + return INVALID_HANDLE_VALUE; + } + + if (ulCreation != OPEN_EXISTING) + { /* We create the file */ + UniChar unicodeFileName[256]; + CFStringRef filePathCFString = CFStringCreateWithCString(NULL, sFileName, kCFStringEncodingUTF8); + CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, filePathCFString, kCFURLPOSIXPathStyle, FALSE); + CFStringRef fileNameCFString = CFURLCopyLastPathComponent(fileURL); + CFStringGetCharacters(fileNameCFString, CFRangeMake(0, CFStringGetLength(fileNameCFString)), + unicodeFileName); + theErr = FSCreateFileUnicode(&theParentRef, CFStringGetLength(fileNameCFString), unicodeFileName, + kFSCatInfoNone, NULL, &theFileRef, NULL); + CFRelease(fileNameCFString); + CFRelease(filePathCFString); + CFRelease(fileURL); + if (theErr != noErr) + { + SetLastError(theErr); + return INVALID_HANDLE_VALUE; + } + } - if (ulMode == GENERIC_READ) - permission = fsRdPerm; - else - { - if (ulMode == GENERIC_WRITE) - permission = fsWrPerm; - else - permission = fsRdWrPerm; - } - theErr = FSOpenDFCompat(&theFileRef, permission, &fileRef); - - SetLastError(theErr); + if (ulMode == GENERIC_READ) + { + permission = fsRdPerm; + } + else + { + if (ulMode == GENERIC_WRITE) + { + permission = fsWrPerm; + } + else + { + permission = fsRdWrPerm; + } + } + theErr = FSOpenDFCompat(&theFileRef, permission, &fileRef); + + SetLastError(theErr); - if (theErr == noErr) - return (HANDLE)(int)fileRef; - else - return INVALID_HANDLE_VALUE; + if (theErr == noErr) + { + return (HANDLE)(int)fileRef; + } + else + { + return INVALID_HANDLE_VALUE; + } } /******************************************************************** -* CloseHandle +* CloseHandle ********************************************************************/ -BOOL CloseHandle( HANDLE hFile ) /* handle to object */ +BOOL CloseHandle( HANDLE hFile ) /* handle to object */ { - OSErr theErr; - - if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE)) - return FALSE; + OSErr theErr; + + if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE)) + { + return FALSE; + } - theErr = FSCloseFork((short)(int)hFile); - - SetLastError(theErr); - - return theErr != noErr; + theErr = FSCloseFork((short)(long)hFile); + + SetLastError(theErr); + + return theErr == noErr; } /******************************************************************** -* GetFileSize +* GetFileSize ********************************************************************/ -DWORD GetFileSize( HANDLE hFile, /* handle to file */ - DWORD *ulOffSetHigh ) /* high-order word of file size */ +DWORD GetFileSize( HANDLE hFile, /* handle to file */ + DWORD *ulOffSetHigh ) /* high-order word of file size */ { - SInt64 fileLength; - OSErr theErr; + SInt64 fileLength; + OSErr theErr; - if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE)) - { - SetLastError(theErr); - return -1u; - } - - theErr = FSGetForkSize((short)(int)hFile, &fileLength); - if (theErr != noErr) - { - SetLastError(theErr); - return -1u; - } - - if (ulOffSetHigh != NULL) - *ulOffSetHigh = fileLength >> 32; + if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE)) + { + SetLastError(theErr); + return -1u; + } + + theErr = FSGetForkSize((short)(long)hFile, &fileLength); + if (theErr != noErr) + { + SetLastError(theErr); + return -1u; + } + + if (ulOffSetHigh != NULL) + { + *ulOffSetHigh = fileLength >> 32; + } - SetLastError(theErr); - - return fileLength; + SetLastError(theErr); + + return fileLength; } /******************************************************************** -* SetFilePointer -* pOffSetHigh: NULL -* ulMethod: FILE_BEGIN, FILE_CURRENT +* SetFilePointer +* pOffSetHigh: NULL +* ulMethod: FILE_BEGIN, FILE_CURRENT ********************************************************************/ -DWORD SetFilePointer( HANDLE hFile, /* handle to file */ - LONG lOffSetLow, /* bytes to move pointer */ - LONG *pOffSetHigh, /* bytes to move pointer */ - DWORD ulMethod ) /* starting point */ +DWORD SetFilePointer( HANDLE hFile, /* handle to file */ + LONG lOffSetLow, /* bytes to move pointer */ + LONG *pOffSetHigh, /* bytes to move pointer */ + DWORD ulMethod ) /* starting point */ { - OSErr theErr; + OSErr theErr; - if (ulMethod == FILE_CURRENT) - { - SInt64 bytesToMove; - - if (pOffSetHigh != NULL) - bytesToMove = ((SInt64)*pOffSetHigh << 32) + lOffSetLow; - else - bytesToMove = lOffSetLow; - - SInt64 newPos; - - theErr = FSSetForkPosition((short)(int)hFile, fsFromMark, bytesToMove); - if (theErr != noErr) - { - SetLastError(theErr); - return -1u; - } - - theErr = FSGetForkPosition((short)(int)hFile, &newPos); - if (theErr != noErr) - { - SetLastError(theErr); - return -1u; - } - - if (pOffSetHigh != NULL) - *pOffSetHigh = newPos >> 32; - - SetLastError(theErr); - return newPos; - } - else if (ulMethod == FILE_BEGIN) - { - SInt64 bytesToMove; - - if (pOffSetHigh != NULL) - bytesToMove = ((SInt64)*pOffSetHigh << 32) + lOffSetLow; - else - bytesToMove = lOffSetLow; - - theErr = FSSetForkPosition((short)(int)hFile, fsFromStart, bytesToMove); - if (theErr != noErr) - { - SetLastError(theErr); - return -1u; - } - - SetLastError(theErr); - return lOffSetLow; - } - else - { - SInt64 bytesToMove; - - if (pOffSetHigh != NULL) - bytesToMove = ((SInt64)*pOffSetHigh << 32) + lOffSetLow; - else - bytesToMove = lOffSetLow; - - SInt64 newPos; - - theErr = FSSetForkPosition((short)(int)hFile, fsFromLEOF, bytesToMove); - if (theErr != noErr) - { - SetLastError(theErr); - return -1u; - } - - theErr = FSGetForkPosition((short)(int)hFile, &newPos); - if (theErr != noErr) - { - SetLastError(theErr); - return -1u; - } - - if (pOffSetHigh != NULL) - *pOffSetHigh = newPos >> 32; - - SetLastError(theErr); - return newPos; - } + if (ulMethod == FILE_CURRENT) + { + SInt64 bytesToMove; + + if (pOffSetHigh != NULL) + { + bytesToMove = ((SInt64)*pOffSetHigh << 32) + lOffSetLow; + } + else + { + bytesToMove = lOffSetLow; + } + + SInt64 newPos; + + theErr = FSSetForkPosition((short)(long)hFile, fsFromMark, bytesToMove); + if (theErr != noErr) + { + SetLastError(theErr); + return -1u; + } + + theErr = FSGetForkPosition((short)(long)hFile, &newPos); + if (theErr != noErr) + { + SetLastError(theErr); + return -1u; + } + + if (pOffSetHigh != NULL) + { + *pOffSetHigh = newPos >> 32; + } + + SetLastError(theErr); + return newPos; + } + else if (ulMethod == FILE_BEGIN) + { + SInt64 bytesToMove; + + if (pOffSetHigh != NULL) + { + bytesToMove = ((SInt64)*pOffSetHigh << 32) + lOffSetLow; + } + else + { + bytesToMove = lOffSetLow; + } + + theErr = FSSetForkPosition((short)(long)hFile, fsFromStart, bytesToMove); + if (theErr != noErr) + { + SetLastError(theErr); + return -1u; + } + + SetLastError(theErr); + return lOffSetLow; + } + else + { + SInt64 bytesToMove; + + if (pOffSetHigh != NULL) + { + bytesToMove = ((SInt64)*pOffSetHigh << 32) + lOffSetLow; + } + else + { + bytesToMove = lOffSetLow; + } + + SInt64 newPos; + + theErr = FSSetForkPosition((short)(long)hFile, fsFromLEOF, bytesToMove); + if (theErr != noErr) + { + SetLastError(theErr); + return -1u; + } + + theErr = FSGetForkPosition((short)(long)hFile, &newPos); + if (theErr != noErr) + { + SetLastError(theErr); + return -1u; + } + + if (pOffSetHigh != NULL) + { + *pOffSetHigh = newPos >> 32; + } + + SetLastError(theErr); + return newPos; + } } /******************************************************************** -* SetEndOfFile +* SetEndOfFile ********************************************************************/ -BOOL SetEndOfFile( HANDLE hFile ) /* handle to file */ +BOOL SetEndOfFile( HANDLE hFile ) /* handle to file */ { - OSErr theErr; - - theErr = FSSetForkSize((short)(int)hFile, fsAtMark, 0); - - SetLastError(theErr); - - return theErr == noErr; + OSErr theErr; + + theErr = FSSetForkSize((short)(long)hFile, fsAtMark, 0); + + SetLastError(theErr); + + return theErr == noErr; } /******************************************************************** -* ReadFile -* pOverLapped: NULL +* ReadFile +* pOverLapped: NULL ********************************************************************/ -BOOL ReadFile( HANDLE hFile, /* handle to file */ - void *pBuffer, /* data buffer */ - DWORD ulLen, /* number of bytes to read */ - DWORD *ulRead, /* number of bytes read */ - void *pOverLapped ) /* overlapped buffer */ +BOOL ReadFile( HANDLE hFile, /* handle to file */ + void *pBuffer, /* data buffer */ + DWORD ulLen, /* number of bytes to read */ + DWORD *ulRead, /* number of bytes read */ + void *pOverLapped ) /* overlapped buffer */ { #pragma unused (pOverLapped) - ByteCount nbCharsRead; - OSErr theErr; - - nbCharsRead = ulLen; - theErr = FSReadFork((short)(int)hFile, fsAtMark, 0, nbCharsRead, pBuffer, &nbCharsRead); - *ulRead = nbCharsRead; - - SetLastError(theErr); - - return theErr == noErr; + ByteCount nbCharsRead; + OSErr theErr; + + nbCharsRead = ulLen; + theErr = FSReadFork((short)(long)hFile, fsAtMark, 0, nbCharsRead, pBuffer, &nbCharsRead); + *ulRead = nbCharsRead; + + SetLastError(theErr); + + return theErr == noErr; } /******************************************************************** -* WriteFile -* pOverLapped: NULL +* WriteFile +* pOverLapped: NULL ********************************************************************/ -BOOL WriteFile( HANDLE hFile, /* handle to file */ - const void *pBuffer, /* data buffer */ - DWORD ulLen, /* number of bytes to write */ - DWORD *ulWritten, /* number of bytes written */ - void *pOverLapped ) /* overlapped buffer */ +BOOL WriteFile( HANDLE hFile, /* handle to file */ + const void *pBuffer, /* data buffer */ + DWORD ulLen, /* number of bytes to write */ + DWORD *ulWritten, /* number of bytes written */ + void *pOverLapped ) /* overlapped buffer */ { #pragma unused (pOverLapped) - ByteCount nbCharsToWrite; - OSErr theErr; - - nbCharsToWrite = ulLen; - theErr = FSWriteFork((short)(int)hFile, fsAtMark, 0, nbCharsToWrite, pBuffer, &nbCharsToWrite); - *ulWritten = nbCharsToWrite; - - SetLastError(theErr); - - return theErr == noErr; + ByteCount nbCharsToWrite; + OSErr theErr; + + nbCharsToWrite = ulLen; + theErr = FSWriteFork((short)(long)hFile, fsAtMark, 0, nbCharsToWrite, pBuffer, &nbCharsToWrite); + *ulWritten = nbCharsToWrite; + + SetLastError(theErr); + + return theErr == noErr; } -// Check if a memory block is accessible for reading. It's probably too -// hard to check on Mac, so sorry, we'll just have to crash +// Check if a memory block is accessible for reading. I doubt it's +// possible to check on Mac, so sorry, we'll just have to crash BOOL IsBadReadPtr(const void * ptr, int size) { #pragma unused (ptr, size) - return FALSE; + return FALSE; } // Returns attributes of a file. Actually, it doesn't, it just checks if // the file exists, since that's all StormLib uses it for DWORD GetFileAttributes(const char * szFileName) { - FSRef theRef; - OSErr theErr; - - theErr = FSLocationFromFullPath(szFileName, &theRef); - - if (theErr != noErr) - return -1u; - else - return 0; + FSRef theRef; + OSErr theErr; + + theErr = FSPathMakeRef((const UInt8 *)szFileName, &theRef, NULL); + + if (theErr != noErr) + { + return -1u; + } + else + { + return 0; + } } #endif diff --git a/src/tools/stuffextract/StormLib/bzip2/blocksort.c b/src/tools/stuffextract/StormLib/bzip2/blocksort.c index 33ec9f5..bd2dec1 100644 --- a/src/tools/stuffextract/StormLib/bzip2/blocksort.c +++ b/src/tools/stuffextract/StormLib/bzip2/blocksort.c @@ -4,66 +4,19 @@ /*--- blocksort.c ---*/ /*-------------------------------------------------------------*/ -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. - - To get some idea how the block sorting algorithms in this file - work, read my paper - On the Performance of BWT Sorting Algorithms - in Proceedings of the IEEE Data Compression Conference 2000, - Snowbird, Utah, USA, 27-30 March 2000. The main sort in this - file implements the algorithm called cache in the paper. ---*/ + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ #include "bzlib_private.h" @@ -155,7 +108,7 @@ void fallbackQSort3 ( UInt32* fmap, while (sp > 0) { - AssertH ( sp < FALLBACK_QSORT_STACK_SIZE, 1004 ); + AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 ); fpop ( lo, hi ); if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { @@ -690,7 +643,7 @@ void mainQSort3 ( UInt32* ptr, while (sp > 0) { - AssertH ( sp < MAIN_QSORT_STACK_SIZE, 1001 ); + AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 ); mpop ( lo, hi, d ); if (hi - lo < MAIN_QSORT_SMALL_THRESH || diff --git a/src/tools/stuffextract/StormLib/bzip2/bzip2.c b/src/tools/stuffextract/StormLib/bzip2/bzip2.c index 79f87a5..3904107 100644 --- a/src/tools/stuffextract/StormLib/bzip2/bzip2.c +++ b/src/tools/stuffextract/StormLib/bzip2/bzip2.c @@ -3,118 +3,26 @@ /*--- A block-sorting, lossless compressor bzip2.c ---*/ /*-----------------------------------------------------------*/ -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ -/*----------------------------------------------------*/ -/*--- IMPORTANT ---*/ -/*----------------------------------------------------*/ - -/*-- - WARNING: - This program and library (attempts to) compress data by - performing several non-trivial transformations on it. - Unless you are 100% familiar with *all* the algorithms - contained herein, and with the consequences of modifying them, - you should NOT meddle with the compression or decompression - machinery. Incorrect changes can and very likely *will* - lead to disasterous loss of data. - - DISCLAIMER: - I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE - USE OF THIS PROGRAM, HOWSOEVER CAUSED. - - Every compression of a file implies an assumption that the - compressed file can be decompressed to reproduce the original. - Great efforts in design, coding and testing have been made to - ensure that this program works correctly. However, the - complexity of the algorithms, and, in particular, the presence - of various special cases in the code which occur with very low - but non-zero probability make it impossible to rule out the - possibility of bugs remaining in the program. DO NOT COMPRESS - ANY DATA WITH THIS PROGRAM AND/OR LIBRARY UNLESS YOU ARE PREPARED - TO ACCEPT THE POSSIBILITY, HOWEVER SMALL, THAT THE DATA WILL - NOT BE RECOVERABLE. - - That is not to say this program is inherently unreliable. - Indeed, I very much hope the opposite is true. bzip2/libbzip2 - has been carefully constructed and extensively tested. - - PATENTS: - To the best of my knowledge, bzip2/libbzip2 does not use any - patented algorithms. However, I do not have the resources - available to carry out a full patent search. Therefore I cannot - give any guarantee of the above statement. ---*/ - - - -/*----------------------------------------------------*/ -/*--- and now for something much more pleasant :-) ---*/ -/*----------------------------------------------------*/ - -/*---------------------------------------------*/ -/*-- - Place a 1 beside your platform, and 0 elsewhere. ---*/ - -/*-- - Generic 32-bit Unix. - Also works on 64-bit Unix boxes. - This is the default. ---*/ +/* Place a 1 beside your platform, and 0 elsewhere. + Generic 32-bit Unix. + Also works on 64-bit Unix boxes. + This is the default. +*/ #define BZ_UNIX 1 /*-- @@ -302,16 +210,17 @@ Char progNameReally[FILE_NAME_LEN]; FILE *outputHandleJustInCase; Int32 workFactor; -static void panic ( Char* ) NORETURN; -static void ioError ( void ) NORETURN; -static void outOfMemory ( void ) NORETURN; -static void configError ( void ) NORETURN; -static void crcError ( void ) NORETURN; -static void cleanUpAndFail ( Int32 ) NORETURN; -static void compressedStreamEOF ( void ) NORETURN; +static void panic ( const Char* ) NORETURN; +static void ioError ( void ) NORETURN; +static void outOfMemory ( void ) NORETURN; +static void configError ( void ) NORETURN; +static void crcError ( void ) NORETURN; +static void cleanUpAndFail ( Int32 ) NORETURN; +static void compressedStreamEOF ( void ) NORETURN; static void copyFileName ( Char*, Char* ); static void* myMalloc ( Int32 ); +static void applySavedFileAttrToOutputFile ( IntNative fd ); @@ -457,6 +366,9 @@ void compressStream ( FILE *stream, FILE *zStream ) ret = fflush ( zStream ); if (ret == EOF) goto errhandler_io; if (zStream != stdout) { + Int32 fd = fileno ( zStream ); + if (fd < 0) goto errhandler_io; + applySavedFileAttrToOutputFile ( fd ); ret = fclose ( zStream ); outputHandleJustInCase = NULL; if (ret == EOF) goto errhandler_io; @@ -569,6 +481,11 @@ Bool uncompressStream ( FILE *zStream, FILE *stream ) closeok: if (ferror(zStream)) goto errhandler_io; + if (stream != stdout) { + Int32 fd = fileno ( stream ); + if (fd < 0) goto errhandler_io; + applySavedFileAttrToOutputFile ( fd ); + } ret = fclose ( zStream ); if (ret == EOF) goto errhandler_io; @@ -826,7 +743,7 @@ void cleanUpAndFail ( Int32 ec ) /*---------------------------------------------*/ static -void panic ( Char* s ) +void panic ( const Char* s ) { fprintf ( stderr, "\n%s: PANIC -- internal consistency error:\n" @@ -1039,6 +956,7 @@ Bool fileExists ( Char* name ) For non-Unix platforms, if we are not worrying about security issues, simple this simply behaves like fopen. */ +static FILE* fopen_output_safely ( Char* name, const char* mode ) { # if BZ_UNIX @@ -1129,7 +1047,7 @@ void saveInputFileMetaInfo ( Char *srcName ) static -void applySavedMetaInfoToOutputFile ( Char *dstName ) +void applySavedTimeInfoToOutputFile ( Char *dstName ) { # if BZ_UNIX IntNative retVal; @@ -1138,13 +1056,21 @@ void applySavedMetaInfoToOutputFile ( Char *dstName ) uTimBuf.actime = fileMetaInfo.st_atime; uTimBuf.modtime = fileMetaInfo.st_mtime; - retVal = chmod ( dstName, fileMetaInfo.st_mode ); - ERROR_IF_NOT_ZERO ( retVal ); - retVal = utime ( dstName, &uTimBuf ); ERROR_IF_NOT_ZERO ( retVal ); +# endif +} - retVal = chown ( dstName, fileMetaInfo.st_uid, fileMetaInfo.st_gid ); +static +void applySavedFileAttrToOutputFile ( IntNative fd ) +{ +# if BZ_UNIX + IntNative retVal; + + retVal = fchmod ( fd, fileMetaInfo.st_mode ); + ERROR_IF_NOT_ZERO ( retVal ); + + (void) fchown ( fd, fileMetaInfo.st_uid, fileMetaInfo.st_gid ); /* chown() will in many cases return with EPERM, which can be safely ignored. */ @@ -1175,13 +1101,13 @@ Bool containsDubiousChars ( Char* name ) /*---------------------------------------------*/ #define BZ_N_SUFFIX_PAIRS 4 -Char* zSuffix[BZ_N_SUFFIX_PAIRS] +const Char* zSuffix[BZ_N_SUFFIX_PAIRS] = { ".bz2", ".bz", ".tbz2", ".tbz" }; -Char* unzSuffix[BZ_N_SUFFIX_PAIRS] +const Char* unzSuffix[BZ_N_SUFFIX_PAIRS] = { "", "", ".tar", ".tar" }; static -Bool hasSuffix ( Char* s, Char* suffix ) +Bool hasSuffix ( Char* s, const Char* suffix ) { Int32 ns = strlen(s); Int32 nx = strlen(suffix); @@ -1192,7 +1118,8 @@ Bool hasSuffix ( Char* s, Char* suffix ) static Bool mapSuffix ( Char* name, - Char* oldSuffix, Char* newSuffix ) + const Char* oldSuffix, + const Char* newSuffix ) { if (!hasSuffix(name,oldSuffix)) return False; name[strlen(name)-strlen(oldSuffix)] = 0; @@ -1217,8 +1144,8 @@ void compress ( Char *name ) switch (srcMode) { case SM_I2O: - copyFileName ( inName, "(stdin)" ); - copyFileName ( outName, "(stdout)" ); + copyFileName ( inName, (Char*)"(stdin)" ); + copyFileName ( outName, (Char*)"(stdout)" ); break; case SM_F2F: copyFileName ( inName, name ); @@ -1227,7 +1154,7 @@ void compress ( Char *name ) break; case SM_F2O: copyFileName ( inName, name ); - copyFileName ( outName, "(stdout)" ); + copyFileName ( outName, (Char*)"(stdout)" ); break; } @@ -1370,7 +1297,7 @@ void compress ( Char *name ) /*--- If there was an I/O error, we won't get here. ---*/ if ( srcMode == SM_F2F ) { - applySavedMetaInfoToOutputFile ( outName ); + applySavedTimeInfoToOutputFile ( outName ); deleteOutputOnInterrupt = False; if ( !keepInputFiles ) { IntNative retVal = remove ( inName ); @@ -1401,8 +1328,8 @@ void uncompress ( Char *name ) cantGuess = False; switch (srcMode) { case SM_I2O: - copyFileName ( inName, "(stdin)" ); - copyFileName ( outName, "(stdout)" ); + copyFileName ( inName, (Char*)"(stdin)" ); + copyFileName ( outName, (Char*)"(stdout)" ); break; case SM_F2F: copyFileName ( inName, name ); @@ -1415,7 +1342,7 @@ void uncompress ( Char *name ) break; case SM_F2O: copyFileName ( inName, name ); - copyFileName ( outName, "(stdout)" ); + copyFileName ( outName, (Char*)"(stdout)" ); break; } @@ -1548,7 +1475,7 @@ void uncompress ( Char *name ) /*--- If there was an I/O error, we won't get here. ---*/ if ( magicNumberOK ) { if ( srcMode == SM_F2F ) { - applySavedMetaInfoToOutputFile ( outName ); + applySavedTimeInfoToOutputFile ( outName ); deleteOutputOnInterrupt = False; if ( !keepInputFiles ) { IntNative retVal = remove ( inName ); @@ -1593,9 +1520,9 @@ void testf ( Char *name ) if (name == NULL && srcMode != SM_I2O) panic ( "testf: bad modes\n" ); - copyFileName ( outName, "(none)" ); + copyFileName ( outName, (Char*)"(none)" ); switch (srcMode) { - case SM_I2O: copyFileName ( inName, "(stdin)" ); break; + case SM_I2O: copyFileName ( inName, (Char*)"(stdin)" ); break; case SM_F2F: copyFileName ( inName, name ); break; case SM_F2O: copyFileName ( inName, name ); break; } @@ -1678,11 +1605,11 @@ void license ( void ) "bzip2, a block-sorting file compressor. " "Version %s.\n" " \n" - " Copyright (C) 1996-2005 by Julian Seward.\n" + " Copyright (C) 1996-2007 by Julian Seward.\n" " \n" " This program is free software; you can redistribute it and/or modify\n" " it under the terms set out in the LICENSE file, which is included\n" - " in the bzip2-1.0 source distribution.\n" + " in the bzip2-1.0.5 source distribution.\n" " \n" " This program is distributed in the hope that it will be useful,\n" " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" @@ -1885,8 +1812,8 @@ IntNative main ( IntNative argc, Char *argv[] ) # endif # endif - copyFileName ( inName, "(none)" ); - copyFileName ( outName, "(none)" ); + copyFileName ( inName, (Char*)"(none)" ); + copyFileName ( outName, (Char*)"(none)" ); copyFileName ( progNameReally, argv[0] ); progName = &progNameReally[0]; @@ -1898,8 +1825,8 @@ IntNative main ( IntNative argc, Char *argv[] ) expand filename wildcards in arg list. --*/ argList = NULL; - addFlagsFromEnvVar ( &argList, "BZIP2" ); - addFlagsFromEnvVar ( &argList, "BZIP" ); + addFlagsFromEnvVar ( &argList, (Char*)"BZIP2" ); + addFlagsFromEnvVar ( &argList, (Char*)"BZIP" ); for (i = 1; i <= argc-1; i++) APPEND_FILESPEC(argList, argv[i]); diff --git a/src/tools/stuffextract/StormLib/bzip2/bzip2recover.c b/src/tools/stuffextract/StormLib/bzip2/bzip2recover.c index 5cd405d..5f6d621 100644 --- a/src/tools/stuffextract/StormLib/bzip2/bzip2recover.c +++ b/src/tools/stuffextract/StormLib/bzip2/bzip2recover.c @@ -1,56 +1,24 @@ - /*-----------------------------------------------------------*/ /*--- Block recoverer program for bzip2 ---*/ /*--- bzip2recover.c ---*/ /*-----------------------------------------------------------*/ -/*-- - This program is bzip2recover, a program to attempt data - salvage from damaged files created by the accompanying - bzip2-1.0.3 program. +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0.3 of 15 February 2005 ---*/ - -/*-- - This program is a complete hack and should be rewritten - properly. It isn't very complicated. ---*/ +/* This program is a complete hack and should be rewritten properly. + It isn't very complicated. */ #include #include @@ -114,7 +82,7 @@ MaybeUInt64 bytesIn = 0; /*---------------------------------------------------*/ /*---------------------------------------------*/ -void readError ( void ) +static void readError ( void ) { fprintf ( stderr, "%s: I/O error reading `%s', possible reason follows.\n", @@ -127,7 +95,7 @@ void readError ( void ) /*---------------------------------------------*/ -void writeError ( void ) +static void writeError ( void ) { fprintf ( stderr, "%s: I/O error reading `%s', possible reason follows.\n", @@ -140,7 +108,7 @@ void writeError ( void ) /*---------------------------------------------*/ -void mallocFail ( Int32 n ) +static void mallocFail ( Int32 n ) { fprintf ( stderr, "%s: malloc failed on request for %d bytes.\n", @@ -152,7 +120,7 @@ void mallocFail ( Int32 n ) /*---------------------------------------------*/ -void tooManyBlocks ( Int32 max_handled_blocks ) +static void tooManyBlocks ( Int32 max_handled_blocks ) { fprintf ( stderr, "%s: `%s' appears to contain more than %d blocks\n", @@ -183,7 +151,7 @@ typedef /*---------------------------------------------*/ -BitStream* bsOpenReadStream ( FILE* stream ) +static BitStream* bsOpenReadStream ( FILE* stream ) { BitStream *bs = malloc ( sizeof(BitStream) ); if (bs == NULL) mallocFail ( sizeof(BitStream) ); @@ -196,7 +164,7 @@ BitStream* bsOpenReadStream ( FILE* stream ) /*---------------------------------------------*/ -BitStream* bsOpenWriteStream ( FILE* stream ) +static BitStream* bsOpenWriteStream ( FILE* stream ) { BitStream *bs = malloc ( sizeof(BitStream) ); if (bs == NULL) mallocFail ( sizeof(BitStream) ); @@ -209,7 +177,7 @@ BitStream* bsOpenWriteStream ( FILE* stream ) /*---------------------------------------------*/ -void bsPutBit ( BitStream* bs, Int32 bit ) +static void bsPutBit ( BitStream* bs, Int32 bit ) { if (bs->buffLive == 8) { Int32 retVal = putc ( (UChar) bs->buffer, bs->handle ); @@ -228,7 +196,7 @@ void bsPutBit ( BitStream* bs, Int32 bit ) /*-- Returns 0 or 1, or 2 to indicate EOF. --*/ -Int32 bsGetBit ( BitStream* bs ) +static Int32 bsGetBit ( BitStream* bs ) { if (bs->buffLive > 0) { bs->buffLive --; @@ -247,7 +215,7 @@ Int32 bsGetBit ( BitStream* bs ) /*---------------------------------------------*/ -void bsClose ( BitStream* bs ) +static void bsClose ( BitStream* bs ) { Int32 retVal; @@ -271,7 +239,7 @@ void bsClose ( BitStream* bs ) /*---------------------------------------------*/ -void bsPutUChar ( BitStream* bs, UChar c ) +static void bsPutUChar ( BitStream* bs, UChar c ) { Int32 i; for (i = 7; i >= 0; i--) @@ -280,7 +248,7 @@ void bsPutUChar ( BitStream* bs, UChar c ) /*---------------------------------------------*/ -void bsPutUInt32 ( BitStream* bs, UInt32 c ) +static void bsPutUInt32 ( BitStream* bs, UInt32 c ) { Int32 i; @@ -290,7 +258,7 @@ void bsPutUInt32 ( BitStream* bs, UInt32 c ) /*---------------------------------------------*/ -Bool endsInBz2 ( Char* name ) +static Bool endsInBz2 ( Char* name ) { Int32 n = strlen ( name ); if (n <= 4) return False; @@ -345,7 +313,7 @@ Int32 main ( Int32 argc, Char** argv ) inFileName[0] = outFileName[0] = 0; fprintf ( stderr, - "bzip2recover 1.0.3: extracts blocks from damaged .bz2 files.\n" ); + "bzip2recover 1.0.5: extracts blocks from damaged .bz2 files.\n" ); if (argc != 2) { fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n", diff --git a/src/tools/stuffextract/StormLib/bzip2/bzlib.c b/src/tools/stuffextract/StormLib/bzip2/bzlib.c index 195f51a..b98f3e5 100644 --- a/src/tools/stuffextract/StormLib/bzip2/bzlib.c +++ b/src/tools/stuffextract/StormLib/bzip2/bzlib.c @@ -4,76 +4,31 @@ /*--- bzlib.c ---*/ /*-------------------------------------------------------------*/ -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - -/*-- - CHANGES - ~~~~~~~ - 0.9.0 -- original version. + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ +/* CHANGES + 0.9.0 -- original version. 0.9.0a/b -- no changes in this file. + 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). + fixed bzWrite/bzRead to ignore zero-length requests. + fixed bzread to correctly handle read requests after EOF. + wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. +*/ - 0.9.0c - * made zero-length BZ_FLUSH work correctly in bzCompress(). - * fixed bzWrite/bzRead to ignore zero-length requests. - * fixed bzread to correctly handle read requests after EOF. - * wrong parameter order in call to bzDecompressInit in - bzBuffToBuffDecompress. Fixed. ---*/ - -#define _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_WARNINGS #include "bzlib_private.h" @@ -94,7 +49,7 @@ void BZ2_bz__AssertH__fail ( int errcode ) "component, you should also report this bug to the author(s)\n" "of that program. Please make an effort to report this bug;\n" "timely and accurate bug reports eventually lead to higher\n" - "quality software. Thanks. Julian Seward, 15 February 2005.\n\n", + "quality software. Thanks. Julian Seward, 10 December 2007.\n\n", errcode, BZ2_bzlibVersion() ); @@ -644,6 +599,7 @@ Bool unRLE_obuf_to_output_FAST ( DState* s ) UInt32 c_tPos = s->tPos; char* cs_next_out = s->strm->next_out; unsigned int cs_avail_out = s->strm->avail_out; + Int32 ro_blockSize100k = s->blockSize100k; /* end restore */ UInt32 avail_out_INIT = cs_avail_out; @@ -1395,8 +1351,7 @@ int BZ_API(BZ2_bzBuffToBuffDecompress) /*---------------------------------------------------*/ /*-- - Code contributed by Yoshioka Tsuneo - (QWF00133@niftyserve.or.jp/tsuneo-y@is.aist-nara.ac.jp), + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) to support better zlib compatibility. This code is not _officially_ part of libbzip2 (yet); I haven't tested it, documented it, or considered the @@ -1407,7 +1362,7 @@ int BZ_API(BZ2_bzBuffToBuffDecompress) /*---------------------------------------------------*/ /*-- - return version like "0.9.0c". + return version like "0.9.5d, 4-Sept-1999". --*/ const char * BZ_API(BZ2_bzlibVersion)(void) { @@ -1560,9 +1515,10 @@ int BZ_API(BZ2_bzflush) (BZFILE *b) void BZ_API(BZ2_bzclose) (BZFILE* b) { int bzerr; - FILE *fp = ((bzFile *)b)->handle; + FILE *fp; if (b==NULL) {return;} + fp = ((bzFile *)b)->handle; if(((bzFile*)b)->writing){ BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); if(bzerr != BZ_OK){ @@ -1581,7 +1537,7 @@ void BZ_API(BZ2_bzclose) (BZFILE* b) /*-- return last error code --*/ -static char *bzerrorstrings[] = { +static const char *bzerrorstrings[] = { "OK" ,"SEQUENCE_ERROR" ,"PARAM_ERROR" diff --git a/src/tools/stuffextract/StormLib/bzip2/bzlib.h b/src/tools/stuffextract/StormLib/bzip2/bzlib.h index 3237243..c5b75d6 100644 --- a/src/tools/stuffextract/StormLib/bzip2/bzlib.h +++ b/src/tools/stuffextract/StormLib/bzip2/bzlib.h @@ -4,59 +4,19 @@ /*--- bzlib.h ---*/ /*-------------------------------------------------------------*/ -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ #ifndef _BZLIB_H @@ -262,8 +222,7 @@ BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( /*-- - Code contributed by Yoshioka Tsuneo - (QWF00133@niftyserve.or.jp/tsuneo-y@is.aist-nara.ac.jp), + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) to support better zlib compatibility. This code is not _officially_ part of libbzip2 (yet); I haven't tested it, documented it, or considered the diff --git a/src/tools/stuffextract/StormLib/bzip2/bzlib_private.h b/src/tools/stuffextract/StormLib/bzip2/bzlib_private.h index ca76fe6..2342787 100644 --- a/src/tools/stuffextract/StormLib/bzip2/bzlib_private.h +++ b/src/tools/stuffextract/StormLib/bzip2/bzlib_private.h @@ -4,59 +4,19 @@ /*--- bzlib_private.h ---*/ /*-------------------------------------------------------------*/ -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ #ifndef _BZLIB_PRIVATE_H @@ -76,7 +36,7 @@ /*-- General stuff. --*/ -#define BZ_VERSION "1.0.3, 15-Feb-2005" +#define BZ_VERSION "1.0.5, 10-Dec-2007" typedef char Char; typedef unsigned char Bool; @@ -94,9 +54,11 @@ typedef unsigned short UInt16; #endif #ifndef BZ_NO_STDIO + extern void BZ2_bz__AssertH__fail ( int errcode ); #define AssertH(cond,errcode) \ { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } + #if BZ_DEBUG #define AssertD(cond,msg) \ { if (!(cond)) { \ @@ -107,6 +69,7 @@ extern void BZ2_bz__AssertH__fail ( int errcode ); #else #define AssertD(cond,msg) /* */ #endif + #define VPrintf0(zf) \ fprintf(stderr,zf) #define VPrintf1(zf,za1) \ @@ -119,17 +82,20 @@ extern void BZ2_bz__AssertH__fail ( int errcode ); fprintf(stderr,zf,za1,za2,za3,za4) #define VPrintf5(zf,za1,za2,za3,za4,za5) \ fprintf(stderr,zf,za1,za2,za3,za4,za5) + #else + extern void bz_internal_error ( int errcode ); #define AssertH(cond,errcode) \ { if (!(cond)) bz_internal_error ( errcode ); } -#define AssertD(cond,msg) /* */ -#define VPrintf0(zf) /* */ -#define VPrintf1(zf,za1) /* */ -#define VPrintf2(zf,za1,za2) /* */ -#define VPrintf3(zf,za1,za2,za3) /* */ -#define VPrintf4(zf,za1,za2,za3,za4) /* */ -#define VPrintf5(zf,za1,za2,za3,za4,za5) /* */ +#define AssertD(cond,msg) do { } while (0) +#define VPrintf0(zf) do { } while (0) +#define VPrintf1(zf,za1) do { } while (0) +#define VPrintf2(zf,za1,za2) do { } while (0) +#define VPrintf3(zf,za1,za2,za3) do { } while (0) +#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0) +#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0) + #endif @@ -476,11 +442,15 @@ typedef /*-- Macros for decompression. --*/ #define BZ_GET_FAST(cccc) \ + /* c_tPos is unsigned, hence test < 0 is pointless. */ \ + if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \ s->tPos = s->tt[s->tPos]; \ cccc = (UChar)(s->tPos & 0xff); \ s->tPos >>= 8; #define BZ_GET_FAST_C(cccc) \ + /* c_tPos is unsigned, hence test < 0 is pointless. */ \ + if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \ c_tPos = c_tt[c_tPos]; \ cccc = (UChar)(c_tPos & 0xff); \ c_tPos >>= 8; @@ -503,8 +473,10 @@ typedef (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) #define BZ_GET_SMALL(cccc) \ - cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ - s->tPos = GET_LL(s->tPos); + /* c_tPos is unsigned, hence test < 0 is pointless. */ \ + if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \ + cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ + s->tPos = GET_LL(s->tPos); /*-- externs for decompression. --*/ diff --git a/src/tools/stuffextract/StormLib/bzip2/compress.c b/src/tools/stuffextract/StormLib/bzip2/compress.c index 7e0c291..8c80a07 100644 --- a/src/tools/stuffextract/StormLib/bzip2/compress.c +++ b/src/tools/stuffextract/StormLib/bzip2/compress.c @@ -4,71 +4,27 @@ /*--- compress.c ---*/ /*-------------------------------------------------------------*/ -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - -/*-- - CHANGES - ~~~~~~~ - 0.9.0 -- original version. - - 0.9.0a/b -- no changes in this file. - - 0.9.0c - * changed setting of nGroups in sendMTFValues() so as to - do a bit better on small files ---*/ +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- changed setting of nGroups in sendMTFValues() + so as to do a bit better on small files +*/ #include "bzlib_private.h" diff --git a/src/tools/stuffextract/StormLib/bzip2/crctable.c b/src/tools/stuffextract/StormLib/bzip2/crctable.c index b6dadfc..215687b 100644 --- a/src/tools/stuffextract/StormLib/bzip2/crctable.c +++ b/src/tools/stuffextract/StormLib/bzip2/crctable.c @@ -4,59 +4,19 @@ /*--- crctable.c ---*/ /*-------------------------------------------------------------*/ -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ #include "bzlib_private.h" diff --git a/src/tools/stuffextract/StormLib/bzip2/decompress.c b/src/tools/stuffextract/StormLib/bzip2/decompress.c index 81c3d2c..bba5e0f 100644 --- a/src/tools/stuffextract/StormLib/bzip2/decompress.c +++ b/src/tools/stuffextract/StormLib/bzip2/decompress.c @@ -4,59 +4,19 @@ /*--- decompress.c ---*/ /*-------------------------------------------------------------*/ -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ #include "bzlib_private.h" diff --git a/src/tools/stuffextract/StormLib/bzip2/dlltest.c b/src/tools/stuffextract/StormLib/bzip2/dlltest.c index eb86bb6..4e27da2 100644 --- a/src/tools/stuffextract/StormLib/bzip2/dlltest.c +++ b/src/tools/stuffextract/StormLib/bzip2/dlltest.c @@ -1,9 +1,8 @@ /* minibz2 libbz2.dll test program. - by Yoshioka Tsuneo(QWF00133@nifty.ne.jp/tsuneo-y@is.aist-nara.ac.jp) - This file is Public Domain. - welcome any email to me. + by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + This file is Public Domain. Welcome any email to me. usage: minibz2 [-d] [-{1,2,..9}] [[srcfilename] destfilename] */ diff --git a/src/tools/stuffextract/StormLib/bzip2/huffman.c b/src/tools/stuffextract/StormLib/bzip2/huffman.c index 5bf190b..87e79e3 100644 --- a/src/tools/stuffextract/StormLib/bzip2/huffman.c +++ b/src/tools/stuffextract/StormLib/bzip2/huffman.c @@ -4,59 +4,19 @@ /*--- huffman.c ---*/ /*-------------------------------------------------------------*/ -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ #include "bzlib_private.h" diff --git a/src/tools/stuffextract/StormLib/bzip2/mk251.c b/src/tools/stuffextract/StormLib/bzip2/mk251.c index 205778a..39e94c0 100644 --- a/src/tools/stuffextract/StormLib/bzip2/mk251.c +++ b/src/tools/stuffextract/StormLib/bzip2/mk251.c @@ -5,6 +5,21 @@ case, which is fixed in this version (1.0.2) and above. */ +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + #include int main () diff --git a/src/tools/stuffextract/StormLib/bzip2/randtable.c b/src/tools/stuffextract/StormLib/bzip2/randtable.c index 940462d..068b763 100644 --- a/src/tools/stuffextract/StormLib/bzip2/randtable.c +++ b/src/tools/stuffextract/StormLib/bzip2/randtable.c @@ -4,59 +4,19 @@ /*--- randtable.c ---*/ /*-------------------------------------------------------------*/ -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. - Copyright (C) 1996-2005 Julian R Seward. All rights reserved. + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ #include "bzlib_private.h" diff --git a/src/tools/stuffextract/StormLib/bzip2/spewG.c b/src/tools/stuffextract/StormLib/bzip2/spewG.c index 7934e76..5892b92 100644 --- a/src/tools/stuffextract/StormLib/bzip2/spewG.c +++ b/src/tools/stuffextract/StormLib/bzip2/spewG.c @@ -9,6 +9,21 @@ (but is otherwise harmless). */ +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + #define _FILE_OFFSET_BITS 64 #include diff --git a/src/tools/stuffextract/StormLib/bzip2/unzcrash.c b/src/tools/stuffextract/StormLib/bzip2/unzcrash.c index f0f17fc..a1b7546 100644 --- a/src/tools/stuffextract/StormLib/bzip2/unzcrash.c +++ b/src/tools/stuffextract/StormLib/bzip2/unzcrash.c @@ -8,11 +8,26 @@ This should not cause any invalid memory accesses. If it does, I want to know about it! - p.s. As you can see from the above description, the process is + PS. As you can see from the above description, the process is incredibly slow. A file of size eg 5KB will cause it to run for many hours. */ +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.5 of 10 December 2007 + Copyright (C) 1996-2007 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + #include #include #include "bzlib.h" diff --git a/src/tools/stuffextract/StormLib/huffman/huff.cpp b/src/tools/stuffextract/StormLib/huffman/huff.cpp index 612fcb0..91dcf78 100644 --- a/src/tools/stuffextract/StormLib/huffman/huff.cpp +++ b/src/tools/stuffextract/StormLib/huffman/huff.cpp @@ -133,54 +133,86 @@ void TOutputStream::PutBits(unsigned long dwBuff, unsigned int nPutBits) //----------------------------------------------------------------------------- // TInputStream functions - + // Gets one bit from input stream unsigned long TInputStream::GetBit() { - unsigned long dwBit = (dwBitBuff & 1); - - dwBitBuff >>= 1; - if(--nBits == 0) + unsigned long dwOneBit = 0; + + // Ensure that the input stream is reloaded, if there are no bits left + if(BitCount == 0) { - dwBitBuff = BSWAP_INT32_UNSIGNED(*(unsigned long *)pbInBuffer); - pbInBuffer += sizeof(unsigned long); - nBits = 32; + // Refill the bit buffer + BitBuffer = *pbInBuffer++; + BitCount = 8; } - return dwBit; + + // Copy the bit from bit buffer to the variable + dwOneBit = (BitBuffer & 0x01); + BitBuffer >>= 1; + BitCount--; + + return dwOneBit; } -// Gets 7 bits from the stream +// Gets 7 bits from the stream. DOES NOT remove the bits from input stream unsigned long TInputStream::Get7Bits() { - if(nBits <= 7) + unsigned long dwReloadByte = 0; + + // If there is not enough bits to get the value, + // we have to add 8 more bits from the input buffer + if(BitCount < 7) { - dwBitBuff |= BSWAP_INT16_UNSIGNED(*(unsigned short *)pbInBuffer) << nBits; - pbInBuffer += sizeof(unsigned short); - nBits += 16; + dwReloadByte = *pbInBuffer++; + BitBuffer |= dwReloadByte << BitCount; + BitCount += 8; } - - // Get 7 bits from input stream - return (dwBitBuff & 0x7F); + + // Return the first available 7 bits. DO NOT remove them from the input stream + return (BitBuffer & 0x7F); } // Gets the whole byte from the input stream. unsigned long TInputStream::Get8Bits() { - unsigned long dwOneByte; - - if(nBits <= 8) + unsigned long dwReloadByte = 0; + unsigned long dwOneByte = 0; + + // If there is not enough bits to get the value, + // we have to add 8 more bits from the input buffer + if(BitCount < 8) { - dwBitBuff |= BSWAP_INT16_UNSIGNED(*(unsigned short *)pbInBuffer) << nBits; - pbInBuffer += sizeof(unsigned short); - nBits += 16; + dwReloadByte = *pbInBuffer++; + BitBuffer |= dwReloadByte << BitCount; + BitCount += 8; } - - dwOneByte = (dwBitBuff & 0xFF); - dwBitBuff >>= 8; - nBits -= 8; + + // Return the lowest 8 its + dwOneByte = (BitBuffer & 0xFF); + BitBuffer >>= 8; + BitCount -= 8; return dwOneByte; } - + +void TInputStream::SkipBits(unsigned int dwBitsToSkip) +{ + unsigned long dwReloadByte = 0; + + // If there is not enough bits in the buffer, + // we have to add 8 more bits from the input buffer + if(BitCount < dwBitsToSkip) + { + dwReloadByte = *pbInBuffer++; + BitBuffer |= dwReloadByte << BitCount; + BitCount += 8; + } + + // Skip the remaining bits + BitBuffer >>= dwBitsToSkip; + BitCount -= dwBitsToSkip; +} + //----------------------------------------------------------------------------- // Functions for huffmann tree items @@ -990,13 +1022,11 @@ unsigned int THuffmannTree::DoDecompression(unsigned char * pbOutBuffer, unsigne { if(qd->nBits > 7) { - is->dwBitBuff >>= 7; - is->nBits -= 7; + is->SkipBits(7); pItem1 = qd->pItem; goto _1500E549; } - is->dwBitBuff >>= qd->nBits; - is->nBits -= qd->nBits; + is->SkipBits(qd->nBits); nDcmpByte = qd->dcmpByte; } else @@ -1450,4 +1480,4 @@ unsigned char THuffmannTree::Table1502A630[] = 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; \ No newline at end of file +}; diff --git a/src/tools/stuffextract/StormLib/huffman/huff.h b/src/tools/stuffextract/StormLib/huffman/huff.h index f06aa77..a133424 100644 --- a/src/tools/stuffextract/StormLib/huffman/huff.h +++ b/src/tools/stuffextract/StormLib/huffman/huff.h @@ -23,7 +23,7 @@ #define PTR_NOT(ptr) (THTreeItem *)(~(DWORD_PTR)(ptr)) #define PTR_PTR(ptr) ((THTreeItem *)(ptr)) -#define PTR_INT(ptr) (LONG_PTR)(ptr) +#define PTR_INT(ptr) (INT_PTR)(ptr) #ifndef NULL #define NULL 0 @@ -40,10 +40,11 @@ class TInputStream unsigned long GetBit(); unsigned long Get7Bits(); unsigned long Get8Bits(); + void SkipBits(unsigned int BitCount); unsigned char * pbInBuffer; // 00 - Input data - unsigned long dwBitBuff; // 04 - Input bit buffer - unsigned int nBits; // 08 - Number of bits remaining in 'dwValue' + unsigned long BitBuffer; // 04 - Input bit buffer + unsigned int BitCount; // 08 - Number of bits remaining in 'dwBitBuff' }; // Output stream for Huffmann compression diff --git a/src/tools/stuffextract/StormLib/pklib/crc32.c b/src/tools/stuffextract/StormLib/pklib/crc32.c new file mode 100644 index 0000000..a155513 --- /dev/null +++ b/src/tools/stuffextract/StormLib/pklib/crc32.c @@ -0,0 +1,72 @@ +/*****************************************************************************/ +/* crc32.c Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Pkware Data Compression Library Version 1.11 */ +/* Dissassembled method crc32 - cdecl version */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 09.04.03 1.00 Lad The first version of crc32.c */ +/* 02.05.03 1.00 Lad Stress test done */ +/*****************************************************************************/ + +#include "pklib.h" + +static char CopyRight[] = "PKWARE Data Compression Library for Win32\r\n" + "Copyright 1989-1995 PKWARE Inc. All Rights Reserved\r\n" + "Patent No. 5,051,745\r\n" + "PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n" + "Version 1.11\r\n"; + +static unsigned long crc_table[] = +{ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + + +unsigned long PKEXPORT crc32pk(char * buffer, unsigned int * psize, unsigned long * old_crc) +{ + unsigned int size = *psize; + unsigned long ch; + unsigned long crc_value = *old_crc; + + while(size-- != 0) + { + ch = *buffer++ ^ (char)crc_value; + crc_value >>= 8; + + crc_value = crc_table[ch & 0x0FF] ^ crc_value; + } + return crc_value; +} diff --git a/src/tools/stuffextract/StormLib/pklib/pklib.h b/src/tools/stuffextract/StormLib/pklib/pklib.h index 881262e..8e58fc7 100644 --- a/src/tools/stuffextract/StormLib/pklib/pklib.h +++ b/src/tools/stuffextract/StormLib/pklib/pklib.h @@ -29,7 +29,11 @@ // Define calling convention #ifndef PKEXPORT -#define PKEXPORT //__cdecl // Use for normal __cdecl calling +#ifdef WIN32 +#define PKEXPORT __cdecl // Use for normal __cdecl calling +#else +#define PKEXPORT +#endif #endif //#define PKEXPORT __stdcall //#define PKEXPORT __fastcall diff --git a/src/tools/stuffextract/StuffExtract.cpp b/src/tools/stuffextract/StuffExtract.cpp index ae7a93a..e823549 100644 --- a/src/tools/stuffextract/StuffExtract.cpp +++ b/src/tools/stuffextract/StuffExtract.cpp @@ -50,8 +50,8 @@ int main(int argc, char *argv[]) if(GetLocale() && FileExists(std::string("Data/")+GetLocale()+"/locale-"+GetLocale()+".MPQ")) { printf("Locale \"%s\" seems valid, starting conversion...\n",GetLocale()); - CreateDir("stuffextract"); - CreateDir("stuffextract/data"); + CreateDir("extractedstuff"); + CreateDir("extractedstuff/data"); ConvertDBC(); if(doMaps) ExtractMaps(); if(doTextures || doModels || doWmos || doWmogroups) ExtractMapDependencies(); @@ -610,7 +610,7 @@ bool ConvertDBC(void) printf("DONE!\n"); //... - CreateDir("stuffextract/data/scp"); + CreateDir("extractedstuff/data/scp"); printf("Writing SCP files:\n"); printf("emote.."); OutSCP(SCPDIR "/emote.scp",EmoteDataStorage, "emote"); @@ -641,7 +641,7 @@ void ExtractMaps(void) uint32 extr,extrtotal=0; MPQHelper mpq("terrain"); MD5FileMap md5map; - CreateDir("stuffextract/data/maps"); + CreateDir("extractedstuff/data/maps"); for(std::map::iterator it = mapNames.begin(); it != mapNames.end(); it++) { // extract the WDT file that stores tile information @@ -726,7 +726,7 @@ void ExtractMapDependencies(void) MPQHelper mpqmodel("model"); MPQHelper mpqtex("texture"); MPQHelper mpqwmo("wmo"); - std::string path = "stuffextract/data"; + std::string path = "extractedstuff/data"; std::string pathtex = path + "/texture"; std::string pathmodel = path + "/model"; std::string pathwmo = path + "/wmo"; diff --git a/src/tools/stuffextract/StuffExtract.h b/src/tools/stuffextract/StuffExtract.h index 7c160cd..0a0b325 100644 --- a/src/tools/stuffextract/StuffExtract.h +++ b/src/tools/stuffextract/StuffExtract.h @@ -6,7 +6,7 @@ #define SE_VERSION 2 #define MAPS_VERSION ((uint32)0) -#define OUTDIR "stuffextract" +#define OUTDIR "extractedstuff" #define SCPDIR OUTDIR "/data/scp" #define MAPSDIR OUTDIR "/data/maps" #define SOUNDDIR OUTDIR "/data/sound" diff --git a/src/tools/stuffextract/dbcfile.cpp b/src/tools/stuffextract/dbcfile.cpp index 32bbe95..6d35a04 100644 --- a/src/tools/stuffextract/dbcfile.cpp +++ b/src/tools/stuffextract/dbcfile.cpp @@ -64,11 +64,12 @@ bool DBCFile::openmem(ByteBuffer bb) printf("DBCFile::openmem(): ByteBuffer too small!"); return false; } - uint32 hdr; bb >> hdr; + if(memcmp(&hdr,"WDBC",4)) // check if its a valid dbc file { + printf("not a valid WDB File??\n"); return false; }