ObjLoading: Be able to load and index IWD files

This commit is contained in:
Jan 2020-01-01 18:46:33 +01:00
parent a4d55ffae7
commit 0abdb64832
27 changed files with 667 additions and 252 deletions

View File

@ -2,6 +2,7 @@ ObjCommon = {}
function ObjCommon:include()
ZoneCommon:include()
minizip:include()
includedirs {
path.join(ProjectFolder(), "ObjCommon")
}
@ -10,6 +11,7 @@ end
function ObjCommon:link()
Utils:link()
ZoneCommon:link()
minizip:link()
links {
"ObjCommon"
}

View File

@ -7,5 +7,5 @@ class IObjContainer
public:
virtual ~IObjContainer() = default;
virtual const std::string& GetName() = 0;
virtual std::string GetName() = 0;
};

View File

@ -0,0 +1,87 @@
#include "ZlibFileWrapper.h"
#include <cassert>
voidpf Wrapper_Zlib_FileOpen(voidpf opaque, const char*, int)
{
return opaque;
}
uLong Wrapper_Zlib_FileRead(voidpf, voidpf stream, void* buf, const uLong size)
{
auto* file = reinterpret_cast<FileAPI::IFile*>(stream);
return file->Read(buf, 1, size);
}
uLong Wrapper_Zlib_FileWrite(voidpf opaque, voidpf stream, const void* buf, const uLong size)
{
auto* file = reinterpret_cast<FileAPI::IFile*>(stream);
return file->Write(buf, 1, size);
}
long Wrapper_Zlib_FileTell(voidpf opaque, voidpf stream)
{
auto* file = reinterpret_cast<FileAPI::IFile*>(stream);
return static_cast<long>(file->Pos());
}
long Wrapper_Zlib_FileSeek(voidpf opaque, voidpf stream, const uLong offset, const int origin)
{
auto* file = reinterpret_cast<FileAPI::IFile*>(stream);
switch (origin)
{
case ZLIB_FILEFUNC_SEEK_CUR:
file->Skip(offset);
break;
case ZLIB_FILEFUNC_SEEK_END:
assert(offset == 0);
file->GotoEnd();
break;
case ZLIB_FILEFUNC_SEEK_SET:
file->Goto(offset);
break;
default:
return -1;
}
return 0;
}
int Wrapper_Zlib_FileClose(voidpf opaque, voidpf stream)
{
auto* file = reinterpret_cast<FileAPI::IFile*>(stream);
if (file->IsOpen())
{
file->Close();
return 0;
}
return -1;
}
int Wrapper_Zlib_FileError(voidpf opaque, voidpf stream)
{
return 0;
}
zlib_filefunc_def ZlibFileWrapper::CreateFunctions32ForFile(FileAPI::IFile* file)
{
return zlib_filefunc_def_s
{
Wrapper_Zlib_FileOpen,
Wrapper_Zlib_FileRead,
Wrapper_Zlib_FileWrite,
Wrapper_Zlib_FileTell,
Wrapper_Zlib_FileSeek,
Wrapper_Zlib_FileClose,
Wrapper_Zlib_FileError,
file
};
}

View File

@ -0,0 +1,10 @@
#pragma once
#include <ioapi.h>
#include "Utils/FileAPI.h"
class ZlibFileWrapper
{
public:
static zlib_filefunc_def CreateFunctions32ForFile(FileAPI::IFile* file);
};

View File

