From c2f3bca26818228d1cf9cb1afb4d98d5c7bc1339 Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 2 Jan 2020 00:52:56 +0100 Subject: [PATCH] ObjLoading: Add indexing and reading of files in IWDs --- ...bFileWrapper.cpp => FileToZlibWrapper.cpp} | 4 +- ...{ZlibFileWrapper.h => FileToZlibWrapper.h} | 2 +- src/ObjLoading/ObjContainer/IWD/IWD.cpp | 179 +++++++++++++++++- src/ObjLoading/ObjLoading.cpp | 13 +- src/ObjLoading/ObjLoading.h | 3 +- 5 files changed, 183 insertions(+), 18 deletions(-) rename src/ObjCommon/Utils/{ZlibFileWrapper.cpp => FileToZlibWrapper.cpp} (93%) rename src/ObjCommon/Utils/{ZlibFileWrapper.h => FileToZlibWrapper.h} (86%) diff --git a/src/ObjCommon/Utils/ZlibFileWrapper.cpp b/src/ObjCommon/Utils/FileToZlibWrapper.cpp similarity index 93% rename from src/ObjCommon/Utils/ZlibFileWrapper.cpp rename to src/ObjCommon/Utils/FileToZlibWrapper.cpp index 0386d114..804b88c6 100644 --- a/src/ObjCommon/Utils/ZlibFileWrapper.cpp +++ b/src/ObjCommon/Utils/FileToZlibWrapper.cpp @@ -1,4 +1,4 @@ -#include "ZlibFileWrapper.h" +#include "FileToZlibWrapper.h" #include voidpf Wrapper_Zlib_FileOpen(voidpf opaque, const char*, int) @@ -71,7 +71,7 @@ int Wrapper_Zlib_FileError(voidpf opaque, voidpf stream) return 0; } -zlib_filefunc_def ZlibFileWrapper::CreateFunctions32ForFile(FileAPI::IFile* file) +zlib_filefunc_def FileToZlibWrapper::CreateFunctions32ForFile(FileAPI::IFile* file) { return zlib_filefunc_def_s { diff --git a/src/ObjCommon/Utils/ZlibFileWrapper.h b/src/ObjCommon/Utils/FileToZlibWrapper.h similarity index 86% rename from src/ObjCommon/Utils/ZlibFileWrapper.h rename to src/ObjCommon/Utils/FileToZlibWrapper.h index e059bf5d..6c2094f5 100644 --- a/src/ObjCommon/Utils/ZlibFileWrapper.h +++ b/src/ObjCommon/Utils/FileToZlibWrapper.h @@ -3,7 +3,7 @@ #include #include "Utils/FileAPI.h" -class ZlibFileWrapper +class FileToZlibWrapper { public: static zlib_filefunc_def CreateFunctions32ForFile(FileAPI::IFile* file); diff --git a/src/ObjLoading/ObjContainer/IWD/IWD.cpp b/src/ObjLoading/ObjContainer/IWD/IWD.cpp index 09c8cafd..f80d97be 100644 --- a/src/ObjLoading/ObjContainer/IWD/IWD.cpp +++ b/src/ObjLoading/ObjContainer/IWD/IWD.cpp @@ -1,27 +1,141 @@ #include "IWD.h" -#include -#include #include "Utils/PathUtils.h" -#include "Utils/ZlibFileWrapper.h" -#include #include "ObjLoading.h" +#include "Utils/FileToZlibWrapper.h" + +#include +#include +#include ObjContainerRepository 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(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(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 { public: std::string m_name; - unz_file_pos m_file_pos; + size_t m_size; + unz_file_pos m_file_pos{}; }; std::string m_path; FileAPI::IFile* m_file; unzFile m_unz_file; + IWDFile* m_last_file; + std::vector m_entries; public: @@ -30,6 +144,7 @@ public: m_unz_file = nullptr; m_path = std::move(path); m_file = file; + m_last_file = nullptr; } ~Impl() @@ -49,7 +164,7 @@ public: bool Initialize() { - auto ioFunctions = ZlibFileWrapper::CreateFunctions32ForFile(m_file); + auto ioFunctions = FileToZlibWrapper::CreateFunctions32ForFile(m_file); m_unz_file = unzOpen2("", &ioFunctions); if (m_unz_file == nullptr) @@ -72,6 +187,7 @@ public: { IWDEntry entry; entry.m_name = std::move(fileName); + entry.m_size = info.uncompressed_size; unzGetFilePos(m_unz_file, &entry.m_file_pos); m_entries.push_back(entry); } @@ -79,7 +195,7 @@ public: 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()); } @@ -94,7 +210,29 @@ public: 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; } @@ -111,7 +249,28 @@ public: void Find(const SearchPathSearchOptions& options, const std::function& 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; } }; diff --git a/src/ObjLoading/ObjLoading.cpp b/src/ObjLoading/ObjLoading.cpp index 6912d314..41284ea4 100644 --- a/src/ObjLoading/ObjLoading.cpp +++ b/src/ObjLoading/ObjLoading.cpp @@ -11,8 +11,6 @@ IObjLoader* objLoaders[] new ObjLoaderT6() }; -SearchPaths iwdSearchPaths; - void ObjLoading::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) { for (auto* loader : objLoaders) @@ -81,7 +79,14 @@ void ObjLoading::UnloadIWDsInSearchPath(ISearchPath* 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; } diff --git a/src/ObjLoading/ObjLoading.h b/src/ObjLoading/ObjLoading.h index d618537b..de618d47 100644 --- a/src/ObjLoading/ObjLoading.h +++ b/src/ObjLoading/ObjLoading.h @@ -2,6 +2,7 @@ #include "Zone/Zone.h" #include "SearchPath/ISearchPath.h" +#include "SearchPath/SearchPaths.h" class ObjLoading { @@ -17,7 +18,7 @@ public: static void LoadIWDsInSearchPath(ISearchPath* searchPath); static void UnloadIWDsInSearchPath(ISearchPath* searchPath); - static ISearchPath* GetIWDSearchPaths(); + static SearchPaths GetIWDSearchPaths(); static void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone); };