ObjLoading: Add indexing and reading of files in IWDs

This commit is contained in:
Jan 2020-01-02 00:52:56 +01:00
parent 0abdb64832
commit c2f3bca268
5 changed files with 183 additions and 18 deletions

View File

@ -1,4 +1,4 @@
#include "ZlibFileWrapper.h" #include "FileToZlibWrapper.h"
#include <cassert> #include <cassert>
voidpf Wrapper_Zlib_FileOpen(voidpf opaque, const char*, int) voidpf Wrapper_Zlib_FileOpen(voidpf opaque, const char*, int)
@ -71,7 +71,7 @@ int Wrapper_Zlib_FileError(voidpf opaque, voidpf stream)
return 0; return 0;
} }
zlib_filefunc_def ZlibFileWrapper::CreateFunctions32ForFile(FileAPI::IFile* file) zlib_filefunc_def FileToZlibWrapper::CreateFunctions32ForFile(FileAPI::IFile* file)
{ {
return zlib_filefunc_def_s return zlib_filefunc_def_s
{ {

View File

@ -3,7 +3,7 @@
#include <ioapi.h> #include <ioapi.h>
#include "Utils/FileAPI.h" #include "Utils/FileAPI.h"
class ZlibFileWrapper class FileToZlibWrapper
{ {
public: public:
static zlib_filefunc_def CreateFunctions32ForFile(FileAPI::IFile* file); static zlib_filefunc_def CreateFunctions32ForFile(FileAPI::IFile* file);

View File

@ -1,27 +1,141 @@
#include "IWD.h" #include "IWD.h"
#include <unzip.h>
#include <cassert>
#include "Utils/PathUtils.h" #include "Utils/PathUtils.h"
#include "Utils/ZlibFileWrapper.h"
#include <filesystem>
#include "ObjLoading.h" #include "ObjLoading.h"
#include "Utils/FileToZlibWrapper.h"
#include <unzip.h>
#include <filesystem>
#include <cassert>
ObjContainerRepository<IWD, ISearchPath> IWD::Repository; ObjContainerRepository<IWD, ISearchPath> IWD::Repository;
class IWD::Impl : public ISearchPath, IObjContainer class IWDFile final : public FileAPI::IFile
{
public:
class IParent
{
public:
virtual ~IParent() = default;
virtual void OnIWDFileClose() = 0;
};
private:
IParent* m_parent;
bool m_open;
size_t m_size;
unzFile m_container;
public:
IWDFile(IParent* parent, const unzFile container, const size_t size)
{
m_parent = parent;
m_container = container;
m_size = size;
m_open = true;
}
~IWDFile()
{
if(m_open)
{
Close();
}
}
bool IsOpen() override
{
return m_open;
}
size_t Read(void* buffer, const size_t elementSize, const size_t elementCount) override
{
const auto result = unzReadCurrentFile(m_container, buffer, elementSize * elementCount);
return result >= 0 ? static_cast<size_t>(result) : 0;
}
size_t Write(const void* data, size_t elementSize, size_t elementCount) override
{
// This is not meant for writing.
assert(false);
throw std::runtime_error("This is not a stream for output!");
}
void Skip(int64_t amount) override
{
while (amount > 0)
{
char temp[1024];
const size_t toRead = amount > sizeof temp ? sizeof temp : static_cast<size_t>(amount);
unzReadCurrentFile(m_container, temp, toRead);
amount -= toRead;
}
}
size_t Printf(const char* fmt, ...) override
{
// This is not meant for writing.
assert(false);
throw std::runtime_error("This is not a stream for output!");
}
int64_t Pos() override
{
return unztell(m_container);
}
void Goto(const int64_t pos) override
{
const auto current = Pos();
if(pos > current)
{
Skip(pos - current);
}
else if(pos == current)
{
// This is fine.
}
else
{
// Unsupported for zip entries
assert(false);
throw std::runtime_error("Going backwards is not supported in IWD files!");
}
}
void GotoEnd() override
{
Goto(m_size);
}
void Close() override
{
unzClose(m_container);
m_open = false;
m_parent->OnIWDFileClose();
}
};
class IWD::Impl : public ISearchPath, public IObjContainer, public IWDFile::IParent
{ {
class IWDEntry class IWDEntry
{ {
public: public:
std::string m_name; std::string m_name;
unz_file_pos m_file_pos; size_t m_size;
unz_file_pos m_file_pos{};
}; };
std::string m_path; std::string m_path;
FileAPI::IFile* m_file; FileAPI::IFile* m_file;
unzFile m_unz_file; unzFile m_unz_file;
IWDFile* m_last_file;
std::vector<IWDEntry> m_entries; std::vector<IWDEntry> m_entries;
public: public:
@ -30,6 +144,7 @@ public:
m_unz_file = nullptr; m_unz_file = nullptr;
m_path = std::move(path); m_path = std::move(path);
m_file = file; m_file = file;
m_last_file = nullptr;
} }
~Impl() ~Impl()
@ -49,7 +164,7 @@ public:
bool Initialize() bool Initialize()
{ {
auto ioFunctions = ZlibFileWrapper::CreateFunctions32ForFile(m_file); auto ioFunctions = FileToZlibWrapper::CreateFunctions32ForFile(m_file);
m_unz_file = unzOpen2("", &ioFunctions); m_unz_file = unzOpen2("", &ioFunctions);
if (m_unz_file == nullptr) if (m_unz_file == nullptr)
@ -72,6 +187,7 @@ public:
{ {
IWDEntry entry; IWDEntry entry;
entry.m_name = std::move(fileName); entry.m_name = std::move(fileName);
entry.m_size = info.uncompressed_size;
unzGetFilePos(m_unz_file, &entry.m_file_pos); unzGetFilePos(m_unz_file, &entry.m_file_pos);
m_entries.push_back(entry); m_entries.push_back(entry);
} }
@ -79,7 +195,7 @@ public:
ret = unzGoToNextFile(m_unz_file); ret = unzGoToNextFile(m_unz_file);
} }
if(ObjLoading::Configuration.Verbose) if (ObjLoading::Configuration.Verbose)
{ {
printf("Loaded IWD \"%s\" with %u entries\n", m_path.c_str(), m_entries.size()); printf("Loaded IWD \"%s\" with %u entries\n", m_path.c_str(), m_entries.size());
} }
@ -94,7 +210,29 @@ public:
return nullptr; return nullptr;
} }
// TODO std::string iwdFilename = fileName;
std::replace(iwdFilename.begin(), iwdFilename.end(), '\\', '/');
const auto iwdEntry = std::find_if(m_entries.begin(), m_entries.end(), [&iwdFilename](IWDEntry& entry) -> bool
{
return entry.m_name == iwdFilename;
});
if (iwdEntry != m_entries.end())
{
if(m_last_file != nullptr)
{
throw std::runtime_error("Trying to open new IWD file while last one was not yet closed.");
}
auto pos = iwdEntry->m_file_pos;
unzGoToFilePos(m_unz_file, &pos);
if (unzOpenCurrentFile(m_unz_file) == UNZ_OK)
{
m_last_file = new IWDFile(this, m_unz_file, iwdEntry->m_size);
}
}
return nullptr; return nullptr;
} }
@ -111,7 +249,28 @@ public:
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override
{ {
// TODO if(options.m_disk_files_only)
{
return;
}
for(auto& entry : m_entries)
{
std::filesystem::path entryPath(entry.m_name);
if(!options.m_should_include_subdirectories && entryPath.has_parent_path())
continue;
if(options.m_filter_extensions && options.m_extension != entryPath.extension().string())
continue;
callback(entry.m_name);
}
}
void OnIWDFileClose() override
{
m_last_file = nullptr;
} }
}; };