@ -1,9 +1,10 @@
#include "ObjLoaderT6.h"
#include "Game/T6/GameT6.h"
#include "Game/T6/GameAssetPoolT6.h"
#include "ObjContainer/IPak/IPak.h"
const int ObjLoaderT6::IPAK_READ_HASH = ObjLoaderT6::Com_HashKey("ipak_read", 64);
const int ObjLoaderT6::GLOBAL_HASH = ObjLoaderT6::Com_HashKey("GLOBAL", 64);
const int ObjLoaderT6::IPAK_READ_HASH = Com_HashKey("ipak_read", 64);
const int ObjLoaderT6::GLOBAL_HASH = Com_HashKey("GLOBAL", 64);
int ObjLoaderT6::Com_HashKey(const char* str, const int maxLen)
{
@ -27,10 +28,18 @@ bool ObjLoaderT6::SupportsZone(Zone* zone)
return zone->m_game == &g_GameT6;
}
void ObjLoaderT6::LoadIPakForZone(const std::string& ipakName, Zone* zone)
void ObjLoaderT6::LoadIPakForZone(ISearchPath* searchPath, const std::string& ipakName, Zone* zone)
{
printf("Loading ipak '%s' for zone '%s'\n", ipakName.c_str(), zone->m_name.c_str());
// TODO
const std::string ipakFilename = ipakName + ".ipak";
auto* file = searchPath->Open(ipakFilename);
if(file && file->IsOpen())
{
}
}
void ObjLoaderT6::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone)
@ -48,13 +57,18 @@ void ObjLoaderT6::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone*
if(variable->namespaceHash == zoneNameHash && variable->keyHash == IPAK_READ_HASH)
{
LoadIPakForZone(variable->value, zone);
LoadIPakForZone(searchPath, variable->value, zone);
}
}
}
}
}
void ObjLoaderT6::UnloadContainersOfZone(Zone* zone)
{
IPak::Repository.RemoveContainerReferences(zone);
}
void ObjLoaderT6::LoadObjDataForZone(ISearchPath* searchPath, Zone* zone)
{
// TODO

View File

@ -1,6 +1,7 @@
#pragma once
#include "IObjLoader.h"
#include "SearchPath/ISearchPath.h"
class ObjLoaderT6 final : public IObjLoader
{
@ -8,10 +9,13 @@ class ObjLoaderT6 final : public IObjLoader
static const int GLOBAL_HASH;
static int Com_HashKey(const char* str, int maxLen);
static void LoadIPakForZone(const std::string& ipakName, Zone* zone);
static void LoadIPakForZone(ISearchPath* searchPath, const std::string& ipakName, Zone* zone);
public:
bool SupportsZone(Zone* zone) override;
void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) override;
void UnloadContainersOfZone(Zone* zone) override;
void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) override;
};

View File

@ -9,6 +9,9 @@ public:
virtual ~IObjLoader() = default;
virtual bool SupportsZone(Zone* zone) = 0;
virtual void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) = 0;
virtual void UnloadContainersOfZone(Zone* zone) = 0;
virtual void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) = 0;
};

View File

