Skip to content

Commit

Permalink
#5108: First working implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
codereader committed Nov 29, 2020
1 parent d9f4dae commit 1f5a51f
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 16 deletions.
40 changes: 30 additions & 10 deletions libs/stream/MapResourceStream.h
Expand Up @@ -5,6 +5,7 @@
#include <fstream>
#include "os/path.h"
#include "itextstream.h"
#include "iarchive.h"
#include "ifilesystem.h"

namespace stream
Expand All @@ -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
Expand Down Expand Up @@ -70,42 +74,53 @@ 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;
}

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();
}

bool isOpen() const override
{
return _vfsFile != nullptr;
return _archiveFile != nullptr;
}

std::istream& getStream() override
Expand All @@ -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<detail::VfsMapResourceStream>(path);
return std::make_shared<detail::ArchivedMapResourceStream>(path);
}
}

inline MapResourceStream::Ptr MapResourceStream::OpenFromArchiveFile(const ArchiveTextFilePtr& archive)
{
return std::make_shared<detail::ArchivedMapResourceStream>(archive);
}

}
67 changes: 66 additions & 1 deletion radiantcore/map/ArchivedMapResource.h
@@ -1,20 +1,85 @@
#pragma once

#include "i18n.h"
#include "ifilesystem.h"
#include "MapResource.h"
#include "stream/MapResourceStream.h"

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));
}
}
};

}
2 changes: 0 additions & 2 deletions radiantcore/map/MapResource.cpp
Expand Up @@ -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();

Expand Down
6 changes: 3 additions & 3 deletions radiantcore/map/MapResource.h
Expand Up @@ -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();
Expand All @@ -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);
};
Expand Down

0 comments on commit 1f5a51f

Please sign in to comment.