|
|
|
|
@ -21,39 +21,23 @@ BOOLEAN save_archive_open;
|
|
|
|
|
|
|
|
|
|
HANDLE sghArchive = INVALID_HANDLE_VALUE; |
|
|
|
|
|
|
|
|
|
BOOL mpqapi_set_hidden(const char *pszArchive, BOOL hidden) |
|
|
|
|
static void mpqapi_xor_buf(char *pbData) |
|
|
|
|
{ |
|
|
|
|
DWORD dwFileAttributes; |
|
|
|
|
DWORD dwFileAttributesToSet; |
|
|
|
|
|
|
|
|
|
dwFileAttributes = GetFileAttributes(pszArchive); |
|
|
|
|
if (dwFileAttributes == INVALID_FILE_ATTRIBUTES) |
|
|
|
|
return GetLastError() == ERROR_FILE_NOT_FOUND; |
|
|
|
|
dwFileAttributesToSet = hidden ? FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN : 0; |
|
|
|
|
if (dwFileAttributes == dwFileAttributesToSet) |
|
|
|
|
return TRUE; |
|
|
|
|
else |
|
|
|
|
return SetFileAttributes(pszArchive, dwFileAttributesToSet); |
|
|
|
|
} |
|
|
|
|
DWORD mask; |
|
|
|
|
char *pbCurrentData; |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
void mpqapi_store_creation_time(const char *pszArchive, DWORD dwChar) |
|
|
|
|
{ |
|
|
|
|
HANDLE handle; |
|
|
|
|
struct _WIN32_FIND_DATAA FindFileData; |
|
|
|
|
char dst[160]; |
|
|
|
|
mask = 0xF0761AB; |
|
|
|
|
pbCurrentData = pbData; |
|
|
|
|
|
|
|
|
|
if (gbMaxPlayers != 1) { |
|
|
|
|
mpqapi_reg_load_modification_time(dst, 160); |
|
|
|
|
handle = FindFirstFile(pszArchive, &FindFileData); |
|
|
|
|
if (handle != INVALID_HANDLE_VALUE) { |
|
|
|
|
FindClose(handle); |
|
|
|
|
*((FILETIME *)(dst) + dwChar * 2) = FindFileData.ftCreationTime; |
|
|
|
|
mpqapi_reg_store_modification_time(dst, 160); |
|
|
|
|
} |
|
|
|
|
for (i = 0; i < 8; i++) { |
|
|
|
|
*pbCurrentData ^= mask; |
|
|
|
|
pbCurrentData++; |
|
|
|
|
mask = _rotl(mask, 1); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
BOOL mpqapi_reg_load_modification_time(char *dst, int size) |
|
|
|
|
static BOOL mpqapi_reg_load_modification_time(char *dst, int size) |
|
|
|
|
{ |
|
|
|
|
char *pszDst; |
|
|
|
|
char *pbData; |
|
|
|
|
@ -81,20 +65,42 @@ BOOL mpqapi_reg_load_modification_time(char *dst, int size)
|
|
|
|
|
return TRUE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void mpqapi_xor_buf(char *pbData) |
|
|
|
|
static BOOLEAN mpqapi_reg_store_modification_time(char *pbData, DWORD dwLen) |
|
|
|
|
{ |
|
|
|
|
DWORD mask; |
|
|
|
|
char *pbCurrentData; |
|
|
|
|
int i; |
|
|
|
|
char *pbCurrentData, *pbDataToXor; |
|
|
|
|
DWORD i; |
|
|
|
|
|
|
|
|
|
mask = 0xF0761AB; |
|
|
|
|
pbCurrentData = pbData; |
|
|
|
|
|
|
|
|
|
for (i = 0; i < 8; i++) { |
|
|
|
|
*pbCurrentData ^= mask; |
|
|
|
|
pbCurrentData++; |
|
|
|
|
mask = _rotl(mask, 1); |
|
|
|
|
if (dwLen >= 8) { |
|
|
|
|
i = dwLen >> 3; |
|
|
|
|
do { |
|
|
|
|
pbDataToXor = pbCurrentData; |
|
|
|
|
pbCurrentData += 8; |
|
|
|
|
mpqapi_xor_buf(pbDataToXor); |
|
|
|
|
i--; |
|
|
|
|
} while (i); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef SPAWN |
|
|
|
|
return SRegSaveData(APP_NAME, "Audio Playback ", 0, (BYTE *)pbData, dwLen); |
|
|
|
|
#else |
|
|
|
|
return SRegSaveData(APP_NAME, "Video Player ", 0, (BYTE *)pbData, dwLen); |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
BOOL mpqapi_set_hidden(const char *pszArchive, BOOL hidden) |
|
|
|
|
{ |
|
|
|
|
DWORD dwFileAttributes; |
|
|
|
|
DWORD dwFileAttributesToSet; |
|
|
|
|
|
|
|
|
|
dwFileAttributes = GetFileAttributes(pszArchive); |
|
|
|
|
if (dwFileAttributes == INVALID_FILE_ATTRIBUTES) |
|
|
|
|
return GetLastError() == ERROR_FILE_NOT_FOUND; |
|
|
|
|
dwFileAttributesToSet = hidden ? FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN : 0; |
|
|
|
|
if (dwFileAttributes == dwFileAttributesToSet) |
|
|
|
|
return TRUE; |
|
|
|
|
else |
|
|
|
|
return SetFileAttributes(pszArchive, dwFileAttributesToSet); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void mpqapi_store_default_time(DWORD dwChar) |
|
|
|
|
@ -115,49 +121,63 @@ void mpqapi_store_default_time(DWORD dwChar)
|
|
|
|
|
*/ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
BOOLEAN mpqapi_reg_store_modification_time(char *pbData, DWORD dwLen) |
|
|
|
|
static void mpqapi_store_modified_time(const char *pszArchive, DWORD dwChar) |
|
|
|
|
{ |
|
|
|
|
char *pbCurrentData, *pbDataToXor; |
|
|
|
|
DWORD i; |
|
|
|
|
HANDLE handle; |
|
|
|
|
struct _WIN32_FIND_DATAA FindFileData; |
|
|
|
|
char dst[160]; |
|
|
|
|
|
|
|
|
|
pbCurrentData = pbData; |
|
|
|
|
if (dwLen >= 8) { |
|
|
|
|
i = dwLen >> 3; |
|
|
|
|
do { |
|
|
|
|
pbDataToXor = pbCurrentData; |
|
|
|
|
pbCurrentData += 8; |
|
|
|
|
mpqapi_xor_buf(pbDataToXor); |
|
|
|
|
i--; |
|
|
|
|
} while (i); |
|
|
|
|
if (gbMaxPlayers != 1) { |
|
|
|
|
mpqapi_reg_load_modification_time(dst, 160); |
|
|
|
|
handle = FindFirstFile(pszArchive, &FindFileData); |
|
|
|
|
if (handle != INVALID_HANDLE_VALUE) { |
|
|
|
|
FindClose(handle); |
|
|
|
|
*((FILETIME *)(dst) + dwChar * 2 + 1) = FindFileData.ftLastWriteTime; |
|
|
|
|
mpqapi_reg_store_modification_time(dst, 160); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef SPAWN |
|
|
|
|
return SRegSaveData(APP_NAME, "Audio Playback ", 0, (BYTE *)pbData, dwLen); |
|
|
|
|
#else |
|
|
|
|
return SRegSaveData(APP_NAME, "Video Player ", 0, (BYTE *)pbData, dwLen); |
|
|
|
|
#endif |
|
|
|
|
void mpqapi_store_creation_time(const char *pszArchive, DWORD dwChar) |
|
|
|
|
{ |
|
|
|
|
HANDLE handle; |
|
|
|
|
struct _WIN32_FIND_DATAA FindFileData; |
|
|
|
|
char dst[160]; |
|
|
|
|
|
|
|
|
|
if (gbMaxPlayers != 1) { |
|
|
|
|
mpqapi_reg_load_modification_time(dst, 160); |
|
|
|
|
handle = FindFirstFile(pszArchive, &FindFileData); |
|
|
|
|
if (handle != INVALID_HANDLE_VALUE) { |
|
|
|
|
FindClose(handle); |
|
|
|
|
*((FILETIME *)(dst) + dwChar * 2) = FindFileData.ftCreationTime; |
|
|
|
|
mpqapi_reg_store_modification_time(dst, 160); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void mpqapi_remove_hash_entry(const char *pszName) |
|
|
|
|
static _BLOCKENTRY *mpqapi_new_block(int *block_index) |
|
|
|
|
{ |
|
|
|
|
_HASHENTRY *pHashTbl; |
|
|
|
|
_BLOCKENTRY *blockEntry; |
|
|
|
|
int hIdx, block_offset, block_size; |
|
|
|
|
DWORD i; |
|
|
|
|
|
|
|
|
|
hIdx = FetchHandle(pszName); |
|
|
|
|
if (hIdx != -1) { |
|
|
|
|
pHashTbl = &sgpHashTbl[hIdx]; |
|
|
|
|
blockEntry = &sgpBlockTbl[pHashTbl->block]; |
|
|
|
|
pHashTbl->block = -2; |
|
|
|
|
block_offset = blockEntry->offset; |
|
|
|
|
block_size = blockEntry->sizealloc; |
|
|
|
|
memset(blockEntry, 0, sizeof(*blockEntry)); |
|
|
|
|
mpqapi_alloc_block(block_offset, block_size); |
|
|
|
|
save_archive_modified = TRUE; |
|
|
|
|
blockEntry = sgpBlockTbl; |
|
|
|
|
|
|
|
|
|
i = 0; |
|
|
|
|
while (blockEntry->offset || blockEntry->sizealloc || blockEntry->flags || blockEntry->sizefile) { |
|
|
|
|
i++; |
|
|
|
|
blockEntry++; |
|
|
|
|
if (i >= 2048) { |
|
|
|
|
app_fatal("Out of free block entries"); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (block_index) |
|
|
|
|
*block_index = i; |
|
|
|
|
|
|
|
|
|
return blockEntry; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void mpqapi_alloc_block(int block_offset, int block_size) |
|
|
|
|
static void mpqapi_alloc_block(int block_offset, int block_size) |
|
|
|
|
{ |
|
|
|
|
_BLOCKENTRY *block; |
|
|
|
|
int i; |
|
|
|
|
@ -196,34 +216,38 @@ void mpqapi_alloc_block(int block_offset, int block_size)
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
_BLOCKENTRY *mpqapi_new_block(int *block_index) |
|
|
|
|
static int mpqapi_find_free_block(int size, int *block_size) |
|
|
|
|
{ |
|
|
|
|
_BLOCKENTRY *blockEntry; |
|
|
|
|
DWORD i; |
|
|
|
|
|
|
|
|
|
blockEntry = sgpBlockTbl; |
|
|
|
|
_BLOCKENTRY *pBlockTbl; |
|
|
|
|
int i, result; |
|
|
|
|
|
|
|
|
|
i = 0; |
|
|
|
|
while (blockEntry->offset || blockEntry->sizealloc || blockEntry->flags || blockEntry->sizefile) { |
|
|
|
|
i++; |
|
|
|
|
blockEntry++; |
|
|
|
|
if (i >= 2048) { |
|
|
|
|
app_fatal("Out of free block entries"); |
|
|
|
|
return NULL; |
|
|
|
|
pBlockTbl = sgpBlockTbl; |
|
|
|
|
i = 2048; |
|
|
|
|
while (1) { |
|
|
|
|
i--; |
|
|
|
|
if (pBlockTbl->offset && !pBlockTbl->flags && !pBlockTbl->sizefile && (DWORD)pBlockTbl->sizealloc >= size) |
|
|
|
|
break; |
|
|
|
|
pBlockTbl++; |
|
|
|
|
if (!i) { |
|
|
|
|
*block_size = size; |
|
|
|
|
result = sgdwMpqOffset; |
|
|
|
|
sgdwMpqOffset += size; |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (block_index) |
|
|
|
|
*block_index = i; |
|
|
|
|
|
|
|
|
|
return blockEntry; |
|
|
|
|
} |
|
|
|
|
result = pBlockTbl->offset; |
|
|
|
|
*block_size = size; |
|
|
|
|
pBlockTbl->offset += size; |
|
|
|
|
pBlockTbl->sizealloc -= size; |
|
|
|
|
|
|
|
|
|
int FetchHandle(const char *pszName) |
|
|
|
|
{ |
|
|
|
|
return mpqapi_get_hash_index(Hash(pszName, 0), Hash(pszName, 1), Hash(pszName, 2), 0); |
|
|
|
|
if (!pBlockTbl->sizealloc) |
|
|
|
|
memset(pBlockTbl, 0, sizeof(*pBlockTbl)); |
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int mpqapi_get_hash_index(short index, int hash_a, int hash_b, int locale) |
|
|
|
|
static int mpqapi_get_hash_index(short index, int hash_a, int hash_b, int locale) |
|
|
|
|
{ |
|
|
|
|
int idx, i; |
|
|
|
|
|
|
|
|
|
@ -238,32 +262,141 @@ int mpqapi_get_hash_index(short index, int hash_a, int hash_b, int locale)
|
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void mpqapi_remove_hash_entries(BOOL(__stdcall *fnGetName)(DWORD, char *)) |
|
|
|
|
static BOOL WriteMPQHeader() |
|
|
|
|
{ |
|
|
|
|
DWORD dwIndex, i; |
|
|
|
|
char pszFileName[MAX_PATH]; |
|
|
|
|
_FILEHEADER fhdr; |
|
|
|
|
DWORD NumberOfBytesWritten; |
|
|
|
|
|
|
|
|
|
dwIndex = 1; |
|
|
|
|
for (i = fnGetName(0, pszFileName); i; i = fnGetName(dwIndex++, pszFileName)) { |
|
|
|
|
mpqapi_remove_hash_entry(pszFileName); |
|
|
|
|
} |
|
|
|
|
memset(&fhdr, 0, sizeof(fhdr)); |
|
|
|
|
fhdr.signature = '\x1AQPM'; |
|
|
|
|
fhdr.headersize = 32; |
|
|
|
|
fhdr.filesize = GetFileSize(sghArchive, 0); |
|
|
|
|
fhdr.version = 0; |
|
|
|
|
fhdr.sectorsizeid = 3; |
|
|
|
|
fhdr.hashoffset = 32872; |
|
|
|
|
fhdr.blockoffset = 104; |
|
|
|
|
fhdr.hashcount = 2048; |
|
|
|
|
fhdr.blockcount = 2048; |
|
|
|
|
|
|
|
|
|
if (SetFilePointer(sghArchive, 0, NULL, FILE_BEGIN) == -1) |
|
|
|
|
return FALSE; |
|
|
|
|
if (!WriteFile(sghArchive, &fhdr, sizeof(fhdr), &NumberOfBytesWritten, 0)) |
|
|
|
|
return FALSE; |
|
|
|
|
|
|
|
|
|
return NumberOfBytesWritten == 104; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
BOOL mpqapi_write_file(const char *pszName, const BYTE *pbData, DWORD dwLen) |
|
|
|
|
static BOOL mpqapi_write_block_table() |
|
|
|
|
{ |
|
|
|
|
_BLOCKENTRY *blockEntry; |
|
|
|
|
BOOL success; |
|
|
|
|
DWORD NumberOfBytesWritten; |
|
|
|
|
|
|
|
|
|
save_archive_modified = TRUE; |
|
|
|
|
mpqapi_remove_hash_entry(pszName); |
|
|
|
|
blockEntry = mpqapi_add_file(pszName, 0, 0); |
|
|
|
|
if (!mpqapi_write_file_contents(pszName, pbData, dwLen, blockEntry)) { |
|
|
|
|
mpqapi_remove_hash_entry(pszName); |
|
|
|
|
if (SetFilePointer(sghArchive, 104, NULL, FILE_BEGIN) == -1) |
|
|
|
|
return FALSE; |
|
|
|
|
|
|
|
|
|
Encrypt((DWORD *)sgpBlockTbl, 0x8000, Hash("(block table)", 3)); |
|
|
|
|
success = WriteFile(sghArchive, sgpBlockTbl, 0x8000, &NumberOfBytesWritten, 0); |
|
|
|
|
Decrypt((DWORD *)sgpBlockTbl, 0x8000, Hash("(block table)", 3)); |
|
|
|
|
return success && NumberOfBytesWritten == 0x8000; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static BOOL mpqapi_write_hash_table() |
|
|
|
|
{ |
|
|
|
|
BOOL success; |
|
|
|
|
DWORD NumberOfBytesWritten; |
|
|
|
|
|
|
|
|
|
if (SetFilePointer(sghArchive, 32872, NULL, FILE_BEGIN) == -1) |
|
|
|
|
return FALSE; |
|
|
|
|
|
|
|
|
|
Encrypt((DWORD *)sgpHashTbl, 0x8000, Hash("(hash table)", 3)); |
|
|
|
|
success = WriteFile(sghArchive, sgpHashTbl, 0x8000, &NumberOfBytesWritten, 0); |
|
|
|
|
Decrypt((DWORD *)sgpHashTbl, 0x8000, Hash("(hash table)", 3)); |
|
|
|
|
return success && NumberOfBytesWritten == 0x8000; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static BOOL mpqapi_can_seek() |
|
|
|
|
{ |
|
|
|
|
if (SetFilePointer(sghArchive, sgdwMpqOffset, NULL, FILE_BEGIN) == -1) |
|
|
|
|
return FALSE; |
|
|
|
|
return SetEndOfFile(sghArchive); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static BOOL ParseMPQHeader(_FILEHEADER *pHdr, DWORD *pdwNextFileStart) |
|
|
|
|
{ |
|
|
|
|
DWORD size; |
|
|
|
|
DWORD NumberOfBytesRead; |
|
|
|
|
|
|
|
|
|
size = GetFileSize(sghArchive, 0); |
|
|
|
|
*pdwNextFileStart = size; |
|
|
|
|
|
|
|
|
|
if (size == -1 |
|
|
|
|
|| size < sizeof(*pHdr) |
|
|
|
|
|| !ReadFile(sghArchive, pHdr, sizeof(*pHdr), &NumberOfBytesRead, NULL) |
|
|
|
|
|| NumberOfBytesRead != 104 |
|
|
|
|
|| pHdr->signature != '\x1AQPM' |
|
|
|
|
|| pHdr->headersize != 32 |
|
|
|
|
|| pHdr->version > 0 |
|
|
|
|
|| pHdr->sectorsizeid != 3 |
|
|
|
|
|| pHdr->filesize != size |
|
|
|
|
|| pHdr->hashoffset != 32872 |
|
|
|
|
|| pHdr->blockoffset != 104 |
|
|
|
|
|| pHdr->hashcount != 2048 |
|
|
|
|
|| pHdr->blockcount != 2048) { |
|
|
|
|
|
|
|
|
|
if (SetFilePointer(sghArchive, 0, NULL, FILE_BEGIN) == -1) |
|
|
|
|
return FALSE; |
|
|
|
|
if (!SetEndOfFile(sghArchive)) |
|
|
|
|
return FALSE; |
|
|
|
|
|
|
|
|
|
memset(pHdr, 0, sizeof(*pHdr)); |
|
|
|
|
pHdr->signature = '\x1AQPM'; |
|
|
|
|
pHdr->headersize = 32; |
|
|
|
|
pHdr->sectorsizeid = 3; |
|
|
|
|
pHdr->version = 0; |
|
|
|
|
*pdwNextFileStart = 0x10068; |
|
|
|
|
save_archive_modified = TRUE; |
|
|
|
|
save_archive_open = TRUE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return TRUE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
_BLOCKENTRY *mpqapi_add_file(const char *pszName, _BLOCKENTRY *pBlk, int block_index) |
|
|
|
|
static int FetchHandle(const char *pszName) |
|
|
|
|
{ |
|
|
|
|
return mpqapi_get_hash_index(Hash(pszName, 0), Hash(pszName, 1), Hash(pszName, 2), 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void mpqapi_remove_hash_entry(const char *pszName) |
|
|
|
|
{ |
|
|
|
|
_HASHENTRY *pHashTbl; |
|
|
|
|
_BLOCKENTRY *blockEntry; |
|
|
|
|
int hIdx, block_offset, block_size; |
|
|
|
|
|
|
|
|
|
hIdx = FetchHandle(pszName); |
|
|
|
|
if (hIdx != -1) { |
|
|
|
|
pHashTbl = &sgpHashTbl[hIdx]; |
|
|
|
|
blockEntry = &sgpBlockTbl[pHashTbl->block]; |
|
|
|
|
pHashTbl->block = -2; |
|
|
|
|
block_offset = blockEntry->offset; |
|
|
|
|
block_size = blockEntry->sizealloc; |
|
|
|
|
memset(blockEntry, 0, sizeof(*blockEntry)); |
|
|
|
|
mpqapi_alloc_block(block_offset, block_size); |
|
|
|
|
save_archive_modified = TRUE; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void mpqapi_remove_hash_entries(BOOL(__stdcall *fnGetName)(DWORD, char *)) |
|
|
|
|
{ |
|
|
|
|
DWORD dwIndex, i; |
|
|
|
|
char pszFileName[MAX_PATH]; |
|
|
|
|
|
|
|
|
|
dwIndex = 1; |
|
|
|
|
for (i = fnGetName(0, pszFileName); i; i = fnGetName(dwIndex++, pszFileName)) { |
|
|
|
|
mpqapi_remove_hash_entry(pszFileName); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static _BLOCKENTRY *mpqapi_add_file(const char *pszName, _BLOCKENTRY *pBlk, int block_index) |
|
|
|
|
{ |
|
|
|
|
DWORD h1, h2, h3; |
|
|
|
|
int i, hIdx; |
|
|
|
|
@ -293,7 +426,7 @@ _BLOCKENTRY *mpqapi_add_file(const char *pszName, _BLOCKENTRY *pBlk, int block_i
|
|
|
|
|
return pBlk; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
BOOL mpqapi_write_file_contents(const char *pszName, const BYTE *pbData, DWORD dwLen, _BLOCKENTRY *pBlk) |
|
|
|
|
static BOOL mpqapi_write_file_contents(const char *pszName, const BYTE *pbData, DWORD dwLen, _BLOCKENTRY *pBlk) |
|
|
|
|
{ |
|
|
|
|
DWORD *sectoroffsettable; |
|
|
|
|
DWORD destsize, num_bytes, block_size, nNumberOfBytesToWrite; |
|
|
|
|
@ -379,35 +512,18 @@ on_error:
|
|
|
|
|
return FALSE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int mpqapi_find_free_block(int size, int *block_size) |
|
|
|
|
BOOL mpqapi_write_file(const char *pszName, const BYTE *pbData, DWORD dwLen) |
|
|
|
|
{ |
|
|
|
|
_BLOCKENTRY *pBlockTbl; |
|
|
|
|
int i, result; |
|
|
|
|
_BLOCKENTRY *blockEntry; |
|
|
|
|
|
|
|
|
|
pBlockTbl = sgpBlockTbl; |
|
|
|
|
i = 2048; |
|
|
|
|
while (1) { |
|
|
|
|
i--; |
|
|
|
|
if (pBlockTbl->offset && !pBlockTbl->flags && !pBlockTbl->sizefile && (DWORD)pBlockTbl->sizealloc >= size) |
|
|
|
|
break; |
|
|
|
|
pBlockTbl++; |
|
|
|
|
if (!i) { |
|
|
|
|
*block_size = size; |
|
|
|
|
result = sgdwMpqOffset; |
|
|
|
|
sgdwMpqOffset += size; |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
save_archive_modified = TRUE; |
|
|
|
|
mpqapi_remove_hash_entry(pszName); |
|
|
|
|
blockEntry = mpqapi_add_file(pszName, 0, 0); |
|
|
|
|
if (!mpqapi_write_file_contents(pszName, pbData, dwLen, blockEntry)) { |
|
|
|
|
mpqapi_remove_hash_entry(pszName); |
|
|
|
|
return FALSE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
result = pBlockTbl->offset; |
|
|
|
|
*block_size = size; |
|
|
|
|
pBlockTbl->offset += size; |
|
|
|
|
pBlockTbl->sizealloc -= size; |
|
|
|
|
|
|
|
|
|
if (!pBlockTbl->sizealloc) |
|
|
|
|
memset(pBlockTbl, 0, sizeof(*pBlockTbl)); |
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
|
return TRUE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void mpqapi_rename(char *pszOld, char *pszNew) |
|
|
|
|
@ -432,6 +548,26 @@ BOOL mpqapi_has_file(const char *pszName)
|
|
|
|
|
return FetchHandle(pszName) != -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void CloseMPQ(const char *pszArchive, BOOL bFree, DWORD dwChar) |
|
|
|
|
{ |
|
|
|
|
if (bFree) { |
|
|
|
|
MemFreeDbg(sgpBlockTbl); |
|
|
|
|
MemFreeDbg(sgpHashTbl); |
|
|
|
|
} |
|
|
|
|
if (sghArchive != INVALID_HANDLE_VALUE) { |
|
|
|
|
CloseHandle(sghArchive); |
|
|
|
|
sghArchive = INVALID_HANDLE_VALUE; |
|
|
|
|
} |
|
|
|
|
if (save_archive_modified) { |
|
|
|
|
save_archive_modified = FALSE; |
|
|
|
|
mpqapi_store_modified_time(pszArchive, dwChar); |
|
|
|
|
} |
|
|
|
|
if (save_archive_open) { |
|
|
|
|
save_archive_open = FALSE; |
|
|
|
|
mpqapi_store_creation_time(pszArchive, dwChar); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
BOOL OpenMPQ(const char *pszArchive, BOOL hidden, DWORD dwChar) |
|
|
|
|
{ |
|
|
|
|
DWORD dwFlagsAndAttributes; |
|
|
|
|
@ -486,83 +622,6 @@ on_error:
|
|
|
|
|
return FALSE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
BOOL ParseMPQHeader(_FILEHEADER *pHdr, DWORD *pdwNextFileStart) |
|
|
|
|
{ |
|
|
|
|
DWORD size; |
|
|
|
|
DWORD NumberOfBytesRead; |
|
|
|
|
|
|
|
|
|
size = GetFileSize(sghArchive, 0); |
|
|
|
|
*pdwNextFileStart = size; |
|
|
|
|
|
|
|
|
|
if (size == -1 |
|
|
|
|
|| size < sizeof(*pHdr) |
|
|
|
|
|| !ReadFile(sghArchive, pHdr, sizeof(*pHdr), &NumberOfBytesRead, NULL) |
|
|
|
|
|| NumberOfBytesRead != 104 |
|
|
|
|
|| pHdr->signature != '\x1AQPM' |
|
|
|
|
|| pHdr->headersize != 32 |
|
|
|
|
|| pHdr->version > 0 |
|
|
|
|
|| pHdr->sectorsizeid != 3 |
|
|
|
|
|| pHdr->filesize != size |
|
|
|
|
|| pHdr->hashoffset != 32872 |
|
|
|
|
|| pHdr->blockoffset != 104 |
|
|
|
|
|| pHdr->hashcount != 2048 |
|
|
|
|
|| pHdr->blockcount != 2048) { |
|
|
|
|
|
|
|
|
|
if (SetFilePointer(sghArchive, 0, NULL, FILE_BEGIN) == -1) |
|
|
|
|
return FALSE; |
|
|
|
|
if (!SetEndOfFile(sghArchive)) |
|
|
|
|
return FALSE; |
|
|
|
|
|
|
|
|
|
memset(pHdr, 0, sizeof(*pHdr)); |
|
|
|
|
pHdr->signature = '\x1AQPM'; |
|
|
|
|
pHdr->headersize = 32; |
|
|
|
|
pHdr->sectorsizeid = 3; |
|
|
|
|
pHdr->version = 0; |
|
|
|
|
*pdwNextFileStart = 0x10068; |
|
|
|
|
save_archive_modified = TRUE; |
|
|
|
|
save_archive_open = TRUE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return TRUE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CloseMPQ(const char *pszArchive, BOOL bFree, DWORD dwChar) |
|
|
|
|
{ |
|
|
|
|
if (bFree) { |
|
|
|
|
MemFreeDbg(sgpBlockTbl); |
|
|
|
|
MemFreeDbg(sgpHashTbl); |
|
|
|
|
} |
|
|
|
|
if (sghArchive != INVALID_HANDLE_VALUE) { |
|
|
|
|
CloseHandle(sghArchive); |
|
|
|
|
sghArchive = INVALID_HANDLE_VALUE; |
|
|
|
|
} |
|
|
|
|
if (save_archive_modified) { |
|
|
|
|
save_archive_modified = FALSE; |
|
|
|
|
mpqapi_store_modified_time(pszArchive, dwChar); |
|
|
|
|
} |
|
|
|
|
if (save_archive_open) { |
|
|
|
|
save_archive_open = FALSE; |
|
|
|
|
mpqapi_store_creation_time(pszArchive, dwChar); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void mpqapi_store_modified_time(const char *pszArchive, DWORD dwChar) |
|
|
|
|
{ |
|
|
|
|
HANDLE handle; |
|
|
|
|
struct _WIN32_FIND_DATAA FindFileData; |
|
|
|
|
char dst[160]; |
|
|
|
|
|
|
|
|
|
if (gbMaxPlayers != 1) { |
|
|
|
|
mpqapi_reg_load_modification_time(dst, 160); |
|
|
|
|
handle = FindFirstFile(pszArchive, &FindFileData); |
|
|
|
|
if (handle != INVALID_HANDLE_VALUE) { |
|
|
|
|
FindClose(handle); |
|
|
|
|
*((FILETIME *)(dst) + dwChar * 2 + 1) = FindFileData.ftLastWriteTime; |
|
|
|
|
mpqapi_reg_store_modification_time(dst, 160); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
BOOL mpqapi_flush_and_close(const char *pszArchive, BOOL bFree, DWORD dwChar) |
|
|
|
|
{ |
|
|
|
|
BOOL ret = FALSE; |
|
|
|
|
@ -582,62 +641,3 @@ BOOL mpqapi_flush_and_close(const char *pszArchive, BOOL bFree, DWORD dwChar)
|
|
|
|
|
CloseMPQ(pszArchive, bFree, dwChar); |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
BOOL WriteMPQHeader() |
|
|
|
|
{ |
|
|
|
|
_FILEHEADER fhdr; |
|
|
|
|
DWORD NumberOfBytesWritten; |
|
|
|
|
|
|
|
|
|
memset(&fhdr, 0, sizeof(fhdr)); |
|
|
|
|
fhdr.signature = '\x1AQPM'; |
|
|
|
|
fhdr.headersize = 32; |
|
|
|
|
fhdr.filesize = GetFileSize(sghArchive, 0); |
|
|
|
|
fhdr.version = 0; |
|
|
|
|
fhdr.sectorsizeid = 3; |
|
|
|
|
fhdr.hashoffset = 32872; |
|
|
|
|
fhdr.blockoffset = 104; |
|
|
|
|
fhdr.hashcount = 2048; |
|
|
|
|
fhdr.blockcount = 2048; |
|
|
|
|
|
|
|
|
|
if (SetFilePointer(sghArchive, 0, NULL, FILE_BEGIN) == -1) |
|
|
|
|
return FALSE; |
|
|
|
|
if (!WriteFile(sghArchive, &fhdr, sizeof(fhdr), &NumberOfBytesWritten, 0)) |
|
|
|
|
return FALSE; |
|
|
|
|
|
|
|
|
|
return NumberOfBytesWritten == 104; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
BOOL mpqapi_write_block_table() |
|
|
|
|
{ |
|
|
|
|
BOOL success; |
|
|
|
|
DWORD NumberOfBytesWritten; |
|
|
|
|
|
|
|
|
|
if (SetFilePointer(sghArchive, 104, NULL, FILE_BEGIN) == -1) |
|
|
|
|
return FALSE; |
|
|
|
|
|
|
|
|
|
Encrypt((DWORD *)sgpBlockTbl, 0x8000, Hash("(block table)", 3)); |
|
|
|
|
success = WriteFile(sghArchive, sgpBlockTbl, 0x8000, &NumberOfBytesWritten, 0); |
|
|
|
|
Decrypt((DWORD *)sgpBlockTbl, 0x8000, Hash("(block table)", 3)); |
|
|
|
|
return success && NumberOfBytesWritten == 0x8000; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
BOOL mpqapi_write_hash_table() |
|
|
|
|
{ |
|
|
|
|
BOOL success; |
|
|
|
|
DWORD NumberOfBytesWritten; |
|
|
|
|
|
|
|
|
|
if (SetFilePointer(sghArchive, 32872, NULL, FILE_BEGIN) == -1) |
|
|
|
|
return FALSE; |
|
|
|
|
|
|
|
|
|
Encrypt((DWORD *)sgpHashTbl, 0x8000, Hash("(hash table)", 3)); |
|
|
|
|
success = WriteFile(sghArchive, sgpHashTbl, 0x8000, &NumberOfBytesWritten, 0); |
|
|
|
|
Decrypt((DWORD *)sgpHashTbl, 0x8000, Hash("(hash table)", 3)); |
|
|
|
|
return success && NumberOfBytesWritten == 0x8000; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
BOOL mpqapi_can_seek() |
|
|
|
|
{ |
|
|
|
|
if (SetFilePointer(sghArchive, sgdwMpqOffset, NULL, FILE_BEGIN) == -1) |
|
|
|
|
return FALSE; |
|
|
|
|
return SetEndOfFile(sghArchive); |
|
|
|
|
} |
|
|
|
|
|