View File

@ -11,8 +11,6 @@ IObjLoader* objLoaders[]
new ObjLoaderT6() new ObjLoaderT6()
}; };
SearchPaths iwdSearchPaths;
void ObjLoading::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) void ObjLoading::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone)
{ {
for (auto* loader : objLoaders) for (auto* loader : objLoaders)
@ -81,7 +79,14 @@ void ObjLoading::UnloadIWDsInSearchPath(ISearchPath* searchPath)
IWD::Repository.RemoveContainerReferences(searchPath); IWD::Repository.RemoveContainerReferences(searchPath);
} }
ISearchPath* ObjLoading::GetIWDSearchPaths() SearchPaths ObjLoading::GetIWDSearchPaths()
{ {
return &iwdSearchPaths; SearchPaths iwdPaths;
for(auto iwd : IWD::Repository)
{
iwdPaths.IncludeSearchPath(iwd);
}
return iwdPaths;
} }

View File

@ -2,6 +2,7 @@
#include "Zone/Zone.h" #include "Zone/Zone.h"
#include "SearchPath/ISearchPath.h" #include "SearchPath/ISearchPath.h"
#include "SearchPath/SearchPaths.h"
class ObjLoading class ObjLoading
{ {
@ -17,7 +18,7 @@ public:
static void LoadIWDsInSearchPath(ISearchPath* searchPath); static void LoadIWDsInSearchPath(ISearchPath* searchPath);
static void UnloadIWDsInSearchPath(ISearchPath* searchPath); static void UnloadIWDsInSearchPath(ISearchPath* searchPath);
static ISearchPath* GetIWDSearchPaths(); static SearchPaths GetIWDSearchPaths();
static void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone); static void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone);
}; };