@ -3,10 +3,13 @@
#include "Exception/IPakLoadException.h"
#include <sstream>
#include "Utils/PathUtils.h"
const uint32_t IPak::MAGIC = 'IPAK';
const uint32_t IPak::VERSION = 0x50000;
ObjContainerRepository<IPak, Zone> IPak::Repository;
uint32_t IPak::R_HashString(const char* str, uint32_t hash)
{
for (const char* pos = str; *pos; pos++)
@ -17,8 +20,9 @@ uint32_t IPak::R_HashString(const char* str, uint32_t hash)
return hash;
}
IPak::IPak(FileAPI::IFile* file)
IPak::IPak(std::string path, FileAPI::IFile* file)
{
m_path = std::move(path);
m_file = file;
m_initialized = false;
m_index_section = nullptr;
@ -34,6 +38,11 @@ IPak::~IPak()
m_data_section = nullptr;
}
std::string IPak::GetName()
{
return utils::Path::GetFilename(m_path);
}
void IPak::ReadSection()
{
IPakSection section{};

View File

@ -3,6 +3,8 @@
#include "Utils/FileAPI.h"
#include "ObjContainer/IPak/IPakTypes.h"
#include "ObjContainer/ObjContainerReferenceable.h"
#include "ObjContainer/ObjContainerRepository.h"
#include "Zone/Zone.h"
#include <vector>
@ -11,6 +13,7 @@ class IPak final : public ObjContainerReferenceable
static const uint32_t MAGIC;
static const uint32_t VERSION;
std::string m_path;
FileAPI::IFile* m_file;
bool m_initialized;
@ -26,9 +29,13 @@ class IPak final : public ObjContainerReferenceable
void ReadHeader();
public:
explicit IPak(FileAPI::IFile* file);
static ObjContainerRepository<IPak, Zone> Repository;
IPak(std::string path, FileAPI::IFile* file);
~IPak();
std::string GetName() override;
void Initialize();
FileAPI::IFile* GetEntryData(IPakHash nameHash, IPakHash dataHash);

View File

@ -1,32 +1,166 @@
#include "IWD.h"
IWD::IWD(std::string path)
#include <unzip.h>
#include <cassert>
#include "Utils/PathUtils.h"
#include "Utils/ZlibFileWrapper.h"
#include <filesystem>
#include "ObjLoading.h"
ObjContainerRepository<IWD, ISearchPath> IWD::Repository;
class IWD::Impl : public ISearchPath, IObjContainer
{
class IWDEntry
{
public:
std::string m_name;
unz_file_pos m_file_pos;
};
std::string m_path;
FileAPI::IFile* m_file;
unzFile m_unz_file;
std::vector<IWDEntry> m_entries;
public:
Impl(std::string path, FileAPI::IFile* file)
{
m_unz_file = nullptr;
m_path = std::move(path);
m_file = file;
}
~Impl()
{
if (m_unz_file != nullptr)
{
unzClose(m_unz_file);
}
if (m_file)
{
m_file->Close();
delete m_file;
m_file = nullptr;
}
}
bool Initialize()
{
auto ioFunctions = ZlibFileWrapper::CreateFunctions32ForFile(m_file);
m_unz_file = unzOpen2("", &ioFunctions);
if (m_unz_file == nullptr)
{
printf("Could not open IWD \"%s\"\n", m_path.c_str());
return false;
}
auto ret = unzGoToFirstFile(m_unz_file);
while (ret == Z_OK)
{
unz_file_info info;
char fileNameBuffer[256];
unzGetCurrentFileInfo(m_unz_file, &info, fileNameBuffer, sizeof fileNameBuffer, nullptr, 0, nullptr, 0);
std::string fileName(fileNameBuffer);
std::filesystem::path path(fileName);
if (path.has_filename())
{
IWDEntry entry;
entry.m_name = std::move(fileName);
unzGetFilePos(m_unz_file, &entry.m_file_pos);
m_entries.push_back(entry);
}
ret = unzGoToNextFile(m_unz_file);
}
if(ObjLoading::Configuration.Verbose)
{
printf("Loaded IWD \"%s\" with %u entries\n", m_path.c_str(), m_entries.size());
}
return true;
}
FileAPI::IFile* Open(const std::string& fileName) override
{
if (m_unz_file == nullptr)
{
return nullptr;
}
// TODO
return nullptr;
}
std::string GetPath() override
{
return m_path;
}
std::string GetName() override
{
return utils::Path::GetFilename(m_path);
}
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override
{
// TODO
}
};
IWD::IWD(std::string path, FileAPI::IFile* file)
{
m_impl = new Impl(std::move(path), file);
}
IWD::~IWD()
{
delete m_impl;
m_impl = nullptr;
}
IWD::IWD(IWD&& other) noexcept
{
m_impl = other.m_impl;
other.m_impl = nullptr;
}
IWD& IWD::operator=(IWD&& other) noexcept
{
m_impl = other.m_impl;
other.m_impl = nullptr;
return *this;
}
bool IWD::Initialize() const
{
return m_impl->Initialize();
}
FileAPI::IFile* IWD::Open(const std::string& fileName)
{
// TODO
return nullptr;
return m_impl->Open(fileName);
}
void IWD::FindAll(std::function<void(const std::string&)> callback)
std::string IWD::GetPath()
{
// TODO
return m_impl->GetPath();
}
void IWD::FindAllOnDisk(std::function<void(const std::string&)> callback)
std::string IWD::GetName()
{
// Files inside an IWD are not on the disk's file system directly. Therefore do nothing here.
return m_impl->GetName();
}
void IWD::FindByExtension(const std::string& extension, std::function<void(const std::string&)> callback)
void IWD::Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback)
{
// TODO
}
void IWD::FindOnDiskByExtension(const std::string& extension, std::function<void(const std::string&)> callback)
{
// Files inside an IWD are not on the disk's file system directly. Therefore do nothing here.
return m_impl->Find(options, callback);
}

View File

