mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-06-27 23:01:55 +00:00
Replace FileAPI with c++ streams and std::filesystem
This commit is contained in:
@ -43,15 +43,14 @@ namespace IW4
|
||||
Texture* loadedTexture = nullptr;
|
||||
IwiLoader loader(zone->GetMemory());
|
||||
|
||||
const std::string imageFileName = "images/" + std::string(image->name) + ".iwi";
|
||||
auto* filePathImage = searchPath->Open(imageFileName);
|
||||
const auto imageFileName = "images/" + std::string(image->name) + ".iwi";
|
||||
|
||||
if (filePathImage != nullptr)
|
||||
{
|
||||
loadedTexture = loader.LoadIwi(filePathImage);
|
||||
|
||||
filePathImage->Close();
|
||||
delete filePathImage;
|
||||
const auto filePathImage = searchPath->Open(imageFileName);
|
||||
if (filePathImage != nullptr)
|
||||
{
|
||||
loadedTexture = loader.LoadIwi(*filePathImage);
|
||||
}
|
||||
}
|
||||
|
||||
if (loadedTexture != nullptr)
|
||||
@ -59,8 +58,8 @@ namespace IW4
|
||||
image->texture.texture = loadedTexture;
|
||||
image->cardMemory.platform[0] = 0;
|
||||
|
||||
const int textureMipCount = loadedTexture->GetMipMapCount();
|
||||
for (int mipLevel = 0; mipLevel < textureMipCount; mipLevel++)
|
||||
const auto textureMipCount = loadedTexture->GetMipMapCount();
|
||||
for (auto mipLevel = 0; mipLevel < textureMipCount; mipLevel++)
|
||||
image->cardMemory.platform[0] += static_cast<int>(loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount());
|
||||
}
|
||||
else
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "ObjLoaderT6.h"
|
||||
|
||||
#include "Game/T6/GameT6.h"
|
||||
#include "Game/T6/GameAssetPoolT6.h"
|
||||
#include "ObjContainer/IPak/IPak.h"
|
||||
@ -22,36 +23,32 @@ namespace T6
|
||||
if (ObjLoading::Configuration.Verbose)
|
||||
printf("Trying to load ipak '%s' for zone '%s'\n", ipakName.c_str(), zone->m_name.c_str());
|
||||
|
||||
IPak* existingIPak = IPak::Repository.GetContainerByName(ipakName);
|
||||
auto* existingIPak = IPak::Repository.GetContainerByName(ipakName);
|
||||
if (existingIPak != nullptr)
|
||||
{
|
||||
if (ObjLoading::Configuration.Verbose)
|
||||
printf("Referencing loaded ipak '%s'.\n", ipakName.c_str());
|
||||
|
||||
IPak::Repository.AddContainer(existingIPak, zone);
|
||||
IPak::Repository.AddContainerReference(existingIPak, zone);
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string ipakFilename = ipakName + ".ipak";
|
||||
const auto ipakFilename = ipakName + ".ipak";
|
||||
|
||||
auto* file = searchPath->Open(ipakFilename);
|
||||
if (file && file->IsOpen())
|
||||
auto file = searchPath->Open(ipakFilename);
|
||||
if (file)
|
||||
{
|
||||
IPak* ipak = new IPak(ipakFilename, file);
|
||||
auto ipak = std::make_unique<IPak>(ipakFilename, std::move(file));
|
||||
|
||||
if (ipak->Initialize())
|
||||
{
|
||||
IPak::Repository.AddContainer(ipak, zone);
|
||||
IPak::Repository.AddContainer(std::move(ipak), zone);
|
||||
|
||||
if (ObjLoading::Configuration.Verbose)
|
||||
printf("Found and loaded ipak '%s'.\n", ipakFilename.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
delete ipak;
|
||||
file->Close();
|
||||
delete file;
|
||||
|
||||
printf("Failed to load ipak '%s'!\n", ipakFilename.c_str());
|
||||
}
|
||||
}
|
||||
@ -108,7 +105,7 @@ namespace T6
|
||||
void ObjLoader::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const
|
||||
{
|
||||
auto* assetPoolT6 = dynamic_cast<GameAssetPoolT6*>(zone->m_pools.get());
|
||||
const int zoneNameHash = CommonT6::Com_HashKey(zone->m_name.c_str(), 64);
|
||||
const auto zoneNameHash = CommonT6::Com_HashKey(zone->m_name.c_str(), 64);
|
||||
|
||||
LoadCommonIPaks(searchPath, zone);
|
||||
|
||||
@ -117,9 +114,9 @@ namespace T6
|
||||
for (auto* keyValuePairsEntry : *assetPoolT6->m_key_value_pairs)
|
||||
{
|
||||
auto* keyValuePairs = keyValuePairsEntry->Asset();
|
||||
for (int variableIndex = 0; variableIndex < keyValuePairs->numVariables; variableIndex++)
|
||||
for (auto variableIndex = 0; variableIndex < keyValuePairs->numVariables; variableIndex++)
|
||||
{
|
||||
KeyValuePair* variable = &keyValuePairs->keyValuePairs[variableIndex];
|
||||
auto* variable = &keyValuePairs->keyValuePairs[variableIndex];
|
||||
|
||||
if (variable->namespaceHash == zoneNameHash && variable->keyHash == IPAK_READ_HASH)
|
||||
{
|
||||
@ -149,14 +146,13 @@ namespace T6
|
||||
{
|
||||
for (auto* ipak : IPak::Repository)
|
||||
{
|
||||
auto* ipakStream = ipak->GetEntryStream(image->hash, image->streamedParts[0].hash);
|
||||
auto ipakStream = ipak->GetEntryStream(image->hash, image->streamedParts[0].hash);
|
||||
|
||||
if (ipakStream != nullptr)
|
||||
if (ipakStream)
|
||||
{
|
||||
loadedTexture = loader.LoadIwi(ipakStream);
|
||||
loadedTexture = loader.LoadIwi(*ipakStream);
|
||||
|
||||
ipakStream->Close();
|
||||
delete ipakStream;
|
||||
ipakStream->close();
|
||||
|
||||
if (loadedTexture != nullptr)
|
||||
{
|
||||
@ -168,15 +164,14 @@ namespace T6
|
||||
|
||||
if (loadedTexture == nullptr)
|
||||
{
|
||||
const std::string imageFileName = "images/" + std::string(image->name) + ".iwi";
|
||||
auto* filePathImage = searchPath->Open(imageFileName);
|
||||
const auto imageFileName = "images/" + std::string(image->name) + ".iwi";
|
||||
|
||||
if (filePathImage != nullptr)
|
||||
{
|
||||
loadedTexture = loader.LoadIwi(filePathImage);
|
||||
|
||||
filePathImage->Close();
|
||||
delete filePathImage;
|
||||
const auto filePathImage = searchPath->Open(imageFileName);
|
||||
if (filePathImage)
|
||||
{
|
||||
loadedTexture = loader.LoadIwi(*filePathImage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,8 +180,8 @@ namespace T6
|
||||
image->texture.texture = loadedTexture;
|
||||
image->loadedSize = 0;
|
||||
|
||||
const int textureMipCount = loadedTexture->GetMipMapCount();
|
||||
for (int mipLevel = 0; mipLevel < textureMipCount; mipLevel++)
|
||||
const auto textureMipCount = loadedTexture->GetMipMapCount();
|
||||
for (auto mipLevel = 0; mipLevel < textureMipCount; mipLevel++)
|
||||
image->loadedSize += loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount();
|
||||
}
|
||||
else
|
||||
|
@ -52,21 +52,22 @@ const ImageFormat* IwiLoader::GetFormat8(int8_t format)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Texture* IwiLoader::LoadIwi8(FileAPI::IFile* file)
|
||||
Texture* IwiLoader::LoadIwi8(std::istream& stream) const
|
||||
{
|
||||
iwi8::IwiHeader header{};
|
||||
|
||||
if (file->Read(&header, sizeof header, 1) != 1)
|
||||
stream.read(reinterpret_cast<char*>(&header), sizeof header);
|
||||
if (stream.gcount() != sizeof header)
|
||||
return nullptr;
|
||||
|
||||
const ImageFormat* format = GetFormat8(header.format);
|
||||
const auto* format = GetFormat8(header.format);
|
||||
if (format == nullptr)
|
||||
return nullptr;
|
||||
|
||||
uint16_t width = header.dimensions[0];
|
||||
uint16_t height = header.dimensions[1];
|
||||
uint16_t depth = header.dimensions[2];
|
||||
bool hasMipMaps = !(header.flags & iwi8::IwiFlags::IMG_FLAG_NOMIPMAPS);
|
||||
auto width = header.dimensions[0];
|
||||
auto height = header.dimensions[1];
|
||||
auto depth = header.dimensions[2];
|
||||
auto hasMipMaps = !(header.flags & iwi8::IwiFlags::IMG_FLAG_NOMIPMAPS);
|
||||
|
||||
Texture* texture;
|
||||
if ((header.flags & iwi8::IwiFlags::IMG_FLAG_MAPTYPE_MASK) == iwi8::IwiFlags::IMG_FLAG_MAPTYPE_CUBE)
|
||||
@ -94,12 +95,12 @@ Texture* IwiLoader::LoadIwi8(FileAPI::IFile* file)
|
||||
|
||||
texture->Allocate();
|
||||
|
||||
size_t currentFileSize = sizeof iwi8::IwiHeader + sizeof IwiVersion;
|
||||
const int mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1;
|
||||
auto currentFileSize = sizeof iwi8::IwiHeader + sizeof IwiVersion;
|
||||
const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1;
|
||||
|
||||
for (int currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--)
|
||||
for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--)
|
||||
{
|
||||
const size_t sizeOfMipLevel = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
|
||||
const auto sizeOfMipLevel = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
|
||||
currentFileSize += sizeOfMipLevel;
|
||||
|
||||
if (currentMipLevel < static_cast<int>(_countof(iwi8::IwiHeader::fileSizeForPicmip))
|
||||
@ -111,7 +112,8 @@ Texture* IwiLoader::LoadIwi8(FileAPI::IFile* file)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (file->Read(texture->GetBufferForMipLevel(currentMipLevel), 1, sizeOfMipLevel) != sizeOfMipLevel)
|
||||
stream.read(reinterpret_cast<char*>(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel);
|
||||
if (stream.gcount() != sizeOfMipLevel)
|
||||
{
|
||||
printf("Unexpected eof of iwi in mip level %i\n", currentMipLevel);
|
||||
|
||||
@ -167,21 +169,22 @@ const ImageFormat* IwiLoader::GetFormat27(int8_t format)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Texture* IwiLoader::LoadIwi27(FileAPI::IFile* file)
|
||||
Texture* IwiLoader::LoadIwi27(std::istream& stream) const
|
||||
{
|
||||
iwi27::IwiHeader header{};
|
||||
|
||||
if (file->Read(&header, sizeof header, 1) != 1)
|
||||
stream.read(reinterpret_cast<char*>(&header), sizeof header);
|
||||
if (stream.gcount() != sizeof header)
|
||||
return nullptr;
|
||||
|
||||
const ImageFormat* format = GetFormat27(header.format);
|
||||
const auto* format = GetFormat27(header.format);
|
||||
if (format == nullptr)
|
||||
return nullptr;
|
||||
|
||||
uint16_t width = header.dimensions[0];
|
||||
uint16_t height = header.dimensions[1];
|
||||
uint16_t depth = header.dimensions[2];
|
||||
bool hasMipMaps = !(header.flags & iwi27::IwiFlags::IMG_FLAG_NOMIPMAPS);
|
||||
auto width = header.dimensions[0];
|
||||
auto height = header.dimensions[1];
|
||||
auto depth = header.dimensions[2];
|
||||
auto hasMipMaps = !(header.flags & iwi27::IwiFlags::IMG_FLAG_NOMIPMAPS);
|
||||
|
||||
Texture* texture;
|
||||
if (header.flags & iwi27::IwiFlags::IMG_FLAG_CUBEMAP)
|
||||
@ -199,12 +202,12 @@ Texture* IwiLoader::LoadIwi27(FileAPI::IFile* file)
|
||||
|
||||
texture->Allocate();
|
||||
|
||||
size_t currentFileSize = sizeof iwi27::IwiHeader + sizeof IwiVersion;
|
||||
const int mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1;
|
||||
auto currentFileSize = sizeof iwi27::IwiHeader + sizeof IwiVersion;
|
||||
const auto mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1;
|
||||
|
||||
for (int currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--)
|
||||
for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--)
|
||||
{
|
||||
const size_t sizeOfMipLevel = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
|
||||
const auto sizeOfMipLevel = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
|
||||
currentFileSize += sizeOfMipLevel;
|
||||
|
||||
if (currentMipLevel < static_cast<int>(_countof(iwi27::IwiHeader::fileSizeForPicmip))
|
||||
@ -216,7 +219,8 @@ Texture* IwiLoader::LoadIwi27(FileAPI::IFile* file)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (file->Read(texture->GetBufferForMipLevel(currentMipLevel), 1, sizeOfMipLevel) != sizeOfMipLevel)
|
||||
stream.read(reinterpret_cast<char*>(texture->GetBufferForMipLevel(currentMipLevel)), sizeOfMipLevel);
|
||||
if (stream.gcount() != sizeOfMipLevel)
|
||||
{
|
||||
printf("Unexpected eof of iwi in mip level %i\n", currentMipLevel);
|
||||
|
||||
@ -228,11 +232,12 @@ Texture* IwiLoader::LoadIwi27(FileAPI::IFile* file)
|
||||
return texture;
|
||||
}
|
||||
|
||||
Texture* IwiLoader::LoadIwi(FileAPI::IFile* file)
|
||||
Texture* IwiLoader::LoadIwi(std::istream& stream)
|
||||
{
|
||||
IwiVersion iwiVersion{};
|
||||
|
||||
if (file->Read(&iwiVersion, sizeof iwiVersion, 1) != 1)
|
||||
stream.read(reinterpret_cast<char*>(&iwiVersion), sizeof iwiVersion);
|
||||
if (stream.gcount() != sizeof iwiVersion)
|
||||
return nullptr;
|
||||
|
||||
if (iwiVersion.tag[0] != 'I'
|
||||
@ -245,10 +250,10 @@ Texture* IwiLoader::LoadIwi(FileAPI::IFile* file)
|
||||
switch (iwiVersion.version)
|
||||
{
|
||||
case 8:
|
||||
return LoadIwi8(file);
|
||||
return LoadIwi8(stream);
|
||||
|
||||
case 27:
|
||||
return LoadIwi27(file);
|
||||
return LoadIwi27(stream);
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utils/FileAPI.h"
|
||||
#include <istream>
|
||||
#include "Utils/MemoryManager.h"
|
||||
#include "Image/Texture.h"
|
||||
|
||||
@ -9,13 +9,13 @@ class IwiLoader
|
||||
MemoryManager* m_memory_manager;
|
||||
|
||||
static const ImageFormat* GetFormat8(int8_t format);
|
||||
Texture* LoadIwi8(FileAPI::IFile* file);
|
||||
Texture* LoadIwi8(std::istream& stream) const;
|
||||
|
||||
static const ImageFormat* GetFormat27(int8_t format);
|
||||
Texture* LoadIwi27(FileAPI::IFile* file);
|
||||
Texture* LoadIwi27(std::istream& stream) const;
|
||||
|
||||
public:
|
||||
explicit IwiLoader(MemoryManager* memoryManager);
|
||||
|
||||
Texture* LoadIwi(FileAPI::IFile* file);
|
||||
Texture* LoadIwi(std::istream& stream);
|
||||
};
|
||||
|
@ -1,27 +1,33 @@
|
||||
#include "IPak.h"
|
||||
#include "zlib.h"
|
||||
#include "Exception/IPakLoadException.h"
|
||||
#include "ObjContainer/IPak/IPakTypes.h"
|
||||
#include "Utils/PathUtils.h"
|
||||
#include "IPakStreamManager.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
|
||||
#include "zlib.h"
|
||||
|
||||
#include "Utils/FileUtils.h"
|
||||
#include "Exception/IPakLoadException.h"
|
||||
#include "ObjContainer/IPak/IPakTypes.h"
|
||||
#include "IPakStreamManager.h"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
ObjContainerRepository<IPak, Zone> IPak::Repository;
|
||||
|
||||
class IPak::Impl : public ObjContainerReferenceable
|
||||
{
|
||||
static const uint32_t MAGIC = 'IPAK';
|
||||
static const uint32_t MAGIC = MakeMagic32('K', 'A', 'P', 'I');
|
||||
static const uint32_t VERSION = 0x50000;
|
||||
|
||||
std::string m_path;
|
||||
FileAPI::IFile* m_file;
|
||||
std::unique_ptr<std::istream> m_stream;
|
||||
|
||||
bool m_initialized;
|
||||
|
||||
IPakSection* m_index_section;
|
||||
IPakSection* m_data_section;
|
||||
std::unique_ptr<IPakSection> m_index_section;
|
||||
std::unique_ptr<IPakSection> m_data_section;
|
||||
|
||||
std::vector<IPakIndexEntry> m_index_entries;
|
||||
|
||||
@ -29,7 +35,7 @@ class IPak::Impl : public ObjContainerReferenceable
|
||||
|
||||
static uint32_t R_HashString(const char* str, uint32_t hash)
|
||||
{
|
||||
for (const char* pos = str; *pos; pos++)
|
||||
for (const auto* pos = str; *pos; pos++)
|
||||
{
|
||||
hash = 33 * hash ^ (*pos | 0x20);
|
||||
}
|
||||
@ -39,12 +45,13 @@ class IPak::Impl : public ObjContainerReferenceable
|
||||
|
||||
bool ReadIndexSection()
|
||||
{
|
||||
m_file->Goto(m_index_section->offset);
|
||||
m_stream->seekg(m_index_section->offset);
|
||||
IPakIndexEntry indexEntry{};
|
||||
|
||||
for (unsigned itemIndex = 0; itemIndex < m_index_section->itemCount; itemIndex++)
|
||||
{
|
||||
if (m_file->Read(&indexEntry, sizeof indexEntry, 1) != 1)
|
||||
m_stream->read(reinterpret_cast<char*>(&indexEntry), sizeof indexEntry);
|
||||
if (m_stream->gcount() != sizeof indexEntry)
|
||||
{
|
||||
printf("Unexpected eof when trying to load index entry %u.\n", itemIndex);
|
||||
return false;
|
||||
@ -66,7 +73,8 @@ class IPak::Impl : public ObjContainerReferenceable
|
||||
{
|
||||
IPakSection section{};
|
||||
|
||||
if (m_file->Read(§ion, sizeof section, 1) != 1)
|
||||
m_stream->read(reinterpret_cast<char*>(§ion), sizeof section);
|
||||
if (m_stream->gcount() != sizeof section)
|
||||
{
|
||||
printf("Unexpected eof when trying to load section.\n");
|
||||
return false;
|
||||
@ -75,11 +83,11 @@ class IPak::Impl : public ObjContainerReferenceable
|
||||
switch (section.type)
|
||||
{
|
||||
case 1:
|
||||
m_index_section = new IPakSection(section);
|
||||
m_index_section = std::make_unique<IPakSection>(section);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
m_data_section = new IPakSection(section);
|
||||
m_data_section = std::make_unique<IPakSection>(section);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -93,7 +101,8 @@ class IPak::Impl : public ObjContainerReferenceable
|
||||
{
|
||||
IPakHeader header{};
|
||||
|
||||
if (m_file->Read(&header, sizeof header, 1) != 1)
|
||||
m_stream->read(reinterpret_cast<char*>(&header), sizeof header);
|
||||
if (m_stream->gcount() != sizeof header)
|
||||
{
|
||||
printf("Unexpected eof when trying to load header.\n");
|
||||
return false;
|
||||
@ -136,28 +145,22 @@ class IPak::Impl : public ObjContainerReferenceable
|
||||
}
|
||||
|
||||
public:
|
||||
Impl(std::string path, FileAPI::IFile* file)
|
||||
: m_stream_manager(file)
|
||||
Impl(std::string path, std::unique_ptr<std::istream> stream)
|
||||
: m_path(std::move(path)),
|
||||
m_stream(std::move(stream)),
|
||||
m_initialized(false),
|
||||
m_index_section(nullptr),
|
||||
m_data_section(nullptr),
|
||||
m_stream_manager(*m_stream)
|
||||
{
|
||||
m_path = std::move(path);
|
||||
m_file = file;
|
||||
m_initialized = false;
|
||||
m_index_section = nullptr;
|
||||
m_data_section = nullptr;
|
||||
}
|
||||
|
||||
~Impl()
|
||||
{
|
||||
delete m_index_section;
|
||||
m_index_section = nullptr;
|
||||
|
||||
delete m_data_section;
|
||||
m_data_section = nullptr;
|
||||
}
|
||||
~Impl() override
|
||||
= default;
|
||||
|
||||
std::string GetName() override
|
||||
{
|
||||
return utils::Path::GetFilenameWithoutExtension(m_path);
|
||||
return fs::path(m_path).filename().replace_extension("").string();
|
||||
}
|
||||
|
||||
bool Initialize()
|
||||
@ -172,7 +175,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
FileAPI::IFile* GetEntryData(const Hash nameHash, const Hash dataHash)
|
||||
std::unique_ptr<iobjstream> GetEntryData(const Hash nameHash, const Hash dataHash)
|
||||
{
|
||||
IPakIndexEntryKey wantedKey{};
|
||||
wantedKey.nameHash = nameHash;
|
||||
@ -182,7 +185,7 @@ public:
|
||||
{
|
||||
if (entry.key.combinedKey == wantedKey.combinedKey)
|
||||
{
|
||||
return m_stream_manager.OpenStream(m_data_section->offset + entry.offset, entry.size);
|
||||
return m_stream_manager.OpenStream(static_cast<int64_t>(m_data_section->offset) + entry.offset, entry.size);
|
||||
}
|
||||
else if (entry.key.combinedKey > wantedKey.combinedKey)
|
||||
{
|
||||
@ -205,9 +208,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
IPak::IPak(std::string path, FileAPI::IFile* file)
|
||||
IPak::IPak(std::string path, std::unique_ptr<std::istream> stream)
|
||||
{
|
||||
m_impl = new Impl(std::move(path), file);
|
||||
m_impl = new Impl(std::move(path), std::move(stream));
|
||||
}
|
||||
|
||||
IPak::~IPak()
|
||||
@ -221,12 +224,12 @@ std::string IPak::GetName()
|
||||
return m_impl->GetName();
|
||||
}
|
||||
|
||||
bool IPak::Initialize() const
|
||||
bool IPak::Initialize()
|
||||
{
|
||||
return m_impl->Initialize();
|
||||
}
|
||||
|
||||
FileAPI::IFile* IPak::GetEntryStream(const Hash nameHash, const Hash dataHash) const
|
||||
std::unique_ptr<iobjstream> IPak::GetEntryStream(const Hash nameHash, const Hash dataHash) const
|
||||
{
|
||||
return m_impl->GetEntryData(nameHash, dataHash);
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utils/FileAPI.h"
|
||||
#include <istream>
|
||||
|
||||
#include "Utils/ClassUtils.h"
|
||||
#include "ObjContainer/ObjContainerReferenceable.h"
|
||||
#include "ObjContainer/ObjContainerRepository.h"
|
||||
#include "Utils/ObjStream.h"
|
||||
#include "Zone/Zone.h"
|
||||
|
||||
class IPak final : public ObjContainerReferenceable
|
||||
@ -15,13 +18,13 @@ public:
|
||||
|
||||
static ObjContainerRepository<IPak, Zone> Repository;
|
||||
|
||||
IPak(std::string path, FileAPI::IFile* file);
|
||||
~IPak();
|
||||
IPak(std::string path, std::unique_ptr<std::istream> stream);
|
||||
~IPak() override;
|
||||
|
||||
std::string GetName() override;
|
||||
|
||||
bool Initialize() const;
|
||||
FileAPI::IFile* GetEntryStream(Hash nameHash, Hash dataHash) const;
|
||||
bool Initialize();
|
||||
_NODISCARD std::unique_ptr<iobjstream> GetEntryStream(Hash nameHash, Hash dataHash) const;
|
||||
|
||||
static Hash HashString(const std::string& str);
|
||||
static Hash HashData(const void* data, size_t dataSize);
|
||||
|
@ -1,48 +1,47 @@
|
||||
#include "IPakEntryReadStream.h"
|
||||
#include "ObjContainer/IPak/IPakTypes.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <minilzo.h>
|
||||
|
||||
#include "ObjContainer/IPak/IPakTypes.h"
|
||||
|
||||
using namespace ipak_consts;
|
||||
|
||||
IPakEntryReadStream::IPakEntryReadStream(IFile* file, IPakStreamManagerActions* streamManagerActions,
|
||||
IPakEntryReadStream::IPakEntryReadStream(std::istream& stream, IPakStreamManagerActions* streamManagerActions,
|
||||
uint8_t* chunkBuffer, const int64_t startOffset, const size_t entrySize)
|
||||
: m_decompress_buffer{}
|
||||
: m_chunk_buffer(chunkBuffer),
|
||||
m_stream(stream),
|
||||
m_stream_manager_actions(streamManagerActions),
|
||||
m_file_offset(0),
|
||||
m_file_head(0),
|
||||
m_entry_size(entrySize),
|
||||
m_decompress_buffer{},
|
||||
m_current_block(nullptr),
|
||||
m_next_command(0),
|
||||
m_current_command_buffer(nullptr),
|
||||
m_current_command_length(0),
|
||||
m_current_command_offset(0),
|
||||
m_pos(startOffset),
|
||||
m_base_pos(startOffset),
|
||||
m_end_pos(startOffset + entrySize),
|
||||
m_buffer_start_pos(0),
|
||||
m_buffer_end_pos(0)
|
||||
{
|
||||
m_file = file;
|
||||
m_stream_manager_actions = streamManagerActions;
|
||||
m_chunk_buffer = chunkBuffer;
|
||||
|
||||
m_file_offset = 0;
|
||||
m_file_head = 0;
|
||||
m_entry_size = entrySize;
|
||||
|
||||
m_base_pos = startOffset;
|
||||
m_end_pos = startOffset + entrySize;
|
||||
m_pos = m_base_pos;
|
||||
m_buffer_start_pos = 0;
|
||||
m_buffer_end_pos = 0;
|
||||
|
||||
m_current_block = nullptr;
|
||||
m_next_command = 0;
|
||||
m_current_command_buffer = nullptr;
|
||||
m_current_command_length = 0;
|
||||
m_current_command_offset = 0;
|
||||
|
||||
lzo_init();
|
||||
}
|
||||
|
||||
IPakEntryReadStream::~IPakEntryReadStream()
|
||||
{
|
||||
Close();
|
||||
close();
|
||||
}
|
||||
|
||||
size_t IPakEntryReadStream::ReadChunks(uint8_t* buffer, const int64_t startPos, const size_t chunkCount) const
|
||||
{
|
||||
m_stream_manager_actions->StartReading();
|
||||
m_file->Goto(startPos);
|
||||
const auto readSize = m_file->Read(buffer, 1, chunkCount * IPAK_CHUNK_SIZE);
|
||||
m_stream.seekg(startPos);
|
||||
m_stream.read(reinterpret_cast<char*>(buffer), static_cast<std::streamsize>(chunkCount) * IPAK_CHUNK_SIZE);
|
||||
const auto readSize = static_cast<size_t>(m_stream.gcount());
|
||||
m_stream_manager_actions->StopReading();
|
||||
|
||||
return readSize / IPAK_CHUNK_SIZE;
|
||||
@ -66,47 +65,42 @@ bool IPakEntryReadStream::SetChunkBufferWindow(const int64_t startPos, size_t ch
|
||||
return true;
|
||||
}
|
||||
|
||||
const int64_t endPos = startPos + static_cast<int64_t>(chunkCount) * IPAK_CHUNK_SIZE;
|
||||
const auto endPos = startPos + static_cast<int64_t>(chunkCount) * IPAK_CHUNK_SIZE;
|
||||
|
||||
if (startPos >= m_buffer_start_pos && startPos < m_buffer_end_pos)
|
||||
{
|
||||
if (m_buffer_start_pos != startPos)
|
||||
{
|
||||
const int64_t moveEnd = endPos < m_buffer_end_pos ? endPos : m_buffer_end_pos;
|
||||
memmove_s(m_chunk_buffer,
|
||||
IPAK_CHUNK_SIZE * IPAK_CHUNK_COUNT_PER_READ,
|
||||
&m_chunk_buffer[startPos - m_buffer_start_pos],
|
||||
const auto moveEnd = endPos < m_buffer_end_pos ? endPos : m_buffer_end_pos;
|
||||
memmove_s(m_chunk_buffer, IPAK_CHUNK_SIZE * IPAK_CHUNK_COUNT_PER_READ, &m_chunk_buffer[startPos - m_buffer_start_pos],
|
||||
static_cast<size_t>(moveEnd - startPos));
|
||||
m_buffer_start_pos = startPos;
|
||||
}
|
||||
|
||||
if (endPos > m_buffer_end_pos)
|
||||
{
|
||||
const size_t readChunkCount = ReadChunks(&m_chunk_buffer[m_buffer_end_pos - startPos],
|
||||
m_buffer_end_pos,
|
||||
static_cast<size_t>(endPos - m_buffer_end_pos) / IPAK_CHUNK_SIZE);
|
||||
const auto readChunkCount = ReadChunks(&m_chunk_buffer[m_buffer_end_pos - startPos], m_buffer_end_pos,
|
||||
static_cast<size_t>(endPos - m_buffer_end_pos) / IPAK_CHUNK_SIZE);
|
||||
|
||||
m_buffer_end_pos += static_cast<int64_t>(readChunkCount) * IPAK_CHUNK_SIZE;
|
||||
|
||||
return m_buffer_end_pos == endPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_buffer_end_pos = endPos;
|
||||
|
||||
return true;
|
||||
}
|
||||
m_buffer_end_pos = endPos;
|
||||
return true;
|
||||
}
|
||||
else if (endPos > m_buffer_start_pos && endPos <= m_buffer_end_pos)
|
||||
|
||||
if (endPos > m_buffer_start_pos && endPos <= m_buffer_end_pos)
|
||||
{
|
||||
memmove_s(&m_chunk_buffer[m_buffer_start_pos - startPos],
|
||||
IPAK_CHUNK_SIZE * IPAK_CHUNK_COUNT_PER_READ - static_cast<size_t>(m_buffer_start_pos - startPos),
|
||||
m_chunk_buffer,
|
||||
static_cast<size_t>(endPos - m_buffer_start_pos));
|
||||
|
||||
const size_t readChunkCount = ReadChunks(m_chunk_buffer,
|
||||
startPos,
|
||||
static_cast<size_t>(m_buffer_start_pos - startPos) / IPAK_CHUNK_SIZE);
|
||||
const auto readChunkCount = ReadChunks(m_chunk_buffer,
|
||||
startPos,
|
||||
static_cast<size_t>(m_buffer_start_pos - startPos) / IPAK_CHUNK_SIZE);
|
||||
|
||||
m_buffer_start_pos = startPos;
|
||||
m_buffer_end_pos = readChunkCount == (m_buffer_start_pos - startPos) / IPAK_CHUNK_SIZE
|
||||
@ -116,9 +110,7 @@ bool IPakEntryReadStream::SetChunkBufferWindow(const int64_t startPos, size_t ch
|
||||
return m_buffer_end_pos == endPos;
|
||||
}
|
||||
|
||||
const size_t readChunkCount = ReadChunks(m_chunk_buffer,
|
||||
startPos,
|
||||
chunkCount);
|
||||
const auto readChunkCount = ReadChunks(m_chunk_buffer, startPos, chunkCount);
|
||||
|
||||
m_buffer_start_pos = startPos;
|
||||
m_buffer_end_pos = startPos + static_cast<int64_t>(readChunkCount) * IPAK_CHUNK_SIZE;
|
||||
@ -136,12 +128,12 @@ bool IPakEntryReadStream::ValidateBlockHeader(IPakDataBlockHeader* blockHeader)
|
||||
if (blockHeader->offset != m_file_head)
|
||||
{
|
||||
// A matching offset is only relevant if a command contains data.
|
||||
for(unsigned currentCommand = 0; currentCommand < blockHeader->count; currentCommand++)
|
||||
for (unsigned currentCommand = 0; currentCommand < blockHeader->count; currentCommand++)
|
||||
{
|
||||
if(blockHeader->_commands[currentCommand].compressed == 0
|
||||
if (blockHeader->_commands[currentCommand].compressed == 0
|
||||
|| blockHeader->_commands[currentCommand].compressed == 1)
|
||||
{
|
||||
printf("IPak block offset is not the file head: %u != %u -> Invalid\n", blockHeader->offset, m_file_head);
|
||||
printf("IPak block offset is not the file head: %u != %lld -> Invalid\n", blockHeader->offset, m_file_head);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -190,8 +182,8 @@ bool IPakEntryReadStream::NextBlock()
|
||||
const auto chunkStartPos = AlignBackwards<int64_t>(m_pos, IPAK_CHUNK_SIZE);
|
||||
const auto blockOffsetInChunk = static_cast<size_t>(m_pos - chunkStartPos);
|
||||
|
||||
const size_t sizeLeftToRead = m_entry_size - m_file_head;
|
||||
size_t estimatedChunksToRead = AlignForward(m_entry_size - static_cast<size_t>(m_pos - m_base_pos), IPAK_CHUNK_SIZE)
|
||||
const auto sizeLeftToRead = m_entry_size - m_file_head;
|
||||
auto estimatedChunksToRead = AlignForward(m_entry_size - static_cast<size_t>(m_pos - m_base_pos), IPAK_CHUNK_SIZE)
|
||||
/ IPAK_CHUNK_SIZE;
|
||||
|
||||
if (estimatedChunksToRead > IPAK_CHUNK_COUNT_PER_READ)
|
||||
@ -263,18 +255,29 @@ bool IPakEntryReadStream::AdvanceStream()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IPakEntryReadStream::IsOpen()
|
||||
bool IPakEntryReadStream::is_open() const
|
||||
{
|
||||
return m_file != nullptr;
|
||||
return !m_stream.eof();
|
||||
}
|
||||
|
||||
size_t IPakEntryReadStream::Read(void* buffer, const size_t elementSize, const size_t elementCount)
|
||||
bool IPakEntryReadStream::close()
|
||||
{
|
||||
auto* destBuffer = static_cast<uint8_t*>(buffer);
|
||||
const size_t bufferSize = elementCount * elementSize;
|
||||
size_t countRead = 0;
|
||||
if (is_open())
|
||||
{
|
||||
m_stream_manager_actions->CloseStream(this);
|
||||
}
|
||||
|
||||
while (countRead < bufferSize)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::streamsize IPakEntryReadStream::showmanyc()
|
||||
{
|
||||
return m_end_pos - m_pos;
|
||||
}
|
||||
|
||||
std::streambuf::int_type IPakEntryReadStream::underflow()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (m_current_command_offset >= m_current_command_length)
|
||||
{
|
||||
@ -282,68 +285,93 @@ size_t IPakEntryReadStream::Read(void* buffer, const size_t elementSize, const s
|
||||
break;
|
||||
}
|
||||
|
||||
size_t sizeToRead = bufferSize - countRead;
|
||||
if (m_current_command_length - m_current_command_offset < 1)
|
||||
continue;
|
||||
|
||||
return m_current_command_buffer[m_current_command_offset];
|
||||
}
|
||||
|
||||
return EOF;
|
||||
}
|
||||
|
||||
std::streambuf::int_type IPakEntryReadStream::uflow()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (m_current_command_offset >= m_current_command_length)
|
||||
{
|
||||
if (!AdvanceStream())
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_current_command_length - m_current_command_offset < 1)
|
||||
continue;
|
||||
|
||||
const auto result = m_current_command_buffer[m_current_command_offset];
|
||||
m_current_command_offset++;
|
||||
m_file_offset++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return EOF;
|
||||
}
|
||||
|
||||
std::streamsize IPakEntryReadStream::xsgetn(char* ptr, const std::streamsize count)
|
||||
{
|
||||
auto* destBuffer = reinterpret_cast<uint8_t*>(ptr);
|
||||
int64_t countRead = 0;
|
||||
|
||||
while (countRead < count)
|
||||
{
|
||||
if (m_current_command_offset >= m_current_command_length)
|
||||
{
|
||||
if (!AdvanceStream())
|
||||
break;
|
||||
}
|
||||
|
||||
auto sizeToRead = count - countRead;
|
||||
if (sizeToRead > m_current_command_length - m_current_command_offset)
|
||||
sizeToRead = m_current_command_length - m_current_command_offset;
|
||||
|
||||
if (sizeToRead > 0)
|
||||
{
|
||||
memcpy_s(&destBuffer[countRead], bufferSize - countRead,
|
||||
&m_current_command_buffer[m_current_command_offset], sizeToRead);
|
||||
memcpy_s(&destBuffer[countRead], static_cast<rsize_t>(count - countRead),
|
||||
&m_current_command_buffer[m_current_command_offset], static_cast<rsize_t>(sizeToRead));
|
||||
countRead += sizeToRead;
|
||||
m_current_command_offset += sizeToRead;
|
||||
m_file_offset += sizeToRead;
|
||||
}
|
||||
}
|
||||
|
||||
return countRead / elementSize;
|
||||
return countRead;
|
||||
}
|
||||
|
||||
size_t IPakEntryReadStream::Write(const void* data, size_t elementSize, size_t elementCount)
|
||||
std::streambuf::pos_type IPakEntryReadStream::seekoff(const off_type off, const std::ios_base::seekdir dir, const std::ios_base::openmode mode)
|
||||
{
|
||||
// This is not meant for writing.
|
||||
assert(false);
|
||||
throw std::runtime_error("This is not a stream for output!");
|
||||
}
|
||||
|
||||
void IPakEntryReadStream::Skip(const int64_t amount)
|
||||
{
|
||||
if (amount > 0)
|
||||
pos_type pos;
|
||||
if (dir == std::ios_base::beg)
|
||||
{
|
||||
const size_t targetOffset = m_file_offset + static_cast<size_t>(amount);
|
||||
|
||||
while (m_file_head < targetOffset)
|
||||
{
|
||||
if (!AdvanceStream())
|
||||
break;
|
||||
}
|
||||
|
||||
if (targetOffset <= m_file_head)
|
||||
{
|
||||
m_current_command_offset = m_current_command_length - (m_file_head - targetOffset);
|
||||
m_file_offset = targetOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_current_command_offset = m_current_command_length;
|
||||
m_file_offset = m_file_head;
|
||||
}
|
||||
pos = off;
|
||||
}
|
||||
else if (dir == std::ios_base::cur)
|
||||
{
|
||||
pos = off + m_file_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = -1;
|
||||
}
|
||||
|
||||
if (pos == 0 || pos > m_file_offset)
|
||||
{
|
||||
return seekpos(pos, mode);
|
||||
}
|
||||
|
||||
return std::streampos(-1);
|
||||
}
|
||||
|
||||
size_t IPakEntryReadStream::Printf(const char* fmt, ...)
|
||||
{
|
||||
// This is not meant for writing.
|
||||
assert(false);
|
||||
throw std::runtime_error("This is not a stream for output!");
|
||||
}
|
||||
|
||||
int64_t IPakEntryReadStream::Pos()
|
||||
{
|
||||
return m_file_offset;
|
||||
}
|
||||
|
||||
void IPakEntryReadStream::Goto(const int64_t pos)
|
||||
std::streambuf::pos_type IPakEntryReadStream::seekpos(const pos_type pos, std::ios_base::openmode mode)
|
||||
{
|
||||
if (pos == 0)
|
||||
{
|
||||
@ -357,34 +385,31 @@ void IPakEntryReadStream::Goto(const int64_t pos)
|
||||
m_current_command_buffer = nullptr;
|
||||
m_current_command_length = 0;
|
||||
m_current_command_offset = 0;
|
||||
}
|
||||
else if (pos > m_file_offset)
|
||||
{
|
||||
Skip(pos - m_file_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not implemented due to being too time consuming.
|
||||
// Can be added if necessary.
|
||||
assert(false);
|
||||
throw std::runtime_error("Operation not supported!");
|
||||
}
|
||||
}
|
||||
|
||||
void IPakEntryReadStream::GotoEnd()
|
||||
{
|
||||
// Not implemented due to being too time consuming.
|
||||
// Can be added if necessary.
|
||||
assert(false);
|
||||
throw std::runtime_error("Operation not supported!");
|
||||
}
|
||||
|
||||
void IPakEntryReadStream::Close()
|
||||
{
|
||||
if (IsOpen())
|
||||
{
|
||||
m_file = nullptr;
|
||||
|
||||
m_stream_manager_actions->CloseStream(this);
|
||||
return pos;
|
||||
}
|
||||
|
||||
if (pos > m_file_offset)
|
||||
{
|
||||
while (m_file_head < pos)
|
||||
{
|
||||
if (!AdvanceStream())
|
||||
break;
|
||||
}
|
||||
|
||||
if (pos <= m_file_head)
|
||||
{
|
||||
m_current_command_offset = m_current_command_length - (m_file_head - pos);
|
||||
m_file_offset = pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_current_command_offset = m_current_command_length;
|
||||
m_file_offset = m_file_head;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
return std::streampos(-1);
|
||||
}
|
||||
|
@ -1,21 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "IPakStreamManager.h"
|
||||
#include "Utils/FileAPI.h"
|
||||
#include "ObjContainer/IPak/IPakTypes.h"
|
||||
#include <mutex>
|
||||
#include <istream>
|
||||
|
||||
class IPakEntryReadStream final : public FileAPI::IFile
|
||||
#include "Utils/ObjStream.h"
|
||||
#include "IPakStreamManager.h"
|
||||
#include "ObjContainer/IPak/IPakTypes.h"
|
||||
|
||||
class IPakEntryReadStream final : public objbuf
|
||||
{
|
||||
static constexpr size_t IPAK_DECOMPRESS_BUFFER_SIZE = 0x8000;
|
||||
|
||||
uint8_t* m_chunk_buffer;
|
||||
|
||||
IFile* m_file;
|
||||
std::istream& m_stream;
|
||||
IPakStreamManagerActions* m_stream_manager_actions;
|
||||
|
||||
size_t m_file_offset;
|
||||
size_t m_file_head;
|
||||
int64_t m_file_offset;
|
||||
int64_t m_file_head;
|
||||
|
||||
size_t m_entry_size;
|
||||
|
||||
@ -53,16 +54,17 @@ class IPakEntryReadStream final : public FileAPI::IFile
|
||||
bool AdvanceStream();
|
||||
|
||||
public:
|
||||
IPakEntryReadStream(IFile* file, IPakStreamManagerActions* streamManagerActions, uint8_t* chunkBuffer, int64_t startOffset, size_t entrySize);
|
||||
IPakEntryReadStream(std::istream& stream, IPakStreamManagerActions* streamManagerActions, uint8_t* chunkBuffer, int64_t startOffset, size_t entrySize);
|
||||
~IPakEntryReadStream() override;
|
||||
|
||||
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(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;
|
||||
_NODISCARD bool is_open() const override;
|
||||
bool close() override;
|
||||
|
||||
protected:
|
||||
std::streamsize showmanyc() override;
|
||||
int_type underflow() override;
|
||||
int_type uflow() override;
|
||||
std::streamsize xsgetn(char* ptr, std::streamsize count) override;
|
||||
pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode mode) override;
|
||||
pos_type seekpos(pos_type pos, std::ios_base::openmode mode) override;
|
||||
};
|
@ -1,9 +1,11 @@
|
||||
#include "IPakStreamManager.h"
|
||||
#include "IPakEntryReadStream.h"
|
||||
#include "ObjContainer/IPak/IPakTypes.h"
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "IPakEntryReadStream.h"
|
||||
#include "ObjContainer/IPak/IPakTypes.h"
|
||||
|
||||
using namespace ipak_consts;
|
||||
|
||||
class IPakStreamManager::Impl final : public IPakStreamManagerActions
|
||||
@ -30,7 +32,7 @@ class IPakStreamManager::Impl final : public IPakStreamManagerActions
|
||||
}
|
||||
};
|
||||
|
||||
FileAPI::IFile* m_file;
|
||||
std::istream& m_stream;
|
||||
|
||||
std::mutex m_read_mutex;
|
||||
std::mutex m_stream_mutex;
|
||||
@ -39,10 +41,9 @@ class IPakStreamManager::Impl final : public IPakStreamManagerActions
|
||||
std::vector<ChunkBuffer*> m_chunk_buffers;
|
||||
|
||||
public:
|
||||
explicit Impl(FileAPI::IFile* file)
|
||||
explicit Impl(std::istream& stream)
|
||||
: m_stream(stream)
|
||||
{
|
||||
m_file = file;
|
||||
|
||||
m_chunk_buffers.push_back(new ChunkBuffer());
|
||||
}
|
||||
|
||||
@ -55,7 +56,7 @@ public:
|
||||
|
||||
for (const auto& openStream : m_open_streams)
|
||||
{
|
||||
openStream.m_stream->Close();
|
||||
openStream.m_stream->close();
|
||||
}
|
||||
m_open_streams.clear();
|
||||
|
||||
@ -65,16 +66,15 @@ public:
|
||||
Impl& operator=(const Impl& other) = delete;
|
||||
Impl& operator=(Impl&& other) noexcept = delete;
|
||||
|
||||
FileAPI::IFile* OpenStream(const int64_t startPosition, const size_t length)
|
||||
std::unique_ptr<iobjstream> OpenStream(const int64_t startPosition, const size_t length)
|
||||
{
|
||||
m_stream_mutex.lock();
|
||||
|
||||
ChunkBuffer* reservedChunkBuffer;
|
||||
const auto freeChunkBuffer = std::find_if(m_chunk_buffers.begin(), m_chunk_buffers.end(),
|
||||
[](ChunkBuffer* chunkBuffer)
|
||||
{
|
||||
return chunkBuffer->m_using_stream == nullptr;
|
||||
});
|
||||
const auto freeChunkBuffer = std::find_if(m_chunk_buffers.begin(), m_chunk_buffers.end(), [](ChunkBuffer* chunkBuffer)
|
||||
{
|
||||
return chunkBuffer->m_using_stream == nullptr;
|
||||
});
|
||||
|
||||
if (freeChunkBuffer == m_chunk_buffers.end())
|
||||
{
|
||||
@ -84,15 +84,15 @@ public:
|
||||
else
|
||||
reservedChunkBuffer = *freeChunkBuffer;
|
||||
|
||||
auto* stream = new IPakEntryReadStream(m_file, this, reservedChunkBuffer->m_buffer, startPosition, length);
|
||||
auto ipakEntryStream = std::make_unique<IPakEntryReadStream>(m_stream, this, reservedChunkBuffer->m_buffer, startPosition, length);
|
||||
|
||||
reservedChunkBuffer->m_using_stream = stream;
|
||||
reservedChunkBuffer->m_using_stream = ipakEntryStream.get();
|
||||
|
||||
m_open_streams.emplace_back(stream, reservedChunkBuffer);
|
||||
m_open_streams.emplace_back(ipakEntryStream.get(), reservedChunkBuffer);
|
||||
|
||||
m_stream_mutex.unlock();
|
||||
|
||||
return stream;
|
||||
return std::make_unique<iobjstream>(std::move(ipakEntryStream));
|
||||
}
|
||||
|
||||
void StartReading() override
|
||||
@ -105,15 +105,14 @@ public:
|
||||
m_read_mutex.unlock();
|
||||
}
|
||||
|
||||
void CloseStream(FileAPI::IFile* stream) override
|
||||
void CloseStream(objbuf* stream) override
|
||||
{
|
||||
m_stream_mutex.lock();
|
||||
|
||||
const auto openStreamEntry = std::find_if(m_open_streams.begin(), m_open_streams.end(),
|
||||
[stream](const ManagedStream& managedStream)
|
||||
{
|
||||
return managedStream.m_stream == stream;
|
||||
});
|
||||
const auto openStreamEntry = std::find_if(m_open_streams.begin(), m_open_streams.end(), [stream](const ManagedStream& managedStream)
|
||||
{
|
||||
return managedStream.m_stream == stream;
|
||||
});
|
||||
|
||||
if (openStreamEntry != m_open_streams.end())
|
||||
{
|
||||
@ -138,9 +137,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
IPakStreamManager::IPakStreamManager(FileAPI::IFile* file)
|
||||
IPakStreamManager::IPakStreamManager(std::istream& stream)
|
||||
: m_impl(new Impl(stream))
|
||||
{
|
||||
m_impl = new Impl(file);
|
||||
}
|
||||
|
||||
IPakStreamManager::~IPakStreamManager()
|
||||
@ -149,7 +148,7 @@ IPakStreamManager::~IPakStreamManager()
|
||||
m_impl = nullptr;
|
||||
}
|
||||
|
||||
FileAPI::IFile* IPakStreamManager::OpenStream(const int64_t startPosition, const size_t length) const
|
||||
std::unique_ptr<iobjstream> IPakStreamManager::OpenStream(const int64_t startPosition, const size_t length) const
|
||||
{
|
||||
return m_impl->OpenStream(startPosition, length);
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utils/FileAPI.h"
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <istream>
|
||||
|
||||
#include "Utils/ClassUtils.h"
|
||||
#include "Utils/ObjStream.h"
|
||||
|
||||
class IPakStreamManagerActions
|
||||
{
|
||||
@ -10,7 +13,7 @@ public:
|
||||
virtual void StartReading() = 0;
|
||||
virtual void StopReading() = 0;
|
||||
|
||||
virtual void CloseStream(FileAPI::IFile* stream) = 0;
|
||||
virtual void CloseStream(objbuf* stream) = 0;
|
||||
};
|
||||
|
||||
class IPakStreamManager
|
||||
@ -19,7 +22,7 @@ class IPakStreamManager
|
||||
Impl* m_impl;
|
||||
|
||||
public:
|
||||
explicit IPakStreamManager(FileAPI::IFile* file);
|
||||
explicit IPakStreamManager(std::istream& stream);
|
||||
IPakStreamManager(const IPakStreamManager& other) = delete;
|
||||
IPakStreamManager(IPakStreamManager&& other) noexcept = delete;
|
||||
~IPakStreamManager();
|
||||
@ -27,5 +30,5 @@ public:
|
||||
IPakStreamManager& operator=(const IPakStreamManager& other) = delete;
|
||||
IPakStreamManager& operator=(IPakStreamManager&& other) noexcept = delete;
|
||||
|
||||
FileAPI::IFile* OpenStream(int64_t startPosition, size_t length) const;
|
||||
_NODISCARD std::unique_ptr<iobjstream> OpenStream(int64_t startPosition, size_t length) const;
|
||||
};
|
@ -1,6 +1,5 @@
|
||||
#include "IWD.h"
|
||||
|
||||
#include "Utils/PathUtils.h"
|
||||
#include "ObjLoading.h"
|
||||
#include "Utils/FileToZlibWrapper.h"
|
||||
|
||||
@ -8,10 +7,14 @@
|
||||
#include <filesystem>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
ObjContainerRepository<IWD, ISearchPath> IWD::Repository;
|
||||
|
||||
class IWDFile final : public FileAPI::IFile
|
||||
class IWDFile final : public objbuf
|
||||
{
|
||||
public:
|
||||
class IParent
|
||||
@ -25,99 +28,135 @@ public:
|
||||
private:
|
||||
IParent* m_parent;
|
||||
bool m_open;
|
||||
size_t m_size;
|
||||
int64_t m_size;
|
||||
unzFile m_container;
|
||||
bool m_peeked;
|
||||
int_type m_peek_symbol;
|
||||
|
||||
public:
|
||||
IWDFile(IParent* parent, const unzFile container, const size_t size)
|
||||
IWDFile(IParent* parent, const unzFile container, const int64_t size)
|
||||
: m_parent(parent),
|
||||
m_open(true),
|
||||
m_size(size),
|
||||
m_container(container),
|
||||
m_peeked(false),
|
||||
m_peek_symbol(0)
|
||||
{
|
||||
m_parent = parent;
|
||||
m_container = container;
|
||||
m_size = size;
|
||||
m_open = true;
|
||||
}
|
||||
|
||||
~IWDFile() override
|
||||
{
|
||||
if(m_open)
|
||||
if (m_open)
|
||||
{
|
||||
Close();
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
bool IsOpen() override
|
||||
protected:
|
||||
int_type underflow() override
|
||||
{
|
||||
if (m_peeked)
|
||||
return m_peek_symbol;
|
||||
|
||||
const auto result = unzReadCurrentFile(m_container, &m_peek_symbol, 1u);
|
||||
|
||||
if (result >= 0)
|
||||
{
|
||||
m_peeked = true;
|
||||
return static_cast<int_type>(m_peek_symbol);
|
||||
}
|
||||
|
||||
return EOF;
|
||||
}
|
||||
|
||||
int_type uflow() override
|
||||
{
|
||||
if (m_peeked)
|
||||
{
|
||||
m_peeked = false;
|
||||
return m_peek_symbol;
|
||||
}
|
||||
|
||||
const auto result = unzReadCurrentFile(m_container, &m_peek_symbol, 1u);
|
||||
return result >= 0 ? static_cast<int_type>(m_peek_symbol) : EOF;
|
||||
}
|
||||
|
||||
std::streamsize xsgetn(char* ptr, std::streamsize count) override
|
||||
{
|
||||
if (m_peeked && count >= 1)
|
||||
{
|
||||
*ptr = static_cast<char>(m_peek_symbol);
|
||||
ptr++;
|
||||
count--;
|
||||
}
|
||||
|
||||
const auto result = unzReadCurrentFile(m_container, ptr, static_cast<unsigned>(count));
|
||||
|
||||
return result >= 0 ? static_cast<std::streamsize>(result) : 0;
|
||||
}
|
||||
|
||||
pos_type seekoff(const off_type off, const std::ios_base::seekdir dir, const std::ios_base::openmode mode) override
|
||||
{
|
||||
const auto currentPos = unztell64(m_container);
|
||||
|
||||
pos_type targetPos;
|
||||
if (dir == std::ios_base::beg)
|
||||
{
|
||||
targetPos = off;
|
||||
}
|
||||
else if (dir == std::ios_base::cur)
|
||||
{
|
||||
targetPos = currentPos + off;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetPos = m_size - off;
|
||||
}
|
||||
|
||||
return seekpos(targetPos, mode);
|
||||
}
|
||||
|
||||
pos_type seekpos(const pos_type pos, const std::ios_base::openmode mode) override
|
||||
{
|
||||
const auto currentPos = unztell64(m_container);
|
||||
|
||||
if (static_cast<pos_type>(currentPos) < pos)
|
||||
{
|
||||
auto skipAmount = pos - static_cast<pos_type>(currentPos);
|
||||
while (skipAmount > 0)
|
||||
{
|
||||
char temp[1024];
|
||||
const auto toRead = skipAmount > sizeof temp ? sizeof temp : static_cast<size_t>(skipAmount);
|
||||
unzReadCurrentFile(m_container, temp, toRead);
|
||||
skipAmount -= toRead;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
if (currentPos == pos)
|
||||
{
|
||||
// This is fine
|
||||
return currentPos;
|
||||
}
|
||||
|
||||
return std::streampos(-1);
|
||||
}
|
||||
|
||||
public:
|
||||
_NODISCARD bool is_open() const 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) / elementSize : 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
|
||||
bool close() override
|
||||
{
|
||||
unzCloseCurrentFile(m_container);
|
||||
m_open = false;
|
||||
|
||||
m_parent->OnIWDFileClose();
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@ -126,12 +165,12 @@ class IWD::Impl : public ISearchPath, public IObjContainer, public IWDFile::IPar
|
||||
class IWDEntry
|
||||
{
|
||||
public:
|
||||
size_t m_size{};
|
||||
int64_t m_size{};
|
||||
unz_file_pos m_file_pos{};
|
||||
};
|
||||
|
||||
std::string m_path;
|
||||
FileAPI::IFile* m_file;
|
||||
std::unique_ptr<std::istream> m_stream;
|
||||
unzFile m_unz_file;
|
||||
|
||||
IWDFile* m_last_file;
|
||||
@ -139,12 +178,12 @@ class IWD::Impl : public ISearchPath, public IObjContainer, public IWDFile::IPar
|
||||
std::map<std::string, IWDEntry> m_entry_map;
|
||||
|
||||
public:
|
||||
Impl(std::string path, FileAPI::IFile* file)
|
||||
Impl(std::string path, std::unique_ptr<std::istream> stream)
|
||||
: m_path(std::move(path)),
|
||||
m_stream(std::move(stream)),
|
||||
m_unz_file(nullptr),
|
||||
m_last_file(nullptr)
|
||||
{
|
||||
m_unz_file = nullptr;
|
||||
m_path = std::move(path);
|
||||
m_file = file;
|
||||
m_last_file = nullptr;
|
||||
}
|
||||
|
||||
~Impl() override
|
||||
@ -152,13 +191,7 @@ public:
|
||||
if (m_unz_file != nullptr)
|
||||
{
|
||||
unzClose(m_unz_file);
|
||||
}
|
||||
|
||||
if (m_file)
|
||||
{
|
||||
m_file->Close();
|
||||
delete m_file;
|
||||
m_file = nullptr;
|
||||
m_unz_file = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,7 +202,7 @@ public:
|
||||
|
||||
bool Initialize()
|
||||
{
|
||||
auto ioFunctions = FileToZlibWrapper::CreateFunctions32ForFile(m_file);
|
||||
auto ioFunctions = FileToZlibWrapper::CreateFunctions32ForFile(m_stream.get());
|
||||
m_unz_file = unzOpen2("", &ioFunctions);
|
||||
|
||||
if (m_unz_file == nullptr)
|
||||
@ -181,9 +214,9 @@ public:
|
||||
auto ret = unzGoToFirstFile(m_unz_file);
|
||||
while (ret == Z_OK)
|
||||
{
|
||||
unz_file_info info;
|
||||
unz_file_info64 info;
|
||||
char fileNameBuffer[256];
|
||||
unzGetCurrentFileInfo(m_unz_file, &info, fileNameBuffer, sizeof fileNameBuffer, nullptr, 0, nullptr, 0);
|
||||
unzGetCurrentFileInfo64(m_unz_file, &info, fileNameBuffer, sizeof fileNameBuffer, nullptr, 0, nullptr, 0);
|
||||
|
||||
std::string fileName(fileNameBuffer);
|
||||
std::filesystem::path path(fileName);
|
||||
@ -207,21 +240,21 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
FileAPI::IFile* Open(const std::string& fileName) override
|
||||
std::unique_ptr<std::istream> Open(const std::string& fileName) override
|
||||
{
|
||||
if (m_unz_file == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string iwdFilename = fileName;
|
||||
auto iwdFilename = fileName;
|
||||
std::replace(iwdFilename.begin(), iwdFilename.end(), '\\', '/');
|
||||
|
||||
const auto iwdEntry = m_entry_map.find(iwdFilename);
|
||||
|
||||
if (iwdEntry != m_entry_map.end())
|
||||
{
|
||||
if(m_last_file != nullptr)
|
||||
if (m_last_file != nullptr)
|
||||
{
|
||||
throw std::runtime_error("Trying to open new IWD file while last one was not yet closed.");
|
||||
}
|
||||
@ -231,10 +264,12 @@ public:
|
||||
|
||||
if (unzOpenCurrentFile(m_unz_file) == UNZ_OK)
|
||||
{
|
||||
m_last_file = new IWDFile(this, m_unz_file, iwdEntry->second.m_size);
|
||||
auto result = std::make_unique<IWDFile>(this, m_unz_file, iwdEntry->second.m_size);
|
||||
m_last_file = result.get();
|
||||
return std::make_unique<iobjstream>(std::move(result));
|
||||
}
|
||||
|
||||
return m_last_file;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -247,24 +282,24 @@ public:
|
||||
|
||||
std::string GetName() override
|
||||
{
|
||||
return utils::Path::GetFilename(m_path);
|
||||
return fs::path(m_path).filename().string();
|
||||
}
|
||||
|
||||
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override
|
||||
{
|
||||
if(options.m_disk_files_only)
|
||||
if (options.m_disk_files_only)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for(auto& [entryName, entry] : m_entry_map)
|
||||
for (auto& [entryName, entry] : m_entry_map)
|
||||
{
|
||||
std::filesystem::path entryPath(entryName);
|
||||
|
||||
if(!options.m_should_include_subdirectories && entryPath.has_parent_path())
|
||||
if (!options.m_should_include_subdirectories && entryPath.has_parent_path())
|
||||
continue;
|
||||
|
||||
if(options.m_filter_extensions && options.m_extension != entryPath.extension().string())
|
||||
if (options.m_filter_extensions && options.m_extension != entryPath.extension().string())
|
||||
continue;
|
||||
|
||||
callback(entryName);
|
||||
@ -277,9 +312,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
IWD::IWD(std::string path, FileAPI::IFile* file)
|
||||
IWD::IWD(std::string path, std::unique_ptr<std::istream> stream)
|
||||
{
|
||||
m_impl = new Impl(std::move(path), file);
|
||||
m_impl = new Impl(std::move(path), std::move(stream));
|
||||
}
|
||||
|
||||
IWD::~IWD()
|
||||
@ -302,12 +337,12 @@ IWD& IWD::operator=(IWD&& other) noexcept
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IWD::Initialize() const
|
||||
bool IWD::Initialize()
|
||||
{
|
||||
return m_impl->Initialize();
|
||||
}
|
||||
|
||||
FileAPI::IFile* IWD::Open(const std::string& fileName)
|
||||
std::unique_ptr<std::istream> IWD::Open(const std::string& fileName)
|
||||
{
|
||||
return m_impl->Open(fileName);
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "Utils/ClassUtils.h"
|
||||
#include "Utils/ObjStream.h"
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
#include "ObjContainer/ObjContainerRepository.h"
|
||||
|
||||
@ -11,7 +15,7 @@ class IWD final : public ISearchPath, IObjContainer
|
||||
public:
|
||||
static ObjContainerRepository<IWD, ISearchPath> Repository;
|
||||
|
||||
IWD(std::string path, FileAPI::IFile* file);
|
||||
IWD(std::string path, std::unique_ptr<std::istream> stream);
|
||||
~IWD();
|
||||
|
||||
IWD(const IWD& other) = delete;
|
||||
@ -23,9 +27,9 @@ public:
|
||||
* \brief Initializes the IWD container.
|
||||
* \return \c true when initialization was successful.
|
||||
*/
|
||||
bool Initialize() const;
|
||||
bool Initialize();
|
||||
|
||||
FileAPI::IFile* Open(const std::string& fileName) override;
|
||||
std::unique_ptr<std::istream> Open(const std::string& fileName) override;
|
||||
std::string GetPath() override;
|
||||
std::string GetName() override;
|
||||
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
|
||||
template <typename ContainerType, typename ReferencerType>
|
||||
class ObjContainerRepository
|
||||
@ -14,51 +15,67 @@ class ObjContainerRepository
|
||||
class ObjContainerEntry
|
||||
{
|
||||
public:
|
||||
ContainerType* m_container;
|
||||
std::unique_ptr<ContainerType> m_container;
|
||||
std::set<ReferencerType*> m_references;
|
||||
|
||||
explicit ObjContainerEntry(ContainerType* container)
|
||||
explicit ObjContainerEntry(std::unique_ptr<ContainerType> container)
|
||||
: m_container(std::move(container))
|
||||
{
|
||||
m_container = container;
|
||||
}
|
||||
|
||||
~ObjContainerEntry() = default;
|
||||
ObjContainerEntry(const ObjContainerEntry& other) = delete;
|
||||
ObjContainerEntry(ObjContainerEntry&& other) noexcept = default;
|
||||
ObjContainerEntry& operator=(const ObjContainerEntry& other) = delete;
|
||||
ObjContainerEntry& operator=(ObjContainerEntry&& other) noexcept = default;
|
||||
};
|
||||
|
||||
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;
|
||||
});
|
||||
ObjContainerRepository() = default;
|
||||
~ObjContainerRepository() = default;
|
||||
ObjContainerRepository(const ObjContainerRepository& other) = delete;
|
||||
ObjContainerRepository(ObjContainerRepository&& other) noexcept = default;
|
||||
ObjContainerRepository& operator=(const ObjContainerRepository& other) = delete;
|
||||
ObjContainerRepository& operator=(ObjContainerRepository&& other) noexcept = default;
|
||||
|
||||
if(firstEntry != m_containers.end())
|
||||
void AddContainer(std::unique_ptr<ContainerType> container, ReferencerType* referencer)
|
||||
{
|
||||
ObjContainerEntry entry(std::move(container));
|
||||
entry.m_references.insert(referencer);
|
||||
m_containers.emplace_back(std::move(entry));
|
||||
}
|
||||
|
||||
bool AddContainerReference(ContainerType* container, ReferencerType* referencer)
|
||||
{
|
||||
auto firstEntry = std::find_if(m_containers.begin(), m_containers.end(), [container](const ObjContainerEntry& entry)
|
||||
{
|
||||
return entry.m_container.get() == container;
|
||||
});
|
||||
|
||||
if (firstEntry != m_containers.end())
|
||||
{
|
||||
firstEntry->m_references.insert(referencer);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
ObjContainerEntry entry(container);
|
||||
entry.m_references.insert(referencer);
|
||||
m_containers.push_back(entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
void RemoveContainerReferences(ReferencerType* referencer)
|
||||
{
|
||||
for(auto iEntry = m_containers.begin(); iEntry != m_containers.end();)
|
||||
for (auto iEntry = m_containers.begin(); iEntry != m_containers.end();)
|
||||
{
|
||||
auto foundReference = iEntry->m_references.find(referencer);
|
||||
|
||||
if(foundReference != iEntry->m_references.end())
|
||||
if (foundReference != iEntry->m_references.end())
|
||||
{
|
||||
iEntry->m_references.erase(foundReference);
|
||||
}
|
||||
|
||||
if(iEntry->m_references.empty())
|
||||
if (iEntry->m_references.empty())
|
||||
{
|
||||
delete iEntry->m_container;
|
||||
iEntry = m_containers.erase(iEntry);
|
||||
}
|
||||
else
|
||||
@ -70,14 +87,14 @@ public:
|
||||
|
||||
ContainerType* 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())
|
||||
auto foundEntry = std::find_if(m_containers.begin(), m_containers.end(), [name](ObjContainerEntry& entry)
|
||||
{
|
||||
return foundEntry->m_container;
|
||||
return entry.m_container->GetName() == name;
|
||||
});
|
||||
|
||||
if (foundEntry != m_containers.end())
|
||||
{
|
||||
return foundEntry->m_container.get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -86,12 +103,12 @@ public:
|
||||
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; });
|
||||
m_containers.begin(), [](ObjContainerEntry& entry) { return entry.m_container.get(); });
|
||||
}
|
||||
|
||||
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; });
|
||||
m_containers.end(), [](ObjContainerEntry& entry){ return entry.m_container.get(); });
|
||||
}
|
||||
};
|
||||
|
@ -1,9 +1,13 @@
|
||||
#include "ObjLoading.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "IObjLoader.h"
|
||||
#include "Game/IW4/ObjLoaderIW4.h"
|
||||
#include "Game/T6/ObjLoaderT6.h"
|
||||
#include "ObjContainer/IWD/IWD.h"
|
||||
#include "SearchPath/SearchPaths.h"
|
||||
#include "Utils/ObjFileStream.h"
|
||||
|
||||
ObjLoading::Configuration_t ObjLoading::Configuration;
|
||||
|
||||
@ -51,29 +55,20 @@ void ObjLoading::UnloadContainersOfZone(Zone* zone)
|
||||
|
||||
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);
|
||||
searchPath->Find(SearchPathSearchOptions().IncludeSubdirectories(false).FilterExtensions("iwd"), [searchPath](const std::string& path)
|
||||
{
|
||||
auto file = std::make_unique<std::ifstream>(path, std::fstream::in | std::fstream::binary);
|
||||
|
||||
if (file.IsOpen())
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (file->is_open())
|
||||
{
|
||||
auto iwd = std::make_unique<IWD>(path, std::move(file));
|
||||
|
||||
if (iwd->Initialize())
|
||||
{
|
||||
IWD::Repository.AddContainer(std::move(iwd), searchPath);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ObjLoading::UnloadIWDsInSearchPath(ISearchPath* searchPath)
|
||||
|
@ -1,8 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "SearchPathSearchOptions.h"
|
||||
#include "Utils/FileAPI.h"
|
||||
#include <functional>
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
|
||||
#include "Utils/ObjStream.h"
|
||||
#include "SearchPathSearchOptions.h"
|
||||
|
||||
class ISearchPath
|
||||
{
|
||||
@ -14,7 +17,7 @@ public:
|
||||
* \param fileName The relative path to the file to open.
|
||||
* \return A pointer to an \c IFile object to read the found file or \c nullptr when no file could be found.
|
||||
*/
|
||||
virtual FileAPI::IFile* Open(const std::string& fileName) = 0;
|
||||
virtual std::unique_ptr<std::istream> Open(const std::string& fileName) = 0;
|
||||
|
||||
/**
|
||||
* \brief Returns the path to the search path.
|
||||
|
@ -1,7 +1,11 @@
|
||||
#include "SearchPathFilesystem.h"
|
||||
#include "Utils/PathUtils.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
#include "Utils/ObjFileStream.h"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
SearchPathFilesystem::SearchPathFilesystem(std::string path)
|
||||
{
|
||||
@ -13,20 +17,19 @@ std::string SearchPathFilesystem::GetPath()
|
||||
return m_path;
|
||||
}
|
||||
|
||||
FileAPI::IFile* SearchPathFilesystem::Open(const std::string& fileName)
|
||||
std::unique_ptr<std::istream> SearchPathFilesystem::Open(const std::string& fileName)
|
||||
{
|
||||
FileAPI::File file = FileAPI::Open(utils::Path::Combine(m_path, fileName), FileAPI::Mode::MODE_READ);
|
||||
auto file = std::make_unique<std::ifstream>(fs::path(m_path).append(fileName).string(), std::fstream::in | std::fstream::binary);
|
||||
|
||||
if (file.IsOpen())
|
||||
if (file->is_open())
|
||||
{
|
||||
return new FileAPI::File(std::move(file));
|
||||
return std::move(file);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SearchPathFilesystem::Find(const SearchPathSearchOptions& options,
|
||||
const std::function<void(const std::string&)>& callback)
|
||||
void SearchPathFilesystem::Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "ISearchPath.h"
|
||||
#include <string>
|
||||
|
||||
#include "ISearchPath.h"
|
||||
|
||||
class SearchPathFilesystem final : public ISearchPath
|
||||
{
|
||||
std::string m_path;
|
||||
@ -10,7 +11,7 @@ class SearchPathFilesystem final : public ISearchPath
|
||||
public:
|
||||
explicit SearchPathFilesystem(std::string path);
|
||||
|
||||
FileAPI::IFile* Open(const std::string& fileName) override;
|
||||
std::unique_ptr<std::istream> Open(const std::string& fileName) override;
|
||||
std::string GetPath() override;
|
||||
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
|
||||
};
|
@ -5,15 +5,7 @@
|
||||
SearchPaths::SearchPaths() = default;
|
||||
|
||||
SearchPaths::~SearchPaths()
|
||||
{
|
||||
for(auto searchPathToFree : m_to_free)
|
||||
{
|
||||
delete searchPathToFree;
|
||||
}
|
||||
m_to_free.clear();
|
||||
|
||||
m_search_paths.clear();
|
||||
}
|
||||
= default;
|
||||
|
||||
SearchPaths::SearchPaths(const SearchPaths& other)
|
||||
: m_search_paths(other.m_search_paths)
|
||||
@ -41,15 +33,15 @@ SearchPaths& SearchPaths::operator=(SearchPaths&& other) noexcept
|
||||
return *this;
|
||||
}
|
||||
|
||||
FileAPI::IFile* SearchPaths::Open(const std::string& fileName)
|
||||
std::unique_ptr<std::istream> SearchPaths::Open(const std::string& fileName)
|
||||
{
|
||||
for(auto searchPathEntry : m_search_paths)
|
||||
for(auto* searchPathEntry : m_search_paths)
|
||||
{
|
||||
auto* file = searchPathEntry->Open(fileName);
|
||||
auto file = searchPathEntry->Open(fileName);
|
||||
|
||||
if(file != nullptr)
|
||||
if(file)
|
||||
{
|
||||
return file;
|
||||
return std::move(file);
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,16 +55,16 @@ std::string SearchPaths::GetPath()
|
||||
|
||||
void SearchPaths::Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback)
|
||||
{
|
||||
for (auto searchPathEntry : m_search_paths)
|
||||
for (auto* searchPathEntry : m_search_paths)
|
||||
{
|
||||
searchPathEntry->Find(options, callback);
|
||||
}
|
||||
}
|
||||
|
||||
void SearchPaths::CommitSearchPath(ISearchPath* searchPath)
|
||||
void SearchPaths::CommitSearchPath(std::unique_ptr<ISearchPath> searchPath)
|
||||
{
|
||||
m_search_paths.push_back(searchPath);
|
||||
m_to_free.push_back(searchPath);
|
||||
m_search_paths.push_back(searchPath.get());
|
||||
m_owned_search_paths.emplace_back(std::move(searchPath));
|
||||
}
|
||||
|
||||
void SearchPaths::IncludeSearchPath(ISearchPath* searchPath)
|
||||
|
@ -1,12 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "ISearchPath.h"
|
||||
#include <vector>
|
||||
|
||||
#include "ISearchPath.h"
|
||||
|
||||
class SearchPaths final : public ISearchPath
|
||||
{
|
||||
std::vector<ISearchPath*> m_search_paths;
|
||||
std::vector<ISearchPath*> m_to_free;
|
||||
std::vector<std::unique_ptr<ISearchPath>> m_owned_search_paths;
|
||||
|
||||
public:
|
||||
using iterator = std::vector<ISearchPath*>::iterator;
|
||||
@ -14,7 +15,7 @@ public:
|
||||
SearchPaths();
|
||||
~SearchPaths() override;
|
||||
|
||||
FileAPI::IFile* Open(const std::string& fileName) override;
|
||||
std::unique_ptr<std::istream> Open(const std::string& fileName) override;
|
||||
std::string GetPath() override;
|
||||
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
|
||||
|
||||
@ -27,7 +28,7 @@ public:
|
||||
* \brief Adds a search path that gets deleted upon destruction of the \c SearchPaths object.
|
||||
* \param searchPath The search path to add.
|
||||
*/
|
||||
void CommitSearchPath(ISearchPath* searchPath);
|
||||
void CommitSearchPath(std::unique_ptr<ISearchPath> searchPath);
|
||||
|
||||
/**
|
||||
* \brief Adds a search path that does \b NOT get deleted upon destruction of the \c SearchPaths object.
|
||||
|
Reference in New Issue
Block a user