Skip to content

Commit 321e662

Browse files
committed
feat(filesystem): Implement access to shadowed files inside archives
1 parent 9ba92fa commit 321e662

File tree

12 files changed

+350
-215
lines changed

12 files changed

+350
-215
lines changed

Core/GameEngine/Include/Common/ArchiveFileSystem.h

Lines changed: 33 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -84,26 +84,19 @@ class ArchivedDirectoryInfo;
8484
class DetailedArchivedDirectoryInfo;
8585
class ArchivedFileInfo;
8686

87-
typedef std::map<AsciiString, DetailedArchivedDirectoryInfo> DetailedArchivedDirectoryInfoMap;
88-
typedef std::map<AsciiString, ArchivedDirectoryInfo> ArchivedDirectoryInfoMap;
89-
typedef std::map<AsciiString, ArchivedFileInfo> ArchivedFileInfoMap;
90-
typedef std::map<AsciiString, ArchiveFile *> ArchiveFileMap;
91-
typedef std::map<AsciiString, AsciiString> ArchivedFileLocationMap; // first string is the file name, second one is the archive filename.
87+
typedef std::map<AsciiString, DetailedArchivedDirectoryInfo> DetailedArchivedDirectoryInfoMap; // Archived directory name to detailed archived directory info
88+
typedef std::map<AsciiString, ArchivedDirectoryInfo> ArchivedDirectoryInfoMap; // Archived directory name to archived directory info
89+
typedef std::map<AsciiString, ArchivedFileInfo> ArchivedFileInfoMap; // Archived file name to archived file info
90+
typedef std::map<AsciiString, ArchiveFile *> ArchiveFileMap; // Archive file name to archive data
91+
typedef std::multimap<AsciiString, ArchiveFile *> ArchivedFileLocationMap; // Archived file name to archive data
9292

9393
class ArchivedDirectoryInfo
9494
{
9595
public:
96-
AsciiString m_directoryName;
97-
ArchivedDirectoryInfoMap m_directories;
98-
ArchivedFileLocationMap m_files;
99-
100-
void clear()
101-
{
102-
m_directoryName.clear();
103-
m_directories.clear();
104-
m_files.clear();
105-
}
106-
96+
AsciiString m_path; // The full path to this directory
97+
AsciiString m_directoryName; // The current directory
98+
ArchivedDirectoryInfoMap m_directories; // Contained leaf directories
99+
ArchivedFileLocationMap m_files; // Contained files
107100
};
108101

109102
class DetailedArchivedDirectoryInfo
@@ -112,13 +105,6 @@ class DetailedArchivedDirectoryInfo
112105
AsciiString m_directoryName;
113106
DetailedArchivedDirectoryInfoMap m_directories;
114107
ArchivedFileInfoMap m_files;
115-
116-
void clear()
117-
{
118-
m_directoryName.clear();
119-
m_directories.clear();
120-
m_files.clear();
121-
}
122108
};
123109

124110
class ArchivedFileInfo
@@ -130,23 +116,16 @@ class ArchivedFileInfo
130116
UnsignedInt m_size;
131117

132118
ArchivedFileInfo()
119+
: m_offset(0)
120+
, m_size(0)
133121
{
134-
clear();
135-
}
136-
137-
void clear()
138-
{
139-
m_filename.clear();
140-
m_archiveFilename.clear();
141-
m_offset = 0;
142-
m_size = 0;
143122
}
144123
};
145124

146125