@ -1,17 +1,28 @@
#pragma once
#include "SearchPath/ISearchPath.h"
#include "ObjContainer/ObjContainerRepository.h"
class IWD final : public ISearchPath
class IWD final : public ISearchPath, IObjContainer
{
std::string m_path;
class Impl;
Impl* m_impl;
public:
explicit IWD(std::string path);
static ObjContainerRepository<IWD, ISearchPath> Repository;
IWD(std::string path, FileAPI::IFile* file);
~IWD();
IWD(const IWD& other) = delete;
IWD(IWD&& other) noexcept;
IWD& operator=(const IWD& other) = delete;
IWD& operator=(IWD&& other) noexcept;
bool Initialize() const;
FileAPI::IFile* Open(const std::string& fileName) override;
void FindAll(std::function<void(const std::string&)> callback) override;
void FindAllOnDisk(std::function<void(const std::string&)> callback) override;
void FindByExtension(const std::string& extension, std::function<void(const std::string&)> callback) override;
void FindOnDiskByExtension(const std::string& extension, std::function<void(const std::string&)> callback) override;
std::string GetPath() override;
std::string GetName() override;
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
};

View File

@ -1,52 +0,0 @@
#include "ObjContainerRegistry.h"
#include <cassert>
ObjContainerRegistry g_ObjContainerRegistry;
IObjContainer* ObjContainerRegistry::GetContainerByName(const std::string& name)
{
for (auto* container : m_containers)
{
if (container->GetName() == name)
{
return container;
}
}
return nullptr;
}
void ObjContainerRegistry::AddContainer(IObjContainer* container)
{
assert(dynamic_cast<ObjContainerReferenceable*>(container) == nullptr);
m_containers.push_back(container);
}
void ObjContainerRegistry::AddContainerWithReference(ObjContainerReferenceable* container, Zone* referencer)
{
container->AddReference(referencer);
m_containers.push_back(container);
}
void ObjContainerRegistry::RemoveContainerReferences(Zone* referencer)
{
auto iContainer = m_containers.begin();
while (iContainer != m_containers.end())
{
auto* container = *iContainer;
if (auto* referenceableContainer = dynamic_cast<ObjContainerReferenceable*>(container))
{
if (referenceableContainer->RemoveReference(referencer) && !referenceableContainer->IsReferenced())
{
delete container;
iContainer = m_containers.erase(iContainer);
continue;
}
}
++iContainer;
}
}

View File

@ -1,22 +0,0 @@
#pragma once
#include "ObjContainer/IObjContainer.h"
#include "ObjContainer/ObjContainerReferenceable.h"
#include "Zone/Zone.h"
#include <string>
#include <vector>
class ObjContainerRegistry
{
std::vector<IObjContainer*> m_containers;
public:
void AddContainer(IObjContainer* container);
void AddContainerWithReference(ObjContainerReferenceable* container, Zone* referencer);
void RemoveContainerReferences(Zone* referencer);
IObjContainer* GetContainerByName(const std::string& name);
};
extern ObjContainerRegistry g_ObjContainerRegistry;

View File

@ -0,0 +1,93 @@
#pragma once
#include "ObjContainer/IObjContainer.h"
#include "Utils/TransformIterator.h"
#include <algorithm>
#include <string>
#include <vector>
#include <set>
template <typename ContainerType, typename ReferencerType>
class ObjContainerRepository
{
class ObjContainerEntry
{
public:
ContainerType* m_container;
std::set<ReferencerType*> m_references;
explicit ObjContainerEntry(ContainerType* container)
{
m_container = container;
}
};
std::vector<ObjContainerEntry> m_containers;
public:
void AddContainer(ContainerType* container, ReferencerType* referencer)
{
auto firstEntry = std::find_if(m_containers.begin(), m_containers.end(),
[container](ObjContainerEntry& entry) -> bool
{
return entry.m_container == container;
});
if(firstEntry != m_containers.end())
{
firstEntry->m_references.insert(referencer);
return;
}
ObjContainerEntry entry(container);
entry.m_references.insert(referencer);
m_containers.push_back(entry);
}
void RemoveContainerReferences(ReferencerType* referencer)
{
for(auto iEntry = m_containers.begin(); iEntry != m_containers.end(); ++iEntry)
{
auto foundReference = iEntry->m_references.find(referencer);
if(foundReference != iEntry->m_references.end())
{
iEntry->m_references.erase(foundReference);
}
if(iEntry->m_references.empty())
{
delete iEntry->m_container;
m_containers.erase(iEntry);
}
}
}
IObjContainer* GetContainerByName(const std::string& name)
{
auto foundEntry = std::find_if(m_containers.begin(), m_containers.end(), [name](ObjContainerEntry& entry) -> bool
{
return entry.m_container->GetName() == name;
});
if(foundEntry != m_containers.end())
{
return foundEntry->m_container;
}
return nullptr;
}
TransformIterator<typename std::vector<ObjContainerEntry>::iterator, ObjContainerEntry&, ContainerType*> begin()
{
return TransformIterator<typename std::vector<ObjContainerEntry>::iterator, ObjContainerEntry&, ContainerType*>(
m_containers.begin(), [](ObjContainerEntry& entry) -> ContainerType* { return entry.m_container; });
}
TransformIterator<typename std::vector<ObjContainerEntry>::iterator, ObjContainerEntry&, ContainerType*> end()
{
return TransformIterator<typename std::vector<ObjContainerEntry>::iterator, ObjContainerEntry&, ContainerType*>(
m_containers.end(), [](ObjContainerEntry& entry) -> ContainerType* { return entry.m_container; });
}
};

