* Updated StormLib to recent Version
* changed stuffextract output dir to "extractedstuff" to avoid conflicts on *nix
This commit is contained in:
parent
f71dc0bd3f
commit
9e5c1fdd30
@ -5,7 +5,20 @@ AM_CFLAGS = -fPIC
|
|||||||
noinst_LIBRARIES = libstormlib.a
|
noinst_LIBRARIES = libstormlib.a
|
||||||
libstormlib_a_SOURCES =huffman/huff.cpp\
|
libstormlib_a_SOURCES =huffman/huff.cpp\
|
||||||
wave/wave.cpp\
|
wave/wave.cpp\
|
||||||
StormPortLinux.cpp\
|
SAttrFile.cpp\
|
||||||
SFileReadFile.cpp SCommon.cpp SCompression.cpp SFileCompactArchive.cpp SFileCreateArchiveEx.cpp SFileExtractFile.cpp SFileFindFile.cpp SFileOpenArchive.cpp\
|
SCommon.cpp\
|
||||||
SFileOpenFileEx.cpp SListFile.cpp\
|
SCompression.cpp\
|
||||||
pklib/crc32_pk.c pklib/explode.c pklib/implode.c
|
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
|
||||||
|
|||||||
354
src/tools/stuffextract/StormLib/SAttrFile.cpp
Normal file
354
src/tools/stuffextract/StormLib/SAttrFile.cpp
Normal 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;
|
||||||
|
}
|
||||||
@ -14,6 +14,9 @@
|
|||||||
#include "StormLib.h"
|
#include "StormLib.h"
|
||||||
#include "SCommon.h"
|
#include "SCommon.h"
|
||||||
|
|
||||||
|
#include "misc/crc32.h"
|
||||||
|
#include "misc/md5.h"
|
||||||
|
|
||||||
char StormLibCopyright[] = "StormLib v 4.50 Copyright Ladislav Zezula 1998-2003";
|
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 filename is given by index, we have to search all hash entries for the right index.
|
||||||
if(dwIndex <= ha->pHeader->dwBlockTableSize)
|
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++)
|
for(pHash = ha->pHashTable; pHash < pHashEnd; pHash++)
|
||||||
{
|
{
|
||||||
if(pHash->dwBlockIndex == dwIndex)
|
if(pHash->dwBlockIndex == dwIndex)
|
||||||
@ -462,9 +465,9 @@ TMPQHash * GetHashEntry(TMPQArchive * ha, const char * szFileName)
|
|||||||
// Retrieves the locale-specific hash entry
|
// Retrieves the locale-specific hash entry
|
||||||
TMPQHash * GetHashEntryEx(TMPQArchive * ha, const char * szFileName, LCID lcLocale)
|
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 * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
||||||
TMPQHash * pHash0 = NULL; // Language-neutral hash entry
|
|
||||||
TMPQHash * pHashX = NULL; // Language-speficic
|
|
||||||
TMPQHash * pHash = GetHashEntry(ha, szFileName);
|
TMPQHash * pHash = GetHashEntry(ha, szFileName);
|
||||||
|
|
||||||
if(pHash != NULL)
|
if(pHash != NULL)
|
||||||
@ -473,38 +476,37 @@ TMPQHash * GetHashEntryEx(TMPQArchive * ha, const char * szFileName, LCID lcLoca
|
|||||||
DWORD dwName1 = pHash->dwName1;
|
DWORD dwName1 = pHash->dwName1;
|
||||||
DWORD dwName2 = pHash->dwName2;
|
DWORD dwName2 = pHash->dwName2;
|
||||||
|
|
||||||
|
// Parse the entire block of equal files (differing by language ID only)
|
||||||
while(pHash->dwBlockIndex != HASH_ENTRY_FREE)
|
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)
|
if(pHash->lcLocale == LANG_NEUTRAL)
|
||||||
pHash0 = pHash;
|
pHashNeutral = pHash;
|
||||||
if(pHash->lcLocale == lcLocale)
|
if(pHash->lcLocale == lcLocale)
|
||||||
pHashX = pHash;
|
pHashExact = pHash;
|
||||||
|
|
||||||
// If both found, break the loop
|
|
||||||
if(pHash0 != NULL && pHashX != NULL)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move to th next hash
|
||||||
if(++pHash >= pHashEnd)
|
if(++pHash >= pHashEnd)
|
||||||
pHash = ha->pHashTable;
|
pHash = ha->pHashTable;
|
||||||
if(pHash == pHashStart)
|
if(pHash == pHashStart)
|
||||||
return NULL;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(lcLocale != LANG_NEUTRAL && pHashX != NULL)
|
// If we found language-exact hash, return that one
|
||||||
return pHashX;
|
// If not, return language neutral hash
|
||||||
if(pHash0 != NULL)
|
if(pHashExact != NULL)
|
||||||
return pHash0;
|
return pHashExact;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pHash;
|
// Not found
|
||||||
|
return pHashNeutral;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypts file name and gets the hash entry
|
// Finds the nearest free hash entry for a file
|
||||||
// Returns the hash pointer, which is always within the allocated array
|
|
||||||
TMPQHash * FindFreeHashEntry(TMPQArchive * ha, const char * szFileName)
|
TMPQHash * FindFreeHashEntry(TMPQArchive * ha, const char * szFileName)
|
||||||
{
|
{
|
||||||
TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
||||||
@ -518,7 +520,7 @@ TMPQHash * FindFreeHashEntry(TMPQArchive * ha, const char * szFileName)
|
|||||||
// Save the starting hash position
|
// Save the starting hash position
|
||||||
pHash = pHash0 = ha->pHashTable + dwIndex;
|
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)
|
while(pHash->dwBlockIndex < HASH_ENTRY_DELETED)
|
||||||
{
|
{
|
||||||
if(++pHash >= pHashEnd)
|
if(++pHash >= pHashEnd)
|
||||||
@ -577,9 +579,67 @@ BOOL IsValidFileHandle(TMPQFile * hf)
|
|||||||
return IsValidMpqHandle(hf->ha);
|
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.
|
// This function writes a local file into the MPQ archive.
|
||||||
// Returns 0 if OK, otherwise error code.
|
// Returns 0 if OK, otherwise error code.
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
int AddFileToArchive(
|
int AddFileToArchive(
|
||||||
TMPQArchive * ha,
|
TMPQArchive * ha,
|
||||||
HANDLE hFile,
|
HANDLE hFile,
|
||||||
@ -589,34 +649,28 @@ int AddFileToArchive(
|
|||||||
int nFileType,
|
int nFileType,
|
||||||
BOOL * pbReplaced)
|
BOOL * pbReplaced)
|
||||||
{
|
{
|
||||||
LARGE_INTEGER RelativePos = {0};
|
LARGE_INTEGER TempPos; // For various file offset calculations
|
||||||
LARGE_INTEGER FilePos = {0};
|
TMPQBlock * pBlockEnd; // Pointer to end of the block table
|
||||||
LARGE_INTEGER TempPos;
|
TMPQFile * hf = NULL; // File structure for newly added file
|
||||||
TMPQBlockEx * pBlockEx = NULL; // Entry in the extended block table
|
BYTE * pbCompressed = NULL; // Compressed (target) data
|
||||||
TMPQBlock * pBlock = NULL; // Entry in the block table
|
BYTE * pbToWrite = NULL; // Data to write to the file
|
||||||
TMPQHash * pHash = NULL; // Entry in the hash table
|
DWORD dwBlockPosLen = 0; // Length of the file block offset (in bytes)
|
||||||
DWORD * pdwBlockPos = NULL; // Block position table (compressed files only)
|
DWORD dwTransferred = 0; // Number of bytes read or written
|
||||||
BYTE * pbFileData = NULL; // Uncompressed (source) data
|
DWORD dwFileSizeHigh = 0; // High 32 bits of the file size
|
||||||
BYTE * pbCompressed = NULL; // Compressed (target) data
|
DWORD dwFileSize = 0; // Low 32-bits of the file size
|
||||||
BYTE * pbToWrite = NULL; // Data to write to the file
|
BOOL bReplaced = FALSE; // TRUE if replaced, FALSE if added
|
||||||
DWORD dwBlockPosLen = 0; // Length of the block table positions
|
int nCmpFirst = nDataCmp; // Compression for the first data block
|
||||||
DWORD dwTransferred = 0; // Number of bytes written into archive file
|
int nCmpNext = nDataCmp; // Compression for the next data blocks
|
||||||
DWORD dwFileSize = 0; // Size of the file to add
|
int nCmp = nDataCmp; // Current compression
|
||||||
DWORD dwSeed1 = 0; // Encryption seed
|
int nCmpLevel = -1; // Compression level
|
||||||
DWORD nBlocks = 0; // Number of file blocks
|
int nError = ERROR_SUCCESS;
|
||||||
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;
|
|
||||||
|
|
||||||
// Set the correct compression types
|
// Set the correct compression types
|
||||||
if(dwFlags & MPQ_FILE_COMPRESS_PKWARE)
|
if(dwFlags & MPQ_FILE_IMPLODE)
|
||||||
nCmpFirst = nCmpNext = MPQ_COMPRESSION_PKWARE;
|
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)
|
if(nFileType == SFILE_TYPE_DATA)
|
||||||
nCmpFirst = nCmpNext = nDataCmp;
|
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(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);
|
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)
|
if(dwFileSize < 0x04)
|
||||||
dwFlags &= ~(MPQ_FILE_ENCRYPTED | MPQ_FILE_FIXSEED);
|
dwFlags &= ~(MPQ_FILE_ENCRYPTED | MPQ_FILE_FIXSEED);
|
||||||
if(dwFileSize < 0x20)
|
if(dwFileSize < 0x20)
|
||||||
dwFlags &= ~MPQ_FILE_COMPRESSED;
|
dwFlags &= ~MPQ_FILE_COMPRESSED;
|
||||||
|
|
||||||
if(pHash->dwBlockIndex == HASH_ENTRY_FREE)
|
// File in MPQ cannot be greater than 4GB
|
||||||
pHash->dwBlockIndex = ha->pHeader->dwBlockTableSize;
|
if(dwFileSizeHigh != 0)
|
||||||
|
nError = ERROR_PARAMETER_QUOTA_EXCEEDED;
|
||||||
// The block table index cannot be larger than hash table size
|
|
||||||
if(pHash->dwBlockIndex >= ha->pHeader->dwHashTableSize)
|
|
||||||
nError = ERROR_HANDLE_DISK_FULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The file will be stored after the end of the last archived file
|
// Allocate the TMPQFile entry for newly added file
|
||||||
// (i.e. at old position of archived file
|
|
||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
TMPQBlock * pBlockEnd = ha->pBlockTable + ha->pHeader->dwBlockTableSize;
|
hf = (TMPQFile *)ALLOCMEM(BYTE, sizeof(TMPQFile) + strlen(szArchivedName));
|
||||||
const char * szTemp = strrchr(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
|
// 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
|
// Search the entire block table and find a free block.
|
||||||
// (Do not use the dwArchiveSize here, because it may or may not
|
// Also find MPQ offset at which the file data will be stored
|
||||||
// include the hash table at the end of the file
|
|
||||||
pBlockEx = ha->pExtBlockTable;
|
pBlockEx = ha->pExtBlockTable;
|
||||||
for(pBlock = ha->pBlockTable; pBlock < pBlockEnd; pBlock++, pBlockEx++)
|
for(pBlock = ha->pBlockTable; pBlock < pBlockEnd; pBlock++, pBlockEx++)
|
||||||
{
|
{
|
||||||
if(pBlock->dwFlags & MPQ_FILE_EXISTS)
|
if(pBlock->dwFlags & MPQ_FILE_EXISTS)
|
||||||
{
|
{
|
||||||
TempPos.HighPart = pBlockEx->wFilePosHigh;
|
TempPos.HighPart = pBlockEx->wFilePosHigh;
|
||||||
TempPos.LowPart = pBlock->dwFilePos;
|
TempPos.LowPart = pBlock->dwFilePos;
|
||||||
TempPos.QuadPart += pBlock->dwCSize;
|
TempPos.QuadPart += pBlock->dwCSize;
|
||||||
|
|
||||||
if(TempPos.QuadPart > RelativePos.QuadPart)
|
if(TempPos.QuadPart > hf->MpqFilePos.QuadPart)
|
||||||
RelativePos = TempPos;
|
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
|
// When format V1, we cannot exceed 4 GB
|
||||||
if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1)
|
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->dwHashTableSize * sizeof(TMPQHash);
|
||||||
TempPos.QuadPart += ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock);
|
TempPos.QuadPart += ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock);
|
||||||
TempPos.QuadPart += dwFileSize;
|
|
||||||
|
|
||||||
if(TempPos.HighPart != 0)
|
if(TempPos.HighPart != 0)
|
||||||
nError = ERROR_DISK_FULL;
|
nError = ERROR_DISK_FULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get pointers to both block entries of the file
|
// If the block offset exceeds number of hash entries,
|
||||||
pBlockEx = ha->pExtBlockTable + pHash->dwBlockIndex;
|
// we cannot add new file to the MPQ
|
||||||
pBlock = ha->pBlockTable + pHash->dwBlockIndex;
|
hf->dwBlockIndex = (DWORD)(hf->pBlock - ha->pBlockTable);
|
||||||
|
if(hf->dwBlockIndex >= ha->pHeader->dwHashTableSize)
|
||||||
// Save the file size info
|
nError = ERROR_HANDLE_DISK_FULL;
|
||||||
pBlockEx->wFilePosHigh = (USHORT)RelativePos.HighPart;
|
}
|
||||||
pBlock->dwFilePos = RelativePos.LowPart;
|
|
||||||
pBlock->dwFSize = GetFileSize(hFile, NULL);
|
// Create seed1 for file encryption
|
||||||
pBlock->dwFlags = dwFlags | MPQ_FILE_EXISTS;
|
if(nError == ERROR_SUCCESS && (dwFlags & MPQ_FILE_ENCRYPTED))
|
||||||
|
{
|
||||||
|
const char * szTemp = strrchr(szArchivedName, '\\');
|
||||||
|
|
||||||
// Create seed1 for file encryption
|
// Create seed1 for file encryption
|
||||||
if(szTemp != NULL)
|
if(szTemp != NULL)
|
||||||
szArchivedName = szTemp + 1;
|
szArchivedName = szTemp + 1;
|
||||||
|
|
||||||
if(dwFlags & MPQ_FILE_ENCRYPTED)
|
hf->dwSeed1 = DecryptFileSeed(szArchivedName);
|
||||||
{
|
if(dwFlags & MPQ_FILE_FIXSEED)
|
||||||
dwSeed1 = DecryptFileSeed(szArchivedName);
|
hf->dwSeed1 = (hf->dwSeed1 + hf->MpqFilePos.LowPart) ^ dwFileSize;
|
||||||
|
|
||||||
if(dwFlags & MPQ_FILE_FIXSEED)
|
|
||||||
dwSeed1 = (dwSeed1 + pBlock->dwFilePos) ^ pBlock->dwFSize;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate buffer for the input data
|
// Resolve CRC32 and MD5 entry for the file
|
||||||
if(nError == ERROR_SUCCESS)
|
// Only do it when the MPQ archive has attributes
|
||||||
|
if(nError == ERROR_SUCCESS && ha->pAttributes != NULL)
|
||||||
{
|
{
|
||||||
nBlocks = (pBlock->dwFSize / ha->dwBlockSize) + 1;
|
if(ha->pAttributes->pCrc32 != NULL)
|
||||||
if(pBlock->dwFSize % ha->dwBlockSize)
|
hf->pCrc32 = ha->pAttributes->pCrc32 + hf->dwBlockIndex;
|
||||||
nBlocks++;
|
if(ha->pAttributes->pFileTime != NULL)
|
||||||
|
hf->pFileTime = ha->pAttributes->pFileTime + hf->dwBlockIndex;
|
||||||
pBlock->dwCSize = 0;
|
if(ha->pAttributes->pMd5 != NULL)
|
||||||
if((pbFileData = ALLOCMEM(BYTE, ha->dwBlockSize)) == NULL)
|
hf->pMd5 = ha->pAttributes->pMd5 + hf->dwBlockIndex;
|
||||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
pbToWrite = pbFileData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate buffers for the compressed data
|
// 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))
|
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);
|
pbCompressed = ALLOCMEM(BYTE, ha->dwBlockSize * 2);
|
||||||
if(pdwBlockPos == NULL || pbCompressed == NULL)
|
if(hf->pdwBlockPos == NULL || pbCompressed == NULL)
|
||||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
nError = ERROR_NOT_ENOUGH_MEMORY;
|
||||||
pbToWrite = pbCompressed;
|
pbToWrite = pbCompressed;
|
||||||
}
|
}
|
||||||
@ -768,88 +860,104 @@ int AddFileToArchive(
|
|||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
// Set the file pointer to file data position
|
// Set the file pointer to file data position
|
||||||
FilePos.QuadPart = ha->MpqPos.QuadPart + RelativePos.QuadPart;
|
SetFilePointer(ha->hFile, hf->RawFilePos.LowPart, &hf->RawFilePos.HighPart, FILE_BEGIN);
|
||||||
if(FilePos.QuadPart != ha->FilePointer.QuadPart)
|
|
||||||
{
|
// Initialize the hash entry for the file
|
||||||
SetFilePointer(ha->hFile, FilePos.LowPart, &FilePos.HighPart, FILE_BEGIN);
|
hf->pHash->dwBlockIndex = hf->dwBlockIndex;
|
||||||
ha->FilePointer = FilePos;
|
|
||||||
}
|
// 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)
|
// Write block positions (if the file will be compressed)
|
||||||
if(nError == ERROR_SUCCESS && (dwFlags & MPQ_FILE_COMPRESSED))
|
if(nError == ERROR_SUCCESS && (dwFlags & MPQ_FILE_COMPRESSED))
|
||||||
{
|
{
|
||||||
dwBlockPosLen = nBlocks * sizeof(DWORD);
|
dwBlockPosLen = hf->nBlocks * sizeof(DWORD);
|
||||||
if(dwFlags & MPQ_FILE_HAS_EXTRA)
|
if(dwFlags & MPQ_FILE_HAS_EXTRA)
|
||||||
dwBlockPosLen += sizeof(DWORD);
|
dwBlockPosLen += sizeof(DWORD);
|
||||||
|
|
||||||
memset(pdwBlockPos, 0, dwBlockPosLen);
|
memset(hf->pdwBlockPos, 0, dwBlockPosLen);
|
||||||
pdwBlockPos[0] = dwBlockPosLen;
|
hf->pdwBlockPos[0] = dwBlockPosLen;
|
||||||
|
|
||||||
// Write the block positions
|
// Write the block positions. Only swap the first item, rest is zeros.
|
||||||
BSWAP_ARRAY32_UNSIGNED((DWORD *)pdwBlockPos, nBlocks);
|
BSWAP_ARRAY32_UNSIGNED(hf->pdwBlockPos, 1);
|
||||||
WriteFile(ha->hFile, pdwBlockPos, dwBlockPosLen, &dwTransferred, NULL);
|
WriteFile(ha->hFile, hf->pdwBlockPos, dwBlockPosLen, &dwTransferred, NULL);
|
||||||
BSWAP_ARRAY32_UNSIGNED((DWORD *)pdwBlockPos, nBlocks);
|
BSWAP_ARRAY32_UNSIGNED(hf->pdwBlockPos, 1);
|
||||||
|
|
||||||
if(dwTransferred == dwBlockPosLen)
|
if(dwTransferred == dwBlockPosLen)
|
||||||
pBlock->dwCSize += dwBlockPosLen;
|
hf->pBlock->dwCSize += dwBlockPosLen;
|
||||||
else
|
else
|
||||||
nError = GetLastError();
|
nError = GetLastError();
|
||||||
|
|
||||||
// Update the current position in the file
|
|
||||||
ha->HashTablePos.QuadPart = FilePos.QuadPart + dwTransferred;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write all file blocks
|
// Write all file blocks
|
||||||
if(nError == ERROR_SUCCESS)
|
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;
|
nCmp = nCmpFirst;
|
||||||
|
|
||||||
|
// Move the file pointer to the begin of the file
|
||||||
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
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 dwInLength = ha->dwBlockSize;
|
||||||
DWORD dwOutLength = ha->dwBlockSize;
|
DWORD dwOutLength = ha->dwBlockSize;
|
||||||
|
|
||||||
// Load the block from the file
|
// Load the block from the file
|
||||||
ReadFile(hFile, pbFileData, ha->dwBlockSize, &dwInLength, NULL);
|
ReadFile(hFile, hf->pbFileBuffer, ha->dwBlockSize, &dwInLength, NULL);
|
||||||
if(dwInLength == 0)
|
if(dwInLength == 0)
|
||||||
break;
|
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
|
// Compress the block, if necessary
|
||||||
dwOutLength = dwInLength;
|
dwOutLength = dwInLength;
|
||||||
if(pBlock->dwFlags & MPQ_FILE_COMPRESSED)
|
if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESSED)
|
||||||
{
|
{
|
||||||
// Should be enough for compression
|
// Should be enough for compression
|
||||||
int nOutLength = ha->dwBlockSize * 2;
|
int nOutLength = ha->dwBlockSize * 2;
|
||||||
int nCmpType = 0;
|
int nCmpType = 0;
|
||||||
|
|
||||||
if(pBlock->dwFlags & MPQ_FILE_COMPRESS_PKWARE)
|
if(hf->pBlock->dwFlags & MPQ_FILE_IMPLODE)
|
||||||
Compress_pklib((char *)pbCompressed, &nOutLength, (char *)pbFileData, dwInLength, &nCmpType, 0);
|
Compress_pklib((char *)pbCompressed, &nOutLength, (char *)hf->pbFileBuffer, dwInLength, &nCmpType, 0);
|
||||||
|
|
||||||
if(pBlock->dwFlags & MPQ_FILE_COMPRESS_MULTI)
|
if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESS)
|
||||||
SCompCompress((char *)pbCompressed, &nOutLength, (char *)pbFileData, dwInLength, nCmp, 0, nCmpLevel);
|
SCompCompress((char *)pbCompressed, &nOutLength, (char *)hf->pbFileBuffer, dwInLength, nCmp, 0, nCmpLevel);
|
||||||
|
|
||||||
// The compressed block size must NOT be the same or greater like
|
// The compressed block size must NOT be the same or greater like
|
||||||
// the original block size. If yes, do not compress the block
|
// the original block size. If yes, do not compress the block
|
||||||
// and store the data as-is.
|
// and store the data as-is.
|
||||||
if(nOutLength >= (int)dwInLength)
|
if(nOutLength >= (int)dwInLength)
|
||||||
{
|
{
|
||||||
memcpy(pbCompressed, pbFileData, dwInLength);
|
memcpy(pbCompressed, hf->pbFileBuffer, dwInLength);
|
||||||
nOutLength = dwInLength;
|
nOutLength = dwInLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update block positions
|
// Update block positions
|
||||||
dwOutLength = nOutLength;
|
dwOutLength = nOutLength;
|
||||||
pdwBlockPos[nBlock+1] = pdwBlockPos[nBlock] + dwOutLength;
|
hf->pdwBlockPos[nBlock+1] = hf->pdwBlockPos[nBlock] + dwOutLength;
|
||||||
nCmp = nCmpNext;
|
nCmp = nCmpNext;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt the block, if necessary
|
// 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));
|
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));
|
BSWAP_ARRAY32_UNSIGNED((DWORD *)pbToWrite, dwOutLength / sizeof(DWORD));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,87 +970,93 @@ int AddFileToArchive(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the hash table position and the compressed file size
|
// Update the hash table position and the compressed file size
|
||||||
ha->HashTablePos.QuadPart += dwTransferred;
|
hf->pBlock->dwCSize += dwTransferred;
|
||||||
pBlock->dwCSize += dwOutLength;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
// 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)
|
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 file is encrypted, block positions are also encrypted
|
||||||
if(dwFlags & MPQ_FILE_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
|
// 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
|
// Write block positions to the archive
|
||||||
BSWAP_ARRAY32_UNSIGNED((DWORD *)pdwBlockPos, nBlocks);
|
BSWAP_ARRAY32_UNSIGNED(hf->pdwBlockPos, hf->nBlocks);
|
||||||
WriteFile(ha->hFile, pdwBlockPos, dwBlockPosLen, &dwTransferred, NULL);
|
WriteFile(ha->hFile, hf->pdwBlockPos, dwBlockPosLen, &dwTransferred, NULL);
|
||||||
if(dwTransferred != dwBlockPosLen)
|
if(dwTransferred != dwBlockPosLen)
|
||||||
nError = ERROR_DISK_FULL;
|
nError = ERROR_DISK_FULL;
|
||||||
|
|
||||||
ha->FilePointer.QuadPart = ha->FilePointer.QuadPart + dwTransferred;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If success, we have to change the settings
|
// If success, we have to change the settings
|
||||||
// in MPQ header. If failed, we have to clean hash entry
|
// in MPQ header. If failed, we have to clean hash entry
|
||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
|
DWORD dwTableSize;
|
||||||
|
|
||||||
ha->pLastFile = NULL;
|
ha->pLastFile = NULL;
|
||||||
ha->dwBlockPos = 0;
|
ha->dwBlockPos = 0;
|
||||||
ha->dwBuffPos = 0;
|
ha->dwBuffPos = 0;
|
||||||
ha->dwFlags |= MPQ_FLAG_CHANGED;
|
|
||||||
|
|
||||||
// Add new entry to the block table (if needed)
|
// Add new entry to the block table (if needed)
|
||||||
if(pHash->dwBlockIndex >= ha->pHeader->dwBlockTableSize)
|
if(hf->dwBlockIndex >= ha->pHeader->dwBlockTableSize)
|
||||||
ha->pHeader->dwBlockTableSize++;
|
ha->pHeader->dwBlockTableSize++;
|
||||||
|
|
||||||
// Hash table size in the TMPQArchive is already set at this point
|
// Calculate positions of all tables
|
||||||
RelativePos.QuadPart = ha->HashTablePos.QuadPart - ha->MpqPos.QuadPart;
|
ha->HashTablePos.QuadPart = hf->RawFilePos.QuadPart + hf->pBlock->dwCSize;
|
||||||
ha->pHeader->dwHashTablePos = RelativePos.LowPart;
|
TempPos.QuadPart = hf->MpqFilePos.QuadPart + hf->pBlock->dwCSize;
|
||||||
ha->pHeader->wHashTablePosHigh = (USHORT)RelativePos.HighPart;
|
|
||||||
|
// 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
|
// Update block table pos
|
||||||
RelativePos.QuadPart += (ha->pHeader->dwHashTableSize * sizeof(TMPQHash));
|
TempPos.QuadPart += dwTableSize;
|
||||||
ha->pHeader->wBlockTablePosHigh = (USHORT)RelativePos.HighPart;
|
ha->BlockTablePos.QuadPart = ha->HashTablePos.QuadPart + dwTableSize;
|
||||||
ha->pHeader->dwBlockTablePos = RelativePos.LowPart;
|
ha->pHeader->wBlockTablePosHigh = (USHORT)TempPos.HighPart;
|
||||||
ha->BlockTablePos.QuadPart = RelativePos.QuadPart + ha->MpqPos.QuadPart;
|
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
|
// If the archive size exceeded 4GB, we have to use extended block table
|
||||||
RelativePos.QuadPart += (ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock));
|
TempPos.QuadPart += dwTableSize;
|
||||||
if(RelativePos.HighPart != 0)
|
if(TempPos.HighPart != 0 || ha->pHeader->ExtBlockTablePos.QuadPart != 0)
|
||||||
{
|
{
|
||||||
ha->pHeader->ExtBlockTablePos = RelativePos;
|
ha->ExtBlockTablePos.QuadPart = ha->BlockTablePos.QuadPart + dwTableSize;
|
||||||
ha->ExtBlockTablePos.QuadPart = RelativePos.QuadPart + ha->MpqPos.QuadPart;
|
ha->pHeader->ExtBlockTablePos = TempPos;
|
||||||
|
TempPos.QuadPart += ha->pHeader->dwBlockTableSize * sizeof(TMPQBlockEx);
|
||||||
RelativePos.QuadPart += (ha->pHeader->dwBlockTableSize * sizeof(TMPQBlockEx));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update archive size (only valid for version V1)
|
// Update archive size (only valid for version V1)
|
||||||
ha->MpqSize = RelativePos;
|
ha->MpqSize = TempPos;
|
||||||
ha->pHeader->dwArchiveSize = ha->MpqSize.LowPart;
|
ha->pHeader->dwArchiveSize = TempPos.LowPart;
|
||||||
|
ha->dwFlags |= MPQ_FLAG_CHANGED;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Clear the hash table entry
|
// Clear the hash table entry
|
||||||
if(pHash != NULL)
|
if(hf != NULL && hf->pHash != NULL)
|
||||||
memset(pHash, 0xFF, sizeof(TMPQHash));
|
memset(hf->pHash, 0xFF, sizeof(TMPQHash));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
if(pbCompressed != NULL)
|
if(pbCompressed != NULL)
|
||||||
FREEMEM(pbCompressed);
|
FREEMEM(pbCompressed);
|
||||||
if(pdwBlockPos != NULL)
|
|
||||||
FREEMEM(pdwBlockPos);
|
|
||||||
if(pbFileData != NULL)
|
|
||||||
FREEMEM(pbFileData);
|
|
||||||
if(pbReplaced != NULL)
|
if(pbReplaced != NULL)
|
||||||
*pbReplaced = bReplaced;
|
*pbReplaced = bReplaced;
|
||||||
|
FreeMPQFile(hf);
|
||||||
return nError;
|
return nError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -953,13 +1067,12 @@ int SetDataCompression(int nDataCompression)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This method saves MPQ header, hash table and block table.
|
// This method saves MPQ header, hash table and block table.
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
int SaveMPQTables(TMPQArchive * ha)
|
int SaveMPQTables(TMPQArchive * ha)
|
||||||
{
|
{
|
||||||
BYTE * pbBuffer = NULL;
|
BYTE * pbBuffer = NULL;
|
||||||
DWORD dwBytes;
|
DWORD dwBytes;
|
||||||
DWORD dwWritten;
|
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;
|
int nError = ERROR_SUCCESS;
|
||||||
|
|
||||||
// Allocate buffer for encrypted tables
|
// Allocate buffer for encrypted tables
|
||||||
@ -1040,7 +1153,6 @@ int SaveMPQTables(TMPQArchive * ha)
|
|||||||
nError = ERROR_DISK_FULL;
|
nError = ERROR_DISK_FULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Set end of file here
|
// Set end of file here
|
||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
@ -1054,7 +1166,6 @@ int SaveMPQTables(TMPQArchive * ha)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Frees the MPQ archive
|
// Frees the MPQ archive
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
void FreeMPQArchive(TMPQArchive *& ha)
|
void FreeMPQArchive(TMPQArchive *& ha)
|
||||||
{
|
{
|
||||||
if(ha != NULL)
|
if(ha != NULL)
|
||||||
@ -1065,6 +1176,8 @@ void FreeMPQArchive(TMPQArchive *& ha)
|
|||||||
FREEMEM(ha->pHashTable);
|
FREEMEM(ha->pHashTable);
|
||||||
if(ha->pListFile != NULL)
|
if(ha->pListFile != NULL)
|
||||||
SListFileFreeListFile(ha);
|
SListFileFreeListFile(ha);
|
||||||
|
if(ha->pAttributes != NULL)
|
||||||
|
FreeMPQAttributes(ha->pAttributes);
|
||||||
|
|
||||||
if(ha->hFile != INVALID_HANDLE_VALUE)
|
if(ha->hFile != INVALID_HANDLE_VALUE)
|
||||||
CloseHandle(ha->hFile);
|
CloseHandle(ha->hFile);
|
||||||
|
|||||||
@ -19,6 +19,14 @@
|
|||||||
#define SFILE_TYPE_DATA 0 // Process the file as data file
|
#define SFILE_TYPE_DATA 0 // Process the file as data file
|
||||||
#define SFILE_TYPE_WAVE 1 // Process the file as WAVe 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
|
// External variables
|
||||||
|
|
||||||
@ -66,21 +74,30 @@ BOOL IsValidFileHandle(TMPQFile * hf);
|
|||||||
// Other functions
|
// Other functions
|
||||||
|
|
||||||
BOOL SFileOpenArchiveEx(const char * szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE * phMPQ, DWORD dwAccessMode = GENERIC_READ);
|
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 AddFileToArchive(TMPQArchive * ha, HANDLE hFile, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality, int nFileType, BOOL * pbReplaced);
|
||||||
int SetDataCompression(int nDataCompression);
|
int SetDataCompression(int nDataCompression);
|
||||||
int SaveMPQTables(TMPQArchive * ha);
|
int SaveMPQTables(TMPQArchive * ha);
|
||||||
void FreeMPQArchive(TMPQArchive *& ha);
|
void FreeMPQArchive(TMPQArchive *& ha);
|
||||||
|
void FreeMPQFile(TMPQFile *& hf);
|
||||||
|
|
||||||
BOOL CheckWildCard(const char * szString, const char * szWildCard);
|
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
|
// Listfile functions
|
||||||
|
|
||||||
int SListFileCreateListFile(TMPQArchive * ha);
|
int SListFileCreateListFile(TMPQArchive * ha);
|
||||||
int SListFileAddNode(TMPQArchive * ha, const char * szAddedFile);
|
int SListFileCreateNode(TMPQArchive * ha, const char * szFileName, LCID lcLocale);
|
||||||
int SListFileRemoveNode(TMPQArchive * ha, const char * szFileName);
|
int SListFileRemoveNode(TMPQArchive * ha, const char * szFileName, LCID lcLocale);
|
||||||
int SListFileRenameNode(TMPQArchive * ha, const char * szOldFileName, const char * szNewFileName);
|
void SListFileFreeListFile(TMPQArchive * ha);
|
||||||
int SListFileFreeListFile(TMPQArchive * ha);
|
|
||||||
|
|
||||||
int SListFileSaveToMpq(TMPQArchive * ha);
|
int SListFileSaveToMpq(TMPQArchive * ha);
|
||||||
|
|
||||||
|
|||||||
@ -228,11 +228,9 @@ int Decompress_huff(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, i
|
|||||||
TInputStream is;
|
TInputStream is;
|
||||||
|
|
||||||
// Initialize input stream
|
// Initialize input stream
|
||||||
// is.pbInBuffer = (unsigned char *)pbInBuffer;
|
is.pbInBuffer = (unsigned char *)pbInBuffer;
|
||||||
is.dwBitBuff = BSWAP_INT32_UNSIGNED(*(unsigned long *)pbInBuffer);
|
is.BitBuffer = 0;
|
||||||
pbInBuffer += sizeof(unsigned long);
|
is.BitCount = 0;
|
||||||
is.pbInBuffer = (unsigned char *)pbInBuffer;
|
|
||||||
is.nBits = 32;
|
|
||||||
|
|
||||||
// Initialize the Huffmann tree for compression
|
// Initialize the Huffmann tree for compression
|
||||||
ht.InitTree(false);
|
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
|
// Fix: If PKLIB is unable to decompress the data, they are uncompressed
|
||||||
if(Info.nOutPos == 0)
|
if(Info.nOutPos == 0)
|
||||||
{
|
{
|
||||||
Info.nOutPos = min(*pdwOutLength, dwInLength);
|
Info.nOutPos = STORMLIB_MIN(*pdwOutLength, dwInLength);
|
||||||
memcpy(pbOutBuffer, pbInBuffer, Info.nOutPos);
|
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)
|
int Decompress_bzip2(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength)
|
||||||
{
|
{
|
||||||
bz_stream strm;
|
bz_stream strm;
|
||||||
|
int nResult = BZ_OK;
|
||||||
|
|
||||||
// Initialize the BZLIB decompression
|
// Initialize the BZLIB decompression
|
||||||
strm.bzalloc = NULL;
|
strm.bzalloc = NULL;
|
||||||
strm.bzfree = NULL;
|
strm.bzfree = NULL;
|
||||||
if(BZ2_bzDecompressInit(&strm, 0, 0) == 0)
|
if(BZ2_bzDecompressInit(&strm, 0, 0) == BZ_OK)
|
||||||
{
|
{
|
||||||
strm.next_in = pbInBuffer;
|
strm.next_in = pbInBuffer;
|
||||||
strm.avail_in = dwInLength;
|
strm.avail_in = dwInLength;
|
||||||
@ -434,18 +433,28 @@ int Decompress_bzip2(char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer,
|
|||||||
strm.avail_out = *pdwOutLength;
|
strm.avail_out = *pdwOutLength;
|
||||||
|
|
||||||
// Perform the decompression
|
// 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
|
// Put the stream into idle state
|
||||||
BZ2_bzDecompressEnd(&strm);
|
BZ2_bzDecompressEnd(&strm);
|
||||||
*pdwOutLength = strm.total_out_lo32;
|
|
||||||
}
|
// If all succeeded, set the number of output bytes
|
||||||
else
|
if(nResult >= BZ_OK)
|
||||||
{
|
{
|
||||||
// Set zero output length
|
*pdwOutLength = strm.total_out_lo32;
|
||||||
*pdwOutLength = 0;
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Something failed, so set number of output bytes to zero
|
||||||
|
*pdwOutLength = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -39,7 +39,6 @@ static TMPQHash * CopyHashTable(TMPQArchive * ha)
|
|||||||
return pHashTableCopy;
|
return pHashTableCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
static int CheckIfAllFilesKnown(TMPQArchive * ha, const char * szListFile, DWORD * pFileSeeds)
|
static int CheckIfAllFilesKnown(TMPQArchive * ha, const char * szListFile, DWORD * pFileSeeds)
|
||||||
{
|
{
|
||||||
TMPQHash * pHashTableCopy = NULL; // Copy of the hash table
|
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,
|
// If there is an unresolved entry, try to detect its seed. If it fails,
|
||||||
// we cannot complete the work
|
// we cannot complete the work
|
||||||
if(pHash->dwName1 != (DWORD)-1 && pHash->dwName2 != (DWORD)-1)
|
if(pHash->dwBlockIndex < ha->pHeader->dwBlockTableSize)
|
||||||
{
|
{
|
||||||
HANDLE hFile = NULL;
|
HANDLE hFile = NULL;
|
||||||
DWORD dwFlags = 0;
|
DWORD dwFlags = 0;
|
||||||
DWORD dwSeed = 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;
|
TMPQFile * hf = (TMPQFile *)hFile;
|
||||||
dwFlags = hf->pBlock->dwFlags;
|
dwFlags = hf->pBlock->dwFlags;
|
||||||
@ -168,7 +167,6 @@ static int CheckIfAllFilesKnown(TMPQArchive * ha, const char * szListFile, DWORD
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copies all file blocks into another archive.
|
// Copies all file blocks into another archive.
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
static int CopyMpqFileBlocks(
|
static int CopyMpqFileBlocks(
|
||||||
HANDLE hFile,
|
HANDLE hFile,
|
||||||
TMPQArchive * ha,
|
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
|
// recompression, because re-compression is not necessary in this case
|
||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
@ -424,7 +422,6 @@ static int CopyNonMpqData(
|
|||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
static int CopyMpqFiles(HANDLE hFile, TMPQArchive * ha, DWORD * pFileSeeds)
|
static int CopyMpqFiles(HANDLE hFile, TMPQArchive * ha, DWORD * pFileSeeds)
|
||||||
{
|
{
|
||||||
TMPQBlockEx * pBlockEx;
|
TMPQBlockEx * pBlockEx;
|
||||||
@ -444,9 +441,6 @@ static int CopyMpqFiles(HANDLE hFile, TMPQArchive * ha, DWORD * pFileSeeds)
|
|||||||
if(CompactCB != NULL)
|
if(CompactCB != NULL)
|
||||||
CompactCB(lpUserData, CCB_COMPACTING_FILES, dwIndex, ha->pHeader->dwBlockTableSize);
|
CompactCB(lpUserData, CCB_COMPACTING_FILES, dwIndex, ha->pHeader->dwBlockTableSize);
|
||||||
|
|
||||||
// if(dwIndex == 0x1B9)
|
|
||||||
// DebugBreak();
|
|
||||||
|
|
||||||
// Copy all the file blocks
|
// Copy all the file blocks
|
||||||
// Debug: Break at (dwIndex == 5973)
|
// Debug: Break at (dwIndex == 5973)
|
||||||
if(pBlock->dwFlags & MPQ_FILE_EXISTS)
|
if(pBlock->dwFlags & MPQ_FILE_EXISTS)
|
||||||
@ -476,7 +470,6 @@ BOOL WINAPI SFileSetCompactCallback(HANDLE /* hMPQ */, COMPACTCB aCompactCB, voi
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Archive compacting (incomplete)
|
// Archive compacting (incomplete)
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
BOOL WINAPI SFileCompactArchive(HANDLE hMPQ, const char * szListFile, BOOL /* bReserved */)
|
BOOL WINAPI SFileCompactArchive(HANDLE hMPQ, const char * szListFile, BOOL /* bReserved */)
|
||||||
{
|
{
|
||||||
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
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
|
// Write the data between the header and between the first file
|
||||||
// For this, we have to determine where the first file begins
|
// 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)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
LARGE_INTEGER FirstFilePos;
|
LARGE_INTEGER FirstFilePos;
|
||||||
@ -596,7 +593,7 @@ BOOL WINAPI SFileCompactArchive(HANDLE hMPQ, const char * szListFile, BOOL /* bR
|
|||||||
FirstFilePos.QuadPart -= ha->pHeader->dwHeaderSize;
|
FirstFilePos.QuadPart -= ha->pHeader->dwHeaderSize;
|
||||||
nError = CopyNonMpqData(ha->hFile, hFile, FirstFilePos);
|
nError = CopyNonMpqData(ha->hFile, hFile, FirstFilePos);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// Now write all file blocks.
|
// Now write all file blocks.
|
||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
nError = CopyMpqFiles(hFile, ha, pFileSeeds);
|
nError = CopyMpqFiles(hFile, ha, pFileSeeds);
|
||||||
@ -643,7 +640,6 @@ BOOL WINAPI SFileCompactArchive(HANDLE hMPQ, const char * szListFile, BOOL /* bR
|
|||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
CloseHandle(ha->hFile);
|
CloseHandle(ha->hFile);
|
||||||
ha->FilePointer.QuadPart = 0;
|
|
||||||
ha->hFile = hFile;
|
ha->hFile = hFile;
|
||||||
hFile = INVALID_HANDLE_VALUE;
|
hFile = INVALID_HANDLE_VALUE;
|
||||||
nError = SaveMPQTables(ha);
|
nError = SaveMPQTables(ha);
|
||||||
@ -672,7 +668,6 @@ BOOL WINAPI SFileCompactArchive(HANDLE hMPQ, const char * szListFile, BOOL /* bR
|
|||||||
// Invalidate the positions of the archive
|
// Invalidate the positions of the archive
|
||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
ha->FilePointer.QuadPart = 0;
|
|
||||||
ha->pLastFile = NULL;
|
ha->pLastFile = NULL;
|
||||||
ha->dwBlockPos = 0;
|
ha->dwBlockPos = 0;
|
||||||
ha->dwBuffPos = 0;
|
ha->dwBuffPos = 0;
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Local tables
|
// Local tables
|
||||||
|
|
||||||
static DWORD PowersOfTwo[] =
|
static DWORD PowersOfTwo[] =
|
||||||
{
|
{
|
||||||
0x0000002, 0x0000004, 0x0000008,
|
0x0000002, 0x0000004, 0x0000008,
|
||||||
@ -30,6 +30,193 @@ static DWORD PowersOfTwo[] =
|
|||||||
0x0000000
|
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 */
|
/* Public functions */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -52,6 +239,7 @@ static DWORD PowersOfTwo[] =
|
|||||||
//
|
//
|
||||||
// MPQ_CREATE_ARCHIVE_V1 - Creates MPQ archive version 1
|
// MPQ_CREATE_ARCHIVE_V1 - Creates MPQ archive version 1
|
||||||
// MPQ_CREATE_ARCHIVE_V2 - Creates MPQ archive version 2
|
// 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).
|
// dwHashTableSize - Size of the hash table (only if creating a new archive).
|
||||||
// Must be between 2^4 (= 16) and 2^18 (= 262 144)
|
// Must be between 2^4 (= 16) and 2^18 (= 262 144)
|
||||||
@ -59,7 +247,6 @@ static DWORD PowersOfTwo[] =
|
|||||||
// phMpq - Receives handle to the archive
|
// phMpq - Receives handle to the archive
|
||||||
//
|
//
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposition, DWORD dwHashTableSize, HANDLE * phMPQ)
|
BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposition, DWORD dwHashTableSize, HANDLE * phMPQ)
|
||||||
{
|
{
|
||||||
LARGE_INTEGER MpqPos = {0}; // Position of MPQ header in the file
|
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
|
HANDLE hFile = INVALID_HANDLE_VALUE; // File handle
|
||||||
DWORD dwTransferred = 0; // Number of bytes written into the archive
|
DWORD dwTransferred = 0; // Number of bytes written into the archive
|
||||||
USHORT wFormatVersion;
|
USHORT wFormatVersion;
|
||||||
|
BOOL bCreateAttributes = FALSE;
|
||||||
BOOL bFileExists = FALSE;
|
BOOL bFileExists = FALSE;
|
||||||
int nIndex = 0;
|
int nIndex = 0;
|
||||||
int nError = ERROR_SUCCESS;
|
int nError = ERROR_SUCCESS;
|
||||||
@ -86,7 +274,8 @@ BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposi
|
|||||||
bFileExists = (GetFileAttributes(szMpqName) != 0xFFFFFFFF);
|
bFileExists = (GetFileAttributes(szMpqName) != 0xFFFFFFFF);
|
||||||
|
|
||||||
// Extract format version from the "dwCreationDisposition"
|
// Extract format version from the "dwCreationDisposition"
|
||||||
wFormatVersion = (USHORT)(dwCreationDisposition >> 0x10);
|
bCreateAttributes = (dwCreationDisposition & MPQ_CREATE_ATTRIBUTES);
|
||||||
|
wFormatVersion = (USHORT)((dwCreationDisposition >> 0x10) & 0x0000000F);
|
||||||
dwCreationDisposition &= 0x0000FFFF;
|
dwCreationDisposition &= 0x0000FFFF;
|
||||||
|
|
||||||
// If the file exists and open required, do it.
|
// 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.
|
// the file exist, but it is not a MPQ archive.
|
||||||
if(SFileOpenArchiveEx(szMpqName, 0, 0, phMPQ, GENERIC_READ | GENERIC_WRITE))
|
if(SFileOpenArchiveEx(szMpqName, 0, 0, phMPQ, GENERIC_READ | GENERIC_WRITE))
|
||||||
return TRUE;
|
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
|
// Two error cases
|
||||||
@ -190,7 +384,6 @@ BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposi
|
|||||||
ha->hFile = hFile;
|
ha->hFile = hFile;
|
||||||
ha->dwBlockSize = 0x200 << DEFAULT_BLOCK_SIZE;
|
ha->dwBlockSize = 0x200 << DEFAULT_BLOCK_SIZE;
|
||||||
ha->MpqPos = MpqPos;
|
ha->MpqPos = MpqPos;
|
||||||
ha->FilePointer = MpqPos;
|
|
||||||
ha->pHeader = &ha->Header;
|
ha->pHeader = &ha->Header;
|
||||||
ha->pHashTable = ALLOCMEM(TMPQHash, dwHashTableSize);
|
ha->pHashTable = ALLOCMEM(TMPQHash, dwHashTableSize);
|
||||||
ha->pBlockTable = ALLOCMEM(TMPQBlock, dwHashTableSize);
|
ha->pBlockTable = ALLOCMEM(TMPQBlock, dwHashTableSize);
|
||||||
@ -253,7 +446,6 @@ BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposi
|
|||||||
if(dwTransferred != ha->pHeader->dwHeaderSize)
|
if(dwTransferred != ha->pHeader->dwHeaderSize)
|
||||||
nError = ERROR_DISK_FULL;
|
nError = ERROR_DISK_FULL;
|
||||||
|
|
||||||
ha->FilePointer.QuadPart = ha->MpqPos.QuadPart + dwTransferred;
|
|
||||||
ha->MpqSize.QuadPart += dwTransferred;
|
ha->MpqSize.QuadPart += dwTransferred;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,9 +453,20 @@ BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposi
|
|||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
nError = SListFileCreateListFile(ha);
|
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)
|
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
|
// Cleanup : If an error, delete all buffers and return
|
||||||
if(nError != ERROR_SUCCESS)
|
if(nError != ERROR_SUCCESS)
|
||||||
@ -272,6 +475,7 @@ BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposi
|
|||||||
if(hFile != INVALID_HANDLE_VALUE)
|
if(hFile != INVALID_HANDLE_VALUE)
|
||||||
CloseHandle(hFile);
|
CloseHandle(hFile);
|
||||||
SetLastError(nError);
|
SetLastError(nError);
|
||||||
|
ha = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the values
|
// Return the values
|
||||||
@ -282,7 +486,6 @@ BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposi
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Changes locale ID of a file
|
// Changes locale ID of a file
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
BOOL WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale)
|
BOOL WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale)
|
||||||
{
|
{
|
||||||
TMPQFile * hf = (TMPQFile *)hFile;
|
TMPQFile * hf = (TMPQFile *)hFile;
|
||||||
@ -306,7 +509,6 @@ BOOL WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale)
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Adds a file into the archive
|
// 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)
|
BOOL WINAPI SFileAddFileEx(HANDLE hMPQ, const char * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality, int nFileType)
|
||||||
{
|
{
|
||||||
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
||||||
@ -321,7 +523,7 @@ BOOL WINAPI SFileAddFileEx(HANDLE hMPQ, const char * szFileName, const char * sz
|
|||||||
nError = ERROR_INVALID_PARAMETER;
|
nError = ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
// Check the values of dwFlags
|
// 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;
|
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
|
// Add the file into listfile also
|
||||||
if(nError == ERROR_SUCCESS && bReplaced == FALSE)
|
if(nError == ERROR_SUCCESS && bReplaced == FALSE)
|
||||||
nError = SListFileAddNode(ha, szArchivedName);
|
nError = SListFileCreateNode(ha, szArchivedName, lcLocale);
|
||||||
|
|
||||||
// Cleanup and exit
|
// Cleanup and exit
|
||||||
if(hFile != INVALID_HANDLE_VALUE)
|
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
|
// 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)
|
BOOL WINAPI SFileAddFile(HANDLE hMPQ, const char * szFileName, const char * szArchivedName, DWORD dwFlags)
|
||||||
{
|
{
|
||||||
return SFileAddFileEx(hMPQ, szFileName, szArchivedName, dwFlags, 0, SFILE_TYPE_DATA);
|
return SFileAddFileEx(hMPQ, szFileName, szArchivedName, dwFlags, 0, SFILE_TYPE_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds a WAVE file into the archive
|
// 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)
|
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);
|
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
|
// remains there, only the entries in the hash table and in the block
|
||||||
// table are updated.
|
// table are updated.
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
BOOL WINAPI SFileRemoveFile(HANDLE hMPQ, const char * szFileName, DWORD dwSearchScope)
|
BOOL WINAPI SFileRemoveFile(HANDLE hMPQ, const char * szFileName, DWORD dwSearchScope)
|
||||||
{
|
{
|
||||||
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
||||||
@ -403,6 +602,10 @@ BOOL WINAPI SFileRemoveFile(HANDLE hMPQ, const char * szFileName, DWORD dwSearch
|
|||||||
nError = ERROR_ACCESS_DENIED;
|
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
|
// Get hash entry belonging to this file
|
||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
@ -445,10 +648,6 @@ BOOL WINAPI SFileRemoveFile(HANDLE hMPQ, const char * szFileName, DWORD dwSearch
|
|||||||
ha->dwFlags |= MPQ_FLAG_CHANGED;
|
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
|
// Resolve error and exit
|
||||||
if(nError != ERROR_SUCCESS)
|
if(nError != ERROR_SUCCESS)
|
||||||
SetLastError(nError);
|
SetLastError(nError);
|
||||||
@ -456,13 +655,14 @@ BOOL WINAPI SFileRemoveFile(HANDLE hMPQ, const char * szFileName, DWORD dwSearch
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Renames the file within the archive.
|
// Renames the file within the archive.
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
BOOL WINAPI SFileRenameFile(HANDLE hMPQ, const char * szFileName, const char * szNewFileName)
|
BOOL WINAPI SFileRenameFile(HANDLE hMPQ, const char * szFileName, const char * szNewFileName)
|
||||||
{
|
{
|
||||||
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
||||||
|
TMPQBlock * pBlock;
|
||||||
TMPQHash * pOldHash = NULL; // Hash entry for the original file
|
TMPQHash * pOldHash = NULL; // Hash entry for the original file
|
||||||
TMPQHash * pNewHash = NULL; // Hash entry for the renamed file
|
TMPQHash * pNewHash = NULL; // Hash entry for the renamed file
|
||||||
DWORD dwBlockIndex = 0;
|
DWORD dwSaveBlockIndex = 0;
|
||||||
|
LCID lcSaveLocale = 0;
|
||||||
int nError = ERROR_SUCCESS;
|
int nError = ERROR_SUCCESS;
|
||||||
|
|
||||||
// Test the valid parameters
|
// Test the valid parameters
|
||||||
@ -481,13 +681,6 @@ BOOL WINAPI SFileRenameFile(HANDLE hMPQ, const char * szFileName, const char * s
|
|||||||
nError = ERROR_ACCESS_DENIED;
|
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
|
// Get the hash table entry for the original file
|
||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
@ -495,11 +688,34 @@ BOOL WINAPI SFileRenameFile(HANDLE hMPQ, const char * szFileName, const char * s
|
|||||||
nError = ERROR_FILE_NOT_FOUND;
|
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)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
// Save block table index and remove the hash table entry
|
// 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->dwName1 = 0xFFFFFFFF;
|
||||||
pOldHash->dwName2 = 0xFFFFFFFF;
|
pOldHash->dwName2 = 0xFFFFFFFF;
|
||||||
pOldHash->lcLocale = 0xFFFF;
|
pOldHash->lcLocale = 0xFFFF;
|
||||||
@ -514,13 +730,13 @@ BOOL WINAPI SFileRenameFile(HANDLE hMPQ, const char * szFileName, const char * s
|
|||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
// Copy the block table index
|
// Copy the block table index
|
||||||
pNewHash->dwBlockIndex = dwBlockIndex;
|
pNewHash->dwBlockIndex = dwSaveBlockIndex;
|
||||||
|
pNewHash->lcLocale = (USHORT)lcSaveLocale;
|
||||||
ha->dwFlags |= MPQ_FLAG_CHANGED;
|
ha->dwFlags |= MPQ_FLAG_CHANGED;
|
||||||
}
|
|
||||||
|
|
||||||
// Rename the file in the list file
|
// Create new name node for the listfile
|
||||||
if(nError == ERROR_SUCCESS)
|
nError = SListFileCreateNode(ha, szNewFileName, lcSaveLocale);
|
||||||
nError = SListFileRenameNode(ha, szFileName, szNewFileName);
|
}
|
||||||
|
|
||||||
// Resolve error and return
|
// Resolve error and return
|
||||||
if(nError != ERROR_SUCCESS)
|
if(nError != ERROR_SUCCESS)
|
||||||
|
|||||||
@ -12,13 +12,23 @@
|
|||||||
#include "StormLib.h"
|
#include "StormLib.h"
|
||||||
#include "SCommon.h"
|
#include "SCommon.h"
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
BOOL WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const char * szExtracted)
|
BOOL WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const char * szExtracted)
|
||||||
{
|
{
|
||||||
HANDLE hLocalFile = INVALID_HANDLE_VALUE;
|
HANDLE hLocalFile = INVALID_HANDLE_VALUE;
|
||||||
HANDLE hMpqFile = NULL;
|
HANDLE hMpqFile = NULL;
|
||||||
|
DWORD dwSearchScope = 0;
|
||||||
int nError = ERROR_SUCCESS;
|
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
|
// Create the local file
|
||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
@ -27,28 +37,27 @@ BOOL WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const char *
|
|||||||
nError = GetLastError();
|
nError = GetLastError();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the MPQ file
|
|
||||||
if(nError == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
if(!SFileOpenFileEx(hMpq, szToExtract, 0, &hMpqFile))
|
|
||||||
nError = GetLastError();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the file's content
|
// Copy the file's content
|
||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
char szBuffer[0x1000];
|
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)
|
if(dwTransferred == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// If something has been actually read, write it
|
||||||
WriteFile(hLocalFile, szBuffer, dwTransferred, &dwTransferred, NULL);
|
WriteFile(hLocalFile, szBuffer, dwTransferred, &dwTransferred, NULL);
|
||||||
if(dwTransferred == 0)
|
if(dwTransferred == 0)
|
||||||
break;
|
nError = ERROR_DISK_FULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -134,54 +134,82 @@ BOOL CheckWildCard(const char * szString, const char * szWildCard)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Performs one MPQ search
|
// Performs one MPQ search
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
static int DoMPQSearch(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData)
|
static int DoMPQSearch(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData)
|
||||||
{
|
{
|
||||||
TMPQArchive * ha = hs->ha;
|
TMPQArchive * ha = hs->ha;
|
||||||
TFileNode * pNode;
|
TFileNode * pNode = NULL;
|
||||||
|
TMPQBlock * pBlock;
|
||||||
|
TMPQHash * pFoundHash = NULL;
|
||||||
TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
||||||
TMPQHash * pHash = ha->pHashTable + hs->dwNextIndex;
|
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)
|
while(pHash < pHashEnd)
|
||||||
{
|
{
|
||||||
pNode = ha->pListFile[hs->dwNextIndex++];
|
pNode = ha->pListFile[dwIndex++];
|
||||||
|
|
||||||
// If this entry is free, do nothing
|
// Is this entry occupied ?
|
||||||
if(pHash->dwBlockIndex < HASH_ENTRY_FREE && (DWORD_PTR)pNode < HASH_ENTRY_FREE)
|
if(pHash->dwBlockIndex < HASH_ENTRY_DELETED && (DWORD_PTR)pNode < LISTFILE_ENTRY_DELETED)
|
||||||
{
|
{
|
||||||
// Check the file name.
|
// Check the file name.
|
||||||
if(CheckWildCard(pNode->szFileName, hs->szSearchMask))
|
if(CheckWildCard(pNode->szFileName, hs->szSearchMask))
|
||||||
{
|
{
|
||||||
TMPQBlock * pBlock = ha->pBlockTable + pHash->dwBlockIndex;
|
pFoundHash = pHash;
|
||||||
|
pHash++;
|
||||||
lpFindFileData->lcLocale = pHash->lcLocale;
|
break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move to the next hash
|
||||||
pHash++;
|
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
|
// No more files found, return error
|
||||||
return ERROR_NO_MORE_FILES;
|
return ERROR_NO_MORE_FILES;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
static void FreeMPQSearch(TMPQSearch *& hs)
|
static void FreeMPQSearch(TMPQSearch *& hs)
|
||||||
{
|
{
|
||||||
if(hs != NULL)
|
if(hs != NULL)
|
||||||
@ -194,7 +222,6 @@ static void FreeMPQSearch(TMPQSearch *& hs)
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Public functions
|
// Public functions
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
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
|
// Include the listfile into the MPQ's internal listfile
|
||||||
// Note that if the listfile name is NULL, do nothing because the
|
// Note that if the listfile name is NULL, do nothing because the
|
||||||
// internal listfile is always included.
|
// internal listfile is always included.
|
||||||
if(nError == ERROR_SUCCESS && szListFile != NULL)
|
if(nError == ERROR_SUCCESS && szListFile != NULL && *szListFile != 0)
|
||||||
nError = SFileAddListFile((HANDLE)ha, szListFile);
|
nError = SFileAddListFile((HANDLE)ha, szListFile);
|
||||||
|
|
||||||
// Allocate the structure for MPQ search
|
// Allocate the structure for MPQ search
|
||||||
@ -250,7 +277,6 @@ HANDLE WINAPI SFileFindFirstFile(HANDLE hMPQ, const char * szMask, SFILE_FIND_DA
|
|||||||
return (HANDLE)hs;
|
return (HANDLE)hs;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
BOOL WINAPI SFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData)
|
BOOL WINAPI SFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData)
|
||||||
{
|
{
|
||||||
TMPQSearch * hs = (TMPQSearch *)hFind;
|
TMPQSearch * hs = (TMPQSearch *)hFind;
|
||||||
@ -274,7 +300,6 @@ BOOL WINAPI SFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
BOOL WINAPI SFileFindClose(HANDLE hFind)
|
BOOL WINAPI SFileFindClose(HANDLE hFind)
|
||||||
{
|
{
|
||||||
TMPQSearch * hs = (TMPQSearch *)hFind;
|
TMPQSearch * hs = (TMPQSearch *)hFind;
|
||||||
|
|||||||
@ -30,7 +30,6 @@ static BOOL IsAviFile(TMPQHeader * pHeader)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This function gets the right positions of the hash table and the block table.
|
// This function gets the right positions of the hash table and the block table.
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
static int RelocateMpqTablePositions(TMPQArchive * ha)
|
static int RelocateMpqTablePositions(TMPQArchive * ha)
|
||||||
{
|
{
|
||||||
TMPQHeader2 * pHeader = ha->pHeader;
|
TMPQHeader2 * pHeader = ha->pHeader;
|
||||||
@ -194,15 +193,19 @@ BOOL SFileOpenArchiveEx(
|
|||||||
// If there is the MPQ shunt signature, process it
|
// If there is the MPQ shunt signature, process it
|
||||||
if(dwHeaderID == ID_MPQ_SHUNT && ha->pShunt == NULL)
|
if(dwHeaderID == ID_MPQ_SHUNT && ha->pShunt == NULL)
|
||||||
{
|
{
|
||||||
// Fill the shunt header
|
// Ignore the MPQ shunt completely if the caller wants to open the MPQ as V1.0
|
||||||
ha->ShuntPos = MpqPos;
|
if((dwFlags & MPQ_OPEN_FORCE_MPQ_V1) == 0)
|
||||||
ha->pShunt = &ha->Shunt;
|
{
|
||||||
memcpy(ha->pShunt, ha->pHeader, sizeof(TMPQShunt));
|
// Fill the shunt header
|
||||||
BSWAP_TMPQSHUNT(ha->pShunt);
|
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
|
// Set the MPQ pos and repeat the search
|
||||||
MpqPos.QuadPart = SearchPos.QuadPart + ha->pShunt->dwHeaderPos;
|
MpqPos.QuadPart = SearchPos.QuadPart + ha->pShunt->dwHeaderPos;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// There must be MPQ header signature
|
// There must be MPQ header signature
|
||||||
@ -218,38 +221,35 @@ BOOL SFileOpenArchiveEx(
|
|||||||
{
|
{
|
||||||
// W3M Map Protectors set some garbage value into the "dwHeaderSize"
|
// W3M Map Protectors set some garbage value into the "dwHeaderSize"
|
||||||
// field of MPQ header. This value is apparently ignored by Storm.dll
|
// field of MPQ header. This value is apparently ignored by Storm.dll
|
||||||
if(ha->pHeader->dwHeaderSize != sizeof(TMPQHeader) &&
|
if(ha->pHeader->dwHeaderSize != sizeof(TMPQHeader))
|
||||||
ha->pHeader->dwHeaderSize != sizeof(TMPQHeader2))
|
|
||||||
{
|
{
|
||||||
ha->dwFlags |= MPQ_FLAG_PROTECTED;
|
ha->dwFlags |= MPQ_FLAG_PROTECTED;
|
||||||
ha->pHeader->dwHeaderSize = sizeof(TMPQHeader);
|
ha->pHeader->dwHeaderSize = sizeof(TMPQHeader);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
if(ha->pHeader->dwHashTablePos < ha->pHeader->dwArchiveSize &&
|
|
||||||
ha->pHeader->dwBlockTablePos < ha->pHeader->dwArchiveSize)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_2)
|
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;
|
nError = ERROR_NOT_SUPPORTED;
|
||||||
break;
|
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
|
// Move to the next possible offset
|
||||||
SearchPos.QuadPart += 0x200;
|
SearchPos.QuadPart += 0x200;
|
||||||
MpqPos = SearchPos;
|
MpqPos = SearchPos;
|
||||||
@ -259,6 +259,17 @@ BOOL SFileOpenArchiveEx(
|
|||||||
// Relocate tables position
|
// Relocate tables position
|
||||||
if(nError == ERROR_SUCCESS)
|
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
|
// Clear the fields not supported in older formats
|
||||||
if(ha->pHeader->wFormatVersion < MPQ_FORMAT_VERSION_2)
|
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
|
// I have found a MPQ which has the block table larger than
|
||||||
// the hash table. We should avoid buffer overruns caused by that.
|
// 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->pHashTable = ALLOCMEM(TMPQHash, ha->pHeader->dwHashTableSize);
|
||||||
ha->pBlockTable = ALLOCMEM(TMPQBlock, dwBlockTableSize);
|
ha->pBlockTable = ALLOCMEM(TMPQBlock, dwBlockTableSize);
|
||||||
@ -306,33 +320,20 @@ BOOL SFileOpenArchiveEx(
|
|||||||
// Decrypt hash table and check if it is correctly decrypted
|
// Decrypt hash table and check if it is correctly decrypted
|
||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
// TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
||||||
TMPQHash * pHash;
|
// TMPQHash * pHash;
|
||||||
|
|
||||||
// We have to convert the hash table from LittleEndian
|
// We have to convert the hash table from LittleEndian
|
||||||
BSWAP_ARRAY32_UNSIGNED((DWORD *)ha->pHashTable, (dwBytes / sizeof(DWORD)));
|
BSWAP_ARRAY32_UNSIGNED((DWORD *)ha->pHashTable, (dwBytes / sizeof(DWORD)));
|
||||||
DecryptHashTable((DWORD *)ha->pHashTable, (BYTE *)"(hash table)", (ha->pHeader->dwHashTableSize * 4));
|
DecryptHashTable((DWORD *)ha->pHashTable, (BYTE *)"(hash table)", (ha->pHeader->dwHashTableSize * 4));
|
||||||
|
|
||||||
|
//
|
||||||
// Check hash table if is correctly decrypted
|
// Check hash table if is correctly decrypted
|
||||||
for(pHash = ha->pHashTable; pHash < pHashEnd; pHash++)
|
//
|
||||||
{
|
// Ladik: Some MPQ protectors corrupt the hash table by rewriting part of it.
|
||||||
// Note: Some MPQs from World of Warcraft have wPlatform set to 0x0100.
|
// To be able to open these, we will not check the entire hash table,
|
||||||
|
// but will check it at the moment of file opening.
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, read the block table
|
// Now, read the block table
|
||||||
@ -340,23 +341,30 @@ BOOL SFileOpenArchiveEx(
|
|||||||
{
|
{
|
||||||
memset(ha->pBlockTable, 0, dwBlockTableSize * sizeof(TMPQBlock));
|
memset(ha->pBlockTable, 0, dwBlockTableSize * sizeof(TMPQBlock));
|
||||||
|
|
||||||
|
// Carefully check the block table size
|
||||||
dwBytes = ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock);
|
dwBytes = ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock);
|
||||||
SetFilePointer(ha->hFile, ha->BlockTablePos.LowPart, &ha->BlockTablePos.HighPart, FILE_BEGIN);
|
SetFilePointer(ha->hFile, ha->BlockTablePos.LowPart, &ha->BlockTablePos.HighPart, FILE_BEGIN);
|
||||||
ReadFile(ha->hFile, ha->pBlockTable, dwBytes, &dwTransferred, NULL);
|
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));
|
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;
|
nError = ERROR_FILE_CORRUPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrypt block table.
|
// 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
|
// We have to check if block table is really encrypted
|
||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
TMPQBlock * pBlockEnd = ha->pBlockTable + ha->pHeader->dwBlockTableSize;
|
TMPQBlock * pBlockEnd = ha->pBlockTable + (dwBytes / sizeof(TMPQBlock));
|
||||||
TMPQBlock * pBlock = ha->pBlockTable;
|
TMPQBlock * pBlock = ha->pBlockTable;
|
||||||
BOOL bBlockTableEncrypted = FALSE;
|
BOOL bBlockTableEncrypted = FALSE;
|
||||||
|
|
||||||
@ -380,14 +388,13 @@ BOOL SFileOpenArchiveEx(
|
|||||||
{
|
{
|
||||||
DecryptBlockTable((DWORD *)ha->pBlockTable,
|
DecryptBlockTable((DWORD *)ha->pBlockTable,
|
||||||
(BYTE *)"(block table)",
|
(BYTE *)"(block table)",
|
||||||
(ha->pHeader->dwBlockTableSize * 4));
|
(dwBytes / sizeof(DWORD)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, read the extended block table.
|
// Now, read the extended block table.
|
||||||
// For V1 archives, we still will maintain the extended block table
|
// For V1 archives, we still will maintain the extended block table
|
||||||
// (it will be filled with zeros)
|
// (it will be filled with zeros)
|
||||||
// TODO: Test with >4GB
|
|
||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
memset(ha->pExtBlockTable, 0, dwBlockTableSize * sizeof(TMPQBlockEx));
|
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)
|
if(nError == ERROR_SUCCESS && (ha->dwFlags & MPQ_FLAG_PROTECTED) == 0)
|
||||||
{
|
{
|
||||||
TMPQBlockEx * pBlockEx = ha->pExtBlockTable;
|
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
|
// include the internal listfile to the TMPQArchive structure
|
||||||
if((dwFlags & MPQ_OPEN_NO_LISTFILE) == 0)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
if(nError == ERROR_SUCCESS)
|
if((dwFlags & MPQ_OPEN_NO_LISTFILE) == 0)
|
||||||
SListFileCreateListFile(ha);
|
{
|
||||||
|
if(nError == ERROR_SUCCESS)
|
||||||
|
SListFileCreateListFile(ha);
|
||||||
|
|
||||||
// Add the internal listfile
|
// Add the internal listfile
|
||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
SFileAddListFile((HANDLE)ha, NULL);
|
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
|
// Cleanup and exit
|
||||||
@ -456,6 +475,7 @@ BOOL SFileOpenArchiveEx(
|
|||||||
if(hFile != INVALID_HANDLE_VALUE)
|
if(hFile != INVALID_HANDLE_VALUE)
|
||||||
CloseHandle(hFile);
|
CloseHandle(hFile);
|
||||||
SetLastError(nError);
|
SetLastError(nError);
|
||||||
|
ha = NULL;
|
||||||
}
|
}
|
||||||
else
|
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 SFileFlushArchive(HANDLE hMpq)
|
||||||
BOOL WINAPI SFileCloseArchive(HANDLE hMPQ)
|
|
||||||
{
|
{
|
||||||
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
TMPQArchive * ha = (TMPQArchive *)hMpq;
|
||||||
|
|
||||||
|
// Do nothing if 'hMpq' is bad parameter
|
||||||
if(!IsValidMpqHandle(ha))
|
if(!IsValidMpqHandle(ha))
|
||||||
{
|
{
|
||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the archive has been changed, update the changes
|
||||||
|
// on the disk drive.
|
||||||
if(ha->dwFlags & MPQ_FLAG_CHANGED)
|
if(ha->dwFlags & MPQ_FLAG_CHANGED)
|
||||||
{
|
{
|
||||||
SListFileSaveToMpq(ha);
|
SListFileSaveToMpq(ha);
|
||||||
|
SAttrFileSaveToMpq(ha);
|
||||||
SaveMPQTables(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);
|
FreeMPQArchive(ha);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,11 +16,10 @@
|
|||||||
/* Local functions */
|
/* Local functions */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
static BOOL OpenLocalFile(const char * szFileName, HANDLE * phFile)
|
static BOOL OpenLocalFile(const char * szFileName, HANDLE * phFile)
|
||||||
{
|
{
|
||||||
TMPQFile * hf = NULL;
|
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)
|
if(hFile != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
@ -41,8 +40,7 @@ static BOOL OpenLocalFile(const char * szFileName, HANDLE * phFile)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
void FreeMPQFile(TMPQFile *& hf)
|
||||||
static void FreeMPQFile(TMPQFile *& hf)
|
|
||||||
{
|
{
|
||||||
if(hf != NULL)
|
if(hf != NULL)
|
||||||
{
|
{
|
||||||
@ -67,7 +65,6 @@ static void FreeMPQFile(TMPQFile *& hf)
|
|||||||
// pointed by plcLocales. There must be enough entries to copy the localed,
|
// pointed by plcLocales. There must be enough entries to copy the localed,
|
||||||
// otherwise the function returns ERROR_INSUFFICIENT_BUFFER.
|
// otherwise the function returns ERROR_INSUFFICIENT_BUFFER.
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
int WINAPI SFileEnumLocales(
|
int WINAPI SFileEnumLocales(
|
||||||
HANDLE hMPQ,
|
HANDLE hMPQ,
|
||||||
const char * szFileName,
|
const char * szFileName,
|
||||||
@ -109,11 +106,8 @@ int WINAPI SFileEnumLocales(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
pHash = GetHashEntry(ha, szFileName);
|
pHash = GetHashEntry(ha, szFileName);
|
||||||
}
|
|
||||||
|
|
||||||
// If the file was not found, sorry
|
// If the file was not found, sorry
|
||||||
if(nError == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
if(pHash == NULL)
|
if(pHash == NULL)
|
||||||
nError = ERROR_FILE_NOT_FOUND;
|
nError = ERROR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
@ -121,22 +115,40 @@ int WINAPI SFileEnumLocales(
|
|||||||
// Count the entries which correspond to the same file name
|
// Count the entries which correspond to the same file name
|
||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
|
TMPQHash * pStartHash = pHash;
|
||||||
TMPQHash * pSaveHash = pHash;
|
TMPQHash * pSaveHash = pHash;
|
||||||
DWORD dwName1 = pHash->dwName1;
|
DWORD dwName1 = pHash->dwName1;
|
||||||
DWORD dwName2 = pHash->dwName2;
|
DWORD dwName2 = pHash->dwName2;
|
||||||
|
LCID PrevLocale = 0xFFFFFFFF;
|
||||||
|
|
||||||
// For nameless access, return 1 locale always
|
if(dwSearchScope != SFILE_OPEN_BY_INDEX)
|
||||||
if(dwSearchScope == SFILE_OPEN_BY_INDEX)
|
|
||||||
dwLocales++;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
while(pHash < pHashEnd && pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2)
|
while(pHash->dwBlockIndex != HASH_ENTRY_FREE)
|
||||||
{
|
{
|
||||||
dwLocales++;
|
if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && pHash->dwBlockIndex != HASH_ENTRY_DELETED)
|
||||||
pHash++;
|
{
|
||||||
|
// 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;
|
pHash = pSaveHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,11 +162,40 @@ int WINAPI SFileEnumLocales(
|
|||||||
nError = ERROR_INSUFFICIENT_BUFFER;
|
nError = ERROR_INSUFFICIENT_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill all the locales
|
// Fill all present locales
|
||||||
if(nError == ERROR_SUCCESS)
|
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;
|
*plcLocales++ = (LCID)pHash->lcLocale;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nError;
|
return nError;
|
||||||
}
|
}
|
||||||
@ -165,7 +206,6 @@ int WINAPI SFileEnumLocales(
|
|||||||
// hMPQ - Handle of opened MPQ archive
|
// hMPQ - Handle of opened MPQ archive
|
||||||
// szFileName - Name of file to look for
|
// szFileName - Name of file to look for
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
BOOL WINAPI SFileHasFile(HANDLE hMPQ, const char * szFileName)
|
BOOL WINAPI SFileHasFile(HANDLE hMPQ, const char * szFileName)
|
||||||
{
|
{
|
||||||
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
TMPQArchive * ha = (TMPQArchive *)hMPQ;
|
||||||
@ -206,7 +246,6 @@ BOOL WINAPI SFileHasFile(HANDLE hMPQ, const char * szFileName)
|
|||||||
// dwSearchScope - Where to search
|
// dwSearchScope - Where to search
|
||||||
// phFile - Pointer to store opened file handle
|
// phFile - Pointer to store opened file handle
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
BOOL WINAPI SFileOpenFileEx(HANDLE hMPQ, const char * szFileName, DWORD dwSearchScope, HANDLE * phFile)
|
BOOL WINAPI SFileOpenFileEx(HANDLE hMPQ, const char * szFileName, DWORD dwSearchScope, HANDLE * phFile)
|
||||||
{
|
{
|
||||||
LARGE_INTEGER FilePos;
|
LARGE_INTEGER FilePos;
|
||||||
@ -282,7 +321,8 @@ BOOL WINAPI SFileOpenFileEx(HANDLE hMPQ, const char * szFileName, DWORD dwSearch
|
|||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
// If index was not found, or is greater than number of files, exit.
|
// 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;
|
nError = ERROR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,11 +363,11 @@ BOOL WINAPI SFileOpenFileEx(HANDLE hMPQ, const char * szFileName, DWORD dwSearch
|
|||||||
hf->pHash = pHash;
|
hf->pHash = pHash;
|
||||||
|
|
||||||
hf->MpqFilePos.HighPart = pBlockEx->wFilePosHigh;
|
hf->MpqFilePos.HighPart = pBlockEx->wFilePosHigh;
|
||||||
hf->MpqFilePos.LowPart = pBlock->dwFilePos;
|
hf->MpqFilePos.LowPart = pBlock->dwFilePos;
|
||||||
hf->MpqFilePos.QuadPart += ha->MpqPos.QuadPart;
|
hf->RawFilePos.QuadPart = hf->MpqFilePos.QuadPart + ha->MpqPos.QuadPart;
|
||||||
|
|
||||||
hf->dwHashIndex = dwHashIndex;
|
hf->dwHashIndex = dwHashIndex;
|
||||||
hf->dwFileIndex = dwBlockIndex;
|
hf->dwBlockIndex = dwBlockIndex;
|
||||||
|
|
||||||
// Allocate buffers for decompression.
|
// Allocate buffers for decompression.
|
||||||
if(hf->pBlock->dwFlags & MPQ_FILE_COMPRESSED)
|
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);
|
strcpy(hf->szFileName, szFileName);
|
||||||
if(szTemp != NULL)
|
if(szTemp != NULL)
|
||||||
szFileName = szTemp + 1;
|
szFileName = szTemp + 1;
|
||||||
hf->dwSeed1 = DecryptFileSeed((char *)szFileName);
|
|
||||||
|
|
||||||
|
hf->dwSeed1 = DecryptFileSeed((char *)szFileName);
|
||||||
if(hf->pBlock->dwFlags & MPQ_FILE_FIXSEED)
|
if(hf->pBlock->dwFlags & MPQ_FILE_FIXSEED)
|
||||||
{
|
{
|
||||||
hf->dwSeed1 = (hf->dwSeed1 + hf->pBlock->dwFilePos) ^ hf->pBlock->dwFSize;
|
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
|
// Cleanup
|
||||||
if(nError != ERROR_SUCCESS)
|
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)
|
BOOL WINAPI SFileCloseFile(HANDLE hFile)
|
||||||
{
|
{
|
||||||
TMPQFile * hf = (TMPQFile *)hFile;
|
TMPQFile * hf = (TMPQFile *)hFile;
|
||||||
|
|||||||
@ -25,7 +25,7 @@
|
|||||||
struct TID2Ext
|
struct TID2Ext
|
||||||
{
|
{
|
||||||
DWORD dwID;
|
DWORD dwID;
|
||||||
const char * szExt;
|
char * szExt;
|
||||||
};
|
};
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -38,7 +38,6 @@ struct TID2Ext
|
|||||||
//
|
//
|
||||||
// Returns number of bytes read.
|
// Returns number of bytes read.
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
static DWORD WINAPI ReadMPQBlocks(TMPQFile * hf, DWORD dwBlockPos, BYTE * buffer, DWORD blockBytes)
|
static DWORD WINAPI ReadMPQBlocks(TMPQFile * hf, DWORD dwBlockPos, BYTE * buffer, DWORD blockBytes)
|
||||||
{
|
{
|
||||||
LARGE_INTEGER FilePos;
|
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)
|
if((hf->pBlock->dwFlags & MPQ_FILE_COMPRESSED) && hf->bBlockPosLoaded == FALSE)
|
||||||
{
|
{
|
||||||
// Move file pointer to the begin of the file in the MPQ
|
// Move file pointer to the begin of the file in the MPQ
|
||||||
if(hf->MpqFilePos.QuadPart != ha->FilePointer.QuadPart)
|
SetFilePointer(ha->hFile, hf->RawFilePos.LowPart, &hf->RawFilePos.HighPart, FILE_BEGIN);
|
||||||
{
|
|
||||||
SetFilePointer(ha->hFile, hf->MpqFilePos.LowPart, &hf->MpqFilePos.HighPart, FILE_BEGIN);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read block positions from begin of file.
|
// Read block positions from begin of file.
|
||||||
dwToRead = (hf->nBlocks+1) * sizeof(DWORD);
|
dwToRead = (hf->nBlocks+1) * sizeof(DWORD);
|
||||||
@ -109,13 +105,20 @@ static DWORD WINAPI ReadMPQBlocks(TMPQFile * hf, DWORD dwBlockPos, BYTE * buffer
|
|||||||
// Decrypt block positions
|
// Decrypt block positions
|
||||||
DecryptMPQBlock(hf->pdwBlockPos, dwBytesRead, hf->dwSeed1 - 1);
|
DecryptMPQBlock(hf->pdwBlockPos, dwBytesRead, hf->dwSeed1 - 1);
|
||||||
|
|
||||||
|
//
|
||||||
// Check if the block positions are correctly decrypted
|
// Check if the block positions are correctly decrypted
|
||||||
// I don't know why, but sometimes it will result invalid block positions on some files
|
// Previous versions of StormLib (up to 6.20) had bug in SFileRenameFile.
|
||||||
if(hf->pdwBlockPos[0] != dwBytesRead)
|
// 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
|
// Try once again to detect file seed and decrypt the blocks
|
||||||
// TODO: Test with >4GB
|
SetFilePointer(ha->hFile, hf->RawFilePos.LowPart, &hf->RawFilePos.HighPart, FILE_BEGIN);
|
||||||
SetFilePointer(ha->hFile, hf->MpqFilePos.LowPart, &hf->MpqFilePos.HighPart, FILE_BEGIN);
|
|
||||||
ReadFile(ha->hFile, hf->pdwBlockPos, dwToRead, &dwBytesRead, NULL);
|
ReadFile(ha->hFile, hf->pdwBlockPos, dwToRead, &dwBytesRead, NULL);
|
||||||
|
|
||||||
BSWAP_ARRAY32_UNSIGNED(hf->pdwBlockPos, (hf->nBlocks+1));
|
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
|
// Update hf's variables
|
||||||
ha->FilePointer.QuadPart = hf->MpqFilePos.QuadPart + dwBytesRead;
|
|
||||||
hf->bBlockPosLoaded = TRUE;
|
hf->bBlockPosLoaded = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +143,12 @@ static DWORD WINAPI ReadMPQBlocks(TMPQFile * hf, DWORD dwBlockPos, BYTE * buffer
|
|||||||
dwFilePos = hf->pdwBlockPos[blockNum];
|
dwFilePos = hf->pdwBlockPos[blockNum];
|
||||||
dwToRead = hf->pdwBlockPos[blockNum + nBlocks] - dwFilePos;
|
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
|
// Get work buffer for store read data
|
||||||
tempBuffer = buffer;
|
tempBuffer = buffer;
|
||||||
@ -154,22 +161,16 @@ static DWORD WINAPI ReadMPQBlocks(TMPQFile * hf, DWORD dwBlockPos, BYTE * buffer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set file pointer, if necessary
|
// Set file pointer, if necessary and read all required blocks
|
||||||
if(ha->FilePointer.QuadPart != FilePos.QuadPart)
|
SetFilePointer(ha->hFile, FilePos.LowPart, &FilePos.HighPart, FILE_BEGIN);
|
||||||
{
|
|
||||||
SetFilePointer(ha->hFile, FilePos.LowPart, &FilePos.HighPart, FILE_BEGIN);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 15018F87 : Read all requested blocks
|
|
||||||
ReadFile(ha->hFile, tempBuffer, dwToRead, &dwBytesRead, NULL);
|
ReadFile(ha->hFile, tempBuffer, dwToRead, &dwBytesRead, NULL);
|
||||||
ha->FilePointer.QuadPart = FilePos.QuadPart + dwBytesRead;
|
|
||||||
|
|
||||||
// Block processing part.
|
// Block processing part.
|
||||||
DWORD blockStart = 0; // Index of block start in work buffer
|
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
|
DWORD index = blockNum; // Current block index
|
||||||
|
|
||||||
dwBytesRead = 0; // Clear read byte counter
|
dwBytesRead = 0; // Clear read byte counter
|
||||||
|
|
||||||
// Walk through all blocks
|
// Walk through all blocks
|
||||||
for(i = 0; i < nBlocks; i++, index++)
|
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);
|
hf->dwSeed1 = DetectFileSeed2((DWORD *)inputBuffer, 2, 0x00905A4D, 0x00000003);
|
||||||
|
|
||||||
if(hf->dwSeed1 == 0)
|
if(hf->dwSeed1 == 0)
|
||||||
return 0;
|
{
|
||||||
|
dwBytesRead = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
DecryptMPQBlock((DWORD *)inputBuffer, blockSize, hf->dwSeed1 + index);
|
DecryptMPQBlock((DWORD *)inputBuffer, blockSize, hf->dwSeed1 + index);
|
||||||
BSWAP_ARRAY32_UNSIGNED((DWORD *)inputBuffer, blockSize / sizeof(DWORD));
|
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)
|
if(blockSize < (DWORD)outLength)
|
||||||
{
|
{
|
||||||
// Is the file compressed with PKWARE Data Compression Library ?
|
// 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);
|
Decompress_pklib((char *)buffer, &outLength, (char *)inputBuffer, (int)blockSize);
|
||||||
|
|
||||||
// Is it a file compressed by Blizzard's multiple compression ?
|
// Is it a file compressed by Blizzard's multiple compression ?
|
||||||
// Note that Storm.dll v 1.0.9 distributed with Warcraft III
|
// 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
|
// 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 *)buffer, &outLength, (char *)inputBuffer, (int)blockSize);
|
{
|
||||||
|
if(!SCompDecompress((char *)buffer, &outLength, (char *)inputBuffer, (int)blockSize))
|
||||||
|
{
|
||||||
|
dwBytesRead = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dwBytesRead += outLength;
|
dwBytesRead += outLength;
|
||||||
buffer += 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
|
// 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)
|
// (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)
|
static DWORD WINAPI ReadMPQFileSingleUnit(TMPQFile * hf, DWORD dwFilePos, BYTE * pbBuffer, DWORD dwToRead)
|
||||||
{
|
{
|
||||||
TMPQArchive * ha = hf->ha;
|
TMPQArchive * ha = hf->ha;
|
||||||
DWORD dwBytesRead = 0;
|
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.
|
// If the file is really compressed, decompress it.
|
||||||
// Otherwise, read the data as-is to the caller.
|
// Otherwise, read the data as-is to the caller.
|
||||||
if(hf->pBlock->dwCSize < hf->pBlock->dwFSize)
|
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 outputBufferSize = (int)hf->pBlock->dwFSize;
|
||||||
int inputBufferSize = (int)hf->pBlock->dwCSize;
|
int inputBufferSize = (int)hf->pBlock->dwCSize;
|
||||||
|
|
||||||
|
// Allocate buffer in the hf
|
||||||
hf->pbFileBuffer = ALLOCMEM(BYTE, outputBufferSize);
|
hf->pbFileBuffer = ALLOCMEM(BYTE, outputBufferSize);
|
||||||
|
if(hf->pbFileBuffer == NULL)
|
||||||
|
return (DWORD)-1;
|
||||||
|
|
||||||
|
// Allocate temporary buffer for reading the file
|
||||||
inputBuffer = ALLOCMEM(BYTE, inputBufferSize);
|
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
|
// Read the compressed file data
|
||||||
ReadFile(ha->hFile, inputBuffer, inputBufferSize, &dwBytesRead, NULL);
|
ReadFile(ha->hFile, inputBuffer, inputBufferSize, &dwBytesRead, NULL);
|
||||||
|
|
||||||
// Is the file compressed with PKWARE Data Compression Library ?
|
// 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);
|
Decompress_pklib((char *)hf->pbFileBuffer, &outputBufferSize, (char *)inputBuffer, (int)inputBufferSize);
|
||||||
|
|
||||||
// Is it a file compressed by Blizzard's multiple compression ?
|
// Is it a file compressed by Blizzard's multiple compression ?
|
||||||
// Note that Storm.dll v 1.0.9 distributed with Warcraft III
|
// 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
|
// 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);
|
SCompDecompress((char *)hf->pbFileBuffer, &outputBufferSize, (char *)inputBuffer, (int)inputBufferSize);
|
||||||
}
|
|
||||||
|
|
||||||
// Free the temporary buffer
|
// Free the temporary input buffer
|
||||||
if(inputBuffer != NULL)
|
|
||||||
FREEMEM(inputBuffer);
|
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
|
// Copy the file data, if any there
|
||||||
if(hf->pbFileBuffer != NULL)
|
if(hf->pbFileBuffer != NULL)
|
||||||
{
|
{
|
||||||
memcpy(pbBuffer, hf->pbFileBuffer + dwFilePos, dwToRead);
|
memcpy(pbBuffer, hf->pbFileBuffer + dwFilePos, dwToRead);
|
||||||
dwBytesRead += dwToRead;
|
dwBytesRead = dwToRead;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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
|
// Read the uncompressed file data
|
||||||
ReadFile(ha->hFile, pbBuffer, dwToRead, &dwBytesRead, NULL);
|
ReadFile(ha->hFile, pbBuffer, dwToRead, &dwBytesRead, NULL);
|
||||||
dwBytesRead = (int)dwBytesRead;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (DWORD)dwBytesRead;
|
return dwBytesRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// ReadMPQFile
|
// ReadMPQFile
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
static DWORD WINAPI ReadMPQFile(TMPQFile * hf, DWORD dwFilePos, BYTE * pbBuffer, DWORD dwToRead)
|
static DWORD WINAPI ReadMPQFile(TMPQFile * hf, DWORD dwFilePos, BYTE * pbBuffer, DWORD dwToRead)
|
||||||
{
|
{
|
||||||
TMPQArchive * ha = hf->ha;
|
TMPQArchive * ha = hf->ha;
|
||||||
@ -427,7 +450,6 @@ static DWORD WINAPI ReadMPQFile(TMPQFile * hf, DWORD dwFilePos, BYTE * pbBuffer,
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// SFileReadFile
|
// SFileReadFile
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
BOOL WINAPI SFileReadFile(HANDLE hFile, VOID * lpBuffer, DWORD dwToRead, DWORD * pdwRead, LPOVERLAPPED lpOverlapped)
|
BOOL WINAPI SFileReadFile(HANDLE hFile, VOID * lpBuffer, DWORD dwToRead, DWORD * pdwRead, LPOVERLAPPED lpOverlapped)
|
||||||
{
|
{
|
||||||
TMPQFile * hf = (TMPQFile *)hFile;
|
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)
|
// 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)
|
DWORD WINAPI SFileGetFilePos(HANDLE hFile, DWORD * pdwFilePosHigh)
|
||||||
{
|
{
|
||||||
TMPQFile * hf = (TMPQFile *)hFile;
|
TMPQFile * hf = (TMPQFile *)hFile;
|
||||||
@ -514,14 +535,13 @@ DWORD WINAPI SFileGetFilePos(HANDLE hFile, DWORD * pdwFilePosHigh)
|
|||||||
|
|
||||||
// If opened from archive, return file size
|
// If opened from archive, return file size
|
||||||
if(pdwFilePosHigh != NULL)
|
if(pdwFilePosHigh != NULL)
|
||||||
*pdwFilePosHigh = hf->MpqFilePos.HighPart;
|
*pdwFilePosHigh = hf->RawFilePos.HighPart;
|
||||||
return hf->MpqFilePos.LowPart;
|
return hf->RawFilePos.LowPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// SFileGetFileSize
|
// SFileGetFileSize
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
DWORD WINAPI SFileGetFileSize(HANDLE hFile, DWORD * pdwFileSizeHigh)
|
DWORD WINAPI SFileGetFileSize(HANDLE hFile, DWORD * pdwFileSizeHigh)
|
||||||
{
|
{
|
||||||
TMPQFile * hf = (TMPQFile *)hFile;
|
TMPQFile * hf = (TMPQFile *)hFile;
|
||||||
@ -543,7 +563,6 @@ DWORD WINAPI SFileGetFileSize(HANDLE hFile, DWORD * pdwFileSizeHigh)
|
|||||||
return hf->pBlock->dwFSize;
|
return hf->pBlock->dwFSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * pdwFilePosHigh, DWORD dwMethod)
|
DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * pdwFilePosHigh, DWORD dwMethod)
|
||||||
{
|
{
|
||||||
TMPQArchive * ha;
|
TMPQArchive * ha;
|
||||||
@ -623,14 +642,14 @@ static TID2Ext id2ext[] =
|
|||||||
{0x3032444D, "m2"}, // WoW ??? .m2
|
{0x3032444D, "m2"}, // WoW ??? .m2
|
||||||
{0x43424457, "dbc"}, // ??? .dbc
|
{0x43424457, "dbc"}, // ??? .dbc
|
||||||
{0x47585053, "bls"}, // WoW pixel shaders
|
{0x47585053, "bls"}, // WoW pixel shaders
|
||||||
|
{0xE0FFD8FF, "jpg"}, // JPEG image
|
||||||
{0, NULL} // Terminator
|
{0, NULL} // Terminator
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
BOOL WINAPI SFileGetFileName(HANDLE hFile, char * szFileName)
|
BOOL WINAPI SFileGetFileName(HANDLE hFile, char * szFileName)
|
||||||
{
|
{
|
||||||
TMPQFile * hf = (TMPQFile *)hFile; // MPQ File handle
|
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 dwFirstBytes[2]; // The first 4 bytes of the file
|
||||||
DWORD dwFilePos; // Saved file position
|
DWORD dwFilePos; // Saved file position
|
||||||
int nError = ERROR_SUCCESS;
|
int nError = ERROR_SUCCESS;
|
||||||
@ -657,7 +676,7 @@ BOOL WINAPI SFileGetFileName(HANDLE hFile, char * szFileName)
|
|||||||
|
|
||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
if(hf->dwFileIndex == (DWORD)-1)
|
if(hf->dwBlockIndex == (DWORD)-1)
|
||||||
nError = ERROR_CAN_NOT_COMPLETE;
|
nError = ERROR_CAN_NOT_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,8 +685,7 @@ BOOL WINAPI SFileGetFileName(HANDLE hFile, char * szFileName)
|
|||||||
{
|
{
|
||||||
dwFirstBytes[0] = dwFirstBytes[1] = 0;
|
dwFirstBytes[0] = dwFirstBytes[1] = 0;
|
||||||
dwFilePos = SFileSetFilePointer(hf, 0, NULL, FILE_CURRENT);
|
dwFilePos = SFileSetFilePointer(hf, 0, NULL, FILE_CURRENT);
|
||||||
if(!SFileReadFile(hFile, &dwFirstBytes, sizeof(dwFirstBytes), NULL))
|
SFileReadFile(hFile, &dwFirstBytes, sizeof(dwFirstBytes), NULL);
|
||||||
nError = GetLastError();
|
|
||||||
BSWAP_ARRAY32_UNSIGNED(dwFirstBytes, sizeof(dwFirstBytes) / sizeof(DWORD));
|
BSWAP_ARRAY32_UNSIGNED(dwFirstBytes, sizeof(dwFirstBytes) / sizeof(DWORD));
|
||||||
SFileSetFilePointer(hf, dwFilePos, NULL, FILE_BEGIN);
|
SFileSetFilePointer(hf, dwFilePos, NULL, FILE_BEGIN);
|
||||||
}
|
}
|
||||||
@ -691,7 +709,7 @@ BOOL WINAPI SFileGetFileName(HANDLE hFile, char * szFileName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the file name
|
// 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)
|
if(szFileName != hf->szFileName)
|
||||||
strcpy(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
|
// hMpqOrFile - Handle to an MPQ archive or to a file
|
||||||
// dwInfoType - Information to obtain
|
// dwInfoType - Information to obtain
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
DWORD_PTR WINAPI SFileGetFileInfo(HANDLE hMpqOrFile, DWORD dwInfoType)
|
DWORD_PTR WINAPI SFileGetFileInfo(HANDLE hMpqOrFile, DWORD dwInfoType)
|
||||||
{
|
{
|
||||||
TMPQArchive * ha = (TMPQArchive *)hMpqOrFile;
|
TMPQArchive * ha = (TMPQArchive *)hMpqOrFile;
|
||||||
@ -781,7 +798,7 @@ DWORD_PTR WINAPI SFileGetFileInfo(HANDLE hMpqOrFile, DWORD dwInfoType)
|
|||||||
|
|
||||||
case SFILE_INFO_BLOCKINDEX:
|
case SFILE_INFO_BLOCKINDEX:
|
||||||
if(IsValidFileHandle(hf))
|
if(IsValidFileHandle(hf))
|
||||||
return hf->dwFileIndex;
|
return hf->dwBlockIndex;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SFILE_INFO_FILE_SIZE:
|
case SFILE_INFO_FILE_SIZE:
|
||||||
@ -814,7 +831,7 @@ DWORD_PTR WINAPI SFileGetFileInfo(HANDLE hMpqOrFile, DWORD dwInfoType)
|
|||||||
{
|
{
|
||||||
dwSeed = hf->dwSeed1;
|
dwSeed = hf->dwSeed1;
|
||||||
if(hf->pBlock->dwFlags & MPQ_FILE_FIXSEED)
|
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;
|
return dwSeed;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -20,10 +20,6 @@
|
|||||||
#define NO_MORE_CHARACTERS 256
|
#define NO_MORE_CHARACTERS 256
|
||||||
#define HASH_TABLE_SIZE 31 // Initial hash table size (should be a prime number)
|
#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
|
struct TListFileCache
|
||||||
{
|
{
|
||||||
HANDLE hFile; // Stormlib file handle
|
HANDLE hFile; // Stormlib file handle
|
||||||
@ -133,9 +129,10 @@ int SListFileCreateListFile(TMPQArchive * ha)
|
|||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds a filename into the listfile. If the file name is already there,
|
// Adds a name into the list of all names. For each locale in the MPQ,
|
||||||
// does nothing.
|
// one entry will be created
|
||||||
int SListFileAddNode(TMPQArchive * ha, const char * szFileName)
|
// If the file name is already there, does nothing.
|
||||||
|
int SListFileCreateNodeForAllLocales(TMPQArchive * ha, const char * szFileName)
|
||||||
{
|
{
|
||||||
TFileNode * pNode = NULL;
|
TFileNode * pNode = NULL;
|
||||||
TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
TMPQHash * pHashEnd = ha->pHashTable + ha->pHeader->dwHashTableSize;
|
||||||
@ -150,44 +147,107 @@ int SListFileAddNode(TMPQArchive * ha, const char * szFileName)
|
|||||||
if(pHash == NULL)
|
if(pHash == NULL)
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
|
|
||||||
// If the listfile entry already exists, do nothing
|
// Remember the name
|
||||||
dwHashIndex = (DWORD)(pHash - ha->pHashTable);
|
dwName1 = pHash->dwName1;
|
||||||
dwName1 = pHash->dwName1;
|
dwName2 = pHash->dwName2;
|
||||||
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);
|
|
||||||
|
|
||||||
// Fill the nodes for all language versions
|
// Pass all entries in the hash table
|
||||||
while(pHash->dwBlockIndex < LISTFILE_ENTRY_DELETED)
|
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++;
|
if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2)
|
||||||
ha->pListFile[pHash - ha->pHashTable] = pNode;
|
{
|
||||||
|
// 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)
|
if(++pHash >= pHashEnd)
|
||||||
pHash = ha->pHashTable;
|
pHash = ha->pHashTable;
|
||||||
if(pHash == pHash0)
|
if(pHash == pHash0)
|
||||||
break;
|
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;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a filename from the listfile.
|
// Removes a filename from the listfile.
|
||||||
// If the name is not there, does nothing
|
// 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;
|
TFileNode * pNode = NULL;
|
||||||
TMPQHash * pHash = GetHashEntry(ha, szFileName);
|
TMPQHash * pHash = GetHashEntryEx(ha, szFileName, lcLocale);
|
||||||
size_t nHashIndex = 0;
|
size_t nHashIndex = 0;
|
||||||
|
|
||||||
if(pHash != NULL)
|
if(pHash != NULL)
|
||||||
@ -196,25 +256,15 @@ int SListFileRemoveNode(TMPQArchive * ha, const char * szFileName)
|
|||||||
pNode = ha->pListFile[nHashIndex];
|
pNode = ha->pListFile[nHashIndex];
|
||||||
ha->pListFile[nHashIndex] = (TFileNode *)LISTFILE_ENTRY_DELETED;
|
ha->pListFile[nHashIndex] = (TFileNode *)LISTFILE_ENTRY_DELETED;
|
||||||
|
|
||||||
// If the reference count has reached zero, do nothing
|
// Free the node
|
||||||
if(--pNode->dwRefCount == 0)
|
pNode->dwRefCount--;
|
||||||
|
if(pNode->dwRefCount == 0)
|
||||||
FREEMEM(pNode);
|
FREEMEM(pNode);
|
||||||
}
|
}
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SListFileFreeListFile(TMPQArchive * ha)
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
if(ha->pListFile != NULL)
|
if(ha->pListFile != NULL)
|
||||||
{
|
{
|
||||||
@ -222,25 +272,22 @@ int SListFileFreeListFile(TMPQArchive * ha)
|
|||||||
{
|
{
|
||||||
TFileNode * pNode = ha->pListFile[i];
|
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);
|
FREEMEM(pNode);
|
||||||
ha->pListFile[i] = (TFileNode *)LISTFILE_ENTRY_FREE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FREEMEM(ha->pListFile);
|
FREEMEM(ha->pListFile);
|
||||||
ha->pListFile = NULL;
|
ha->pListFile = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Saves the whole listfile into the MPQ.
|
// Saves the whole listfile into the MPQ.
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
int SListFileSaveToMpq(TMPQArchive * ha)
|
int SListFileSaveToMpq(TMPQArchive * ha)
|
||||||
{
|
{
|
||||||
TFileNode * pNode = NULL;
|
TFileNode * pNode = NULL;
|
||||||
@ -265,7 +312,7 @@ int SListFileSaveToMpq(TMPQArchive * ha)
|
|||||||
if(nError == ERROR_SUCCESS)
|
if(nError == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
GetListFileName(ha, szListFile);
|
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)
|
if(hFile == INVALID_HANDLE_VALUE)
|
||||||
nError = GetLastError();
|
nError = GetLastError();
|
||||||
}
|
}
|
||||||
@ -281,7 +328,7 @@ int SListFileSaveToMpq(TMPQArchive * ha)
|
|||||||
{
|
{
|
||||||
for(;;)
|
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;
|
dwName1 = pHash->dwName1;
|
||||||
dwName2 = pHash->dwName2;
|
dwName2 = pHash->dwName2;
|
||||||
@ -314,14 +361,22 @@ int SListFileSaveToMpq(TMPQArchive * ha)
|
|||||||
|
|
||||||
// Add the listfile into the archive.
|
// Add the listfile into the archive.
|
||||||
SFileSetLocale(LANG_NEUTRAL);
|
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)
|
if(hFile != INVALID_HANDLE_VALUE)
|
||||||
CloseHandle(hFile);
|
CloseHandle(hFile);
|
||||||
|
DeleteFile(szListFile);
|
||||||
|
|
||||||
lcLocale = lcSave;
|
|
||||||
return nError;
|
return nError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +385,6 @@ int SListFileSaveToMpq(TMPQArchive * ha)
|
|||||||
|
|
||||||
// Adds a listfile into the MPQ archive.
|
// Adds a listfile into the MPQ archive.
|
||||||
// Note that the function does not remove the
|
// Note that the function does not remove the
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
int WINAPI SFileAddListFile(HANDLE hMpq, const char * szListFile)
|
int WINAPI SFileAddListFile(HANDLE hMpq, const char * szListFile)
|
||||||
{
|
{
|
||||||
TListFileCache * pCache = NULL;
|
TListFileCache * pCache = NULL;
|
||||||
@ -392,15 +446,15 @@ int WINAPI SFileAddListFile(HANDLE hMpq, const char * szListFile)
|
|||||||
pCache->pPos = &pCache->Buffer[0];
|
pCache->pPos = &pCache->Buffer[0];
|
||||||
pCache->pEnd = pCache->pBegin + pCache->dwBuffSize;
|
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)
|
while((nLength = ReadLine(pCache, szFileName, sizeof(szFileName) - 1)) > 0)
|
||||||
SListFileAddNode(ha, szFileName);
|
SListFileCreateNodeForAllLocales(ha, szFileName);
|
||||||
|
|
||||||
// Add well-known names
|
// Also, add three special files to the listfile:
|
||||||
// Sometimes, they are not in listfile, but they exist in the archive
|
// (listfile) itself, (attributes) and (signature)
|
||||||
SListFileAddNode(ha, LISTFILE_NAME);
|
SListFileCreateNodeForAllLocales(ha, LISTFILE_NAME);
|
||||||
SListFileAddNode(ha, SIGNATURE_NAME);
|
SListFileCreateNodeForAllLocales(ha, SIGNATURE_NAME);
|
||||||
SListFileAddNode(ha, ATTRIBUTES_NAME);
|
SListFileCreateNodeForAllLocales(ha, ATTRIBUTES_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup & exit
|
// Cleanup & exit
|
||||||
@ -412,7 +466,6 @@ int WINAPI SFileAddListFile(HANDLE hMpq, const char * szListFile)
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Passing through the listfile
|
// Passing through the listfile
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
HANDLE SListFileFindFirstFile(HANDLE hMpq, const char * szListFile, const char * szMask, SFILE_FIND_DATA * lpFindFileData)
|
HANDLE SListFileFindFirstFile(HANDLE hMpq, const char * szListFile, const char * szMask, SFILE_FIND_DATA * lpFindFileData)
|
||||||
{
|
{
|
||||||
TListFileCache * pCache = NULL;
|
TListFileCache * pCache = NULL;
|
||||||
@ -509,7 +562,6 @@ HANDLE SListFileFindFirstFile(HANDLE hMpq, const char * szListFile, const char *
|
|||||||
return (HANDLE)pCache;
|
return (HANDLE)pCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
BOOL SListFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData)
|
BOOL SListFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData)
|
||||||
{
|
{
|
||||||
TListFileCache * pCache = (TListFileCache *)hFind;
|
TListFileCache * pCache = (TListFileCache *)hFind;
|
||||||
@ -540,7 +592,6 @@ BOOL SListFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData)
|
|||||||
return bResult;
|
return bResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test for archives > 4GB
|
|
||||||
BOOL SListFileFindClose(HANDLE hFind)
|
BOOL SListFileFindClose(HANDLE hFind)
|
||||||
{
|
{
|
||||||
TListFileCache * pCache = (TListFileCache *)hFind;
|
TListFileCache * pCache = (TListFileCache *)hFind;
|
||||||
|
|||||||
@ -43,6 +43,18 @@
|
|||||||
/* 15.05.06 5.02 Lad Fixed issue with WoW 1.10+ */
|
/* 15.05.06 5.02 Lad Fixed issue with WoW 1.10+ */
|
||||||
/* 07.09.06 5.10 Lad Fixed processing files longer than 2GB */
|
/* 07.09.06 5.10 Lad Fixed processing files longer than 2GB */
|
||||||
/* 22.11.06 6.00 Lad Support for MPQ archives V2 */
|
/* 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_
|
#ifndef __STORMLIB_H_
|
||||||
@ -61,8 +73,6 @@
|
|||||||
// Z - S for static C library, D for multithreaded DLL C-library
|
// Z - S for static C library, D for multithreaded DLL C-library
|
||||||
//
|
//
|
||||||
|
|
||||||
#define __STORMLIB_SELF__
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) && !defined (__STORMLIB_SELF__)
|
#if defined(_MSC_VER) && !defined (__STORMLIB_SELF__)
|
||||||
#ifdef _DEBUG // DEBUG VERSIONS
|
#ifdef _DEBUG // DEBUG VERSIONS
|
||||||
#ifdef _DLL
|
#ifdef _DLL
|
||||||
@ -88,7 +98,7 @@
|
|||||||
#define ERROR_AVI_FILE 10000 // No MPQ file, but AVI file.
|
#define ERROR_AVI_FILE 10000 // No MPQ file, but AVI file.
|
||||||
|
|
||||||
// Values for SFileCreateArchiveEx
|
// Values for SFileCreateArchiveEx
|
||||||
#define HASH_TABLE_SIZE_MIN 0x00002
|
#define HASH_TABLE_SIZE_MIN 0x00004
|
||||||
#define HASH_TABLE_SIZE_MAX 0x40000
|
#define HASH_TABLE_SIZE_MAX 0x40000
|
||||||
|
|
||||||
#define HASH_ENTRY_DELETED 0xFFFFFFFE // Block index for deleted hash entry
|
#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)
|
#define MPQ_FLAG_PROTECTED 0x00000002 // Set on protected MPQs (like W3M maps)
|
||||||
|
|
||||||
// Flags for SFileAddFile
|
// Flags for SFileAddFile
|
||||||
#define MPQ_FILE_COMPRESS_PKWARE 0x00000100 // Compression made by PKWARE Data Compression Library
|
// Note: MPQ_FILE_COMPRESS_PKWARE has been replaced by MPQ_FILE_IMPLODE
|
||||||
#define MPQ_FILE_COMPRESS_MULTI 0x00000200 // Multiple compressions
|
// 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_COMPRESSED 0x0000FF00 // File is compressed
|
||||||
#define MPQ_FILE_ENCRYPTED 0x00010000 // Indicates whether file is encrypted
|
#define MPQ_FILE_ENCRYPTED 0x00010000 // Indicates whether file is encrypted
|
||||||
#define MPQ_FILE_FIXSEED 0x00020000 // File decrypt seed has to be fixed
|
#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_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_REPLACEEXISTING 0x80000000 // Replace when the file exist (SFileAddFile)
|
||||||
|
|
||||||
#define MPQ_FILE_VALID_FLAGS (MPQ_FILE_COMPRESS_PKWARE | \
|
#define MPQ_FILE_VALID_FLAGS (MPQ_FILE_IMPLODE | \
|
||||||
MPQ_FILE_COMPRESS_MULTI | \
|
MPQ_FILE_COMPRESS | \
|
||||||
MPQ_FILE_ENCRYPTED | \
|
MPQ_FILE_ENCRYPTED | \
|
||||||
MPQ_FILE_FIXSEED | \
|
MPQ_FILE_FIXSEED | \
|
||||||
MPQ_FILE_SINGLE_UNIT | \
|
MPQ_FILE_SINGLE_UNIT | \
|
||||||
MPQ_FILE_DUMMY_FILE | \
|
MPQ_FILE_DUMMY_FILE | \
|
||||||
MPQ_FILE_HAS_EXTRA | \
|
MPQ_FILE_HAS_EXTRA | \
|
||||||
MPQ_FILE_EXISTS)
|
MPQ_FILE_EXISTS)
|
||||||
|
|
||||||
// Compression types for multilpe compressions
|
// Compression types for multilpe compressions
|
||||||
@ -175,18 +187,29 @@
|
|||||||
#define SIGNATURE_NAME "(signature)" // Name of internal signature
|
#define SIGNATURE_NAME "(signature)" // Name of internal signature
|
||||||
#define ATTRIBUTES_NAME "(attributes)" // Name of internal attributes file
|
#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_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
|
// Flags for SFileOpenArchiveEx
|
||||||
#define MPQ_OPEN_NO_LISTFILE 0x00000001 // Don't add the internal listfile
|
#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
|
// Additional flags for SFileCreateArchiveEx
|
||||||
#define MPQ_CREATE_ARCHIVE_V1 0x00000000 // Creates archive with size up to 4GB
|
#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_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
|
// Structures
|
||||||
@ -194,7 +217,7 @@
|
|||||||
#if (defined(WIN32) || defined(WIN64))
|
#if (defined(WIN32) || defined(WIN64))
|
||||||
#include <pshpack1.h>
|
#include <pshpack1.h>
|
||||||
#else
|
#else
|
||||||
#pragma pack(1)
|
#pragma pack(push,1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct TMPQFile;
|
struct TMPQFile;
|
||||||
@ -273,7 +296,7 @@ struct TMPQHash
|
|||||||
// The hash of the file path, using method B.
|
// The hash of the file path, using method B.
|
||||||
DWORD dwName2;
|
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.
|
// 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.
|
// 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
|
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))
|
#if (defined(WIN32) || defined(WIN64))
|
||||||
#include <poppack.h>
|
#include <poppack.h>
|
||||||
#else
|
#else
|
||||||
#pragma options align=reset
|
#pragma pack(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Archive handle structure. Note that it does not agree with Storm.dll's structure.
|
// Archive handle structure
|
||||||
struct TMPQArchive
|
struct TMPQArchive
|
||||||
{
|
{
|
||||||
// TMPQArchive * pNext; // Next archive (used by Storm.dll only)
|
// TMPQArchive * pNext; // Next archive (used by Storm.dll only)
|
||||||
@ -356,13 +413,12 @@ struct TMPQArchive
|
|||||||
char szFileName[MAX_PATH]; // Opened archive file name
|
char szFileName[MAX_PATH]; // Opened archive file name
|
||||||
HANDLE hFile; // File handle
|
HANDLE hFile; // File handle
|
||||||
DWORD dwPriority; // Priority of the archive
|
DWORD dwPriority; // Priority of the archive
|
||||||
LARGE_INTEGER ShuntPos; // Position of MPQShunt (only valid if a shunt is present)
|
LARGE_INTEGER ShuntPos; // MPQShunt offset (only valid if a shunt is present)
|
||||||
LARGE_INTEGER MpqPos; // MPQ position in the file, relative to the begin of the file
|
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 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
|
TMPQFile * pLastFile; // Recently read file
|
||||||
DWORD dwBlockPos; // Position of loaded block in the 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
|
TMPQShunt Shunt; // MPQ shunt. Valid only when ID_MPQ_SHUNT has been found
|
||||||
TMPQHeader2 Header; // MPQ header
|
TMPQHeader2 Header; // MPQ header
|
||||||
|
|
||||||
// Non-Storm.dll members
|
TMPQAttr * pAttributes; // MPQ attributes from "(attributes)" file (NULL if none)
|
||||||
TFileNode ** pListFile; // File name array
|
TFileNode ** pListFile; // File name array
|
||||||
// HANDLE hListFile; // Handle to temporary listfile (when open with write access)
|
|
||||||
DWORD dwFlags; // See MPQ_FLAG_XXXXX
|
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
|
struct TMPQFile
|
||||||
{
|
{
|
||||||
HANDLE hFile; // File handle
|
HANDLE hFile; // File handle
|
||||||
TMPQArchive * ha; // Archive handle
|
TMPQArchive * ha; // Archive handle
|
||||||
TMPQHash * pHash; // Hash table entry
|
TMPQHash * pHash; // Hash table entry
|
||||||
TMPQBlockEx * pBlockEx; // Pointer to extended file block entry
|
TMPQBlockEx * pBlockEx; // Pointer to extended file block entry
|
||||||
TMPQBlock * pBlock; // File block pointer
|
TMPQBlock * pBlock; // File block pointer
|
||||||
DWORD dwSeed1; // Seed used for file decrypt
|
DWORD dwSeed1; // Seed used for file decrypt
|
||||||
DWORD dwFilePos; // Current file position
|
DWORD dwFilePos; // Current file position
|
||||||
LARGE_INTEGER MpqFilePos; // Position of the file data in MPQ archive
|
LARGE_INTEGER RawFilePos; // Offset in MPQ archive (relative to file begin)
|
||||||
// (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 * pdwBlockPos; // Position of each file block (only for compressed files)
|
||||||
DWORD nBlocks; // Number of blocks in the file (incl. the last noncomplete one)
|
DWORD nBlocks; // Number of blocks in the file (incl. the last incomplete one)
|
||||||
BOOL bBlockPosLoaded; // TRUE if block positions loaded
|
BOOL bBlockPosLoaded; // TRUE if block positions loaded
|
||||||
BYTE * pbFileBuffer; // Decompressed file (for single unit files, size is the uncompressed file size)
|
BYTE * pbFileBuffer; // Decompressed file (for single unit files, size is the uncompressed file size)
|
||||||
|
|
||||||
DWORD dwHashIndex; // Index to Hash table
|
TMPQCRC32 * pCrc32; // Pointer to CRC32 (NULL if none)
|
||||||
DWORD dwFileIndex; // Index to Block table
|
TMPQFileTime * pFileTime; // Pointer to file's FILETIME (NULL if none)
|
||||||
char szFileName[1]; // File name (variable length)
|
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
|
// Used by searching in MPQ archives
|
||||||
struct TMPQSearch
|
struct TMPQSearch
|
||||||
{
|
{
|
||||||
TMPQArchive * ha; // Handle to MPQ, where the search runs
|
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 dwName1; // Lastly found Name1
|
||||||
DWORD dwName2; // Lastly found Name2
|
DWORD dwName2; // Lastly found Name2
|
||||||
char szSearchMask[1]; // Search mask (variable length)
|
char szSearchMask[1]; // Search mask (variable length)
|
||||||
@ -457,7 +513,7 @@ __inline void * DebugMalloc(char * szFile, int nLine, int nSize)
|
|||||||
if(plain == NULL)
|
if(plain == NULL)
|
||||||
plain = szFile;
|
plain = szFile;
|
||||||
|
|
||||||
#if _MSC_VER > 0x1300
|
#if _MSC_VER > 1300
|
||||||
sprintf_s((char *)ptr, nSize+100, "%s(%u)", plain, nLine);
|
sprintf_s((char *)ptr, nSize+100, "%s(%u)", plain, nLine);
|
||||||
#else
|
#else
|
||||||
sprintf((char *)ptr, "%s(%u)", plain, nLine);
|
sprintf((char *)ptr, "%s(%u)", plain, nLine);
|
||||||
@ -497,11 +553,12 @@ typedef BOOL (WINAPI * SFILEREADFILE)(HANDLE, VOID *, DWORD, DWORD *, LPOVERLAP
|
|||||||
// Archive opening/closing
|
// Archive opening/closing
|
||||||
LCID WINAPI SFileSetLocale(LCID lcNewLocale);
|
LCID WINAPI SFileSetLocale(LCID lcNewLocale);
|
||||||
LCID WINAPI SFileGetLocale();
|
LCID WINAPI SFileGetLocale();
|
||||||
BOOL WINAPI SFileOpenArchive(const char * szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE * phMPQ);
|
BOOL WINAPI SFileOpenArchive(const char * szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE * phMpq);
|
||||||
BOOL WINAPI SFileCloseArchive(HANDLE hMPQ);
|
BOOL WINAPI SFileFlushArchive(HANDLE hMpq);
|
||||||
|
BOOL WINAPI SFileCloseArchive(HANDLE hMpq);
|
||||||
|
|
||||||
// File opening/closing
|
// 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);
|
BOOL WINAPI SFileCloseFile(HANDLE hFile);
|
||||||
|
|
||||||
// File I/O
|
// 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);
|
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 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,
|
// Adds another listfile into MPQ. The currently added listfile(s) remain,
|
||||||
// so you can use this API to combining more listfiles.
|
// so you can use this API to combining more listfiles.
|
||||||
// Note that this function is internally called by SFileFindFirstFile
|
// 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
|
// Functions in StormLib - not implemented in Storm.dll
|
||||||
|
|
||||||
// Archive creating and editing
|
// Archive creating and editing
|
||||||
BOOL WINAPI SFileCreateArchiveEx(const char * szMpqName, DWORD dwCreationDisposition, DWORD dwHashTableSize, HANDLE * phMPQ);
|
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 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 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 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 SFileRenameFile(HANDLE hMpq, const char * szOldFileName, const char * szNewFileName);
|
||||||
BOOL WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale);
|
BOOL WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale);
|
||||||
|
|
||||||
// Retrieving info about the file
|
// 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);
|
BOOL WINAPI SFileGetFileName(HANDLE hFile, char * szFileName);
|
||||||
DWORD_PTR WINAPI SFileGetFileInfo(HANDLE hMpqOrFile, DWORD dwInfoType);
|
DWORD_PTR WINAPI SFileGetFileInfo(HANDLE hMpqOrFile, DWORD dwInfoType);
|
||||||
|
|
||||||
// File search
|
// File search
|
||||||
// Note that the SFileFindFirstFileEx has been removed. Use SListFileFindFirst/Next
|
// 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 SFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData);
|
||||||
BOOL WINAPI SFileFindClose(HANDLE hFind);
|
BOOL WINAPI SFileFindClose(HANDLE hFind);
|
||||||
|
|
||||||
@ -546,11 +601,11 @@ BOOL SListFileFindClose(HANDLE hFind);
|
|||||||
|
|
||||||
// Archive compacting
|
// Archive compacting
|
||||||
typedef void (WINAPI * COMPACTCB)(void * lpUserData, DWORD dwWorkType, DWORD dwParam1, DWORD dwParam2);
|
typedef void (WINAPI * COMPACTCB)(void * lpUserData, DWORD dwWorkType, DWORD dwParam1, DWORD dwParam2);
|
||||||
BOOL WINAPI SFileSetCompactCallback(HANDLE hMPQ, COMPACTCB CompactCB, void * lpData);
|
BOOL WINAPI SFileSetCompactCallback(HANDLE hMpq, COMPACTCB CompactCB, void * lpData);
|
||||||
BOOL WINAPI SFileCompactArchive(HANDLE hMPQ, const char * szListFile = NULL, BOOL bReserved = 0);
|
BOOL WINAPI SFileCompactArchive(HANDLE hMpq, const char * szListFile = NULL, BOOL bReserved = 0);
|
||||||
|
|
||||||
// Locale support
|
// 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
|
// (De)compression
|
||||||
int WINAPI SCompCompress (char * pbOutBuffer, int * pdwOutLength, char * pbInBuffer, int dwInLength, int uCompressions, int nCmpType, int nCmpLevel);
|
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,
|
// Sets the default data compression for files added to MPQ,
|
||||||
// if MPQ_FILE_COMPRESS_MULTI has been specified in call to SFileAddFile
|
// 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);
|
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
|
// Functions from Storm.dll. They use slightly different names for keeping
|
||||||
// possibility to use them together with StormLib (StormXXX instead of SFileXXX)
|
// possibility to use them together with StormLib (StormXXX instead of SFileXXX)
|
||||||
|
|||||||
@ -55,14 +55,6 @@
|
|||||||
|
|
||||||
// Macintosh using Carbon
|
// Macintosh using Carbon
|
||||||
#include <Carbon/Carbon.h> // Mac OS X
|
#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 PKEXPORT
|
||||||
#define __SYS_ZLIB
|
#define __SYS_ZLIB
|
||||||
@ -74,6 +66,13 @@
|
|||||||
#else
|
#else
|
||||||
#define PLATFORM_LITTLE_ENDIAN 1 // Apple is now making Macs with Intel CPUs
|
#define PLATFORM_LITTLE_ENDIAN 1 // Apple is now making Macs with Intel CPUs
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __LP64__
|
||||||
|
#define PLATFORM_64BIT
|
||||||
|
#else
|
||||||
|
#define PLATFORM_32BIT
|
||||||
|
#endif
|
||||||
|
|
||||||
#define PLATFORM_DEFINED // The platform is known now
|
#define PLATFORM_DEFINED // The platform is known now
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -105,14 +104,15 @@
|
|||||||
|
|
||||||
// Typedefs for ANSI C
|
// Typedefs for ANSI C
|
||||||
typedef unsigned char BYTE;
|
typedef unsigned char BYTE;
|
||||||
typedef short SHORT;
|
typedef int16_t SHORT;
|
||||||
typedef unsigned short WORD;
|
typedef uint16_t WORD;
|
||||||
typedef unsigned short USHORT;
|
typedef uint16_t USHORT;
|
||||||
typedef long LONG;
|
typedef int32_t LONG;
|
||||||
typedef unsigned long DWORD;
|
typedef uint32_t DWORD;
|
||||||
typedef unsigned long DWORD_PTR;
|
typedef intptr_t DWORD_PTR;
|
||||||
typedef long LONG_PTR;
|
typedef intptr_t LONG_PTR;
|
||||||
typedef long long LONGLONG;
|
typedef intptr_t INT_PTR;
|
||||||
|
typedef int64_t LONGLONG;
|
||||||
#ifndef __OBJC__
|
#ifndef __OBJC__
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#define BOOL bool
|
#define BOOL bool
|
||||||
@ -121,15 +121,13 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
typedef void * HANDLE;
|
typedef void * HANDLE;
|
||||||
typedef void * LPOVERLAPPED; // Unsupported on Linux
|
typedef void * LPOVERLAPPED; // Unsupported on Linux and Mac
|
||||||
typedef char TCHAR;
|
typedef char TCHAR;
|
||||||
typedef unsigned long LCID;
|
typedef uint32_t LCID;
|
||||||
|
typedef unsigned int UINT;
|
||||||
typedef void * LPCSTR;
|
typedef LONG * PLONG;
|
||||||
typedef unsigned long * LPDWORD;
|
typedef DWORD * LPDWORD;
|
||||||
typedef long * PLONG;
|
typedef BYTE * LPBYTE;
|
||||||
typedef void * LPVOID;
|
|
||||||
typedef unsigned int UINT;
|
|
||||||
|
|
||||||
typedef struct _FILETIME
|
typedef struct _FILETIME
|
||||||
{
|
{
|
||||||
@ -186,9 +184,6 @@
|
|||||||
#define GENERIC_WRITE 0x40000000
|
#define GENERIC_WRITE 0x40000000
|
||||||
#define GENERIC_READ 0x80000000
|
#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_SUCCESS 0
|
||||||
#define ERROR_INVALID_FUNCTION 1
|
#define ERROR_INVALID_FUNCTION 1
|
||||||
#define ERROR_FILE_NOT_FOUND 2
|
#define ERROR_FILE_NOT_FOUND 2
|
||||||
@ -196,6 +191,7 @@
|
|||||||
#define ERROR_NOT_ENOUGH_MEMORY 8
|
#define ERROR_NOT_ENOUGH_MEMORY 8
|
||||||
#define ERROR_BAD_FORMAT 11
|
#define ERROR_BAD_FORMAT 11
|
||||||
#define ERROR_NO_MORE_FILES 18
|
#define ERROR_NO_MORE_FILES 18
|
||||||
|
#define ERROR_WRITE_FAULT 29
|
||||||
#define ERROR_GEN_FAILURE 31
|
#define ERROR_GEN_FAILURE 31
|
||||||
#define ERROR_HANDLE_EOF 38
|
#define ERROR_HANDLE_EOF 38
|
||||||
#define ERROR_HANDLE_DISK_FULL 39
|
#define ERROR_HANDLE_DISK_FULL 39
|
||||||
@ -211,14 +207,6 @@
|
|||||||
|
|
||||||
#define INVALID_HANDLE_VALUE ((HANDLE) -1)
|
#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 _stricmp strcasecmp
|
||||||
#define _strnicmp strncasecmp
|
#define _strnicmp strncasecmp
|
||||||
|
|
||||||
@ -226,7 +214,7 @@
|
|||||||
|
|
||||||
void SetLastError(int err);
|
void SetLastError(int err);
|
||||||
int GetLastError();
|
int GetLastError();
|
||||||
const char *ErrString(int err);
|
char *ErrString(int err);
|
||||||
|
|
||||||
// Emulation of functions for file I/O available in Win32
|
// 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);
|
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_TMPQSHUNT(a) {}
|
||||||
#define BSWAP_TMPQHEADER(a) {}
|
#define BSWAP_TMPQHEADER(a) {}
|
||||||
#else
|
#else
|
||||||
extern unsigned short SwapUShort(unsigned short);
|
extern uint16_t SwapUShort(uint16_t);
|
||||||
extern unsigned long SwapULong(unsigned long);
|
extern uint32_t SwapULong(uint32_t);
|
||||||
extern short SwapShort(unsigned short);
|
extern int16_t SwapShort(uint16_t);
|
||||||
extern long SwapLong(unsigned long);
|
extern int32_t SwapLong(uint32_t);
|
||||||
extern void ConvertUnsignedLongBuffer(unsigned long *buffer, unsigned long nbLongs);
|
extern void ConvertUnsignedLongBuffer(uint32_t *buffer, uint32_t nbLongs);
|
||||||
extern void ConvertUnsignedShortBuffer(unsigned short *buffer, unsigned long nbShorts);
|
extern void ConvertUnsignedShortBuffer(uint16_t *buffer, uint32_t nbShorts);
|
||||||
extern void ConvertTMPQShunt(void *shunt);
|
extern void ConvertTMPQShunt(void *shunt);
|
||||||
extern void ConvertTMPQHeader(void *header);
|
extern void ConvertTMPQHeader(void *header);
|
||||||
#define BSWAP_INT16_UNSIGNED(a) SwapUShort((a))
|
#define BSWAP_INT16_UNSIGNED(a) SwapUShort((a))
|
||||||
|
|||||||
@ -23,8 +23,8 @@
|
|||||||
* Copyright (c) 2001 BMX-Chemnitz.DE All rights reserved.
|
* Copyright (c) 2001 BMX-Chemnitz.DE All rights reserved.
|
||||||
*
|
*
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
#include <string>
|
|
||||||
#if defined(__linux) || defined(linux)
|
#ifndef _WIN32
|
||||||
#include "StormPort.h"
|
#include "StormPort.h"
|
||||||
|
|
||||||
int globalerr;
|
int globalerr;
|
||||||
@ -39,47 +39,52 @@ int GetLastError()
|
|||||||
return(globalerr);
|
return(globalerr);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *ErrString(int err)
|
char *ErrString(int err)
|
||||||
{
|
{
|
||||||
switch (err)
|
switch (err) {
|
||||||
{
|
case ERROR_INVALID_FUNCTION:
|
||||||
case ERROR_INVALID_FUNCTION:
|
return "function not implemented";
|
||||||
return "function not implemented";
|
case ERROR_FILE_NOT_FOUND:
|
||||||
case ERROR_FILE_NOT_FOUND:
|
return "file not found";
|
||||||
return "file not found";
|
case ERROR_ACCESS_DENIED:
|
||||||
case ERROR_ACCESS_DENIED:
|
return "access denied";
|
||||||
return "access denied";
|
case ERROR_NOT_ENOUGH_MEMORY:
|
||||||
case ERROR_NOT_ENOUGH_MEMORY:
|
return "not enough memory";
|
||||||
return "not enough memory";
|
case ERROR_BAD_FORMAT:
|
||||||
case ERROR_BAD_FORMAT:
|
return "bad format";
|
||||||
return "bad format";
|
case ERROR_NO_MORE_FILES:
|
||||||
case ERROR_NO_MORE_FILES:
|
return "no more files";
|
||||||
return "no more files";
|
case ERROR_HANDLE_EOF:
|
||||||
case ERROR_HANDLE_EOF:
|
return "access beyound EOF";
|
||||||
return "access beyond EOF";
|
case ERROR_HANDLE_DISK_FULL:
|
||||||
case ERROR_INVALID_PARAMETER:
|
return "no space left on device";
|
||||||
return "invalid parameter";
|
case ERROR_INVALID_PARAMETER:
|
||||||
case ERROR_HANDLE_DISK_FULL:
|
return "invalid parameter";
|
||||||
case ERROR_DISK_FULL:
|
case ERROR_DISK_FULL:
|
||||||
return "no space left on device";
|
return "no space left on device";
|
||||||
case ERROR_ALREADY_EXISTS:
|
case ERROR_ALREADY_EXISTS:
|
||||||
return "file exists";
|
return "file exists";
|
||||||
case ERROR_CAN_NOT_COMPLETE:
|
case ERROR_CAN_NOT_COMPLETE:
|
||||||
return "operation cannot be completed";
|
return "operation cannot be completed";
|
||||||
default:
|
default:
|
||||||
return "unknown error";
|
return "unknown error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE CreateFile(const char *sFileName, DWORD ulMode, DWORD ulSharing, void *pSecAttrib, DWORD ulCreation, DWORD ulFlags, HANDLE hFile)
|
HANDLE CreateFile(const char *sFileName, DWORD ulMode, DWORD ulSharing, void *pSecAttrib, DWORD ulCreation, DWORD ulFlags, HANDLE hFile)
|
||||||
{
|
{
|
||||||
switch (ulCreation) {
|
switch (ulCreation)
|
||||||
|
{
|
||||||
case OPEN_EXISTING:
|
case OPEN_EXISTING:
|
||||||
return (HANDLE)open(sFileName, O_RDONLY | O_LARGEFILE);
|
return (HANDLE)open(sFileName, O_RDONLY | O_LARGEFILE);
|
||||||
|
|
||||||
case OPEN_ALWAYS:
|
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:
|
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:
|
default:
|
||||||
return INVALID_HANDLE_VALUE;
|
return INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
@ -87,34 +92,49 @@ HANDLE CreateFile(const char *sFileName, DWORD ulMode, DWORD ulSharing, void *pS
|
|||||||
|
|
||||||
BOOL CloseHandle(HANDLE hFile)
|
BOOL CloseHandle(HANDLE hFile)
|
||||||
{
|
{
|
||||||
return (close((unsigned long long)hFile) == 0);
|
return (close((intptr_t)hFile) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD GetFileSize(HANDLE hFile, DWORD *ulOffSetHigh)
|
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;
|
return 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
struct stat fileinfo;
|
struct stat64 fileinfo;
|
||||||
fstat((unsigned long long)hFile, &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)
|
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)
|
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)
|
BOOL ReadFile(HANDLE hFile, void *pBuffer, DWORD ulLen, DWORD *ulRead, void *pOverLapped)
|
||||||
{
|
{
|
||||||
ssize_t count;
|
ssize_t count;
|
||||||
if ((count = read((unsigned long long)hFile, pBuffer, ulLen)) == -1) {
|
if ((count = read((intptr_t)hFile, pBuffer, ulLen)) == -1) {
|
||||||
*ulRead = 0;
|
*ulRead = 0;
|
||||||
return false;
|
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)
|
BOOL WriteFile(HANDLE hFile, const void *pBuffer, DWORD ulLen, DWORD *ulWritten, void *pOverLapped)
|
||||||
{
|
{
|
||||||
ssize_t count;
|
ssize_t count;
|
||||||
if ((count = write((unsigned long long)hFile, pBuffer, ulLen)) == -1) {
|
if ((count = write((intptr_t)hFile, pBuffer, ulLen)) == -1) {
|
||||||
*ulWritten = 0;
|
*ulWritten = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -152,7 +172,15 @@ void GetTempPath(DWORD szTempLength, char * szTemp)
|
|||||||
|
|
||||||
void GetTempFileName(const char * lpTempFolderPath, const char * lpFileName, DWORD something, char * szLFName)
|
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)
|
BOOL DeleteFile(const char *lpFileName)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -4,66 +4,19 @@
|
|||||||
/*--- blocksort.c ---*/
|
/*--- blocksort.c ---*/
|
||||||
/*-------------------------------------------------------------*/
|
/*-------------------------------------------------------------*/
|
||||||
|
|
||||||
/*--
|
/* ------------------------------------------------------------------
|
||||||
This file is a part of bzip2 and/or libbzip2, a program and
|
This file is part of bzip2/libbzip2, a program and library for
|
||||||
library for lossless, block-sorting data compression.
|
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
|
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||||
modification, are permitted provided that the following conditions
|
README file.
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
This program is released under the terms of the license contained
|
||||||
notice, this list of conditions and the following disclaimer.
|
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.
|
|
||||||
|
|
||||||
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.
|
|
||||||
--*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "bzlib_private.h"
|
#include "bzlib_private.h"
|
||||||
@ -155,7 +108,7 @@ void fallbackQSort3 ( UInt32* fmap,
|
|||||||
|
|
||||||
while (sp > 0) {
|
while (sp > 0) {
|
||||||
|
|
||||||
AssertH ( sp < FALLBACK_QSORT_STACK_SIZE, 1004 );
|
AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 );
|
||||||
|
|
||||||
fpop ( lo, hi );
|
fpop ( lo, hi );
|
||||||
if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) {
|
if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) {
|
||||||
@ -690,7 +643,7 @@ void mainQSort3 ( UInt32* ptr,
|
|||||||
|
|
||||||
while (sp > 0) {
|
while (sp > 0) {
|
||||||
|
|
||||||
AssertH ( sp < MAIN_QSORT_STACK_SIZE, 1001 );
|
AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 );
|
||||||
|
|
||||||
mpop ( lo, hi, d );
|
mpop ( lo, hi, d );
|
||||||
if (hi - lo < MAIN_QSORT_SMALL_THRESH ||
|
if (hi - lo < MAIN_QSORT_SMALL_THRESH ||
|
||||||
|
|||||||
@ -3,118 +3,26 @@
|
|||||||
/*--- A block-sorting, lossless compressor bzip2.c ---*/
|
/*--- A block-sorting, lossless compressor bzip2.c ---*/
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/*--
|
/* ------------------------------------------------------------------
|
||||||
This file is a part of bzip2 and/or libbzip2, a program and
|
This file is part of bzip2/libbzip2, a program and library for
|
||||||
library for lossless, block-sorting data compression.
|
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
|
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||||
modification, are permitted provided that the following conditions
|
README file.
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
This program is released under the terms of the license contained
|
||||||
notice, this list of conditions and the following disclaimer.
|
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.
|
|
||||||
--*/
|
|
||||||
|
|
||||||
|
|
||||||
/*----------------------------------------------------*/
|
/* Place a 1 beside your platform, and 0 elsewhere.
|
||||||
/*--- IMPORTANT ---*/
|
Generic 32-bit Unix.
|
||||||
/*----------------------------------------------------*/
|
Also works on 64-bit Unix boxes.
|
||||||
|
This is the default.
|
||||||
/*--
|
*/
|
||||||
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.
|
|
||||||
--*/
|
|
||||||
#define BZ_UNIX 1
|
#define BZ_UNIX 1
|
||||||
|
|
||||||
/*--
|
/*--
|
||||||
@ -302,16 +210,17 @@ Char progNameReally[FILE_NAME_LEN];
|
|||||||
FILE *outputHandleJustInCase;
|
FILE *outputHandleJustInCase;
|
||||||
Int32 workFactor;
|
Int32 workFactor;
|
||||||
|
|
||||||
static void panic ( Char* ) NORETURN;
|
static void panic ( const Char* ) NORETURN;
|
||||||
static void ioError ( void ) NORETURN;
|
static void ioError ( void ) NORETURN;
|
||||||
static void outOfMemory ( void ) NORETURN;
|
static void outOfMemory ( void ) NORETURN;
|
||||||
static void configError ( void ) NORETURN;
|
static void configError ( void ) NORETURN;
|
||||||
static void crcError ( void ) NORETURN;
|
static void crcError ( void ) NORETURN;
|
||||||
static void cleanUpAndFail ( Int32 ) NORETURN;
|
static void cleanUpAndFail ( Int32 ) NORETURN;
|
||||||
static void compressedStreamEOF ( void ) NORETURN;
|
static void compressedStreamEOF ( void ) NORETURN;
|
||||||
|
|
||||||
static void copyFileName ( Char*, Char* );
|
static void copyFileName ( Char*, Char* );
|
||||||
static void* myMalloc ( Int32 );
|
static void* myMalloc ( Int32 );
|
||||||
|
static void applySavedFileAttrToOutputFile ( IntNative fd );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -457,6 +366,9 @@ void compressStream ( FILE *stream, FILE *zStream )
|
|||||||
ret = fflush ( zStream );
|
ret = fflush ( zStream );
|
||||||
if (ret == EOF) goto errhandler_io;
|
if (ret == EOF) goto errhandler_io;
|
||||||
if (zStream != stdout) {
|
if (zStream != stdout) {
|
||||||
|
Int32 fd = fileno ( zStream );
|
||||||
|
if (fd < 0) goto errhandler_io;
|
||||||
|
applySavedFileAttrToOutputFile ( fd );
|
||||||
ret = fclose ( zStream );
|
ret = fclose ( zStream );
|
||||||
outputHandleJustInCase = NULL;
|
outputHandleJustInCase = NULL;
|
||||||
if (ret == EOF) goto errhandler_io;
|
if (ret == EOF) goto errhandler_io;
|
||||||
@ -569,6 +481,11 @@ Bool uncompressStream ( FILE *zStream, FILE *stream )
|
|||||||
|
|
||||||
closeok:
|
closeok:
|
||||||
if (ferror(zStream)) goto errhandler_io;
|
if (ferror(zStream)) goto errhandler_io;
|
||||||
|
if (stream != stdout) {
|
||||||
|
Int32 fd = fileno ( stream );
|
||||||
|
if (fd < 0) goto errhandler_io;
|
||||||
|
applySavedFileAttrToOutputFile ( fd );
|
||||||
|
}
|
||||||
ret = fclose ( zStream );
|
ret = fclose ( zStream );
|
||||||
if (ret == EOF) goto errhandler_io;
|
if (ret == EOF) goto errhandler_io;
|
||||||
|
|
||||||
@ -826,7 +743,7 @@ void cleanUpAndFail ( Int32 ec )
|
|||||||
|
|
||||||
/*---------------------------------------------*/
|
/*---------------------------------------------*/
|
||||||
static
|
static
|
||||||
void panic ( Char* s )
|
void panic ( const Char* s )
|
||||||
{
|
{
|
||||||
fprintf ( stderr,
|
fprintf ( stderr,
|
||||||
"\n%s: PANIC -- internal consistency error:\n"
|
"\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
|
For non-Unix platforms, if we are not worrying about
|
||||||
security issues, simple this simply behaves like fopen.
|
security issues, simple this simply behaves like fopen.
|
||||||
*/
|
*/
|
||||||
|
static
|
||||||
FILE* fopen_output_safely ( Char* name, const char* mode )
|
FILE* fopen_output_safely ( Char* name, const char* mode )
|
||||||
{
|
{
|
||||||
# if BZ_UNIX
|
# if BZ_UNIX
|
||||||
@ -1129,7 +1047,7 @@ void saveInputFileMetaInfo ( Char *srcName )
|
|||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
void applySavedMetaInfoToOutputFile ( Char *dstName )
|
void applySavedTimeInfoToOutputFile ( Char *dstName )
|
||||||
{
|
{
|
||||||
# if BZ_UNIX
|
# if BZ_UNIX
|
||||||
IntNative retVal;
|
IntNative retVal;
|
||||||
@ -1138,13 +1056,21 @@ void applySavedMetaInfoToOutputFile ( Char *dstName )
|
|||||||
uTimBuf.actime = fileMetaInfo.st_atime;
|
uTimBuf.actime = fileMetaInfo.st_atime;
|
||||||
uTimBuf.modtime = fileMetaInfo.st_mtime;
|
uTimBuf.modtime = fileMetaInfo.st_mtime;
|
||||||
|
|
||||||
retVal = chmod ( dstName, fileMetaInfo.st_mode );
|
|
||||||
ERROR_IF_NOT_ZERO ( retVal );
|
|
||||||
|
|
||||||
retVal = utime ( dstName, &uTimBuf );
|
retVal = utime ( dstName, &uTimBuf );
|
||||||
ERROR_IF_NOT_ZERO ( retVal );
|
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
|
/* chown() will in many cases return with EPERM, which can
|
||||||
be safely ignored.
|
be safely ignored.
|
||||||
*/
|
*/
|
||||||
@ -1175,13 +1101,13 @@ Bool containsDubiousChars ( Char* name )
|
|||||||
/*---------------------------------------------*/
|
/*---------------------------------------------*/
|
||||||
#define BZ_N_SUFFIX_PAIRS 4
|
#define BZ_N_SUFFIX_PAIRS 4
|
||||||
|
|
||||||
Char* zSuffix[BZ_N_SUFFIX_PAIRS]
|
const Char* zSuffix[BZ_N_SUFFIX_PAIRS]
|
||||||
= { ".bz2", ".bz", ".tbz2", ".tbz" };
|
= { ".bz2", ".bz", ".tbz2", ".tbz" };
|
||||||
Char* unzSuffix[BZ_N_SUFFIX_PAIRS]
|
const Char* unzSuffix[BZ_N_SUFFIX_PAIRS]
|
||||||
= { "", "", ".tar", ".tar" };
|
= { "", "", ".tar", ".tar" };
|
||||||
|
|
||||||
static
|
static
|
||||||
Bool hasSuffix ( Char* s, Char* suffix )
|
Bool hasSuffix ( Char* s, const Char* suffix )
|
||||||
{
|
{
|
||||||
Int32 ns = strlen(s);
|
Int32 ns = strlen(s);
|
||||||
Int32 nx = strlen(suffix);
|
Int32 nx = strlen(suffix);
|
||||||
@ -1192,7 +1118,8 @@ Bool hasSuffix ( Char* s, Char* suffix )
|
|||||||
|
|
||||||
static
|
static
|
||||||
Bool mapSuffix ( Char* name,
|
Bool mapSuffix ( Char* name,
|
||||||
Char* oldSuffix, Char* newSuffix )
|
const Char* oldSuffix,
|
||||||
|
const Char* newSuffix )
|
||||||
{
|
{
|
||||||
if (!hasSuffix(name,oldSuffix)) return False;
|
if (!hasSuffix(name,oldSuffix)) return False;
|
||||||
name[strlen(name)-strlen(oldSuffix)] = 0;
|
name[strlen(name)-strlen(oldSuffix)] = 0;
|
||||||
@ -1217,8 +1144,8 @@ void compress ( Char *name )
|
|||||||
|
|
||||||
switch (srcMode) {
|
switch (srcMode) {
|
||||||
case SM_I2O:
|
case SM_I2O:
|
||||||
copyFileName ( inName, "(stdin)" );
|
copyFileName ( inName, (Char*)"(stdin)" );
|
||||||
copyFileName ( outName, "(stdout)" );
|
copyFileName ( outName, (Char*)"(stdout)" );
|
||||||
break;
|
break;
|
||||||
case SM_F2F:
|
case SM_F2F:
|
||||||
copyFileName ( inName, name );
|
copyFileName ( inName, name );
|
||||||
@ -1227,7 +1154,7 @@ void compress ( Char *name )
|
|||||||
break;
|
break;
|
||||||
case SM_F2O:
|
case SM_F2O:
|
||||||
copyFileName ( inName, name );
|
copyFileName ( inName, name );
|
||||||
copyFileName ( outName, "(stdout)" );
|
copyFileName ( outName, (Char*)"(stdout)" );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1370,7 +1297,7 @@ void compress ( Char *name )
|
|||||||
|
|
||||||
/*--- If there was an I/O error, we won't get here. ---*/
|
/*--- If there was an I/O error, we won't get here. ---*/
|
||||||
if ( srcMode == SM_F2F ) {
|
if ( srcMode == SM_F2F ) {
|
||||||
applySavedMetaInfoToOutputFile ( outName );
|
applySavedTimeInfoToOutputFile ( outName );
|
||||||
deleteOutputOnInterrupt = False;
|
deleteOutputOnInterrupt = False;
|
||||||
if ( !keepInputFiles ) {
|
if ( !keepInputFiles ) {
|
||||||
IntNative retVal = remove ( inName );
|
IntNative retVal = remove ( inName );
|
||||||
@ -1401,8 +1328,8 @@ void uncompress ( Char *name )
|
|||||||
cantGuess = False;
|
cantGuess = False;
|
||||||
switch (srcMode) {
|
switch (srcMode) {
|
||||||
case SM_I2O:
|
case SM_I2O:
|
||||||
copyFileName ( inName, "(stdin)" );
|
copyFileName ( inName, (Char*)"(stdin)" );
|
||||||
copyFileName ( outName, "(stdout)" );
|
copyFileName ( outName, (Char*)"(stdout)" );
|
||||||
break;
|
break;
|
||||||
case SM_F2F:
|
case SM_F2F:
|
||||||
copyFileName ( inName, name );
|
copyFileName ( inName, name );
|
||||||
@ -1415,7 +1342,7 @@ void uncompress ( Char *name )
|
|||||||
break;
|
break;
|
||||||
case SM_F2O:
|
case SM_F2O:
|
||||||
copyFileName ( inName, name );
|
copyFileName ( inName, name );
|
||||||
copyFileName ( outName, "(stdout)" );
|
copyFileName ( outName, (Char*)"(stdout)" );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1548,7 +1475,7 @@ void uncompress ( Char *name )
|
|||||||
/*--- If there was an I/O error, we won't get here. ---*/
|
/*--- If there was an I/O error, we won't get here. ---*/
|
||||||
if ( magicNumberOK ) {
|
if ( magicNumberOK ) {
|
||||||
if ( srcMode == SM_F2F ) {
|
if ( srcMode == SM_F2F ) {
|
||||||
applySavedMetaInfoToOutputFile ( outName );
|
applySavedTimeInfoToOutputFile ( outName );
|
||||||
deleteOutputOnInterrupt = False;
|
deleteOutputOnInterrupt = False;
|
||||||
if ( !keepInputFiles ) {
|
if ( !keepInputFiles ) {
|
||||||
IntNative retVal = remove ( inName );
|
IntNative retVal = remove ( inName );
|
||||||
@ -1593,9 +1520,9 @@ void testf ( Char *name )
|
|||||||
if (name == NULL && srcMode != SM_I2O)
|
if (name == NULL && srcMode != SM_I2O)
|
||||||
panic ( "testf: bad modes\n" );
|
panic ( "testf: bad modes\n" );
|
||||||
|
|
||||||
copyFileName ( outName, "(none)" );
|
copyFileName ( outName, (Char*)"(none)" );
|
||||||
switch (srcMode) {
|
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_F2F: copyFileName ( inName, name ); break;
|
||||||
case SM_F2O: copyFileName ( inName, name ); break;
|
case SM_F2O: copyFileName ( inName, name ); break;
|
||||||
}
|
}
|
||||||
@ -1678,11 +1605,11 @@ void license ( void )
|
|||||||
"bzip2, a block-sorting file compressor. "
|
"bzip2, a block-sorting file compressor. "
|
||||||
"Version %s.\n"
|
"Version %s.\n"
|
||||||
" \n"
|
" \n"
|
||||||
" Copyright (C) 1996-2005 by Julian Seward.\n"
|
" Copyright (C) 1996-2007 by Julian Seward.\n"
|
||||||
" \n"
|
" \n"
|
||||||
" This program is free software; you can redistribute it and/or modify\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"
|
" 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"
|
" \n"
|
||||||
" This program is distributed in the hope that it will be useful,\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"
|
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||||
@ -1885,8 +1812,8 @@ IntNative main ( IntNative argc, Char *argv[] )
|
|||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
copyFileName ( inName, "(none)" );
|
copyFileName ( inName, (Char*)"(none)" );
|
||||||
copyFileName ( outName, "(none)" );
|
copyFileName ( outName, (Char*)"(none)" );
|
||||||
|
|
||||||
copyFileName ( progNameReally, argv[0] );
|
copyFileName ( progNameReally, argv[0] );
|
||||||
progName = &progNameReally[0];
|
progName = &progNameReally[0];
|
||||||
@ -1898,8 +1825,8 @@ IntNative main ( IntNative argc, Char *argv[] )
|
|||||||
expand filename wildcards in arg list.
|
expand filename wildcards in arg list.
|
||||||
--*/
|
--*/
|
||||||
argList = NULL;
|
argList = NULL;
|
||||||
addFlagsFromEnvVar ( &argList, "BZIP2" );
|
addFlagsFromEnvVar ( &argList, (Char*)"BZIP2" );
|
||||||
addFlagsFromEnvVar ( &argList, "BZIP" );
|
addFlagsFromEnvVar ( &argList, (Char*)"BZIP" );
|
||||||
for (i = 1; i <= argc-1; i++)
|
for (i = 1; i <= argc-1; i++)
|
||||||
APPEND_FILESPEC(argList, argv[i]);
|
APPEND_FILESPEC(argList, argv[i]);
|
||||||
|
|
||||||
|
|||||||
@ -1,56 +1,24 @@
|
|||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
/*--- Block recoverer program for bzip2 ---*/
|
/*--- Block recoverer program for bzip2 ---*/
|
||||||
/*--- bzip2recover.c ---*/
|
/*--- bzip2recover.c ---*/
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/*--
|
/* ------------------------------------------------------------------
|
||||||
This program is bzip2recover, a program to attempt data
|
This file is part of bzip2/libbzip2, a program and library for
|
||||||
salvage from damaged files created by the accompanying
|
lossless, block-sorting data compression.
|
||||||
bzip2-1.0.3 program.
|
|
||||||
|
|
||||||
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
|
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||||
modification, are permitted provided that the following conditions
|
README file.
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
This program is released under the terms of the license contained
|
||||||
notice, this list of conditions and the following disclaimer.
|
in the file LICENSE.
|
||||||
|
------------------------------------------------------------------ */
|
||||||
|
|
||||||
2. The origin of this software must not be misrepresented; you must
|
/* This program is a complete hack and should be rewritten properly.
|
||||||
not claim that you wrote the original software. If you use this
|
It isn't very complicated. */
|
||||||
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.
|
|
||||||
--*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -114,7 +82,7 @@ MaybeUInt64 bytesIn = 0;
|
|||||||
/*---------------------------------------------------*/
|
/*---------------------------------------------------*/
|
||||||
|
|
||||||
/*---------------------------------------------*/
|
/*---------------------------------------------*/
|
||||||
void readError ( void )
|
static void readError ( void )
|
||||||
{
|
{
|
||||||
fprintf ( stderr,
|
fprintf ( stderr,
|
||||||
"%s: I/O error reading `%s', possible reason follows.\n",
|
"%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,
|
fprintf ( stderr,
|
||||||
"%s: I/O error reading `%s', possible reason follows.\n",
|
"%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,
|
fprintf ( stderr,
|
||||||
"%s: malloc failed on request for %d bytes.\n",
|
"%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,
|
fprintf ( stderr,
|
||||||
"%s: `%s' appears to contain more than %d blocks\n",
|
"%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) );
|
BitStream *bs = malloc ( sizeof(BitStream) );
|
||||||
if (bs == NULL) mallocFail ( 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) );
|
BitStream *bs = malloc ( sizeof(BitStream) );
|
||||||
if (bs == NULL) mallocFail ( 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) {
|
if (bs->buffLive == 8) {
|
||||||
Int32 retVal = putc ( (UChar) bs->buffer, bs->handle );
|
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.
|
Returns 0 or 1, or 2 to indicate EOF.
|
||||||
--*/
|
--*/
|
||||||
Int32 bsGetBit ( BitStream* bs )
|
static Int32 bsGetBit ( BitStream* bs )
|
||||||
{
|
{
|
||||||
if (bs->buffLive > 0) {
|
if (bs->buffLive > 0) {
|
||||||
bs->buffLive --;
|
bs->buffLive --;
|
||||||
@ -247,7 +215,7 @@ Int32 bsGetBit ( BitStream* bs )
|
|||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------*/
|
/*---------------------------------------------*/
|
||||||
void bsClose ( BitStream* bs )
|
static void bsClose ( BitStream* bs )
|
||||||
{
|
{
|
||||||
Int32 retVal;
|
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;
|
Int32 i;
|
||||||
for (i = 7; i >= 0; 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;
|
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 );
|
Int32 n = strlen ( name );
|
||||||
if (n <= 4) return False;
|
if (n <= 4) return False;
|
||||||
@ -345,7 +313,7 @@ Int32 main ( Int32 argc, Char** argv )
|
|||||||
inFileName[0] = outFileName[0] = 0;
|
inFileName[0] = outFileName[0] = 0;
|
||||||
|
|
||||||
fprintf ( stderr,
|
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) {
|
if (argc != 2) {
|
||||||
fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n",
|
fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n",
|
||||||
|
|||||||
@ -4,76 +4,31 @@
|
|||||||
/*--- bzlib.c ---*/
|
/*--- bzlib.c ---*/
|
||||||
/*-------------------------------------------------------------*/
|
/*-------------------------------------------------------------*/
|
||||||
|
|
||||||
/*--
|
/* ------------------------------------------------------------------
|
||||||
This file is a part of bzip2 and/or libbzip2, a program and
|
This file is part of bzip2/libbzip2, a program and library for
|
||||||
library for lossless, block-sorting data compression.
|
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
|
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||||
modification, are permitted provided that the following conditions
|
README file.
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
This program is released under the terms of the license contained
|
||||||
notice, this list of conditions and the following disclaimer.
|
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.
|
|
||||||
|
|
||||||
|
/* CHANGES
|
||||||
|
0.9.0 -- original version.
|
||||||
0.9.0a/b -- no changes in this file.
|
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
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
* 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
|
|
||||||
#include "bzlib_private.h"
|
#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"
|
"component, you should also report this bug to the author(s)\n"
|
||||||
"of that program. Please make an effort to report this bug;\n"
|
"of that program. Please make an effort to report this bug;\n"
|
||||||
"timely and accurate bug reports eventually lead to higher\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,
|
errcode,
|
||||||
BZ2_bzlibVersion()
|
BZ2_bzlibVersion()
|
||||||
);
|
);
|
||||||
@ -644,6 +599,7 @@ Bool unRLE_obuf_to_output_FAST ( DState* s )
|
|||||||
UInt32 c_tPos = s->tPos;
|
UInt32 c_tPos = s->tPos;
|
||||||
char* cs_next_out = s->strm->next_out;
|
char* cs_next_out = s->strm->next_out;
|
||||||
unsigned int cs_avail_out = s->strm->avail_out;
|
unsigned int cs_avail_out = s->strm->avail_out;
|
||||||
|
Int32 ro_blockSize100k = s->blockSize100k;
|
||||||
/* end restore */
|
/* end restore */
|
||||||
|
|
||||||
UInt32 avail_out_INIT = cs_avail_out;
|
UInt32 avail_out_INIT = cs_avail_out;
|
||||||
@ -1395,8 +1351,7 @@ int BZ_API(BZ2_bzBuffToBuffDecompress)
|
|||||||
|
|
||||||
/*---------------------------------------------------*/
|
/*---------------------------------------------------*/
|
||||||
/*--
|
/*--
|
||||||
Code contributed by Yoshioka Tsuneo
|
Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
|
||||||
(QWF00133@niftyserve.or.jp/tsuneo-y@is.aist-nara.ac.jp),
|
|
||||||
to support better zlib compatibility.
|
to support better zlib compatibility.
|
||||||
This code is not _officially_ part of libbzip2 (yet);
|
This code is not _officially_ part of libbzip2 (yet);
|
||||||
I haven't tested it, documented it, or considered the
|
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)
|
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)
|
void BZ_API(BZ2_bzclose) (BZFILE* b)
|
||||||
{
|
{
|
||||||
int bzerr;
|
int bzerr;
|
||||||
FILE *fp = ((bzFile *)b)->handle;
|
FILE *fp;
|
||||||
|
|
||||||
if (b==NULL) {return;}
|
if (b==NULL) {return;}
|
||||||
|
fp = ((bzFile *)b)->handle;
|
||||||
if(((bzFile*)b)->writing){
|
if(((bzFile*)b)->writing){
|
||||||
BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL);
|
BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL);
|
||||||
if(bzerr != BZ_OK){
|
if(bzerr != BZ_OK){
|
||||||
@ -1581,7 +1537,7 @@ void BZ_API(BZ2_bzclose) (BZFILE* b)
|
|||||||
/*--
|
/*--
|
||||||
return last error code
|
return last error code
|
||||||
--*/
|
--*/
|
||||||
static char *bzerrorstrings[] = {
|
static const char *bzerrorstrings[] = {
|
||||||
"OK"
|
"OK"
|
||||||
,"SEQUENCE_ERROR"
|
,"SEQUENCE_ERROR"
|
||||||
,"PARAM_ERROR"
|
,"PARAM_ERROR"
|
||||||
|
|||||||
@ -4,59 +4,19 @@
|
|||||||
/*--- bzlib.h ---*/
|
/*--- bzlib.h ---*/
|
||||||
/*-------------------------------------------------------------*/
|
/*-------------------------------------------------------------*/
|
||||||
|
|
||||||
/*--
|
/* ------------------------------------------------------------------
|
||||||
This file is a part of bzip2 and/or libbzip2, a program and
|
This file is part of bzip2/libbzip2, a program and library for
|
||||||
library for lossless, block-sorting data compression.
|
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
|
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||||
modification, are permitted provided that the following conditions
|
README file.
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
This program is released under the terms of the license contained
|
||||||
notice, this list of conditions and the following disclaimer.
|
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.
|
|
||||||
--*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _BZLIB_H
|
#ifndef _BZLIB_H
|
||||||
@ -262,8 +222,7 @@ BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) (
|
|||||||
|
|
||||||
|
|
||||||
/*--
|
/*--
|
||||||
Code contributed by Yoshioka Tsuneo
|
Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
|
||||||
(QWF00133@niftyserve.or.jp/tsuneo-y@is.aist-nara.ac.jp),
|
|
||||||
to support better zlib compatibility.
|
to support better zlib compatibility.
|
||||||
This code is not _officially_ part of libbzip2 (yet);
|
This code is not _officially_ part of libbzip2 (yet);
|
||||||
I haven't tested it, documented it, or considered the
|
I haven't tested it, documented it, or considered the
|
||||||
|
|||||||
@ -4,59 +4,19 @@
|
|||||||
/*--- bzlib_private.h ---*/
|
/*--- bzlib_private.h ---*/
|
||||||
/*-------------------------------------------------------------*/
|
/*-------------------------------------------------------------*/
|
||||||
|
|
||||||
/*--
|
/* ------------------------------------------------------------------
|
||||||
This file is a part of bzip2 and/or libbzip2, a program and
|
This file is part of bzip2/libbzip2, a program and library for
|
||||||
library for lossless, block-sorting data compression.
|
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
|
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||||
modification, are permitted provided that the following conditions
|
README file.
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
This program is released under the terms of the license contained
|
||||||
notice, this list of conditions and the following disclaimer.
|
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.
|
|
||||||
--*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _BZLIB_PRIVATE_H
|
#ifndef _BZLIB_PRIVATE_H
|
||||||
@ -76,7 +36,7 @@
|
|||||||
|
|
||||||
/*-- General stuff. --*/
|
/*-- General stuff. --*/
|
||||||
|
|
||||||
#define BZ_VERSION "1.0.3, 15-Feb-2005"
|
#define BZ_VERSION "1.0.5, 10-Dec-2007"
|
||||||
|
|
||||||
typedef char Char;
|
typedef char Char;
|
||||||
typedef unsigned char Bool;
|
typedef unsigned char Bool;
|
||||||
@ -94,9 +54,11 @@ typedef unsigned short UInt16;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef BZ_NO_STDIO
|
#ifndef BZ_NO_STDIO
|
||||||
|
|
||||||
extern void BZ2_bz__AssertH__fail ( int errcode );
|
extern void BZ2_bz__AssertH__fail ( int errcode );
|
||||||
#define AssertH(cond,errcode) \
|
#define AssertH(cond,errcode) \
|
||||||
{ if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); }
|
{ if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); }
|
||||||
|
|
||||||
#if BZ_DEBUG
|
#if BZ_DEBUG
|
||||||
#define AssertD(cond,msg) \
|
#define AssertD(cond,msg) \
|
||||||
{ if (!(cond)) { \
|
{ if (!(cond)) { \
|
||||||
@ -107,6 +69,7 @@ extern void BZ2_bz__AssertH__fail ( int errcode );
|
|||||||
#else
|
#else
|
||||||
#define AssertD(cond,msg) /* */
|
#define AssertD(cond,msg) /* */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define VPrintf0(zf) \
|
#define VPrintf0(zf) \
|
||||||
fprintf(stderr,zf)
|
fprintf(stderr,zf)
|
||||||
#define VPrintf1(zf,za1) \
|
#define VPrintf1(zf,za1) \
|
||||||
@ -119,17 +82,20 @@ extern void BZ2_bz__AssertH__fail ( int errcode );
|
|||||||
fprintf(stderr,zf,za1,za2,za3,za4)
|
fprintf(stderr,zf,za1,za2,za3,za4)
|
||||||
#define VPrintf5(zf,za1,za2,za3,za4,za5) \
|
#define VPrintf5(zf,za1,za2,za3,za4,za5) \
|
||||||
fprintf(stderr,zf,za1,za2,za3,za4,za5)
|
fprintf(stderr,zf,za1,za2,za3,za4,za5)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
extern void bz_internal_error ( int errcode );
|
extern void bz_internal_error ( int errcode );
|
||||||
#define AssertH(cond,errcode) \
|
#define AssertH(cond,errcode) \
|
||||||
{ if (!(cond)) bz_internal_error ( errcode ); }
|
{ if (!(cond)) bz_internal_error ( errcode ); }
|
||||||
#define AssertD(cond,msg) /* */
|
#define AssertD(cond,msg) do { } while (0)
|
||||||
#define VPrintf0(zf) /* */
|
#define VPrintf0(zf) do { } while (0)
|
||||||
#define VPrintf1(zf,za1) /* */
|
#define VPrintf1(zf,za1) do { } while (0)
|
||||||
#define VPrintf2(zf,za1,za2) /* */
|
#define VPrintf2(zf,za1,za2) do { } while (0)
|
||||||
#define VPrintf3(zf,za1,za2,za3) /* */
|
#define VPrintf3(zf,za1,za2,za3) do { } while (0)
|
||||||
#define VPrintf4(zf,za1,za2,za3,za4) /* */
|
#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0)
|
||||||
#define VPrintf5(zf,za1,za2,za3,za4,za5) /* */
|
#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -476,11 +442,15 @@ typedef
|
|||||||
/*-- Macros for decompression. --*/
|
/*-- Macros for decompression. --*/
|
||||||
|
|
||||||
#define BZ_GET_FAST(cccc) \
|
#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]; \
|
s->tPos = s->tt[s->tPos]; \
|
||||||
cccc = (UChar)(s->tPos & 0xff); \
|
cccc = (UChar)(s->tPos & 0xff); \
|
||||||
s->tPos >>= 8;
|
s->tPos >>= 8;
|
||||||
|
|
||||||
#define BZ_GET_FAST_C(cccc) \
|
#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]; \
|
c_tPos = c_tt[c_tPos]; \
|
||||||
cccc = (UChar)(c_tPos & 0xff); \
|
cccc = (UChar)(c_tPos & 0xff); \
|
||||||
c_tPos >>= 8;
|
c_tPos >>= 8;
|
||||||
@ -503,8 +473,10 @@ typedef
|
|||||||
(((UInt32)s->ll16[i]) | (GET_LL4(i) << 16))
|
(((UInt32)s->ll16[i]) | (GET_LL4(i) << 16))
|
||||||
|
|
||||||
#define BZ_GET_SMALL(cccc) \
|
#define BZ_GET_SMALL(cccc) \
|
||||||
cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \
|
/* c_tPos is unsigned, hence test < 0 is pointless. */ \
|
||||||
s->tPos = GET_LL(s->tPos);
|
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. --*/
|
/*-- externs for decompression. --*/
|
||||||
|
|||||||
@ -4,71 +4,27 @@
|
|||||||
/*--- compress.c ---*/
|
/*--- compress.c ---*/
|
||||||
/*-------------------------------------------------------------*/
|
/*-------------------------------------------------------------*/
|
||||||
|
|
||||||
/*--
|
/* ------------------------------------------------------------------
|
||||||
This file is a part of bzip2 and/or libbzip2, a program and
|
This file is part of bzip2/libbzip2, a program and library for
|
||||||
library for lossless, block-sorting data compression.
|
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
|
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||||
modification, are permitted provided that the following conditions
|
README file.
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
This program is released under the terms of the license contained
|
||||||
notice, this list of conditions and the following disclaimer.
|
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
|
/* CHANGES
|
||||||
not be misrepresented as being the original software.
|
0.9.0 -- original version.
|
||||||
|
0.9.0a/b -- no changes in this file.
|
||||||
4. The name of the author may not be used to endorse or promote
|
0.9.0c -- changed setting of nGroups in sendMTFValues()
|
||||||
products derived from this software without specific prior written
|
so as to do a bit better on small files
|
||||||
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
|
|
||||||
--*/
|
|
||||||
|
|
||||||
#include "bzlib_private.h"
|
#include "bzlib_private.h"
|
||||||
|
|
||||||
|
|||||||
@ -4,59 +4,19 @@
|
|||||||
/*--- crctable.c ---*/
|
/*--- crctable.c ---*/
|
||||||
/*-------------------------------------------------------------*/
|
/*-------------------------------------------------------------*/
|
||||||
|
|
||||||
/*--
|
/* ------------------------------------------------------------------
|
||||||
This file is a part of bzip2 and/or libbzip2, a program and
|
This file is part of bzip2/libbzip2, a program and library for
|
||||||
library for lossless, block-sorting data compression.
|
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
|
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||||
modification, are permitted provided that the following conditions
|
README file.
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
This program is released under the terms of the license contained
|
||||||
notice, this list of conditions and the following disclaimer.
|
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.
|
|
||||||
--*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "bzlib_private.h"
|
#include "bzlib_private.h"
|
||||||
|
|||||||
@ -4,59 +4,19 @@
|
|||||||
/*--- decompress.c ---*/
|
/*--- decompress.c ---*/
|
||||||
/*-------------------------------------------------------------*/
|
/*-------------------------------------------------------------*/
|
||||||
|
|
||||||
/*--
|
/* ------------------------------------------------------------------
|
||||||
This file is a part of bzip2 and/or libbzip2, a program and
|
This file is part of bzip2/libbzip2, a program and library for
|
||||||
library for lossless, block-sorting data compression.
|
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
|
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||||
modification, are permitted provided that the following conditions
|
README file.
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
This program is released under the terms of the license contained
|
||||||
notice, this list of conditions and the following disclaimer.
|
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.
|
|
||||||
--*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "bzlib_private.h"
|
#include "bzlib_private.h"
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
minibz2
|
minibz2
|
||||||
libbz2.dll test program.
|
libbz2.dll test program.
|
||||||
by Yoshioka Tsuneo(QWF00133@nifty.ne.jp/tsuneo-y@is.aist-nara.ac.jp)
|
by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
|
||||||
This file is Public Domain.
|
This file is Public Domain. Welcome any email to me.
|
||||||
welcome any email to me.
|
|
||||||
|
|
||||||
usage: minibz2 [-d] [-{1,2,..9}] [[srcfilename] destfilename]
|
usage: minibz2 [-d] [-{1,2,..9}] [[srcfilename] destfilename]
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -4,59 +4,19 @@
|
|||||||
/*--- huffman.c ---*/
|
/*--- huffman.c ---*/
|
||||||
/*-------------------------------------------------------------*/
|
/*-------------------------------------------------------------*/
|
||||||
|
|
||||||
/*--
|
/* ------------------------------------------------------------------
|
||||||
This file is a part of bzip2 and/or libbzip2, a program and
|
This file is part of bzip2/libbzip2, a program and library for
|
||||||
library for lossless, block-sorting data compression.
|
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
|
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||||
modification, are permitted provided that the following conditions
|
README file.
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
This program is released under the terms of the license contained
|
||||||
notice, this list of conditions and the following disclaimer.
|
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.
|
|
||||||
--*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "bzlib_private.h"
|
#include "bzlib_private.h"
|
||||||
|
|||||||
@ -5,6 +5,21 @@
|
|||||||
case, which is fixed in this version (1.0.2) and above.
|
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>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main ()
|
int main ()
|
||||||
|
|||||||
@ -4,59 +4,19 @@
|
|||||||
/*--- randtable.c ---*/
|
/*--- randtable.c ---*/
|
||||||
/*-------------------------------------------------------------*/
|
/*-------------------------------------------------------------*/
|
||||||
|
|
||||||
/*--
|
/* ------------------------------------------------------------------
|
||||||
This file is a part of bzip2 and/or libbzip2, a program and
|
This file is part of bzip2/libbzip2, a program and library for
|
||||||
library for lossless, block-sorting data compression.
|
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
|
Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
||||||
modification, are permitted provided that the following conditions
|
README file.
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
This program is released under the terms of the license contained
|
||||||
notice, this list of conditions and the following disclaimer.
|
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.
|
|
||||||
--*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "bzlib_private.h"
|
#include "bzlib_private.h"
|
||||||
|
|||||||
@ -9,6 +9,21 @@
|
|||||||
(but is otherwise harmless).
|
(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
|
#define _FILE_OFFSET_BITS 64
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|||||||
@ -8,11 +8,26 @@
|
|||||||
This should not cause any invalid memory accesses. If it does,
|
This should not cause any invalid memory accesses. If it does,
|
||||||
I want to know about it!
|
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
|
incredibly slow. A file of size eg 5KB will cause it to run for
|
||||||
many hours.
|
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 <stdio.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "bzlib.h"
|
#include "bzlib.h"
|
||||||
|
|||||||
@ -133,54 +133,86 @@ void TOutputStream::PutBits(unsigned long dwBuff, unsigned int nPutBits)
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// TInputStream functions
|
// TInputStream functions
|
||||||
|
|
||||||
// Gets one bit from input stream
|
// Gets one bit from input stream
|
||||||
unsigned long TInputStream::GetBit()
|
unsigned long TInputStream::GetBit()
|
||||||
{
|
{
|
||||||
unsigned long dwBit = (dwBitBuff & 1);
|
unsigned long dwOneBit = 0;
|
||||||
|
|
||||||
dwBitBuff >>= 1;
|
// Ensure that the input stream is reloaded, if there are no bits left
|
||||||
if(--nBits == 0)
|
if(BitCount == 0)
|
||||||
{
|
{
|
||||||
dwBitBuff = BSWAP_INT32_UNSIGNED(*(unsigned long *)pbInBuffer);
|
// Refill the bit buffer
|
||||||
pbInBuffer += sizeof(unsigned long);
|
BitBuffer = *pbInBuffer++;
|
||||||
nBits = 32;
|
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()
|
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;
|
dwReloadByte = *pbInBuffer++;
|
||||||
pbInBuffer += sizeof(unsigned short);
|
BitBuffer |= dwReloadByte << BitCount;
|
||||||
nBits += 16;
|
BitCount += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 7 bits from input stream
|
// Return the first available 7 bits. DO NOT remove them from the input stream
|
||||||
return (dwBitBuff & 0x7F);
|
return (BitBuffer & 0x7F);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the whole byte from the input stream.
|
// Gets the whole byte from the input stream.
|
||||||
unsigned long TInputStream::Get8Bits()
|
unsigned long TInputStream::Get8Bits()
|
||||||
{
|
{
|
||||||
unsigned long dwOneByte;
|
unsigned long dwReloadByte = 0;
|
||||||
|
unsigned long dwOneByte = 0;
|
||||||
if(nBits <= 8)
|
|
||||||
|
// 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;
|
dwReloadByte = *pbInBuffer++;
|
||||||
pbInBuffer += sizeof(unsigned short);
|
BitBuffer |= dwReloadByte << BitCount;
|
||||||
nBits += 16;
|
BitCount += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
dwOneByte = (dwBitBuff & 0xFF);
|
// Return the lowest 8 its
|
||||||
dwBitBuff >>= 8;
|
dwOneByte = (BitBuffer & 0xFF);
|
||||||
nBits -= 8;
|
BitBuffer >>= 8;
|
||||||
|
BitCount -= 8;
|
||||||
return dwOneByte;
|
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
|
// Functions for huffmann tree items
|
||||||
|
|
||||||
@ -990,13 +1022,11 @@ unsigned int THuffmannTree::DoDecompression(unsigned char * pbOutBuffer, unsigne
|
|||||||
{
|
{
|
||||||
if(qd->nBits > 7)
|
if(qd->nBits > 7)
|
||||||
{
|
{
|
||||||
is->dwBitBuff >>= 7;
|
is->SkipBits(7);
|
||||||
is->nBits -= 7;
|
|
||||||
pItem1 = qd->pItem;
|
pItem1 = qd->pItem;
|
||||||
goto _1500E549;
|
goto _1500E549;
|
||||||
}
|
}
|
||||||
is->dwBitBuff >>= qd->nBits;
|
is->SkipBits(qd->nBits);
|
||||||
is->nBits -= qd->nBits;
|
|
||||||
nDcmpByte = qd->dcmpByte;
|
nDcmpByte = qd->dcmpByte;
|
||||||
}
|
}
|
||||||
else
|
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, 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
|
||||||
};
|
};
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#define PTR_NOT(ptr) (THTreeItem *)(~(DWORD_PTR)(ptr))
|
#define PTR_NOT(ptr) (THTreeItem *)(~(DWORD_PTR)(ptr))
|
||||||
#define PTR_PTR(ptr) ((THTreeItem *)(ptr))
|
#define PTR_PTR(ptr) ((THTreeItem *)(ptr))
|
||||||
#define PTR_INT(ptr) (LONG_PTR)(ptr)
|
#define PTR_INT(ptr) (INT_PTR)(ptr)
|
||||||
|
|
||||||
#ifndef NULL
|
#ifndef NULL
|
||||||
#define NULL 0
|
#define NULL 0
|
||||||
@ -40,10 +40,11 @@ class TInputStream
|
|||||||
unsigned long GetBit();
|
unsigned long GetBit();
|
||||||
unsigned long Get7Bits();
|
unsigned long Get7Bits();
|
||||||
unsigned long Get8Bits();
|
unsigned long Get8Bits();
|
||||||
|
void SkipBits(unsigned int BitCount);
|
||||||
|
|
||||||
unsigned char * pbInBuffer; // 00 - Input data
|
unsigned char * pbInBuffer; // 00 - Input data
|
||||||
unsigned long dwBitBuff; // 04 - Input bit buffer
|
unsigned long BitBuffer; // 04 - Input bit buffer
|
||||||
unsigned int nBits; // 08 - Number of bits remaining in 'dwValue'
|
unsigned int BitCount; // 08 - Number of bits remaining in 'dwBitBuff'
|
||||||
};
|
};
|
||||||
|
|
||||||
// Output stream for Huffmann compression
|
// Output stream for Huffmann compression
|
||||||
|
|||||||
72
src/tools/stuffextract/StormLib/pklib/crc32.c
Normal file
72
src/tools/stuffextract/StormLib/pklib/crc32.c
Normal 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;
|
||||||
|
}
|
||||||
@ -29,7 +29,11 @@
|
|||||||
// Define calling convention
|
// Define calling convention
|
||||||
|
|
||||||
#ifndef PKEXPORT
|
#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
|
#endif
|
||||||
//#define PKEXPORT __stdcall
|
//#define PKEXPORT __stdcall
|
||||||
//#define PKEXPORT __fastcall
|
//#define PKEXPORT __fastcall
|
||||||
|
|||||||
@ -50,8 +50,8 @@ int main(int argc, char *argv[])
|
|||||||
if(GetLocale() && FileExists(std::string("Data/")+GetLocale()+"/locale-"+GetLocale()+".MPQ"))
|
if(GetLocale() && FileExists(std::string("Data/")+GetLocale()+"/locale-"+GetLocale()+".MPQ"))
|
||||||
{
|
{
|
||||||
printf("Locale \"%s\" seems valid, starting conversion...\n",GetLocale());
|
printf("Locale \"%s\" seems valid, starting conversion...\n",GetLocale());
|
||||||
CreateDir("stuffextract");
|
CreateDir("extractedstuff");
|
||||||
CreateDir("stuffextract/data");
|
CreateDir("extractedstuff/data");
|
||||||
ConvertDBC();
|
ConvertDBC();
|
||||||
if(doMaps) ExtractMaps();
|
if(doMaps) ExtractMaps();
|
||||||
if(doTextures || doModels || doWmos || doWmogroups) ExtractMapDependencies();
|
if(doTextures || doModels || doWmos || doWmogroups) ExtractMapDependencies();
|
||||||
@ -610,7 +610,7 @@ bool ConvertDBC(void)
|
|||||||
printf("DONE!\n");
|
printf("DONE!\n");
|
||||||
//...
|
//...
|
||||||
|
|
||||||
CreateDir("stuffextract/data/scp");
|
CreateDir("extractedstuff/data/scp");
|
||||||
|
|
||||||
printf("Writing SCP files:\n");
|
printf("Writing SCP files:\n");
|
||||||
printf("emote.."); OutSCP(SCPDIR "/emote.scp",EmoteDataStorage, "emote");
|
printf("emote.."); OutSCP(SCPDIR "/emote.scp",EmoteDataStorage, "emote");
|
||||||
@ -641,7 +641,7 @@ void ExtractMaps(void)
|
|||||||
uint32 extr,extrtotal=0;
|
uint32 extr,extrtotal=0;
|
||||||
MPQHelper mpq("terrain");
|
MPQHelper mpq("terrain");
|
||||||
MD5FileMap md5map;
|
MD5FileMap md5map;
|
||||||
CreateDir("stuffextract/data/maps");
|
CreateDir("extractedstuff/data/maps");
|
||||||
for(std::map<uint32,std::string>::iterator it = mapNames.begin(); it != mapNames.end(); it++)
|
for(std::map<uint32,std::string>::iterator it = mapNames.begin(); it != mapNames.end(); it++)
|
||||||
{
|
{
|
||||||
// extract the WDT file that stores tile information
|
// extract the WDT file that stores tile information
|
||||||
@ -726,7 +726,7 @@ void ExtractMapDependencies(void)
|
|||||||
MPQHelper mpqmodel("model");
|
MPQHelper mpqmodel("model");
|
||||||
MPQHelper mpqtex("texture");
|
MPQHelper mpqtex("texture");
|
||||||
MPQHelper mpqwmo("wmo");
|
MPQHelper mpqwmo("wmo");
|
||||||
std::string path = "stuffextract/data";
|
std::string path = "extractedstuff/data";
|
||||||
std::string pathtex = path + "/texture";
|
std::string pathtex = path + "/texture";
|
||||||
std::string pathmodel = path + "/model";
|
std::string pathmodel = path + "/model";
|
||||||
std::string pathwmo = path + "/wmo";
|
std::string pathwmo = path + "/wmo";
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#define SE_VERSION 2
|
#define SE_VERSION 2
|
||||||
#define MAPS_VERSION ((uint32)0)
|
#define MAPS_VERSION ((uint32)0)
|
||||||
#define OUTDIR "stuffextract"
|
#define OUTDIR "extractedstuff"
|
||||||
#define SCPDIR OUTDIR "/data/scp"
|
#define SCPDIR OUTDIR "/data/scp"
|
||||||
#define MAPSDIR OUTDIR "/data/maps"
|
#define MAPSDIR OUTDIR "/data/maps"
|
||||||
#define SOUNDDIR OUTDIR "/data/sound"
|
#define SOUNDDIR OUTDIR "/data/sound"
|
||||||
|
|||||||
@ -64,11 +64,12 @@ bool DBCFile::openmem(ByteBuffer bb)
|
|||||||
printf("DBCFile::openmem(): ByteBuffer too small!");
|
printf("DBCFile::openmem(): ByteBuffer too small!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 hdr;
|
uint32 hdr;
|
||||||
bb >> hdr;
|
bb >> hdr;
|
||||||
|
|
||||||
if(memcmp(&hdr,"WDBC",4)) // check if its a valid dbc file
|
if(memcmp(&hdr,"WDBC",4)) // check if its a valid dbc file
|
||||||
{
|
{
|
||||||
|
printf("not a valid WDB File??\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user