* Updated StormLib to recent Version

* changed stuffextract output dir to "extractedstuff" to avoid conflicts on *nix
This commit is contained in:
shlainn 2010-03-03 15:42:01 +00:00
parent f71dc0bd3f
commit 9e5c1fdd30
39 changed files with 2616 additions and 1992 deletions

View File

@ -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

View File

@ -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 <assert.h>
#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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 <pshpack1.h>
#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 <poppack.h>
#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)

View File

@ -55,14 +55,6 @@
// Macintosh using Carbon
#include <Carbon/Carbon.h> // 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))

View File

@ -23,8 +23,8 @@
* Copyright (c) 2001 BMX-Chemnitz.DE All rights reserved.
*
********************************************************************/
#include <string>
#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)

File diff suppressed because it is too large Load Diff

View File

@ -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 <jseward@bzip.org>
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 ||

View File

@ -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 <jseward@bzip.org>
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]);

View File

@ -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 <jseward@bzip.org>
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 <stdio.h>
#include <errno.h>
@ -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",

View File

@ -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 <jseward@bzip.org>
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"

View File

@ -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 <jseward@bzip.org>
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

View File

@ -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 <jseward@bzip.org>
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. --*/

View File

@ -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 <jseward@bzip.org>
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"

View File

@ -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 <jseward@bzip.org>
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"

View File

@ -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 <jseward@bzip.org>
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"

View File

@ -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]
*/

View File

@ -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 <jseward@bzip.org>
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"

View File

@ -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 <jseward@bzip.org>
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 <stdio.h>
int main ()

View File

@ -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 <jseward@bzip.org>
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"

View File

@ -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 <jseward@bzip.org>
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 <stdio.h>

View File

@ -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 <jseward@bzip.org>
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 <stdio.h>
#include <assert.h>
#include "bzlib.h"

View File

@ -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
};
};

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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<uint32,std::string>::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";

View File

@ -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"

View File

@ -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;
}