View File

@ -1,13 +1,18 @@
#include "ObjLoading.h"
#include "IObjLoader.h"
#include "Game/T6/ObjLoaderT6.h"
#include "ObjContainer/ObjContainerRegistry.h"
#include "ObjContainer/IWD/IWD.h"
#include "SearchPath/SearchPaths.h"
ObjLoading::Configuration_t ObjLoading::Configuration;
IObjLoader* objLoaders[]
{
new ObjLoaderT6()
};
SearchPaths iwdSearchPaths;
void ObjLoading::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone)
{
for (auto* loader : objLoaders)
@ -34,5 +39,49 @@ void ObjLoading::LoadObjDataForZone(ISearchPath* searchPath, Zone* zone)
void ObjLoading::UnloadContainersOfZone(Zone* zone)
{
g_ObjContainerRegistry.RemoveContainerReferences(zone);
for (auto* loader : objLoaders)
{
if (loader->SupportsZone(zone))
{
loader->UnloadContainersOfZone(zone);
return;
}
}
}
void ObjLoading::LoadIWDsInSearchPath(ISearchPath* searchPath)
{
searchPath->Find(SearchPathSearchOptions().IncludeSubdirectories(false).FilterExtensions("iwd"),
[searchPath](const std::string& path) -> void
{
auto file = FileAPI::Open(path, FileAPI::Mode::MODE_READ);
if (file.IsOpen())
{
const auto fileP = new FileAPI::File(std::move(file));
IWD* iwd = new IWD(path, fileP);
if (iwd->Initialize())
{
IWD::Repository.AddContainer(iwd, searchPath);
}
else
{
delete iwd;
fileP->Close();
delete fileP;
}
}
});
}
void ObjLoading::UnloadIWDsInSearchPath(ISearchPath* searchPath)
{
IWD::Repository.RemoveContainerReferences(searchPath);
}
ISearchPath* ObjLoading::GetIWDSearchPaths()
{
return &iwdSearchPaths;
}

View File

@ -6,8 +6,18 @@
class ObjLoading
{
public:
static class Configuration_t
{
public:
bool Verbose = false;
} Configuration;
static void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone);
static void UnloadContainersOfZone(Zone* zone);
static void LoadIWDsInSearchPath(ISearchPath* searchPath);
static void UnloadIWDsInSearchPath(ISearchPath* searchPath);
static ISearchPath* GetIWDSearchPaths();
static void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone);
};

View File

