mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 15:40:45 +01:00
215 lines
7.4 KiB
C++
215 lines
7.4 KiB
C++
/*****************************************************************************/
|
|
/* CascRootFile_SC1.cpp Copyright (c) Ladislav Zezula 2017 */
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Support for loading Starcraft 1 ROOT file */
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Date Ver Who Comment */
|
|
/* -------- ---- --- ------- */
|
|
/* 28.10.15 1.00 Lad The first version of CascRootFile_SC1.cpp */
|
|
/*****************************************************************************/
|
|
|
|
#define __CASCLIB_SELF__
|
|
#include "CascLib.h"
|
|
#include "CascCommon.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Structure definitions for Overwatch root file
|
|
|
|
typedef struct _CASC_FILE_ENTRY
|
|
{
|
|
ENCODING_KEY EncodingKey; // Encoding key
|
|
ULONGLONG FileNameHash; // File name hash
|
|
DWORD dwFileName; // Offset of the file name in the name cache
|
|
} CASC_FILE_ENTRY, *PCASC_FILE_ENTRY;
|
|
|
|
struct TRootHandler_SC1 : public TRootHandler
|
|
{
|
|
// Linear global list of file entries
|
|
DYNAMIC_ARRAY FileTable;
|
|
|
|
// Linear global list of names
|
|
DYNAMIC_ARRAY FileNames;
|
|
|
|
// Global map of FileName -> FileEntry
|
|
PCASC_MAP pRootMap;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Local functions
|
|
|
|
static int InsertFileEntry(
|
|
TRootHandler_SC1 * pRootHandler,
|
|
const char * szFileName,
|
|
LPBYTE pbEncodingKey)
|
|
{
|
|
PCASC_FILE_ENTRY pFileEntry;
|
|
size_t nLength = strlen(szFileName);
|
|
|
|
// Attempt to insert the file name to the global buffer
|
|
szFileName = (char *)Array_Insert(&pRootHandler->FileNames, szFileName, nLength + 1);
|
|
if(szFileName == NULL)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
// Attempt to insert the entry to the array of file entries
|
|
pFileEntry = (PCASC_FILE_ENTRY)Array_Insert(&pRootHandler->FileTable, NULL, 1);
|
|
if(pFileEntry == NULL)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
// Fill the file entry
|
|
pFileEntry->EncodingKey = *(PENCODING_KEY)pbEncodingKey;
|
|
pFileEntry->FileNameHash = CalcFileNameHash(szFileName);
|
|
pFileEntry->dwFileName = (DWORD)Array_IndexOf(&pRootHandler->FileNames, szFileName);
|
|
|
|
// Insert the file entry to the map
|
|
assert(Map_FindObject(pRootHandler->pRootMap, &pFileEntry->FileNameHash, NULL) == NULL);
|
|
Map_InsertObject(pRootHandler->pRootMap, pFileEntry, &pFileEntry->FileNameHash);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Implementation of Overwatch root file
|
|
|
|
static int SC1Handler_Insert(
|
|
TRootHandler_SC1 * pRootHandler,
|
|
const char * szFileName,
|
|
LPBYTE pbEncodingKey)
|
|
{
|
|
return InsertFileEntry(pRootHandler, szFileName, pbEncodingKey);
|
|
}
|
|
|
|
static LPBYTE SC1Handler_Search(TRootHandler_SC1 * pRootHandler, TCascSearch * pSearch, PDWORD /* PtrFileSize */, PDWORD /* PtrLocaleFlags */, PDWORD /* PtrFileDataId */)
|
|
{
|
|
PCASC_FILE_ENTRY pFileEntry;
|
|
|
|
// Are we still inside the root directory range?
|
|
while(pSearch->IndexLevel1 < pRootHandler->FileTable.ItemCount)
|
|
{
|
|
// Retrieve the file item
|
|
pFileEntry = (PCASC_FILE_ENTRY)Array_ItemAt(&pRootHandler->FileTable, pSearch->IndexLevel1);
|
|
|
|
// Prepare the pointer to the next search
|
|
pSearch->IndexLevel1++;
|
|
|
|
char *filename = (char *)Array_ItemAt(&pRootHandler->FileNames, pFileEntry->dwFileName);
|
|
if (CheckWildCard(filename, pSearch->szMask)) {
|
|
strcpy(pSearch->szFileName, filename);
|
|
return pFileEntry->EncodingKey.Value;
|
|
}
|
|
}
|
|
|
|
// No more entries
|
|
return NULL;
|
|
}
|
|
|
|
static void SC1Handler_EndSearch(TRootHandler_SC1 * /* pRootHandler */, TCascSearch * /* pSearch */)
|
|
{
|
|
// Do nothing
|
|
}
|
|
|
|
static LPBYTE SC1Handler_GetKey(TRootHandler_SC1 * pRootHandler, const char * szFileName)
|
|
{
|
|
ULONGLONG FileNameHash = CalcFileNameHash(szFileName);
|
|
|
|
return (LPBYTE)Map_FindObject(pRootHandler->pRootMap, &FileNameHash, NULL);
|
|
}
|
|
|
|
static DWORD SC1Handler_GetFileId(TRootHandler_SC1 * /* pRootHandler */, const char * /* szFileName */)
|
|
{
|
|
// Not implemented for Overwatch
|
|
return 0;
|
|
}
|
|
|
|
static void SC1Handler_Close(TRootHandler_SC1 * pRootHandler)
|
|
{
|
|
if(pRootHandler != NULL)
|
|
{
|
|
// Free the file map
|
|
if(pRootHandler->pRootMap)
|
|
Map_Free(pRootHandler->pRootMap);
|
|
pRootHandler->pRootMap = NULL;
|
|
|
|
// Free the array of the file names and file items
|
|
Array_Free(&pRootHandler->FileTable);
|
|
Array_Free(&pRootHandler->FileNames);
|
|
|
|
// Free the root file itself
|
|
CASC_FREE(pRootHandler);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Public functions
|
|
|
|
int RootHandler_CreateSC1(TCascStorage * hs, LPBYTE pbRootFile, DWORD cbRootFile)
|
|
{
|
|
TRootHandler_SC1 * pRootHandler;
|
|
ENCODING_KEY KeyBuffer;
|
|
QUERY_KEY EncodingKey = {KeyBuffer.Value, MD5_HASH_SIZE};
|
|
void * pTextFile;
|
|
size_t nLength;
|
|
char szOneLine[0x200];
|
|
DWORD dwFileCountMax = (DWORD)hs->pEncodingMap->TableSize;
|
|
int nError = ERROR_SUCCESS;
|
|
|
|
// Allocate the root handler object
|
|
hs->pRootHandler = pRootHandler = CASC_ALLOC(TRootHandler_SC1, 1);
|
|
if(pRootHandler == NULL)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
// Fill-in the handler functions
|
|
memset(pRootHandler, 0, sizeof(TRootHandler_SC1));
|
|
pRootHandler->Insert = (ROOT_INSERT)SC1Handler_Insert;
|
|
pRootHandler->Search = (ROOT_SEARCH)SC1Handler_Search;
|
|
pRootHandler->EndSearch = (ROOT_ENDSEARCH)SC1Handler_EndSearch;
|
|
pRootHandler->GetKey = (ROOT_GETKEY)SC1Handler_GetKey;
|
|
pRootHandler->Close = (ROOT_CLOSE)SC1Handler_Close;
|
|
pRootHandler->GetFileId = (ROOT_GETFILEID)SC1Handler_GetFileId;
|
|
|
|
// Fill-in the flags
|
|
pRootHandler->dwRootFlags |= ROOT_FLAG_HAS_NAMES;
|
|
|
|
// Allocate the linear array of file entries
|
|
nError = Array_Create(&pRootHandler->FileTable, CASC_FILE_ENTRY, 0x10000);
|
|
if(nError != ERROR_SUCCESS)
|
|
return nError;
|
|
|
|
// Allocate the buffer for the file names
|
|
nError = Array_Create(&pRootHandler->FileNames, char, 0x10000);
|
|
if(nError != ERROR_SUCCESS)
|
|
return nError;
|
|
|
|
// Create map of ROOT_ENTRY -> FileEntry
|
|
pRootHandler->pRootMap = Map_Create(dwFileCountMax, sizeof(ULONGLONG), FIELD_OFFSET(CASC_FILE_ENTRY, FileNameHash));
|
|
if(pRootHandler->pRootMap == NULL)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
// Parse the ROOT file
|
|
pTextFile = ListFile_FromBuffer(pbRootFile, cbRootFile);
|
|
if(pTextFile != NULL)
|
|
{
|
|
// Parse the next lines
|
|
while((nLength = ListFile_GetNextLine(pTextFile, szOneLine, _maxchars(szOneLine))) > 0)
|
|
{
|
|
LPSTR szEncodingKey;
|
|
BYTE EncodingKey[MD5_HASH_SIZE];
|
|
|
|
szEncodingKey = strchr(szOneLine, _T('|'));
|
|
if(szEncodingKey != NULL)
|
|
{
|
|
// Split the name and encoding key
|
|
*szEncodingKey++ = 0;
|
|
|
|
// Insert the entry to the map
|
|
ConvertStringToBinary(szEncodingKey, MD5_STRING_SIZE, EncodingKey);
|
|
InsertFileEntry(pRootHandler, szOneLine, EncodingKey);
|
|
}
|
|
}
|
|
|
|
// Free the listfile
|
|
ListFile_Free(pTextFile);
|
|
}
|
|
|
|
// Succeeded
|
|
return nError;
|
|
}
|