📄 sfileopenarchive.cpp.svn-base
字号:
/*****************************************************************************/
/* SFileOpenArchive.cpp Copyright Ladislav Zezula 1999 */
/* */
/* Author : Ladislav Zezula */
/* E-mail : ladik@zezula.net */
/* WWW : www.zezula.net */
/*---------------------------------------------------------------------------*/
/* Archive functions of Storm.dll */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* xx.xx.xx 1.00 Lad The first version of SFileOpenArchive.cpp */
/* 19.11.03 1.01 Dan Big endian handling */
/*****************************************************************************/
#define __STORMLIB_SELF__
#include "StormLib.h"
#include "SCommon.h"
/*****************************************************************************/
/* Local functions */
/*****************************************************************************/
static BOOL IsAviFile(TMPQHeader * pHeader)
{
DWORD * AviHdr = (DWORD *)pHeader;
// Test for 'RIFF', 'AVI ' or 'LIST'
return (AviHdr[0] == 'FFIR' && AviHdr[2] == ' IVA' && AviHdr[3] == 'TSIL');
}
// This function gets the right positions of the hash table and the block table.
// TODO: Test for archives > 4GB
static int RelocateMpqTablePositions(TMPQArchive * ha)
{
TMPQHeader2 * pHeader = ha->pHeader;
LARGE_INTEGER FileSize;
LARGE_INTEGER TempSize;
// Get the size of the file
FileSize.LowPart = GetFileSize(ha->hFile, (LPDWORD)&FileSize.HighPart);
// Set the proper hash table position
ha->HashTablePos.HighPart = pHeader->wHashTablePosHigh;
ha->HashTablePos.LowPart = pHeader->dwHashTablePos;
ha->HashTablePos.QuadPart += ha->MpqPos.QuadPart;
if(ha->HashTablePos.QuadPart > FileSize.QuadPart)
return ERROR_BAD_FORMAT;
// Set the proper block table position
ha->BlockTablePos.HighPart = pHeader->wBlockTablePosHigh;
ha->BlockTablePos.LowPart = pHeader->dwBlockTablePos;
ha->BlockTablePos.QuadPart += ha->MpqPos.QuadPart;
if(ha->BlockTablePos.QuadPart > FileSize.QuadPart)
return ERROR_BAD_FORMAT;
// Set the proper position of the extended block table
if(pHeader->ExtBlockTablePos.QuadPart != 0)
{
ha->ExtBlockTablePos = pHeader->ExtBlockTablePos;
ha->ExtBlockTablePos.QuadPart += ha->MpqPos.QuadPart;
if(ha->ExtBlockTablePos.QuadPart > FileSize.QuadPart)
return ERROR_BAD_FORMAT;
}
// Size of MPQ archive is computed as the biggest of
// (EndOfBlockTable, EndOfHashTable, EndOfExtBlockTable)
TempSize.QuadPart = ha->HashTablePos.QuadPart + (pHeader->dwHashTableSize * sizeof(TMPQHash));
if(TempSize.QuadPart > ha->MpqSize.QuadPart)
ha->MpqSize = TempSize;
TempSize.QuadPart = ha->BlockTablePos.QuadPart + (pHeader->dwBlockTableSize * sizeof(TMPQBlock));
if(TempSize.QuadPart > ha->MpqSize.QuadPart)
ha->MpqSize = TempSize;
TempSize.QuadPart = ha->ExtBlockTablePos.QuadPart + (pHeader->dwBlockTableSize * sizeof(TMPQBlockEx));
if(TempSize.QuadPart > ha->MpqSize.QuadPart)
ha->MpqSize = TempSize;
// MPQ size does not include the bytes before MPQ header
ha->MpqSize.QuadPart -= ha->MpqPos.QuadPart;
return ERROR_SUCCESS;
}
/*****************************************************************************/
/* Public functions */
/*****************************************************************************/
//-----------------------------------------------------------------------------
// SFileGetLocale and SFileSetLocale
// Set the locale for all neewly opened archives and files
LCID WINAPI SFileGetLocale()
{
return lcLocale;
}
LCID WINAPI SFileSetLocale(LCID lcNewLocale)
{
lcLocale = lcNewLocale;
return lcLocale;
}
//-----------------------------------------------------------------------------
// SFileOpenArchiveEx (not a public function !!!)
//
// szFileName - MPQ archive file name to open
// dwPriority - When SFileOpenFileEx called, this contains the search priority for searched archives
// dwFlags - If contains MPQ_OPEN_NO_LISTFILE, then the internal list file will not be used.
// phMPQ - Pointer to store open archive handle
BOOL SFileOpenArchiveEx(
const char * szMpqName,
DWORD dwPriority,
DWORD dwFlags,
HANDLE * phMPQ,
DWORD dwAccessMode)
{
LARGE_INTEGER TempPos;
TMPQArchive * ha = NULL; // Archive handle
HANDLE hFile = INVALID_HANDLE_VALUE;// Opened archive file handle
DWORD dwMaxBlockIndex = 0; // Maximum value of block entry
DWORD dwBlockTableSize = 0; // Block table size.
DWORD dwTransferred; // Number of bytes read
DWORD dwBytes = 0; // Number of bytes to read
int nError = ERROR_SUCCESS;
// Check the right parameters
if(nError == ERROR_SUCCESS)
{
if(szMpqName == NULL || *szMpqName == 0 || phMPQ == NULL)
nError = ERROR_INVALID_PARAMETER;
}
// Ensure that StormBuffer is allocated
if(nError == ERROR_SUCCESS)
nError = PrepareStormBuffer();
// Open the MPQ archive file
if(nError == ERROR_SUCCESS)
{
hFile = CreateFile(szMpqName, dwAccessMode, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if(hFile == INVALID_HANDLE_VALUE)
nError = GetLastError();
}
// Allocate the MPQhandle
if(nError == ERROR_SUCCESS)
{
if((ha = ALLOCMEM(TMPQArchive, 1)) == NULL)
nError = ERROR_NOT_ENOUGH_MEMORY;
}
// Initialize handle structure and allocate structure for MPQ header
if(nError == ERROR_SUCCESS)
{
memset(ha, 0, sizeof(TMPQArchive));
strncpy(ha->szFileName, szMpqName, strlen(szMpqName));
ha->hFile = hFile;
ha->dwPriority = dwPriority;
ha->pHeader = &ha->Header;
ha->pListFile = NULL;
hFile = INVALID_HANDLE_VALUE;
}
// Find the offset of MPQ header within the file
if(nError == ERROR_SUCCESS)
{
LARGE_INTEGER SearchPos = {0};
LARGE_INTEGER MpqPos = {0};
DWORD dwHeaderID;
for(;;)
{
// Invalidate the MPQ ID and read the eventual header
SetFilePointer(ha->hFile, MpqPos.LowPart, &MpqPos.HighPart, FILE_BEGIN);
ReadFile(ha->hFile, ha->pHeader, sizeof(TMPQHeader2), &dwTransferred, NULL);
dwHeaderID = BSWAP_INT32_UNSIGNED(ha->pHeader->dwID);
// Special check : Some MPQs are actually AVI files, only with
// changed extension.
if(MpqPos.QuadPart == 0 && IsAviFile(ha->pHeader))
{
nError = ERROR_AVI_FILE;
break;
}
// If different number of bytes read, break the loop
if(dwTransferred != sizeof(TMPQHeader2))
{
nError = ERROR_BAD_FORMAT;
break;
}
// If there is the MPQ shunt signature, process it
if(dwHeaderID == ID_MPQ_SHUNT && ha->pShunt == NULL)
{
// Fill the shunt header
ha->ShuntPos = MpqPos;
ha->pShunt = &ha->Shunt;
memcpy(ha->pShunt, ha->pHeader, sizeof(TMPQShunt));
BSWAP_TMPQSHUNT(ha->pShunt);
// Set the MPQ pos and repeat the search
MpqPos.QuadPart = SearchPos.QuadPart + ha->pShunt->dwHeaderPos;
continue;
}
// There must be MPQ header signature
if(dwHeaderID == ID_MPQ)
{
BSWAP_TMPQHEADER(ha->pHeader);
// Save the position where the MPQ header has been found
ha->MpqPos = MpqPos;
// If valid signature has been found, break the loop
if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1)
{
// W3M Map Protectors set some garbage value into the "dwHeaderSize"
// field of MPQ header. This value is apparently ignored by Storm.dll
if(ha->pHeader->dwHeaderSize != sizeof(TMPQHeader) &&
ha->pHeader->dwHeaderSize != sizeof(TMPQHeader2))
{
ha->dwFlags |= MPQ_FLAG_PROTECTED;
ha->pHeader->dwHeaderSize = sizeof(TMPQHeader);
}
if(ha->pHeader->dwHashTablePos < ha->pHeader->dwArchiveSize &&
ha->pHeader->dwBlockTablePos < ha->pHeader->dwArchiveSize)
{
break;
}
}
if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_2)
{
break;
}
nError = ERROR_NOT_SUPPORTED;
break;
}
// If a MPQ shunt already has been found,
// and no MPQ header was at potision pointed by the shunt,
// then the archive is corrupt
if(ha->pShunt != NULL)
{
nError = ERROR_BAD_FORMAT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -