diff --git a/include/iarchive.h b/include/iarchive.h index 59a4180c6c..ec9b16baff 100644 --- a/include/iarchive.h +++ b/include/iarchive.h @@ -57,3 +57,49 @@ class ArchiveTextFile : }; typedef std::shared_ptr ArchiveTextFilePtr; +/** + * Representation of an archive in the virtual filesystem. + * This might be a PK4/ZIP file or a regular mod directory. + * + * \ingroup vfs + */ +class IArchive +{ +public: + typedef std::shared_ptr Ptr; + + virtual ~IArchive() {} + + class Visitor + { + public: + virtual ~Visitor() {} + + // Invoked for each file in an Archive + virtual void visitFile(const std::string& name) = 0; + + // Invoked for each directory in an Archive. Return true to skip the directory. + virtual bool visitDirectory(const std::string& name, std::size_t depth) = 0; + }; + + /// \brief Returns a new object associated with the file identified by \p name, or 0 if the file cannot be opened. + /// Name comparisons are case-insensitive. + virtual ArchiveFilePtr openFile(const std::string& name) = 0; + + /// \brief Returns a new object associated with the file identified by \p name, or 0 if the file cannot be opened. + /// Name comparisons are case-insensitive. + virtual ArchiveTextFilePtr openTextFile(const std::string& name) = 0; + + /// Returns true if the file identified by \p name can be opened. + /// Name comparisons are case-insensitive. + virtual bool containsFile(const std::string& name) = 0; + + /// \brief Performs a depth-first traversal of the archive tree starting at \p root. + /// Traverses the entire tree if \p root is "". + /// When a file is encountered, calls \c visitor.file passing the file name. + /// When a directory is encountered, calls \c visitor.directory passing the directory name. + /// Skips the directory if \c visitor.directory returned true. + /// Root comparisons are case-insensitive. + /// Names are mixed-case. + virtual void traverse(Visitor& visitor, const std::string& root) = 0; +}; diff --git a/include/ifilesystem.h b/include/ifilesystem.h index 1a33a9a587..56644566e1 100644 --- a/include/ifilesystem.h +++ b/include/ifilesystem.h @@ -14,11 +14,7 @@ #include #include "imodule.h" - -class ArchiveFile; -typedef std::shared_ptr ArchiveFilePtr; -class ArchiveTextFile; -typedef std::shared_ptr ArchiveTextFilePtr; +#include "iarchive.h" namespace vfs { @@ -171,6 +167,11 @@ class VirtualFileSystem : /// This is a variant of openTextFile taking an absolute path as argument. virtual ArchiveTextFilePtr openTextFileInAbsolutePath(const std::string& filename) = 0; + // Opens an independent archive located in the given physical path. + // (This archive can be located somewhere outside the current VFS hierarchy.) + // Loading this archive won't have any effect on the VFS setup, it is opened stand-alone. + virtual IArchive::Ptr openArchiveInAbsolutePath(const std::string& pathToArchive) = 0; + /// \brief Calls the visitor function for each file under \p basedir matching \p extension. /// Use "*" as \p extension to match all file extensions. virtual void forEachFile(const std::string& basedir, diff --git a/radiantcore/vfs/Archive.h b/radiantcore/vfs/Archive.h deleted file mode 100644 index ab5dd19e32..0000000000 --- a/radiantcore/vfs/Archive.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include "iarchive.h" - -/** - * Representation of an archive in the virtual filesystem. - * This might be a PK4/ZIP file or a regular mod directory. - * - * \ingroup vfs - */ -class Archive -{ -public: - class Visitor - { - public: - virtual ~Visitor() {} - - // Invoked for each file in an Archive - virtual void visitFile(const std::string& name) = 0; - - // Invoked for each directory in an Archive. Return true to skip the directory. - virtual bool visitDirectory(const std::string& name, std::size_t depth) = 0; - }; - - /// \brief destructor - virtual ~Archive() {} - - /// \brief Returns a new object associated with the file identified by \p name, or 0 if the file cannot be opened. - /// Name comparisons are case-insensitive. - virtual ArchiveFilePtr openFile(const std::string& name) = 0; - - /// \brief Returns a new object associated with the file identified by \p name, or 0 if the file cannot be opened. - /// Name comparisons are case-insensitive. - virtual ArchiveTextFilePtr openTextFile(const std::string& name) = 0; - - /// Returns true if the file identified by \p name can be opened. - /// Name comparisons are case-insensitive. - virtual bool containsFile(const std::string& name) = 0; - - /// \brief Performs a depth-first traversal of the archive tree starting at \p root. - /// Traverses the entire tree if \p root is "". - /// When a file is encountered, calls \c visitor.file passing the file name. - /// When a directory is encountered, calls \c visitor.directory passing the directory name. - /// Skips the directory if \c visitor.directory returned true. - /// Root comparisons are case-insensitive. - /// Names are mixed-case. - virtual void traverse(Visitor& visitor, const std::string& root) = 0; -}; -typedef std::shared_ptr ArchivePtr; - diff --git a/radiantcore/vfs/DirectoryArchive.h b/radiantcore/vfs/DirectoryArchive.h index 8b892e1c57..a6f55516e2 100644 --- a/radiantcore/vfs/DirectoryArchive.h +++ b/radiantcore/vfs/DirectoryArchive.h @@ -1,6 +1,6 @@ #pragma once -#include "Archive.h" +#include "iarchive.h" /** * greebo: This wraps around a certain path in the "real" @@ -10,7 +10,7 @@ * added to the list of PK4 archives, using this class. */ class DirectoryArchive : - public Archive + public IArchive { std::string _root; diff --git a/radiantcore/vfs/Doom3FileSystem.cpp b/radiantcore/vfs/Doom3FileSystem.cpp index c7c96f30ee..5657010f8e 100644 --- a/radiantcore/vfs/Doom3FileSystem.cpp +++ b/radiantcore/vfs/Doom3FileSystem.cpp @@ -30,6 +30,7 @@ #include "string/encoding.h" #include "os/path.h" #include "os/dir.h" +#include "os/file.h" #include "string/split.h" #include "debugging/ScopedDebugTimer.h" @@ -120,13 +121,14 @@ class AssetsList }; /* - * Archive::Visitor class used in GlobalFileSystem().foreachFile(). + * IArchive::Visitor class used in GlobalFileSystem().foreachFile(). * It's filtering out the files matching the defined extension only. * The directory part is cut off the filename. * On top of that, this class maintains a list of visited files to avoid * hitting the same file twice (it might be present in more than one Archive). */ -class FileVisitor: public Archive::Visitor +class FileVisitor : + public IArchive::Visitor { // Maximum traversal depth std::size_t _maxDepth; @@ -446,6 +448,17 @@ ArchiveTextFilePtr Doom3FileSystem::openTextFileInAbsolutePath(const std::string return ArchiveTextFilePtr(); } +IArchive::Ptr Doom3FileSystem::openArchiveInAbsolutePath(const std::string& pathToArchive) +{ + if (!os::fileIsReadable(pathToArchive)) + { + rWarning() << "Requested file is not readable: " << pathToArchive << std::endl; + return IArchive::Ptr(); + } + + return std::make_shared(pathToArchive); +} + void Doom3FileSystem::forEachFile(const std::string& basedir, const std::string& extension, const VisitorFunc& visitorFunc, diff --git a/radiantcore/vfs/Doom3FileSystem.h b/radiantcore/vfs/Doom3FileSystem.h index 436b04a417..f3531119d2 100644 --- a/radiantcore/vfs/Doom3FileSystem.h +++ b/radiantcore/vfs/Doom3FileSystem.h @@ -1,6 +1,6 @@ #pragma once -#include "Archive.h" +#include "iarchive.h" #include "ifilesystem.h" namespace vfs @@ -20,7 +20,7 @@ class Doom3FileSystem : struct ArchiveDescriptor { std::string name; - ArchivePtr archive; + IArchive::Ptr archive; bool is_pakfile; }; @@ -42,6 +42,7 @@ class Doom3FileSystem : ArchiveFilePtr openFileInAbsolutePath(const std::string& filename) override; ArchiveTextFilePtr openTextFileInAbsolutePath(const std::string& filename) override; + IArchive::Ptr openArchiveInAbsolutePath(const std::string& pathToArchive) override; // Call the specified callback function for each file matching extension // inside basedir. diff --git a/radiantcore/vfs/GenericFileSystem.h b/radiantcore/vfs/GenericFileSystem.h index 447674679e..391f8b060e 100644 --- a/radiantcore/vfs/GenericFileSystem.h +++ b/radiantcore/vfs/GenericFileSystem.h @@ -1,6 +1,6 @@ #pragma once -#include "Archive.h" +#include "iarchive.h" #include "string/string.h" #include "os/path.h" @@ -164,7 +164,7 @@ class GenericFileSystem /// Traverses the entire tree if \p root is "". /// Calls \p visitor.file() with the path to each file relative to the filesystem root. /// Calls \p visitor.directory() with the path to each directory relative to the filesystem root. - void traverse(Archive::Visitor& visitor, const std::string& root) + void traverse(IArchive::Visitor& visitor, const std::string& root) { unsigned int start_depth = getPathDepth(root.c_str()); unsigned int skip_depth = 0; diff --git a/radiantcore/vfs/ZipArchive.h b/radiantcore/vfs/ZipArchive.h index ae57a99010..c9cb6fbd10 100644 --- a/radiantcore/vfs/ZipArchive.h +++ b/radiantcore/vfs/ZipArchive.h @@ -18,7 +18,7 @@ namespace archive * Archives are owned and instantiated by the GlobalFileSystem instance. */ class ZipArchive : - public Archive + public IArchive { private: class ZipRecord diff --git a/tools/msvc/DarkRadiantCore.vcxproj b/tools/msvc/DarkRadiantCore.vcxproj index c398d68e18..1e9539663b 100644 --- a/tools/msvc/DarkRadiantCore.vcxproj +++ b/tools/msvc/DarkRadiantCore.vcxproj @@ -1016,7 +1016,6 @@ - diff --git a/tools/msvc/DarkRadiantCore.vcxproj.filters b/tools/msvc/DarkRadiantCore.vcxproj.filters index b8ed5d5739..da7f34b145 100644 --- a/tools/msvc/DarkRadiantCore.vcxproj.filters +++ b/tools/msvc/DarkRadiantCore.vcxproj.filters @@ -1047,9 +1047,6 @@ src\xmlregistry - - src\vfs - src\vfs