mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-06-28 07:11:52 +00:00
ObjLoading: Be able to load and index IWD files
This commit is contained in:
@ -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{};
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
m_path = std::move(path);
|
||||
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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
93
src/ObjLoading/ObjContainer/ObjContainerRepository.h
Normal file
93
src/ObjLoading/ObjContainer/ObjContainerRepository.h
Normal 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; });
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user