diff --git a/include/iarchive.h b/include/iarchive.h index 235a457765..3384f60e0f 100644 --- a/include/iarchive.h +++ b/include/iarchive.h @@ -91,7 +91,7 @@ class IArchive virtual ~Visitor() {} // Invoked for each file in an Archive - virtual void visitFile(const std::string& name) = 0; + virtual void visitFile(const std::string& name, IArchiveFileInfoProvider& infoProvider) = 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; diff --git a/libs/os/file.h b/libs/os/file.h index 76292815f6..5480577cb2 100644 --- a/libs/os/file.h +++ b/libs/os/file.h @@ -99,7 +99,7 @@ inline bool fileOrDirExists(const fs::path& path) } } -// Returns the file size in bytes, or static_cast(-1) +// Returns the file size in bytes, or static_cast(-1) inline std::size_t getFileSize(const std::string& path) { try diff --git a/libs/wxutil/fsview/Populator.cpp b/libs/wxutil/fsview/Populator.cpp index bcdefa0a2e..012e51d871 100644 --- a/libs/wxutil/fsview/Populator.cpp +++ b/libs/wxutil/fsview/Populator.cpp @@ -77,8 +77,7 @@ void Populator::visitFile(const vfs::FileInfo& fileInfo) if (!isFolder) { // Get the file size if possible - auto file = GlobalFileSystem().openFile(_basePath + path); - row[_columns.size] = os::getFormattedFileSize(file ? file->size() : -1); + row[_columns.size] = os::getFormattedFileSize(fileInfo.getSize()); } }); } diff --git a/radiantcore/vfs/DirectoryArchive.cpp b/radiantcore/vfs/DirectoryArchive.cpp index 0515034afb..191262a445 100644 --- a/radiantcore/vfs/DirectoryArchive.cpp +++ b/radiantcore/vfs/DirectoryArchive.cpp @@ -87,7 +87,7 @@ void DirectoryArchive::traverse(Visitor& visitor, const std::string& root) else { // File - visitor.visitFile(candidateStr.substr(rootLen)); + visitor.visitFile(candidateStr.substr(rootLen), *this); } } catch (const std::system_error& ex) @@ -98,3 +98,15 @@ void DirectoryArchive::traverse(Visitor& visitor, const std::string& root) } } } + +std::size_t DirectoryArchive::getFileSize(const std::string& relativePath) +{ + UnixPath path(_root); + return os::getFileSize(std::string(path) + relativePath); +} + +bool DirectoryArchive::getIsPhysical(const std::string& relativePath) +{ + // this whole class represents a physical directory, we don't even check + return true; +} diff --git a/radiantcore/vfs/DirectoryArchive.h b/radiantcore/vfs/DirectoryArchive.h index a6f55516e2..f8f8397769 100644 --- a/radiantcore/vfs/DirectoryArchive.h +++ b/radiantcore/vfs/DirectoryArchive.h @@ -9,8 +9,9 @@ * A real folder is treated like any other "archive" and gets * added to the list of PK4 archives, using this class. */ -class DirectoryArchive : - public IArchive +class DirectoryArchive final : + public IArchive, + public IArchiveFileInfoProvider { std::string _root; @@ -23,12 +24,12 @@ class DirectoryArchive : // Pass the root path to the constructor DirectoryArchive(const std::string& root); - virtual ArchiveFilePtr openFile(const std::string& name) override; + ArchiveFilePtr openFile(const std::string& name) override; + ArchiveTextFilePtr openTextFile(const std::string& name) override; + bool containsFile(const std::string& name) override; + void traverse(Visitor& visitor, const std::string& root) override; - virtual ArchiveTextFilePtr openTextFile(const std::string& name) override; - - virtual bool containsFile(const std::string& name) override; - - virtual void traverse(Visitor& visitor, const std::string& root) override; + std::size_t getFileSize(const std::string& relativePath) override; + bool getIsPhysical(const std::string& relativePath) override; }; typedef std::shared_ptr DirectoryArchivePtr; diff --git a/radiantcore/vfs/FileVisitor.h b/radiantcore/vfs/FileVisitor.h index ec2c9be519..8e3c7ce192 100644 --- a/radiantcore/vfs/FileVisitor.h +++ b/radiantcore/vfs/FileVisitor.h @@ -64,7 +64,7 @@ class FileVisitor : } // Archive::Visitor interface - void visitFile(const std::string& name) override + void visitFile(const std::string& name, IArchiveFileInfoProvider& infoProvider) override { #ifdef OS_CASE_INSENSITIVE // The name should start with the directory, "def/" for instance, case-insensitively. @@ -112,7 +112,7 @@ class FileVisitor : // Suitable file, call the callback and add to visited file set vfs::Visibility vis = _assetsList ? _assetsList->getVisibility(subname) : Visibility::NORMAL; - _visitorFunc(vfs::FileInfo{ _directory, subname, vis }); + _visitorFunc(vfs::FileInfo(_directory, subname, vis, infoProvider)); _visitedFiles.insert(subname); } diff --git a/radiantcore/vfs/GenericFileSystem.h b/radiantcore/vfs/GenericFileSystem.h index 391f8b060e..c644033ac4 100644 --- a/radiantcore/vfs/GenericFileSystem.h +++ b/radiantcore/vfs/GenericFileSystem.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(IArchive::Visitor& visitor, const std::string& root) + void traverse(IArchive::Visitor& visitor, const std::string& root, IArchiveFileInfoProvider& infoProvider) { unsigned int start_depth = getPathDepth(root.c_str()); unsigned int skip_depth = 0; @@ -180,7 +180,7 @@ class GenericFileSystem { if (!i->second.isDirectory()) { - visitor.visitFile(i->first.string()); + visitor.visitFile(i->first.string(), infoProvider); } else if (visitor.visitDirectory(i->first.string(), i->first.depth() - start_depth)) { diff --git a/radiantcore/vfs/ZipArchive.cpp b/radiantcore/vfs/ZipArchive.cpp index 3e510e7114..3050ee3080 100644 --- a/radiantcore/vfs/ZipArchive.cpp +++ b/radiantcore/vfs/ZipArchive.cpp @@ -143,7 +143,19 @@ bool ZipArchive::containsFile(const std::string& name) void ZipArchive::traverse(Visitor& visitor, const std::string& root) { - _filesystem.traverse(visitor, root); + _filesystem.traverse(visitor, root, *this); +} + +std::size_t ZipArchive::getFileSize(const std::string& relativePath) +{ + auto i = _filesystem.find(relativePath); + return i != _filesystem.end() ? i->second.getRecord()->file_size : 0; +} + +bool ZipArchive::getIsPhysical(const std::string& relativePath) +{ + // this archive is a ZIP file, so no physicality here + return false; } void ZipArchive::readZipRecord() diff --git a/radiantcore/vfs/ZipArchive.h b/radiantcore/vfs/ZipArchive.h index c9cb6fbd10..73835254ca 100644 --- a/radiantcore/vfs/ZipArchive.h +++ b/radiantcore/vfs/ZipArchive.h @@ -17,8 +17,9 @@ namespace archive * * Archives are owned and instantiated by the GlobalFileSystem instance. */ -class ZipArchive : - public IArchive +class ZipArchive final : + public IArchive, + public IArchiveFileInfoProvider { private: class ZipRecord @@ -59,11 +60,14 @@ class ZipArchive : virtual ~ZipArchive(); // Archive implementation - virtual ArchiveFilePtr openFile(const std::string& name) override; - virtual ArchiveTextFilePtr openTextFile(const std::string& name) override; + ArchiveFilePtr openFile(const std::string& name) override; + ArchiveTextFilePtr openTextFile(const std::string& name) override; bool containsFile(const std::string& name) override; void traverse(Visitor& visitor, const std::string& root) override; + std::size_t getFileSize(const std::string& relativePath) override; + bool getIsPhysical(const std::string& relativePath) override; + private: void readZipRecord(); void loadZipFile();