aboutsummaryrefslogtreecommitdiff
path: root/dep/CascLib/src/CascRootFile_SC1.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dep/CascLib/src/CascRootFile_SC1.cpp')
-rw-r--r--dep/CascLib/src/CascRootFile_SC1.cpp216
1 files changed, 216 insertions, 0 deletions
diff --git a/dep/CascLib/src/CascRootFile_SC1.cpp b/dep/CascLib/src/CascRootFile_SC1.cpp
new file mode 100644
index 00000000000..76c7756ea23
--- /dev/null
+++ b/dep/CascLib/src/CascRootFile_SC1.cpp
@@ -0,0 +1,216 @@
+/*****************************************************************************/
+/* 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];
+ char szFileName[MAX_PATH+1];
+ DWORD dwFileCountMax = (DWORD)hs->pEncodingMap->TableSize;
+ int nFileNameIndex;
+ 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;
+}