@ -1,7 +1,7 @@
#pragma once
#include "SearchPathSearchOptions.h"
#include "Utils/FileAPI.h"
#include <string>
#include <functional>
class ISearchPath
@ -16,29 +16,25 @@ public:
*/
virtual FileAPI::IFile* Open(const std::string& fileName) = 0;
/**
* \brief Returns the path to the search path.
* \return The path to the search path.
*/
virtual std::string GetPath() = 0;
/**
* \brief Iterates through all files of the search path.
* \param callback The callback to call for each found file with it's path relative to the search path.
* \param options Options that modify the search.
*/
virtual void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) = 0;
/**
* \brief Iterates through all files of the search path.
* \param callback The callback to call for each found file with it's path relative to the search path.
*/
virtual void FindAll(std::function<void(const std::string&)> callback) = 0;
/**
* \brief Iterates through all files available through the OS file system.
* \param callback The callback to call for each found file with it's full path.
*/
virtual void FindAllOnDisk(std::function<void(const std::string&)> callback) = 0;
/**
* \brief Iterates through all files of the search path with the specified extension.
* \param extension The extension of all files to find.
* \param callback The callback to call for each found file with it's path relative to the search path.
*/
virtual void FindByExtension(const std::string& extension, std::function<void(const std::string&)> callback) = 0;
/**
* \brief Iterates through all files available through the OS file system with the specified extension.
* \param extension The extension of all files to find.
* \param callback The callback to call for each found file with it's full path.
*/
virtual void FindOnDiskByExtension(const std::string& extension, std::function<void(const std::string&)> callback) = 0;
void Find(const std::function<void(const std::string&)>& callback)
{
Find(SearchPathSearchOptions(), callback);
}
};

View File

@ -8,7 +8,7 @@ SearchPathFilesystem::SearchPathFilesystem(std::string path)
m_path = std::move(path);
}
const std::string& SearchPathFilesystem::GetPath() const
std::string SearchPathFilesystem::GetPath()
{
return m_path;
}
@ -25,55 +25,28 @@ FileAPI::IFile* SearchPathFilesystem::Open(const std::string& fileName)
return nullptr;
}
void SearchPathFilesystem::FindAll(const std::function<void(const std::string&)> callback)
void SearchPathFilesystem::Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback)
{
if (options.m_should_include_subdirectories)
{
std::filesystem::recursive_directory_iterator iterator(m_path);
for (const auto entry = begin(iterator); iterator != end(iterator); ++iterator)
{
callback(entry->path().string());
auto path = entry->path();
if (options.m_filter_extensions && path.extension().string() != options.m_extension)
continue;
callback(options.m_absolute_paths ? absolute(path).string() : path.string());
}
}
void SearchPathFilesystem::FindAllOnDisk(const std::function<void(const std::string&)> callback)
{
std::filesystem::recursive_directory_iterator iterator(m_path);
for (const auto entry = begin(iterator); iterator != end(iterator); ++iterator)
{
callback(absolute(entry->path()).string());
}
}
void SearchPathFilesystem::FindByExtension(const std::string& extension,
const std::function<void(const std::string&)> callback)
{
std::filesystem::recursive_directory_iterator iterator(m_path);
else
{
std::filesystem::directory_iterator iterator(m_path);
for (const auto entry = begin(iterator); iterator != end(iterator); ++iterator)
{
auto entryPath = entry->path();
if (entryPath.extension().string() == extension)
{
callback(entryPath.string());
}
}
}
void SearchPathFilesystem::FindOnDiskByExtension(const std::string& extension,
const std::function<void(const std::string&)> callback)
{
std::filesystem::recursive_directory_iterator iterator(m_path);
for (const auto entry = begin(iterator); iterator != end(iterator); ++iterator)
{
auto entryPath = entry->path();
if (entryPath.extension().string() == extension)
{
callback(absolute(entryPath).string());
auto path = entry->path();
if (options.m_filter_extensions && path.extension().string() != options.m_extension)
continue;
callback(options.m_absolute_paths ? absolute(path).string() : path.string());
}
}
}

View File

@ -9,11 +9,8 @@ class SearchPathFilesystem final : public ISearchPath
public:
explicit SearchPathFilesystem(std::string path);
const std::string& GetPath() const;
FileAPI::IFile* Open(const std::string& fileName) override;
void FindAll(std::function<void(const std::string&)> callback) override;
void FindAllOnDisk(std::function<void(const std::string&)> callback) override;
void FindByExtension(const std::string& extension, std::function<void(const std::string&)> callback) override;
void FindOnDiskByExtension(const std::string& extension, std::function<void(const std::string&)> callback) override;
std::string GetPath() override;
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
};

View File

@ -0,0 +1,41 @@
#include "SearchPathSearchOptions.h"
SearchPathSearchOptions::SearchPathSearchOptions()
{
m_should_include_subdirectories = true;
m_disk_files_only = false;
m_absolute_paths = false;
m_filter_extensions = false;
}
SearchPathSearchOptions& SearchPathSearchOptions::IncludeSubdirectories(const bool value)
{
m_should_include_subdirectories = value;
return *this;
}
SearchPathSearchOptions& SearchPathSearchOptions::OnlyDiskFiles(const bool value)
{
m_disk_files_only = value;
return *this;
}
SearchPathSearchOptions& SearchPathSearchOptions::AbsolutePaths(const bool value)
{
m_absolute_paths = value;
return *this;
}
SearchPathSearchOptions& SearchPathSearchOptions::FilterExtensions(std::string extension)
{
m_extension = std::move(extension);
m_filter_extensions = true;
if(m_extension[0] != '.')
m_extension = "." + m_extension;
return *this;
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <string>
class SearchPathSearchOptions
{
public:
bool m_should_include_subdirectories;
bool m_disk_files_only;
bool m_absolute_paths;
bool m_filter_extensions;
std::string m_extension;
SearchPathSearchOptions();
SearchPathSearchOptions& IncludeSubdirectories(bool value);
SearchPathSearchOptions& OnlyDiskFiles(bool value);
SearchPathSearchOptions& AbsolutePaths(bool value);
SearchPathSearchOptions& FilterExtensions(std::string extension);
};

View File

@ -56,36 +56,16 @@ FileAPI::IFile* SearchPaths::Open(const std::string& fileName)
return nullptr;
}
void SearchPaths::FindAll(const std::function<void(const std::string&)> callback)
std::string SearchPaths::GetPath()
{
for (auto searchPathEntry : m_search_paths)
{
searchPathEntry->FindAll(callback);
}
return "SearchPaths: " + std::to_string(m_search_paths.size()) + " entries";
}
void SearchPaths::FindAllOnDisk(const std::function<void(const std::string&)> callback)
void SearchPaths::Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback)
{
for (auto searchPathEntry : m_search_paths)
{
searchPathEntry->FindAllOnDisk(callback);
}
}
void SearchPaths::FindByExtension(const std::string& extension, const std::function<void(const std::string&)> callback)
{
for (auto searchPathEntry : m_search_paths)
{
searchPathEntry->FindByExtension(extension, callback);
}
}
void SearchPaths::FindOnDiskByExtension(const std::string& extension, const std::function<void(const std::string&)> callback)
{
for (auto searchPathEntry : m_search_paths)
{
searchPathEntry->FindOnDiskByExtension(extension, callback);
searchPathEntry->Find(options, callback);
}
}

