aboutsummaryrefslogtreecommitdiff
path: root/dep/CascLib/src/common/FileTree.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dep/CascLib/src/common/FileTree.cpp')
-rw-r--r--dep/CascLib/src/common/FileTree.cpp174
1 files changed, 85 insertions, 89 deletions
diff --git a/dep/CascLib/src/common/FileTree.cpp b/dep/CascLib/src/common/FileTree.cpp
index fa21863c5e9..453034c057d 100644
--- a/dep/CascLib/src/common/FileTree.cpp
+++ b/dep/CascLib/src/common/FileTree.cpp
@@ -13,7 +13,22 @@
#include "../CascCommon.h"
//-----------------------------------------------------------------------------
-// Local defines
+// Local arrays
+
+static BYTE PathSeparators[256] =
+{
+/* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+/* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* 0x50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
+
+ // Filled by zeros up to 256 bytes
+};
+
+//-----------------------------------------------------------------------------
+// Local functions
#define START_ITEM_COUNT 0x4000
@@ -31,6 +46,28 @@ inline void SET_NODE_INT32(void * node, size_t offset, DWORD value)
PtrValue[0] = value;
}
+#ifdef CASCLIB_DEV
+//static DWORD dwFileCount = 0;
+//
+//static void WatchFileNode(PCASC_FILE_NODE pFileNode, const char * szFileName, bool bNewNodeInserted)
+//{
+// const char * szSuffix = bNewNodeInserted ? "NEW" : "EXISTING";
+// const char * szFormat = "FileNode %p: CKey: %s, NameHash: %I64x (\"%s\") - %s\n";
+// char szBuffer[MD5_STRING_SIZE + 1];
+//
+// // Selected nodes only
+// if(dwFileCount < 10 && !_strnicmp(szFileName, "base", 4))
+// {
+// printf(szFormat, pFileNode,
+// StringFromBinary(pFileNode->pCKeyEntry->CKey, MD5_HASH_SIZE, szBuffer),
+// pFileNode->FileNameHash,
+// szFileName,
+// szSuffix);
+// dwFileCount++;
+// }
+//}
+#endif
+
//-----------------------------------------------------------------------------
// Protected functions
@@ -91,7 +128,7 @@ PCASC_FILE_NODE CASC_FILE_TREE::InsertNew()
}
// Insert the node to the map of FileNameHash -> CASC_FILE_NODE
-bool CASC_FILE_TREE::InsertToHashTable(PCASC_FILE_NODE pFileNode)
+bool CASC_FILE_TREE::InsertToNameMap(PCASC_FILE_NODE pFileNode)
{
bool bResult = false;
@@ -189,7 +226,7 @@ bool CASC_FILE_TREE::RebuildNameMaps()
{
// Insert it to the map "FileNameHash -> CASC_FILE_NODE"
if(pFileNode->FileNameHash != 0)
- InsertToHashTable(pFileNode);
+ InsertToNameMap(pFileNode);
// Insert it to the array "FileDataId -> CASC_FILE_NODE"
if(FileDataIds.IsInitialized())
@@ -288,13 +325,12 @@ PCASC_FILE_NODE CASC_FILE_TREE::InsertByName(PCASC_CKEY_ENTRY pCKeyEntry, const
{
PCASC_FILE_NODE pFileNode;
ULONGLONG FileNameHash;
+ //bool bNewNodeInserted = false;
// Sanity checks
assert(szFileName != NULL && szFileName[0] != 0);
assert(pCKeyEntry != NULL);
- //BREAK_ON_XKEY3(pCKeyEntry->EKey, 0x00, 0x00, 0x0F);
-
// Calculate the file name hash
FileNameHash = CalcFileNameHash(szFileName);
@@ -313,7 +349,7 @@ PCASC_FILE_NODE CASC_FILE_TREE::InsertByName(PCASC_CKEY_ENTRY pCKeyEntry, const
SetExtras(pFileNode, FileDataId, LocaleFlags, ContentFlags);
// Insert the file node to the hash map
- InsertToHashTable(pFileNode);
+ InsertToNameMap(pFileNode);
// Also make sure that it's in the file data id table, if the table is initialized
InsertToIdTable(pFileNode);
@@ -323,11 +359,16 @@ PCASC_FILE_NODE CASC_FILE_TREE::InsertByName(PCASC_CKEY_ENTRY pCKeyEntry, const
// If we created a new node, we need to increment the reference count
assert(pCKeyEntry->RefCount != 0xFFFF);
+ //bNewNodeInserted = true;
pCKeyEntry->RefCount++;
FileNodes++;
}
}
+#ifdef CASCLIB_DEV
+ //WatchFileNode(pFileNode, szFileName, bNewNodeInserted);
+#endif
+
return pFileNode;
}
@@ -349,7 +390,7 @@ PCASC_FILE_NODE CASC_FILE_TREE::InsertByHash(PCASC_CKEY_ENTRY pCKeyEntry, ULONGL
pFileNode->FileNameHash = FileNameHash;
// Insert the file node to the hash map
- InsertToHashTable(pFileNode);
+ InsertToNameMap(pFileNode);
}
return pFileNode;
@@ -543,13 +584,21 @@ bool CASC_FILE_TREE::SetNodeFileName(PCASC_FILE_NODE pFileNode, const char * szF
{
char chOneChar = szFileName[i];
- // Is there a path separator?
- // Note: Warcraft III paths may contain "mount points".
- // Example: "frFR-War3Local.mpq:Maps/FrozenThrone/Campaign/NightElfX06Interlude.w3x:war3map.j"
- if(chOneChar == '\\' || chOneChar == '/' || chOneChar == ':')
+ // Is there a path separator, such as '\\' or '/'?
+ // Also support TVFS "mount points", like "DivideAndConquer.w3m:war3map.doo"
+ if(PathSeparators[chOneChar])
{
+ size_t nHashLength = i;
+
+ // If there is a reparse point mark (':'), we need to include it as part of the name
+ if(PathSeparators[chOneChar] == 0x02)
+ {
+ PathBuffer.AppendChar(chOneChar);
+ nHashLength++;
+ }
+
// Calculate hash of the file name up to the end of the node name
- FileNameHash = CalcNormNameHash(PathBuffer, i);
+ FileNameHash = CalcNormNameHash(PathBuffer, nHashLength);
// If the entry is not there yet, create new one
if((pFolderNode = Find(FileNameHash)) == NULL)
@@ -559,95 +608,36 @@ bool CASC_FILE_TREE::SetNodeFileName(PCASC_FILE_NODE pFileNode, const char * szF
if(pFolderNode == NULL)
return false;
- // Populate the file entry
+ // Fill-in flags, name hash and parent
+ pFolderNode->Flags |= (chOneChar == ':') ? (CFN_FLAG_FOLDER | CFN_FLAG_MOUNT_POINT) : CFN_FLAG_FOLDER;
pFolderNode->FileNameHash = FileNameHash;
pFolderNode->Parent = Parent;
- pFolderNode->Flags |= (chOneChar == ':') ? (CFN_FLAG_FOLDER | CFN_FLAG_MOUNT_POINT) : CFN_FLAG_FOLDER;
FolderNodes++;
// Set the node sub name to the node
SetNodePlainName(pFolderNode, szNodeBegin, szFileName + i);
// Insert the entry to the name map
- InsertToHashTable(pFolderNode);
+ InsertToNameMap(pFolderNode);
}
- // Move the parent to the current node
- Parent = (DWORD)NodeTable.IndexOf(pFolderNode);
-
- // Move the begin of the node after the separator
- szNodeBegin = szFileName + i + 1;
- }
-
- // Copy the next character, even if it was slash/backslash before
- PathBuffer.AppendChar(AsciiToUpperTable_BkSlash[chOneChar]);
- }
-
- // If anything left, this is gonna be our node name
- if(szNodeBegin < szFileName + i)
- {
- // We need to reset the file node pointer, as the file node table might have changed
- pFileNode = (PCASC_FILE_NODE)NodeTable.ItemAt(nFileNode);
-
- // Write the plain file name to the node
- SetNodePlainName(pFileNode, szNodeBegin, szFileName + i);
- pFileNode->Parent = Parent;
-
- // Also insert the node to the hash table so CascOpenFile can find it
- if(pFileNode->FileNameHash == 0)
- {
- pFileNode->FileNameHash = CalcNormNameHash(PathBuffer, i);
- InsertToHashTable(pFileNode);
- }
- }
- return true;
-}
-/*
-bool CASC_FILE_TREE::SetNodeFileName(PCASC_FILE_NODE pFileNode, const char * szFileName)
-{
- ULONGLONG FileNameHash = 0;
- PCASC_FILE_NODE pFolderNode = NULL;
- LPCSTR szNodeBegin = szFileName;
- char szPathBuffer[MAX_PATH+1];
- size_t nFileNode = NodeTable.IndexOf(pFileNode);
- size_t i;
- DWORD Parent = 0;
-
- // Sanity checks
- assert(szFileName != NULL && szFileName[0] != 0);
-
- // Traverse the entire path. For each subfolder, we insert an appropriate fake entry
- for(i = 0; szFileName[i] != 0; i++)
- {
- char chOneChar = szFileName[i];
-
- // Is there a path separator?
- // Note: Warcraft III paths may contain "mount points".
- // Example: "frFR-War3Local.mpq:Maps/FrozenThrone/Campaign/NightElfX06Interlude.w3x:war3map.j"
- if(chOneChar == '\\' || chOneChar == '/' || chOneChar == ':')
- {
- // Calculate hash of the file name up to the end of the node name
- FileNameHash = CalcNormNameHash(szPathBuffer, i);
-
- // If the entry is not there yet, create new one
- if((pFolderNode = Find(FileNameHash)) == NULL)
+ // In case we're in the middle a mount point construction (called by CASC_FILE_TREE::InsertByName()),
+ // then we can get into situation where the call to Find() found the newly constructed item.
+ // In that case, we just set the name and bail out
+ else if(pFolderNode == pFileNode)
{
- // Insert new entry to the tree
- pFolderNode = InsertNew();
- if(pFolderNode == NULL)
- return false;
+ // The item must be a mount point, with name hash already set.
+ assert(pFolderNode->FileNameHash == FileNameHash);
+ assert(szFileName[i + 1] == 0);
- // Populate the file entry
- pFolderNode->FileNameHash = FileNameHash;
+ // Fill-in the flags and parent
+ pFolderNode->Flags |= (CFN_FLAG_FOLDER | CFN_FLAG_MOUNT_POINT);
pFolderNode->Parent = Parent;
- pFolderNode->Flags |= (chOneChar == ':') ? (CFN_FLAG_FOLDER | CFN_FLAG_MOUNT_POINT) : CFN_FLAG_FOLDER;
FolderNodes++;
// Set the node sub name to the node
SetNodePlainName(pFolderNode, szNodeBegin, szFileName + i);
-
- // Insert the entry to the name map
- InsertToHashTable(pFolderNode);
+ return true;
}
// Move the parent to the current node
@@ -655,10 +645,16 @@ bool CASC_FILE_TREE::SetNodeFileName(PCASC_FILE_NODE pFileNode, const char * szF
// Move the begin of the node after the separator
szNodeBegin = szFileName + i + 1;
+
+ // If the separator character was already appended, skip the rest of the loop
+ if(PathSeparators[chOneChar] == 0x02)
+ {
+ continue;
+ }
}
- // Copy the next character, even if it was slash/backslash before
- szPathBuffer[i] = AsciiToUpperTable_BkSlash[chOneChar];
+ // Append the character, if not appended yet
+ PathBuffer.AppendChar(AsciiToUpperTable_BkSlash[chOneChar]);
}
// If anything left, this is gonna be our node name
@@ -674,13 +670,13 @@ bool CASC_FILE_TREE::SetNodeFileName(PCASC_FILE_NODE pFileNode, const char * szF
// Also insert the node to the hash table so CascOpenFile can find it
if(pFileNode->FileNameHash == 0)
{
- pFileNode->FileNameHash = CalcNormNameHash(szPathBuffer, i);
- InsertToHashTable(pFileNode);
+ pFileNode->FileNameHash = CalcNormNameHash(PathBuffer, i);
+ InsertToNameMap(pFileNode);
}
}
return true;
}
-*/
+
size_t CASC_FILE_TREE::GetMaxFileIndex()
{
if(FileDataIds.IsInitialized())