diff options
Diffstat (limited to 'dep/CascLib/src/common/FileTree.cpp')
-rw-r--r-- | dep/CascLib/src/common/FileTree.cpp | 174 |
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()) |