147126
class ArchiveFileSystem : public SubsystemInterface
148127
{
149-
public:
128+
public:
150129
ArchiveFileSystem();
151130
virtual ~ArchiveFileSystem();
152131

@@ -158,24 +137,38 @@ class ArchiveFileSystem : public SubsystemInterface
158137
// ArchiveFile operations
159138
virtual ArchiveFile* openArchiveFile( const Char *filename ) = 0; ///< Create new or return existing Archive file from file name
160139
virtual void closeArchiveFile( const Char *filename ) = 0; ///< Close the one specified big file.
161-
virtual void closeAllArchiveFiles( void ) = 0; ///< Close all Archivefiles currently open
140+
virtual void closeAllArchiveFiles( void ) = 0; ///< Close all Archive files currently open
162141

163142
// File operations
164-
virtual File* openFile( const Char *filename, Int access = 0); ///< Search Archive files for specified file name and open it if found
165-
virtual void closeAllFiles( void ) = 0; ///< Close all files associated with ArchiveFiles
166-
virtual Bool doesFileExist(const Char *filename) const; ///< return true if that file exists in an archive file somewhere.
143+
virtual File* openFile( const Char *filename, Int access = 0, UnsignedInt instance = 0); ///< Search Archive files for specified file name and open it if found
144+
virtual void closeAllFiles( void ) = 0; ///< Close all files associated with Archive files
145+
virtual Bool doesFileExist(const Char *filename, UnsignedInt instance = 0) const; ///< return true if that file exists in an archive file somewhere.
167146

168147
void getFileListInDirectory(const AsciiString& currentDirectory, const AsciiString& originalDirectory, const AsciiString& searchName, FilenameList &filenameList, Bool searchSubdirectories) const; ///< search the given directory for files matching the searchName (egs. *.ini, *.rep). Possibly search subdirectories. Scans each Archive file.
169-
Bool getFileInfo(const AsciiString& filename, FileInfo *fileInfo) const; ///< see FileSystem.h
148+
Bool getFileInfo(const AsciiString& filename, FileInfo *fileInfo, UnsignedInt instance = 0) const; ///< see FileSystem.h
170149

171150
virtual Bool loadBigFilesFromDirectory(AsciiString dir, AsciiString fileMask, Bool overwrite = FALSE) = 0;
172151

173152
// Unprotected this for copy-protection routines
174-
AsciiString getArchiveFilenameForFile(const AsciiString& filename) const;
153+
ArchiveFile* getArchiveFile(const AsciiString& filename, UnsignedInt instance = 0) const;
154+
175155
void loadMods( void );
176156

157+
ArchivedDirectoryInfo* friend_getArchivedDirectoryInfo(const Char* directory);
158+
177159
protected:
178-
virtual void loadIntoDirectoryTree(const ArchiveFile *archiveFile, const AsciiString& archiveFilename, Bool overwrite = FALSE ); ///< load the archive file's header information and apply it to the global archive directory tree.
160+
struct ArchivedDirectoryInfoResult
161+
{
162+
ArchivedDirectoryInfoResult() : dirInfo(NULL) {}
163+
Bool valid() const { return dirInfo != NULL; }
164+
165+
ArchivedDirectoryInfo* dirInfo;
166+
AsciiString lastToken; ///< Synonymous for file name if the search directory was a file path
167+
};
168+
169+
ArchivedDirectoryInfoResult getArchivedDirectoryInfo(const Char* directory);
170+
171+
virtual void loadIntoDirectoryTree(ArchiveFile *archiveFile, Bool overwrite = FALSE); ///< load the archive file's header information and apply it to the global archive directory tree.
179172

180173
ArchiveFileMap m_archiveFileMap;
181174
ArchivedDirectoryInfo m_rootDirectory;

Core/GameEngine/Include/Common/FileSystem.h

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,16 @@ typedef FilenameList::iterator FilenameListIter;
102102
#define TEST_TGA_DIR_PATH "../TestArt/" ///< .tga texture files live here
103103
#endif
104104

105+
#ifndef ENABLE_FILESYSTEM_LOGGING
106+
#define ENABLE_FILESYSTEM_LOGGING (0)
107+
#endif
108+
109+
105110
struct FileInfo {
111+
112+
Int64 size() const { return (Int64)sizeHigh << 32 | sizeLow; }
113+
Int64 timestamp() const { return (Int64)timestampHigh << 32 | timestampLow; }
114+
106115
Int sizeHigh;
107116
Int sizeLow;
108117
Int timestampHigh;
@@ -115,11 +124,13 @@ struct FileInfo {
115124
/**
116125
* FileSystem is an interface class for creating specific FileSystem objects.
117126
*
118-
* A FileSystem object's implemenation decides what derivative of File object needs to be
127+
* A FileSystem object's implementation decides what derivative of File object needs to be
119128
* created when FileSystem::Open() gets called.
120129
*/
130+
// TheSuperHackers @feature xezon 23/08/2025 Implements file instance access.
131+
// Can be used to access different versions of files in different archives under the same name.
132+
// Instance 0 refers to the top file that shadows all other files under the same name.
121133
//===============================
122-
123134
class FileSystem : public SubsystemInterface
124135
{
125136
FileSystem(const FileSystem&);
@@ -133,23 +144,30 @@ class FileSystem : public SubsystemInterface
133144
void reset();
134145
void update();
135146

136-
File* openFile( const Char *filename, Int access = File::NONE, size_t bufferSize = File::BUFFERSIZE ); ///< opens a File interface to the specified file
137-
Bool doesFileExist(const Char *filename) const; ///< returns TRUE if the file exists. filename should have no directory.
147+
File* openFile( const Char *filename, Int access = File::NONE, size_t bufferSize = File::BUFFERSIZE, UnsignedInt instance = 0 ); ///< opens a File interface to the specified file
148+
Bool doesFileExist(const Char *filename, UnsignedInt instance = 0) const; ///< returns TRUE if the file exists. filename should have no directory.
138149
void getFileListInDirectory(const AsciiString& directory, const AsciiString& searchName, FilenameList &filenameList, Bool searchSubdirectories) const; ///< search the given directory for files matching the searchName (egs. *.ini, *.rep). Possibly search subdirectories.
139-
Bool getFileInfo(const AsciiString& filename, FileInfo *fileInfo) const; ///< fills in the FileInfo struct for the file given. returns TRUE if successful.
150+
Bool getFileInfo(const AsciiString& filename, FileInfo *fileInfo, UnsignedInt instance = 0) const; ///< fills in the FileInfo struct for the file given. returns TRUE if successful.
140151

141152
Bool createDirectory(AsciiString directory); ///< create a directory of the given name.
142153

143154
Bool areMusicFilesOnCD();
144155
void loadMusicFilesFromCD();
145156
void unloadMusicFilesFromCD();
146-
AsciiString normalizePath(const AsciiString& path) const; ///< normalizes a file path. The path can refer to a directory. File path must be absolute, but does not need to exist. Returns an empty string on failure.
157+
158+
static AsciiString normalizePath(const AsciiString& path); ///< normalizes a file path. The path can refer to a directory. File path must be absolute, but does not need to exist. Returns an empty string on failure.
147159
static Bool isPathInDirectory(const AsciiString& testPath, const AsciiString& basePath); ///< determines if a file path is within a base path. Both paths must be absolute, but do not need to exist.
148160

149161
protected:
150162
#if ENABLE_FILESYSTEM_EXISTENCE_CACHE
163+
struct FileExistData
164+
{
165+
FileExistData() : instanceExists(0), instanceDoesNotExist(~0u) {}
166+
UnsignedInt instanceExists;
167+
UnsignedInt instanceDoesNotExist;
168+
};
151169
typedef std::hash_map<
152-
rts::string_key<AsciiString>, bool,
170+
rts::string_key<AsciiString>, FileExistData,
153171
rts::string_key_hash<AsciiString>,
154172
rts::string_key_equal<AsciiString> > FileExistMap;
155173
mutable FileExistMap m_fileExist;

Core/GameEngine/Source/Common/System/ArchiveFile.cpp

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -90,50 +90,46 @@ ArchiveFile::~ArchiveFile()
9090
}
9191

9292
ArchiveFile::ArchiveFile()
93+
: m_file(NULL)
9394
{
94-
m_rootDirectory.clear();
9595
}
9696

9797
void ArchiveFile::addFile(const AsciiString& path, const ArchivedFileInfo *fileInfo)
9898
{
99-
AsciiString temp;
100-
temp = path;
101-
temp.toLower();
102-
AsciiString token;
103-
AsciiString debugpath;
104-
10599
DetailedArchivedDirectoryInfo *dirInfo = &m_rootDirectory;
106100

107-
temp.nextToken(&token, "\\/");
101+
AsciiString token;
102+
AsciiString tokenizer = path;
103+
tokenizer.toLower();
104+
tokenizer.nextToken(&token, "\\/");
108105

109-
while (token.getLength() > 0) {
110-
if (dirInfo->m_directories.find(token) == dirInfo->m_directories.end())
106+
while (token.getLength() > 0)
107+
{
108+
DetailedArchivedDirectoryInfoMap::iterator tempiter = dirInfo->m_directories.find(token);
109+
if (tempiter == dirInfo->m_directories.end())
110+
{
111+
dirInfo = &(dirInfo->m_directories[token]);
112+
dirInfo->m_directoryName = token;
113+
}
114+
else
111115
{
112-
dirInfo->m_directories[token].clear();
113-
dirInfo->m_directories[token].m_directoryName = token;
116+
dirInfo = &tempiter->second;
114117
}
115118

116-
debugpath.concat(token);
117-
debugpath.concat('\\');
118-
dirInfo = &(dirInfo->m_directories[token]);
119-
temp.nextToken(&token, "\\/");
119+
tokenizer.nextToken(&token, "\\/");
120120
}
121121

122122
dirInfo->m_files[fileInfo->m_filename] = *fileInfo;
123-
//path.concat(fileInfo->m_filename);
124123
}
125124

126125
void ArchiveFile::getFileListInDirectory(const AsciiString& currentDirectory, const AsciiString& originalDirectory, const AsciiString& searchName, FilenameList &filenameList, Bool searchSubdirectories) const
127126
{
128-
129-
AsciiString searchDir;
130127
const DetailedArchivedDirectoryInfo *dirInfo = &m_rootDirectory;
131128

132-
searchDir = originalDirectory;
133-
searchDir.toLower();
134129
AsciiString token;
135-
136-
searchDir.nextToken(&token, "\\/");
130+
AsciiString tokenizer = originalDirectory;
131+
tokenizer.toLower();
132+
tokenizer.nextToken(&token, "\\/");
137133

138134
while (token.getLength() > 0) {
139135

@@ -148,7 +144,7 @@ void ArchiveFile::getFileListInDirectory(const AsciiString& currentDirectory, co
148144
return;
149145
}
150146

151-
searchDir.nextToken(&token, "\\/");
147+
tokenizer.nextToken(&token, "\\/");
152148
}
153149

154150
getFileListInDirectory(dirInfo, originalDirectory, searchName, filenameList, searchSubdirectories);
@@ -198,17 +194,15 @@ void ArchiveFile::attachFile(File *file)
198194

199195
const ArchivedFileInfo * ArchiveFile::getArchivedFileInfo(const AsciiString& filename) const
200196
{
201-
AsciiString path;
202-
path = filename;
203-
path.toLower();
204-
AsciiString token;
205-
206197
const DetailedArchivedDirectoryInfo *dirInfo = &m_rootDirectory;
207198

208-
path.nextToken(&token, "\\/");
209-
210-
while ((token.find('.') == NULL) || (path.find('.') != NULL)) {
199+
AsciiString token;
200+
AsciiString tokenizer = filename;
201+
tokenizer.toLower();
202+
tokenizer.nextToken(&token, "\\/");
211203

204+
while (!token.find('.') || tokenizer.find('.'))
205+
{
212206
DetailedArchivedDirectoryInfoMap::const_iterator it = dirInfo->m_directories.find(token);
213207
if (it != dirInfo->m_directories.end())
214208
{
@@ -219,7 +213,7 @@ const ArchivedFileInfo * ArchiveFile::getArchivedFileInfo(const AsciiString& fil
219213
return NULL;
220214
}
221215

222-
path.nextToken(&token, "\\/");
216+
tokenizer.nextToken(&token, "\\/");
223217
}
224218

225219
ArchivedFileInfoMap::const_iterator it = dirInfo->m_files.find(token);

0 commit comments

Comments
 (0)