Files
TrinityCore/dep/CascLib/src/CascDumpData.cpp

336 lines
11 KiB
C++

/*****************************************************************************/
/* CascDumpData.cpp Copyright (c) Ladislav Zezula 2014 */
/*---------------------------------------------------------------------------*/
/* System-dependent directory functions for CascLib */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 07.05.14 1.00 Lad The first version of CascDumpData.cpp */
/*****************************************************************************/
#define __CASCLIB_SELF__
#include "CascLib.h"
#include "CascCommon.h"
#include "CascMndx.h"
#ifdef _DEBUG // The entire feature is only valid for debug purposes
//-----------------------------------------------------------------------------
// Forward definitions
//LPBYTE VerifyLocaleBlock(PROOT_BLOCK_INFO pBlockInfo, LPBYTE pbFilePointer, LPBYTE pbFileEnd);
//-----------------------------------------------------------------------------
// Sort compare functions
static int CompareIndexEntries_FilePos(const void *, const void * pvIndexEntry1, const void * pvIndexEntry2)
{
PCASC_INDEX_ENTRY pIndexEntry1 = (PCASC_INDEX_ENTRY)pvIndexEntry1;
PCASC_INDEX_ENTRY pIndexEntry2 = (PCASC_INDEX_ENTRY)pvIndexEntry2;
ULONGLONG FileOffset1 = ConvertBytesToInteger_5(pIndexEntry1->FileOffsetBE);
ULONGLONG FileOffset2 = ConvertBytesToInteger_5(pIndexEntry2->FileOffsetBE);
DWORD ArchIndex1 = (DWORD)(FileOffset1 >> 0x1E);
DWORD ArchIndex2 = (DWORD)(FileOffset2 >> 0x1E);
// First, compare the archive index
if(ArchIndex1 < ArchIndex2)
return -1;
if(ArchIndex1 > ArchIndex2)
return +1;
// Second, compare the archive offset
FileOffset1 &= 0x3FFFFFFF;
FileOffset2 &= 0x3FFFFFFF;
if(FileOffset1 < FileOffset2)
return -1;
if(FileOffset1 > FileOffset2)
return +1;
return 0;
}
//-----------------------------------------------------------------------------
// Public functions
void CascDumpSparseArray(const char * szFileName, void * pvSparseArray)
{
TSparseArray * pSparseArray = (TSparseArray *)pvSparseArray;
FILE * fp;
// Create the dump file
fp = fopen(szFileName, "wt");
if(fp != NULL)
{
// Write header
fprintf(fp, "## Value\n-- -----\n");
// Write the values
for(DWORD i = 0; i < pSparseArray->TotalItemCount; i++)
{
DWORD Value = 0;
if(pSparseArray->IsItemPresent(i))
{
Value = pSparseArray->GetItemValue(i);
fprintf(fp, "%02X %02X\n", i, Value);
}
else
{
fprintf(fp, "%02X --\n", i);
}
}
fclose(fp);
}
}
void CascDumpNameFragTable(const char * szFileName, void * pMarFile)
{
TFileNameDatabase * pDB = ((PMAR_FILE)pMarFile)->pDatabasePtr->pDB;
FILE * fp;
// Create the dump file
fp = fopen(szFileName, "wt");
if(fp != NULL)
{
PNAME_FRAG pNameTable = pDB->NameFragTable.NameFragArray;
const char * szNames = pDB->IndexStruct_174.NameFragments.CharArray;
const char * szLastEntry;
char szMatchType[0x100];
// Dump the table header
fprintf(fp, "Indx ThisHash NextHash FragOffs\n");
fprintf(fp, "---- -------- -------- --------\n");
// Dump all name entries
for(DWORD i = 0; i < pDB->NameFragTable.ItemCount; i++)
{
// Reset both match types
szMatchType[0] = 0;
szLastEntry = "";
// Only if the table entry is not empty
if(pNameTable->ItemIndex != 0xFFFFFFFF)
{
// Prepare the entry
if(IS_SINGLE_CHAR_MATCH(pDB->NameFragTable, i))
sprintf(szMatchType, "SINGLE_CHAR (\'%c\')", (pNameTable->FragOffs & 0xFF));
else
sprintf(szMatchType, "NAME_FRAGMT (\"%s\")", szNames + pNameTable->FragOffs);
}
// Dump the entry
fprintf(fp, "0x%02X %08x %08x %08x %s%s\n", i, pNameTable->ItemIndex,
pNameTable->NextIndex,
pNameTable->FragOffs,
szMatchType,
szLastEntry);
pNameTable++;
}
fclose(fp);
}
}
void CascDumpFileNames(const char * szFileName, void * pvMarFile)
{
TMndxFindResult Struct1C;
PMAR_FILE pMarFile = (PMAR_FILE)pvMarFile;
FILE * fp;
char szNameBuff[0x200];
bool bFindResult;
// Create the dump file
fp = fopen(szFileName, "wt");
if(fp != NULL)
{
// Set an empty path as search mask (?)
Struct1C.SetSearchPath("", 0);
// Keep searching
for(;;)
{
// Search the next file name
pMarFile->pDatabasePtr->sub_1956CE0(&Struct1C, &bFindResult);
// Stop the search in case of failure
if(!bFindResult)
break;
// Printf the found file name
memcpy(szNameBuff, Struct1C.szFoundPath, Struct1C.cchFoundPath);
szNameBuff[Struct1C.cchFoundPath] = 0;
fprintf(fp, "%s\n", szNameBuff);
}
fclose(fp);
}
// Free the search structures
Struct1C.FreeStruct40();
}
void CascDumpIndexEntry(
TCascStorage * /* hs */,
TDumpContext * dc,
PCASC_INDEX_ENTRY pIndexEntry,
int /* nDumpLevel */)
{
if(pIndexEntry != NULL)
{
ULONGLONG FileOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffsetBE);
DWORD ArchIndex = (DWORD)(FileOffset >> 0x1E);
DWORD FileSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE);
// Mask the file offset
FileOffset &= 0x3FFFFFFF;
dump_print(dc, " data.%03u at 0x%08x (0x%lx bytes)\n",
ArchIndex,
(DWORD)FileOffset,
FileSize);
//if(nDumpLevel > 2)
//{
// QueryKey.pbData = pIndexEntry->IndexKey;
// QueryKey.cbData = MD5_HASH_SIZE;
// if(CascOpenFileByIndexKey((HANDLE)hs, &QueryKey, 0, &hFile))
// {
// // Make sure that the data file is open and frame header loaded
// CascGetFileSize(hFile, NULL);
// hf = IsValidFileHandle(hFile);
// assert(hf->pStream != NULL);
// // Read the header area
// FileOffset = hf->HeaderOffset - BLTE_HEADER_DELTA;
// FileStream_Read(hf->pStream, &FileOffset, HeaderArea, sizeof(HeaderArea));
// CascCloseFile(hFile);
// // Dump the header area
// dump_print(dc, " FileSize: %X Rest: %s\n",
// ConvertBytesToInteger_4_LE(&HeaderArea[0x10]),
// StringFromBinary(&HeaderArea[0x14], 10, szBuffer));
// }
//}
}
else
{
dump_print(dc, " NO INDEX ENTRY\n");
}
}
void CascDumpEncodingEntry(
TCascStorage * hs,
TDumpContext * dc,
PCASC_ENCODING_ENTRY pEncodingEntry,
int nDumpLevel)
{
PCASC_INDEX_ENTRY pIndexEntry;
QUERY_KEY QueryKey;
LPBYTE pbIndexKey;
char szMd5[MD5_STRING_SIZE+1];
// If the encoding key exists
if(pEncodingEntry != NULL)
{
dump_print(dc, " Size %lx Key Count: %u\n",
ConvertBytesToInteger_4(pEncodingEntry->FileSizeBE),
pEncodingEntry->KeyCount);
// Dump all index keys
pbIndexKey = pEncodingEntry->EncodingKey + MD5_HASH_SIZE;
for(DWORD j = 0; j < pEncodingEntry->KeyCount; j++, pbIndexKey += MD5_HASH_SIZE)
{
// Dump the index key
dump_print(dc, " %s\n", StringFromMD5(pbIndexKey, szMd5));
// Dump the index entry as well
if(nDumpLevel >= DUMP_LEVEL_INDEX_ENTRIES)
{
QueryKey.pbData = pbIndexKey;
QueryKey.cbData = MD5_HASH_SIZE;
pIndexEntry = FindIndexEntry(hs, &QueryKey);
CascDumpIndexEntry(hs, dc, pIndexEntry, nDumpLevel);
}
}
}
else
{
dump_print(dc, " NO ENCODING KEYS\n");
}
}
void CascDumpIndexEntries(const char * szFileName, TCascStorage * hs)
{
PCASC_INDEX_ENTRY * ppIndexEntries;
FILE * fp;
size_t nIndexEntries = hs->pIndexEntryMap->ItemCount;
char szIndexKey[0x40];
// Create the dump file
fp = fopen(szFileName, "wt");
if(fp != NULL)
{
// Create linear aray
ppIndexEntries = CASC_ALLOC(PCASC_INDEX_ENTRY, nIndexEntries);
if(ppIndexEntries != NULL)
{
// Obtain the linear array of index entries
Map_EnumObjects(hs->pIndexEntryMap, (void **)ppIndexEntries);
// Sort the array by archive number and archive offset
qsort_pointer_array((void **)ppIndexEntries, nIndexEntries, CompareIndexEntries_FilePos, NULL);
// Parse the array
fprintf(fp, "ArNo ArOffset FileSize IndexKey\n==== ======== ======== ================================\n");
for(size_t i = 0; i < nIndexEntries; i++)
{
PCASC_INDEX_ENTRY pIndexEntry = ppIndexEntries[i];
ULONGLONG ArchOffset = ConvertBytesToInteger_5(pIndexEntry->FileOffsetBE);
DWORD ArchIndex = (DWORD)(ArchOffset >> 0x1E);
DWORD FileSize;
FileSize = ConvertBytesToInteger_4_LE(pIndexEntry->FileSizeLE);
ArchOffset &= 0x3FFFFFFF;
fprintf(fp, " %02X %08X %08X %s\n", ArchIndex, (DWORD)ArchOffset, FileSize, StringFromBinary(pIndexEntry->IndexKey, CASC_FILE_KEY_SIZE, szIndexKey));
}
CASC_FREE(ppIndexEntries);
}
fclose(fp);
}
}
void CascDumpFile(const char * szFileName, HANDLE hFile)
{
FILE * fp;
DWORD dwBytesRead = 1;
DWORD dwFilePos = CascSetFilePointer(hFile, 0, NULL, FILE_BEGIN);
BYTE Buffer[0x1000];
// Create the dump file
fp = fopen(szFileName, "wb");
if(fp != NULL)
{
// Read data as long as we can, write as long as we can
while(dwBytesRead != 0)
{
// Read from the source file
if(!CascReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead))
break;
// Write to the destination file
if(fwrite(Buffer, 1, dwBytesRead, fp) != dwBytesRead)
break;
}
// Close the local file
fclose(fp);
// Restore the file pointer
CascSetFilePointer(hFile, dwFilePos, NULL, FILE_BEGIN);
}
}
#endif // _DEBUG