From 1f5a51f9cc01e0de24e3f95f641bd06da96c343f Mon Sep 17 00:00:00 2001 From: codereader Date: Sun, 29 Nov 2020 05:02:14 +0100 Subject: [PATCH] #5108: First working implementation --- libs/stream/MapResourceStream.h | 40 ++++++++++++---- radiantcore/map/ArchivedMapResource.h | 67 ++++++++++++++++++++++++++- radiantcore/map/MapResource.cpp | 2 - radiantcore/map/MapResource.h | 6 +-- 4 files changed, 99 insertions(+), 16 deletions(-) diff --git a/libs/stream/MapResourceStream.h b/libs/stream/MapResourceStream.h index 562127b8ad..6af52ab3e7 100644 --- a/libs/stream/MapResourceStream.h +++ b/libs/stream/MapResourceStream.h @@ -5,6 +5,7 @@ #include #include "os/path.h" #include "itextstream.h" +#include "iarchive.h" #include "ifilesystem.h" namespace stream @@ -30,6 +31,9 @@ class MapResourceStream // Factory method which will return a stream reference for the given path // Will always return a non-empty reference static Ptr OpenFromPath(const std::string& path); + + // Factory method which will return a stream reference of the given ArchiveTextFile + static Ptr OpenFromArchiveFile(const ArchiveTextFilePtr& archive); }; namespace detail @@ -70,26 +74,26 @@ class FileMapResourceStream : }; /** - * MapResourceStream implementation working with a VFS file. - * Since VFS deflated file streams are not seekable, the whole + * MapResourceStream implementation working with a PAK file. + * Since deflated file streams are not seekable, the whole * file contents are pre-loaded into a seekable stringstream. */ -class VfsMapResourceStream : +class ArchivedMapResourceStream : public MapResourceStream { private: - ArchiveTextFilePtr _vfsFile; + ArchiveTextFilePtr _archiveFile; std::stringstream _contentStream; public: - VfsMapResourceStream(const std::string& path) + ArchivedMapResourceStream(const std::string& path) { rMessage() << "Trying to open file " << path << " from VFS..."; - _vfsFile = GlobalFileSystem().openTextFile(path); + _archiveFile = GlobalFileSystem().openTextFile(path); - if (!_vfsFile) + if (!_archiveFile) { rError() << "failure" << std::endl; return; @@ -97,7 +101,18 @@ class VfsMapResourceStream : rMessage() << "success." << std::endl; - std::istream vfsStream(&(_vfsFile->getInputStream())); + std::istream vfsStream(&(_archiveFile->getInputStream())); + + // Load everything into one large string + _contentStream << vfsStream.rdbuf(); + } + + ArchivedMapResourceStream(const ArchiveTextFilePtr& archive) : + _archiveFile(archive) + { + rMessage() << "Opened text file in PAK: " << archive->getName() << std::endl; + + std::istream vfsStream(&(_archiveFile->getInputStream())); // Load everything into one large string _contentStream << vfsStream.rdbuf(); @@ -105,7 +120,7 @@ class VfsMapResourceStream : bool isOpen() const override { - return _vfsFile != nullptr; + return _archiveFile != nullptr; } std::istream& getStream() override @@ -125,8 +140,13 @@ inline MapResourceStream::Ptr MapResourceStream::OpenFromPath(const std::string& else { // Not an absolute path, might as well be a VFS path, so try to load it from the PAKs - return std::make_shared(path); + return std::make_shared(path); } } +inline MapResourceStream::Ptr MapResourceStream::OpenFromArchiveFile(const ArchiveTextFilePtr& archive) +{ + return std::make_shared(archive); +} + } diff --git a/radiantcore/map/ArchivedMapResource.h b/radiantcore/map/ArchivedMapResource.h index 4f6b88f30c..dc29a4ef4d 100644 --- a/radiantcore/map/ArchivedMapResource.h +++ b/radiantcore/map/ArchivedMapResource.h @@ -1,6 +1,9 @@ #pragma once +#include "i18n.h" +#include "ifilesystem.h" #include "MapResource.h" +#include "stream/MapResourceStream.h" namespace map { @@ -8,13 +11,75 @@ namespace map class ArchivedMapResource : public MapResource { +private: + std::string _archivePath; + std::string _filePathWithinArchive; + + IArchive::Ptr _archive; + public: ArchivedMapResource(const std::string& archivePath, const std::string& filePathWithinArchive) : - MapResource(filePathWithinArchive) + MapResource(filePathWithinArchive), + _archivePath(archivePath), + _filePathWithinArchive(filePathWithinArchive) {} protected: + virtual stream::MapResourceStream::Ptr openMapfileStream() override + { + ensureArchiveOpened(); + + return openFileInArchive(_filePathWithinArchive); + } + + virtual stream::MapResourceStream::Ptr openInfofileStream() override + { + ensureArchiveOpened(); + + try + { + auto infoFilename = _filePathWithinArchive.substr(0, _filePathWithinArchive.rfind('.')); + infoFilename += getInfoFileExtension(); + + return openFileInArchive(infoFilename); + } + catch (const OperationException& ex) + { + // Info file load file does not stop us, just issue a warning + rWarning() << ex.what() << std::endl; + return stream::MapResourceStream::Ptr(); + } + } + +private: + stream::MapResourceStream::Ptr openFileInArchive(const std::string& filePathWithinArchive) + { + assert(_archive); + + auto archiveFile = _archive->openTextFile(filePathWithinArchive); + + if (!archiveFile) + { + throw OperationException(fmt::format(_("Could not open file in archive: {0}"), _archivePath)); + } + + return stream::MapResourceStream::OpenFromArchiveFile(archiveFile); + } + + void ensureArchiveOpened() + { + if (_archive) + { + return; + } + + _archive = GlobalFileSystem().openArchiveInAbsolutePath(_archivePath); + if (!_archive) + { + throw OperationException(fmt::format(_("Could not open archive: {0}"), _archivePath)); + } + } }; } diff --git a/radiantcore/map/MapResource.cpp b/radiantcore/map/MapResource.cpp index 8373fd7fd7..d42864d2d5 100644 --- a/radiantcore/map/MapResource.cpp +++ b/radiantcore/map/MapResource.cpp @@ -326,8 +326,6 @@ stream::MapResourceStream::Ptr MapResource::openInfofileStream() try { auto fullpath = getAbsoluteResourcePath(); - - // Load for an additional info file auto infoFilename = fullpath.substr(0, fullpath.rfind('.')); infoFilename += getInfoFileExtension(); diff --git a/radiantcore/map/MapResource.h b/radiantcore/map/MapResource.h index 5d25192315..94a7d37eb3 100644 --- a/radiantcore/map/MapResource.h +++ b/radiantcore/map/MapResource.h @@ -58,6 +58,9 @@ class MapResource : // May return an empty reference, may throw OperationException on failure virtual stream::MapResourceStream::Ptr openInfofileStream(); + // Returns the extension of the auxiliary info file (including the leading dot character) + static std::string getInfoFileExtension(); + private: void constructPaths(const std::string& resourcePath); std::string getAbsoluteResourcePath(); @@ -76,9 +79,6 @@ class MapResource : // Throws IMapResource::OperationException on stream open failure. stream::MapResourceStream::Ptr openFileStream(const std::string& path); - // Returns the extension of the auxiliary info file (including the leading dot character) - static std::string getInfoFileExtension(); - // Checks if file can be overwritten (throws on failure) static void throwIfNotWriteable(const fs::path& path); };