mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-20 17:27:36 +01:00
@@ -69,115 +69,47 @@ PCASC_ENCODING_ENTRY FindEncodingEntry(TCascStorage * hs, PQUERY_KEY pEncodingKe
|
||||
}
|
||||
|
||||
// Also used in CascSearchFile
|
||||
PCASC_ROOT_ENTRY FindFirstRootEntry(TCascStorage * hs, const char * szFileName, size_t * PtrIndex)
|
||||
PCASC_ROOT_ENTRY FindRootEntry(TCascStorage * hs, const char * szFileName, DWORD * PtrTableIndex)
|
||||
{
|
||||
PCASC_ROOT_ENTRY pFoundEntry = NULL;
|
||||
PCASC_ROOT_ENTRY pRootEntry;
|
||||
ULONGLONG FileNameHash;
|
||||
DWORD TableIndex;
|
||||
uint32_t dwHashHigh = 0;
|
||||
uint32_t dwHashLow = 0;
|
||||
size_t StartEntry = 0;
|
||||
size_t MidlEntry = 0;
|
||||
size_t EndEntry = hs->nRootEntries;
|
||||
|
||||
// Calculate the HASH value of the normalized file name
|
||||
hashlittle2(szFileName, strlen(szFileName), &dwHashHigh, &dwHashLow);
|
||||
FileNameHash = ((ULONGLONG)dwHashHigh << 0x20) | dwHashLow;
|
||||
|
||||
// Perform binary search
|
||||
while(StartEntry < EndEntry)
|
||||
{
|
||||
// Calculate the middle of the interval
|
||||
MidlEntry = StartEntry + ((EndEntry - StartEntry) / 2);
|
||||
pRootEntry = hs->ppRootEntries[MidlEntry];
|
||||
// Get the first table index
|
||||
TableIndex = (DWORD)(FileNameHash & (hs->RootTable.TableSize - 1));
|
||||
assert(hs->RootTable.ItemCount < hs->RootTable.TableSize);
|
||||
|
||||
// Did we find it?
|
||||
// Search the proper entry
|
||||
for(;;)
|
||||
{
|
||||
// Does the has match?
|
||||
pRootEntry = hs->RootTable.TablePtr + TableIndex;
|
||||
if(pRootEntry->FileNameHash == FileNameHash)
|
||||
{
|
||||
pFoundEntry = pRootEntry;
|
||||
break;
|
||||
if(PtrTableIndex != NULL)
|
||||
PtrTableIndex[0] = TableIndex;
|
||||
return pRootEntry;
|
||||
}
|
||||
|
||||
// Move the interval to the left or right
|
||||
(FileNameHash < pRootEntry->FileNameHash) ? EndEntry = MidlEntry : StartEntry = MidlEntry + 1;
|
||||
// If the entry is free, the file is not there
|
||||
if(pRootEntry->FileNameHash == 0 && pRootEntry->SumValue == 0)
|
||||
return NULL;
|
||||
|
||||
// Move to the next entry
|
||||
TableIndex = (DWORD)((TableIndex + 1) & (hs->RootTable.TableSize - 1));
|
||||
}
|
||||
|
||||
// Move the pointer back to the first entry with that hash
|
||||
if(pFoundEntry != NULL)
|
||||
{
|
||||
while(MidlEntry > 0 && hs->ppRootEntries[MidlEntry - 1]->FileNameHash == FileNameHash)
|
||||
{
|
||||
pFoundEntry = hs->ppRootEntries[MidlEntry - 1];
|
||||
MidlEntry--;
|
||||
}
|
||||
}
|
||||
|
||||
// Return what we found
|
||||
if(PtrIndex != NULL)
|
||||
*PtrIndex = MidlEntry;
|
||||
return pFoundEntry;
|
||||
}
|
||||
|
||||
// Check the root directory for that hash
|
||||
PCASC_ROOT_ENTRY FindRootEntryLocale(TCascStorage * hs, char * szFileName, DWORD Locale)
|
||||
{
|
||||
PCASC_ROOT_ENTRY pThatEntry = NULL;
|
||||
PCASC_ROOT_ENTRY pENUSEntry = NULL;
|
||||
PCASC_ROOT_ENTRY pENGBEntry = NULL;
|
||||
PCASC_ROOT_ENTRY pAnyEntry = NULL;
|
||||
PCASC_ROOT_ENTRY pEndEntry = NULL;
|
||||
PCASC_ROOT_ENTRY pRootEntry = NULL;
|
||||
ULONGLONG FileNameHash;
|
||||
size_t EntryIndex = 0;
|
||||
size_t EndEntry = hs->nRootEntries;
|
||||
|
||||
// Find a root entry with the given name hash
|
||||
pRootEntry = FindFirstRootEntry(hs, szFileName, &EntryIndex);
|
||||
if(pRootEntry != NULL)
|
||||
{
|
||||
// Rememeber the file name hash
|
||||
pEndEntry = hs->pRootEntries + hs->nRootEntries;
|
||||
FileNameHash = pRootEntry->FileNameHash;
|
||||
|
||||
// Find all suitable root entries
|
||||
while(EntryIndex < EndEntry)
|
||||
{
|
||||
// Get the root entry
|
||||
pRootEntry = hs->ppRootEntries[EntryIndex++];
|
||||
if(pRootEntry->FileNameHash != FileNameHash)
|
||||
break;
|
||||
|
||||
// If a locale has been given, check it
|
||||
if(pThatEntry == NULL && Locale != 0 && (Locale & pRootEntry->Locales))
|
||||
pThatEntry = pRootEntry;
|
||||
if(pENUSEntry == NULL && (pRootEntry->Locales & CASC_LOCALE_ENUS))
|
||||
pENUSEntry = pRootEntry;
|
||||
if(pENGBEntry == NULL && (pRootEntry->Locales & CASC_LOCALE_ENGB))
|
||||
pENGBEntry = pRootEntry;
|
||||
if(pAnyEntry == NULL)
|
||||
pAnyEntry = pRootEntry;
|
||||
|
||||
// Move to the next one
|
||||
pRootEntry++;
|
||||
}
|
||||
|
||||
// Return the key by priority
|
||||
if(pThatEntry != NULL)
|
||||
return pThatEntry;
|
||||
if(pENGBEntry != NULL)
|
||||
return pENGBEntry;
|
||||
if(pENUSEntry != NULL)
|
||||
return pENUSEntry;
|
||||
}
|
||||
|
||||
// Return whatever we got
|
||||
return pAnyEntry;
|
||||
}
|
||||
|
||||
static TCascFile * CreateFileHandle(TCascStorage * hs, PCASC_INDEX_ENTRY pIndexEntry)
|
||||
{
|
||||
ULONGLONG FileOffsMask = ((ULONGLONG)1 << hs->KeyMapping[0].SegmentBits) - 1;
|
||||
ULONGLONG FileOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffset);
|
||||
ULONGLONG FileOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffsetBE);
|
||||
TCascFile * hf;
|
||||
|
||||
// Allocate the CASC file structure
|
||||
@@ -190,12 +122,13 @@ static TCascFile * CreateFileHandle(TCascStorage * hs, PCASC_INDEX_ENTRY pIndexE
|
||||
hf->HeaderOffset = (DWORD)(FileOffset & FileOffsMask);
|
||||
hf->szClassName = "TCascFile";
|
||||
|
||||
// Copy the compressed file size
|
||||
hf->CompressedSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSize) - 0x1E;
|
||||
// Copy the file size. Note that for all files except ENCODING,
|
||||
// this is the compressed file size
|
||||
hf->CompressedSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE);
|
||||
|
||||
// For now, we set the file size to be equal to compressed size
|
||||
// This is used when loading the "encoding" file, which does not
|
||||
// have entry in the encoding itself
|
||||
// This is used when loading the ENCODING file, which does not
|
||||
// have entry in the encoding table
|
||||
hf->FileSize = hf->CompressedSize;
|
||||
|
||||
// Increment the number of references to the archive
|
||||
@@ -206,10 +139,9 @@ static TCascFile * CreateFileHandle(TCascStorage * hs, PCASC_INDEX_ENTRY pIndexE
|
||||
return hf;
|
||||
}
|
||||
|
||||
static bool OpenFileByIndexKey(TCascStorage * hs, PQUERY_KEY pIndexKey, DWORD dwFlags, HANDLE * phFile)
|
||||
static bool OpenFileByIndexKey(TCascStorage * hs, PQUERY_KEY pIndexKey, DWORD dwFlags, TCascFile ** ppCascFile)
|
||||
{
|
||||
PCASC_INDEX_ENTRY pIndexEntry;
|
||||
TCascFile * hf = NULL;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
CASCLIB_UNUSED(dwFlags);
|
||||
@@ -222,43 +154,53 @@ static bool OpenFileByIndexKey(TCascStorage * hs, PQUERY_KEY pIndexKey, DWORD dw
|
||||
// Create the file handle structure
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
hf = CreateFileHandle(hs, pIndexEntry);
|
||||
*phFile = (HANDLE)hf;
|
||||
if(hf == NULL)
|
||||
ppCascFile[0] = CreateFileHandle(hs, pIndexEntry);
|
||||
if(ppCascFile[0] == NULL)
|
||||
nError = ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
#ifdef CASCLIB_TEST
|
||||
if(nError == ERROR_SUCCESS && ppCascFile[0] != NULL)
|
||||
{
|
||||
ppCascFile[0]->FileSize_IdxEntry = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(nError != ERROR_SUCCESS)
|
||||
SetLastError(nError);
|
||||
return (nError == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
static bool OpenFileByEncodingKey(TCascStorage * hs, PQUERY_KEY pEncodingKey, DWORD dwFlags, HANDLE * phFile)
|
||||
static bool OpenFileByEncodingKey(TCascStorage * hs, PQUERY_KEY pEncodingKey, DWORD dwFlags, TCascFile ** ppCascFile)
|
||||
{
|
||||
PCASC_ENCODING_ENTRY pEncodingEntry;
|
||||
QUERY_KEY IndexKey;
|
||||
TCascFile * hf = NULL;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
// Find the encoding entry
|
||||
pEncodingEntry = FindEncodingEntry(hs, pEncodingKey, NULL);
|
||||
if(pEncodingEntry == NULL)
|
||||
nError = ERROR_FILE_NOT_FOUND;
|
||||
{
|
||||
SetLastError(ERROR_FILE_NOT_FOUND);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prepare the file index and open the file by index
|
||||
// Note: We don't know what to do if there is more than just one index key
|
||||
// We always take the first file present. Is that correct?
|
||||
// IndexKey.pbData = pEncodingEntry->EncodingKey + (MD5_HASH_SIZE * pEncodingEntry->KeyCount);
|
||||
// assert(pEncodingEntry->KeyCount == 1);
|
||||
IndexKey.pbData = pEncodingEntry->EncodingKey + MD5_HASH_SIZE;
|
||||
IndexKey.cbData = MD5_HASH_SIZE;
|
||||
if(OpenFileByIndexKey(hs, &IndexKey, dwFlags, phFile))
|
||||
if(OpenFileByIndexKey(hs, &IndexKey, dwFlags, ppCascFile))
|
||||
{
|
||||
// Fix the file size from the encoding key
|
||||
hf = IsValidFileHandle(*phFile);
|
||||
if(hf != NULL)
|
||||
// Check if the file handle was created
|
||||
if(ppCascFile[0] != NULL)
|
||||
{
|
||||
hf->FileSize = ConvertBytesToInteger_4(pEncodingEntry->FileSizeBytes);
|
||||
// Fill-in the file size. For all files except ENCODING,
|
||||
// this overrides the value stored in the index entry.
|
||||
ppCascFile[0]->FileSize = ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE);
|
||||
|
||||
#ifdef CASCLIB_TEST
|
||||
ppCascFile[0]->FileSize_EncEntry = ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -289,7 +231,7 @@ bool WINAPI CascOpenFileByIndexKey(HANDLE hStorage, PQUERY_KEY pIndexKey, DWORD
|
||||
}
|
||||
|
||||
// Use the internal function to open the file
|
||||
return OpenFileByIndexKey(hs, pIndexKey, dwFlags, phFile);
|
||||
return OpenFileByIndexKey(hs, pIndexKey, dwFlags, (TCascFile **)phFile);
|
||||
}
|
||||
|
||||
bool WINAPI CascOpenFileByEncodingKey(HANDLE hStorage, PQUERY_KEY pEncodingKey, DWORD dwFlags, HANDLE * phFile)
|
||||
@@ -312,12 +254,12 @@ bool WINAPI CascOpenFileByEncodingKey(HANDLE hStorage, PQUERY_KEY pEncodingKey,
|
||||
}
|
||||
|
||||
// Use the internal function fo open the file
|
||||
return OpenFileByEncodingKey(hs, pEncodingKey, dwFlags, phFile);
|
||||
return OpenFileByEncodingKey(hs, pEncodingKey, dwFlags, (TCascFile **)phFile);
|
||||
}
|
||||
|
||||
bool WINAPI CascOpenFile(HANDLE hStorage, const char * szFileName, DWORD dwLocale, DWORD dwFlags, HANDLE * phFile)
|
||||
{
|
||||
CASC_ROOT_KEY_INFO EncodingKeyInfo;
|
||||
PCASC_ROOT_ENTRY_MNDX pRootEntryMndx = NULL;
|
||||
PCASC_ROOT_ENTRY pRootEntry;
|
||||
PCASC_PACKAGE pPackage;
|
||||
TCascStorage * hs;
|
||||
@@ -326,6 +268,8 @@ bool WINAPI CascOpenFile(HANDLE hStorage, const char * szFileName, DWORD dwLocal
|
||||
char * szFileName2;
|
||||
int nError = ERROR_SUCCESS;
|
||||
|
||||
CASCLIB_UNUSED(dwLocale);
|
||||
|
||||
// Validate the storage handle
|
||||
hs = IsValidStorageHandle(hStorage);
|
||||
if(hs == NULL)
|
||||
@@ -360,11 +304,11 @@ bool WINAPI CascOpenFile(HANDLE hStorage, const char * szFileName, DWORD dwLocal
|
||||
while(szStrippedName[0] == '/')
|
||||
szStrippedName++;
|
||||
|
||||
nError = SearchMndxInfo(hs->pMndxInfo, szStrippedName, (DWORD)(pPackage - hs->pPackages->Packages), &EncodingKeyInfo);
|
||||
nError = SearchMndxInfo(hs->pMndxInfo, szStrippedName, (DWORD)(pPackage - hs->pPackages->Packages), &pRootEntryMndx);
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
// Prepare the encoding key
|
||||
EncodingKey.pbData = EncodingKeyInfo.EncodingKey;
|
||||
EncodingKey.pbData = pRootEntryMndx->EncodingKey;
|
||||
EncodingKey.cbData = MD5_HASH_SIZE;
|
||||
}
|
||||
}
|
||||
@@ -376,23 +320,27 @@ bool WINAPI CascOpenFile(HANDLE hStorage, const char * szFileName, DWORD dwLocal
|
||||
else
|
||||
{
|
||||
// Convert the file name to lowercase + slashes
|
||||
NormalizeFileName_UpperBkSlash(szFileName2);
|
||||
NormalizeFileName_UpperBkSlash(szFileName2, szFileName2);
|
||||
|
||||
// Check the root directory for that hash
|
||||
pRootEntry = FindRootEntryLocale(hs, szFileName2, dwLocale);
|
||||
nError = (pRootEntry != NULL) ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND;
|
||||
pRootEntry = FindRootEntry(hs, szFileName2, NULL);
|
||||
if(pRootEntry != NULL)
|
||||
{
|
||||
// Prepare the root key
|
||||
EncodingKey.pbData = pRootEntry->EncodingKey;
|
||||
EncodingKey.pbData = (LPBYTE)pRootEntry->EncodingKey;
|
||||
EncodingKey.cbData = MD5_HASH_SIZE;
|
||||
nError = ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
nError = ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
// Use the root key to find the file in the encoding table entry
|
||||
if(nError == ERROR_SUCCESS)
|
||||
{
|
||||
if(!OpenFileByEncodingKey(hs, &EncodingKey, dwFlags, phFile))
|
||||
if(!OpenFileByEncodingKey(hs, &EncodingKey, dwFlags, (TCascFile **)phFile))
|
||||
{
|
||||
assert(GetLastError() != ERROR_SUCCESS);
|
||||
nError = GetLastError();
|
||||
@@ -400,11 +348,18 @@ bool WINAPI CascOpenFile(HANDLE hStorage, const char * szFileName, DWORD dwLocal
|
||||
}
|
||||
|
||||
// Delete the file name copy
|
||||
delete [] szFileName2;
|
||||
CASC_FREE(szFileName2);
|
||||
}
|
||||
else
|
||||
nError = ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
#ifdef CASCLIB_TEST
|
||||
if(phFile[0] != NULL && pRootEntryMndx != NULL)
|
||||
{
|
||||
((TCascFile *)(phFile[0]))->FileSize_RootEntry = pRootEntryMndx->FileSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(nError != ERROR_SUCCESS)
|
||||
SetLastError(nError);
|
||||
return (nError == ERROR_SUCCESS);
|
||||
|
||||
Reference in New Issue
Block a user