1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
#pragma once
#include <memory>
#include <string>
#include <fstream>
#include "os/path.h"
#include "itextstream.h"
#include "iarchive.h"
#include "ifilesystem.h"
namespace stream
{
/**
* RAII object representing a file stream used for map loading.
* It may either refer to a physical file or a VFS file.
*/
class MapResourceStream
{
public:
using Ptr = std::shared_ptr<MapResourceStream>;
virtual ~MapResourceStream() {}
// Returns true if the stream has been successfully opened
virtual bool isOpen() const = 0;
// Returns the (seekable) input stream
virtual std::istream& getStream() = 0;
// 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
{
// Stream implementation targeting a physical file
class FileMapResourceStream :
public MapResourceStream
{
private:
std::ifstream _stream;
public:
FileMapResourceStream(const std::string& path)
{
rMessage() << "Open file " << path << " from filesystem...";
_stream.open(path);
if (!_stream)
{
rError() << "failure" << std::endl;
return;
}
rMessage() << "success." << std::endl;
}
bool isOpen() const override
{
return _stream.good();
}
std::istream& getStream() override
{
return _stream;
}
};
/**
* 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 ArchivedMapResourceStream :
public MapResourceStream
{
private:
ArchiveTextFilePtr _archiveFile;
std::stringstream _contentStream;
public:
ArchivedMapResourceStream(const std::string& path)
{
rMessage() << "Trying to open file " << path << " from VFS...";
_archiveFile = GlobalFileSystem().openTextFile(path);
if (!_archiveFile)
{
rError() << "failure" << std::endl;
return;
}
rMessage() << "success." << std::endl;
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 _archiveFile != nullptr;
}
std::istream& getStream() override
{
return _contentStream;
}
};
}
inline MapResourceStream::Ptr MapResourceStream::OpenFromPath(const std::string& path)
{
if (path_is_absolute(path.c_str()))
{
return std::make_shared<detail::FileMapResourceStream>(path);
}
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::ArchivedMapResourceStream>(path);
}
}
inline MapResourceStream::Ptr MapResourceStream::OpenFromArchiveFile(const ArchiveTextFilePtr& archive)
{
return std::make_shared<detail::ArchivedMapResourceStream>(archive);
}
}
|