View File

@ -15,10 +15,8 @@ public:
~SearchPaths() override;
FileAPI::IFile* Open(const std::string& fileName) override;
void FindAll(std::function<void(const std::string&)> callback) override;
void FindAllOnDisk(std::function<void(const std::string&)> callback) override;
void FindByExtension(const std::string& extension, std::function<void(const std::string&)> callback) override;
void FindOnDiskByExtension(const std::string& extension, std::function<void(const std::string&)> callback) override;
std::string GetPath() override;
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
SearchPaths(const SearchPaths& other);
SearchPaths(SearchPaths&& other) noexcept;

View File

@ -14,6 +14,7 @@
#include <set>
#include <regex>
#include <filesystem>
#include "ObjContainer/IWD/IWD.h"
const CommandLineOption* optionHelp = CommandLineOption::Builder::Create()
.WithShortName("?")
@ -80,14 +81,16 @@ class Unlinker::Impl
* \brief Loads a search path.
* \param searchPath The search path to load.
*/
void LoadSearchPath(SearchPathFilesystem* searchPath)
void LoadSearchPath(ISearchPath* searchPath) const
{
if(m_should_load_obj)
if (m_should_load_obj)
{
if(m_verbose)
if (m_verbose)
{
printf("Loading search path: \"%s\"\n", searchPath->GetPath().c_str());
}
ObjLoading::LoadIWDsInSearchPath(searchPath);
}
}
@ -95,14 +98,16 @@ class Unlinker::Impl
* \brief Unloads a search path.
* \param searchPath The search path to unload.
*/
void UnloadSearchPath(SearchPathFilesystem* searchPath)
void UnloadSearchPath(ISearchPath* searchPath) const
{
if(m_should_load_obj)
if (m_should_load_obj)
{
if(m_verbose)
if (m_verbose)
{
printf("Unloading search path: \"%s\"\n", searchPath->GetPath().c_str());
}
ObjLoading::UnloadIWDsInSearchPath(searchPath);
}
}
@ -220,6 +225,12 @@ class Unlinker::Impl
{
std::string absolutePath = std::filesystem::absolute(path).string();
if (!FileAPI::DirectoryExists(absolutePath))
{
printf("Could not find directory of search path: \"%s\"\n", path.c_str());
return false;
}
SearchPathFilesystem* searchPath = new SearchPathFilesystem(absolutePath);
LoadSearchPath(searchPath);
m_search_paths.CommitSearchPath(searchPath);
@ -327,6 +338,12 @@ class Unlinker::Impl
return true;
}
void SetVerbose(const bool verbose)
{
m_verbose = verbose;
ObjLoading::Configuration.Verbose = verbose;
}
public:
Impl()
: m_argument_parser(commandLineOptions, _countof(commandLineOptions))
@ -347,7 +364,7 @@ public:
return false;
}
m_verbose = m_argument_parser.IsOptionSpecified(optionVerbose);
SetVerbose(m_argument_parser.IsOptionSpecified(optionVerbose));
m_should_load_obj = !m_argument_parser.IsOptionSpecified(optionList);
// Check if the user requested help
@ -385,7 +402,7 @@ public:
return false;
}
if(m_verbose)
if (m_verbose)
{
printf("Loaded zone \"%s\"\n", zone->m_name.c_str());
}

