Tools/Extractors: Updated map extractor

This commit is contained in:
Shauren
2014-10-10 20:17:30 +02:00
parent bc97908822
commit 88ae3da637
339 changed files with 18349 additions and 75612 deletions

View File

@@ -0,0 +1,364 @@
/*****************************************************************************/
/* CascFindFile.cpp Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* System-dependent directory functions for CascLib */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 10.05.14 1.00 Lad The first version of CascFindFile.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"
#include "CascMndxRoot.h"
//-----------------------------------------------------------------------------
// Local functions
static TCascSearch * IsValidSearchHandle(HANDLE hFind)
{
TCascSearch * pSearch = (TCascSearch *)hFind;
return (pSearch != NULL && pSearch->szClassName != NULL && !strcmp(pSearch->szClassName, "TCascSearch") && pSearch->szMask != NULL) ? pSearch : NULL;
}
static void FreeSearchHandle(TCascSearch * pSearch)
{
// Only if the storage handle is valid
assert(pSearch != NULL);
// Close (dereference) the archive handle
if(pSearch->hs != NULL)
CascCloseStorage((HANDLE)pSearch->hs);
pSearch->hs = NULL;
// Free the file cache and frame array
if(pSearch->szMask != NULL)
CASC_FREE(pSearch->szMask);
if(pSearch->szListFile != NULL)
CASC_FREE(pSearch->szListFile);
if(pSearch->pStruct1C != NULL)
delete pSearch->pStruct1C;
if(pSearch->pCache != NULL)
ListFile_Free(pSearch->pCache);
// Free the structure itself
pSearch->szClassName = NULL;
CASC_FREE(pSearch);
}
/*
DWORD dwRootEntries = 0;
DWORD dwEncoEntries = 0;
DWORD dwIndexEntries = 0;
*/
static bool VerifyRootEntry(TCascSearch * pSearch, PCASC_ROOT_ENTRY pRootEntry, PCASC_FIND_DATA pFindData, size_t nRootIndex)
{
PCASC_ENCODING_ENTRY pEncodingEntry;
PCASC_INDEX_ENTRY pIndexEntry;
TCascStorage * hs = pSearch->hs;
QUERY_KEY QueryKey;
DWORD dwByteIndex = (DWORD)(nRootIndex / 0x08);
DWORD dwBitIndex = (DWORD)(nRootIndex & 0x07);
// First of all, check if that entry has been reported before
// If the bit is set, then the file has already been reported
// by a previous search iteration
if(pSearch->BitArray[dwByteIndex] & (1 << dwBitIndex))
return false;
pSearch->BitArray[dwByteIndex] |= (1 << dwBitIndex);
// Increment the number of root entries
// dwRootEntries++;
// Now try to find that encoding key in the array of encoding keys
QueryKey.pbData = pRootEntry->EncodingKey;
QueryKey.cbData = MD5_HASH_SIZE;
pEncodingEntry = FindEncodingEntry(hs, &QueryKey, NULL);
if(pEncodingEntry == NULL)
return false;
// dwEncoEntries++;
// Now try to find the index entry. Note that we take the first key
QueryKey.pbData = pEncodingEntry->EncodingKey + MD5_HASH_SIZE;
QueryKey.cbData = MD5_HASH_SIZE;
pIndexEntry = FindIndexEntry(hs, &QueryKey);
if(pIndexEntry == NULL)
return false;
// dwIndexEntries++;
// Fill the name hash and the MD5
memcpy(pFindData->EncodingKey, pRootEntry->EncodingKey, MD5_HASH_SIZE);
pFindData->FileNameHash = pRootEntry->FileNameHash;
pFindData->dwPackageIndex = 0;
pFindData->dwLocaleFlags = pRootEntry->Locales;
pFindData->dwFileSize = ConvertBytesToInteger_4(pEncodingEntry->FileSizeBytes);
return true;
}
static TCascSearch * AllocateSearchHandle(TCascStorage * hs, const TCHAR * szListFile, const char * szMask)
{
TCascSearch * pSearch;
size_t cbToAllocate;
// When using the MNDX info, do not allocate the extra bit array
cbToAllocate = sizeof(TCascSearch) + ((hs->pMndxInfo == NULL) ? (hs->nRootEntries / 8) : 0);
pSearch = (TCascSearch *)CASC_ALLOC(BYTE, cbToAllocate);
if(pSearch != NULL)
{
// Initialize the structure
memset(pSearch, 0, cbToAllocate);
pSearch->szClassName = "TCascSearch";
// Save the search handle
pSearch->hs = hs;
hs->dwRefCount++;
// If the mask was not given, use default
if(szMask == NULL)
szMask = "*";
// Save the other variables
if(szListFile != NULL)
{
pSearch->szListFile = NewStr(szListFile, 0);
if(pSearch->szListFile == NULL)
{
FreeSearchHandle(pSearch);
return NULL;
}
}
// Allocate the search mask
pSearch->szMask = NewStr(szMask, 0);
if(pSearch->szMask == NULL)
{
FreeSearchHandle(pSearch);
return NULL;
}
}
return pSearch;
}
static bool DoStorageSearch_ListFile(TCascSearch * pSearch, PCASC_FIND_DATA pFindData)
{
PCASC_ROOT_ENTRY pRootEntry;
TCascStorage * hs = pSearch->hs;
size_t RootIndex;
for(;;)
{
// Shall we get a new file name from the listfile?
if(pSearch->FileNameHash == 0)
{
// Try to get next file from the listfile
if(!ListFile_GetNext(pSearch->pCache, pSearch->szMask, pSearch->szFileName, MAX_PATH))
break;
// if(!_stricmp(pSearch->szFileName, "Interface\\Glues\\MODELS\\UI_MainMenu_Warlords\\Caustic_MedFreq.blp"))
// DebugBreak();
// Normalize the file name
strcpy(pSearch->szNormName, pSearch->szFileName);
NormalizeFileName_UpperBkSlash(pSearch->szNormName);
// Find the first root entry belonging to this file name
pRootEntry = FindFirstRootEntry(pSearch->hs, pSearch->szNormName, &RootIndex);
if(pRootEntry == NULL)
continue;
// We have the name now, search all locales
pSearch->FileNameHash = pRootEntry->FileNameHash;
pSearch->RootIndex = RootIndex;
}
// Is the root index in range?
while(pSearch->RootIndex < hs->nRootEntries)
{
// Get the next root entry. If name mismatches, stop searching
pRootEntry = hs->ppRootEntries[pSearch->RootIndex];
if(pRootEntry->FileNameHash != pSearch->FileNameHash)
break;
// Verify whether the file exists in the storage
if(VerifyRootEntry(pSearch, pRootEntry, pFindData, pSearch->RootIndex++))
{
strcpy(pFindData->szFileName, pSearch->szFileName);
pFindData->szPlainName = (char *)GetPlainFileName(pFindData->szFileName);
return true;
}
}
// Reset the name hash and root index and retry search
pSearch->FileNameHash = 0;
}
// Listfile search ended
return false;
}
static bool DoStorageSearch_Hash(TCascSearch * pSearch, PCASC_FIND_DATA pFindData)
{
PCASC_ROOT_ENTRY pRootEntry;
TCascStorage * hs = pSearch->hs;
// Check if there is more files with the same name hash
while(pSearch->RootIndex < hs->nRootEntries)
{
// Get the pointer to the root entry
pRootEntry = hs->ppRootEntries[pSearch->RootIndex];
// Verify if that root entry exists in the CASC storage
// Note that the file name will be there from the previous search
if(VerifyRootEntry(pSearch, pRootEntry, pFindData, pSearch->RootIndex))
{
pFindData->szFileName[0] = 0;
pFindData->szPlainName = NULL;
return true;
}
// Move to the next entry
pSearch->RootIndex++;
}
// Nameless search ended
return false;
}
static bool DoStorageSearch(TCascSearch * pSearch, PCASC_FIND_DATA pFindData)
{
// Are we searching using the MNDX ?
if(pSearch->hs->pMndxInfo != NULL)
return DoStorageSearch_MNDX(pSearch, pFindData);
// State 0: No search done yet
if(pSearch->dwState == 0)
{
// Does the search specify listfile?
if(pSearch->szListFile != NULL)
pSearch->pCache = ListFile_OpenExternal(pSearch->szListFile);
// Move the search phase to the listfile searching
pSearch->FileNameHash = 0;
pSearch->RootIndex = 0;
pSearch->dwState++;
// If either file stream or listfile cache are invalid,
// move to the next phase
if(pSearch->pCache == NULL)
pSearch->dwState++;
}
// State 1: Searching the list file
if(pSearch->dwState == 1)
{
if(DoStorageSearch_ListFile(pSearch, pFindData))
return true;
// Move to the nameless search state
pSearch->RootIndex = 0;
pSearch->dwState++;
}
// State 2: Searching the remaining entries
if(pSearch->dwState == 2)
{
if(DoStorageSearch_Hash(pSearch, pFindData))
return true;
// Move to the final search state
pSearch->dwState++;
}
return false;
}
//-----------------------------------------------------------------------------
// Public functions
HANDLE WINAPI CascFindFirstFile(
HANDLE hStorage,
const char * szMask,
PCASC_FIND_DATA pFindData,
const TCHAR * szListFile)
{
TCascStorage * hs;
TCascSearch * pSearch = NULL;
int nError = ERROR_SUCCESS;
// Check parameters
if((hs = IsValidStorageHandle(hStorage)) == NULL)
nError = ERROR_INVALID_HANDLE;
if(szMask == NULL || pFindData == NULL)
nError = ERROR_INVALID_PARAMETER;
// Allocate the structure for archive search
if(nError == ERROR_SUCCESS)
{
// Clear the entire search structure
memset(pFindData, 0, sizeof(CASC_FIND_DATA));
// We must have listfile for non-MNDX storages
if(hs->pMndxInfo == NULL && szListFile == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
// Allocate the search handle
pSearch = AllocateSearchHandle(hs, szListFile, szMask);
if(pSearch == NULL)
nError = ERROR_NOT_ENOUGH_MEMORY;
}
// Perform search
if(nError == ERROR_SUCCESS)
{
if(!DoStorageSearch(pSearch, pFindData))
nError = ERROR_NO_MORE_FILES;
}
if(nError != ERROR_SUCCESS)
{
if(pSearch != NULL)
FreeSearchHandle(pSearch);
pSearch = NULL;
}
return (HANDLE)pSearch;
}
bool WINAPI CascFindNextFile(
HANDLE hFind,
PCASC_FIND_DATA pFindData)
{
TCascSearch * pSearch;
pSearch = IsValidSearchHandle(hFind);
if(pSearch == NULL || pFindData == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
// Perform search
return DoStorageSearch(pSearch, pFindData);
}
bool WINAPI CascFindClose(HANDLE hFind)
{
TCascSearch * pSearch;
pSearch = IsValidSearchHandle(hFind);
if(pSearch == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
FreeSearchHandle(pSearch);
return true;
}