View File

@ -27,7 +27,7 @@ bool FileAPI::DirectoryExists(const std::string& directoryName)
FileAPI::File FileAPI::Open(const std::string& filename, const Mode mode)
{
const char* modeStr;
switch(mode)
switch (mode)
{
default:
case Mode::MODE_READ:
@ -98,12 +98,17 @@ size_t FileAPI::File::Write(const void* data, const size_t elementSize, const si
return fwrite(data, elementSize, elementCount, static_cast<FILE*>(m_handle));
}
void FileAPI::File::Skip(const size_t amount)
void FileAPI::File::Skip(const int64_t amount)
{
if(!this->IsOpen())
if (!this->IsOpen())
return;
fseek(static_cast<FILE*>(m_handle), amount, SEEK_CUR);
_fseeki64(static_cast<FILE*>(m_handle), amount, SEEK_CUR);
}
void FileAPI::File::GotoEnd()
{
_fseeki64(static_cast<FILE*>(m_handle), 0, SEEK_END);
}
size_t FileAPI::File::Printf(const char* fmt, ...)

View File

@ -20,10 +20,11 @@ public:
virtual bool IsOpen() = 0;
virtual size_t Read(void* buffer, size_t elementSize, size_t elementCount) = 0;
virtual size_t Write(const void* data, size_t elementSize, size_t elementCount) = 0;
virtual void Skip(size_t amount) = 0;
virtual void Skip(int64_t amount) = 0;
virtual size_t Printf(const char* fmt, ...) = 0;
virtual int64_t Pos() = 0;
virtual void Goto(int64_t pos) = 0;
virtual void GotoEnd() = 0;
virtual void Close() = 0;
};
@ -44,10 +45,11 @@ public:
bool IsOpen() override;
size_t Read(void* buffer, size_t elementSize, size_t elementCount) override;
size_t Write(const void* data, size_t elementSize, size_t elementCount) override;
void Skip(size_t amount) override;
void Skip(int64_t amount) override;
size_t Printf(const char* fmt, ...) override;
int64_t Pos() override;
void Goto(int64_t pos) override;
void GotoEnd() override;
void Close() override;
};

View File

@ -0,0 +1,26 @@
#pragma once
#include <functional>
template <typename BaseIteratorType, typename SourceType, typename TargetType>
class TransformIterator
{
BaseIteratorType m_base;
std::function<TargetType(SourceType)> m_transform;
public:
TransformIterator(BaseIteratorType base, std::function<TargetType(SourceType)> transform)
: m_base(base), m_transform(transform)
{
}
TransformIterator& operator++()
{
++m_base;
return *this;
}
bool operator==(TransformIterator other) const { return m_base == other.m_base; }
bool operator!=(TransformIterator other) const { return !(m_base == other.m_base); }
TargetType operator*() { return m_transform(*m_base); }
};