Replace FileAPI with c++ streams and std::filesystem

This commit is contained in:
Jan 2021-03-03 14:04:35 +01:00
parent b6b0a57232
commit 1cd06668e0
96 changed files with 1355 additions and 1061 deletions

View File

@ -103,6 +103,11 @@ workspace "OpenAssetTools"
} }
filter {} filter {}
defines {
"__STDC_LIB_EXT1__",
"__STDC_WANT_LIB_EXT1__=1"
}
-- ======================== -- ========================
-- ThirdParty -- ThirdParty
-- ======================== -- ========================

View File

@ -1,49 +1,74 @@
#include "FileToZlibWrapper.h" #include "FileToZlibWrapper.h"
#include <cassert> #include <cassert>
#include <fstream>
voidpf Wrapper_Zlib_FileOpen(voidpf opaque, const char*, int) voidpf Wrapper_Zlib_FileOpen(voidpf opaque, const char*, int)
{ {
return opaque; return opaque;
} }
uLong Wrapper_Zlib_FileRead(voidpf, voidpf stream, void* buf, const uLong size) template<typename T>
uLong Wrapper_Zlib_FileRead(voidpf opaque, voidpf stream, void* buf, const uLong size)
{ {
auto* file = reinterpret_cast<FileAPI::IFile*>(stream); auto* file = static_cast<T*>(stream);
return file->Read(buf, 1, size); file->read(static_cast<char*>(buf), size);
return static_cast<uLong>(file->gcount());
} }
uLong Wrapper_Zlib_NoFileRead(voidpf opaque, voidpf stream, void* buf, const uLong size)
{
return 0;
}
template<typename T>
uLong Wrapper_Zlib_FileWrite(voidpf opaque, voidpf stream, const void* buf, const uLong size) uLong Wrapper_Zlib_FileWrite(voidpf opaque, voidpf stream, const void* buf, const uLong size)
{ {
auto* file = reinterpret_cast<FileAPI::IFile*>(stream); auto* file = static_cast<T*>(stream);
file->write(static_cast<const char*>(buf), size);
return file->Write(buf, 1, size); return size;
} }
long Wrapper_Zlib_FileTell(voidpf opaque, voidpf stream) uLong Wrapper_Zlib_NoFileWrite(voidpf opaque, voidpf stream, const void* buf, const uLong size)
{ {
auto* file = reinterpret_cast<FileAPI::IFile*>(stream); return 0;
return static_cast<long>(file->Pos());
} }
long Wrapper_Zlib_FileSeek(voidpf opaque, voidpf stream, const uLong offset, const int origin) template<typename T>
long Wrapper_Zlib_FileTellRead(voidpf opaque, voidpf stream)
{ {
auto* file = reinterpret_cast<FileAPI::IFile*>(stream); auto* file = static_cast<T*>(stream);
return static_cast<long>(file->tellg());
}
template<typename T>
long Wrapper_Zlib_FileTellWrite(voidpf opaque, voidpf stream)
{
auto* file = static_cast<T*>(stream);
return static_cast<long>(file->tellp());
}
template<typename T>
long Wrapper_Zlib_FileSeekRead(voidpf opaque, voidpf stream, const uLong offset, const int origin)
{
auto* file = static_cast<T*>(stream);
switch (origin) switch (origin)
{ {
case ZLIB_FILEFUNC_SEEK_CUR: case ZLIB_FILEFUNC_SEEK_CUR:
file->Skip(offset); file->seekg(offset, SEEK_CUR);
break; break;
case ZLIB_FILEFUNC_SEEK_END: case ZLIB_FILEFUNC_SEEK_END:
assert(offset == 0); file->seekg(offset, SEEK_END);
file->GotoEnd();
break; break;
case ZLIB_FILEFUNC_SEEK_SET: case ZLIB_FILEFUNC_SEEK_SET:
file->Goto(offset); file->seekg(offset, SEEK_SET);
break; break;
default: default:
@ -53,17 +78,45 @@ long Wrapper_Zlib_FileSeek(voidpf opaque, voidpf stream, const uLong offset, con
return 0; return 0;
} }
int Wrapper_Zlib_FileClose(voidpf opaque, voidpf stream) template<typename T>
long Wrapper_Zlib_FileSeekWrite(voidpf opaque, voidpf stream, const uLong offset, const int origin)
{ {
auto* file = reinterpret_cast<FileAPI::IFile*>(stream); auto* file = static_cast<T*>(stream);
if (file->IsOpen()) switch (origin)
{ {
file->Close(); case ZLIB_FILEFUNC_SEEK_CUR:
return 0; file->seekp(offset, SEEK_CUR);
break;
case ZLIB_FILEFUNC_SEEK_END:
file->seekp(offset, SEEK_END);
break;
case ZLIB_FILEFUNC_SEEK_SET:
file->seekp(offset, SEEK_SET);
break;
default:
return -1;
} }
return -1; return 0;
}
template<typename T>
int Wrapper_Zlib_FileClose(voidpf opaque, voidpf stream)
{
return 0;
// auto* file = static_cast<T*>(stream);
//
// if (file->is_open())
// {
// file->close();
// return 0;
// }
//
// return -1;
} }
int Wrapper_Zlib_FileError(voidpf opaque, voidpf stream) int Wrapper_Zlib_FileError(voidpf opaque, voidpf stream)
@ -71,17 +124,47 @@ int Wrapper_Zlib_FileError(voidpf opaque, voidpf stream)
return 0; return 0;
} }
zlib_filefunc_def FileToZlibWrapper::CreateFunctions32ForFile(FileAPI::IFile* file) zlib_filefunc_def FileToZlibWrapper::CreateFunctions32ForFile(std::iostream* stream)
{ {
return zlib_filefunc_def_s return zlib_filefunc_def_s
{ {
Wrapper_Zlib_FileOpen, Wrapper_Zlib_FileOpen,
Wrapper_Zlib_FileRead, Wrapper_Zlib_FileRead<std::iostream>,
Wrapper_Zlib_FileWrite, Wrapper_Zlib_FileWrite<std::iostream>,
Wrapper_Zlib_FileTell, Wrapper_Zlib_FileTellRead<std::iostream>,
Wrapper_Zlib_FileSeek, Wrapper_Zlib_FileSeekRead<std::iostream>,
Wrapper_Zlib_FileClose, Wrapper_Zlib_FileClose<std::iostream>,
Wrapper_Zlib_FileError, Wrapper_Zlib_FileError,
file stream
};
}
zlib_filefunc_def FileToZlibWrapper::CreateFunctions32ForFile(std::istream* stream)
{
return zlib_filefunc_def_s
{
Wrapper_Zlib_FileOpen,
Wrapper_Zlib_FileRead<std::istream>,
Wrapper_Zlib_NoFileWrite,
Wrapper_Zlib_FileTellRead<std::istream>,
Wrapper_Zlib_FileSeekRead<std::istream>,
Wrapper_Zlib_FileClose<std::istream>,
Wrapper_Zlib_FileError,
stream
};
}
zlib_filefunc_def FileToZlibWrapper::CreateFunctions32ForFile(std::ostream* stream)
{
return zlib_filefunc_def_s
{
Wrapper_Zlib_FileOpen,
Wrapper_Zlib_NoFileRead,
Wrapper_Zlib_FileWrite<std::ostream>,
Wrapper_Zlib_FileTellWrite<std::ostream>,
Wrapper_Zlib_FileSeekWrite<std::ostream>,
Wrapper_Zlib_FileClose<std::ostream>,
Wrapper_Zlib_FileError,
stream
}; };
} }

View File

@ -1,10 +1,16 @@
#pragma once #pragma once
#include <ioapi.h> #include <ioapi.h>
#include "Utils/FileAPI.h" #include <iostream>
#include <istream>
#include <ostream>
#include "ObjStream.h"
class FileToZlibWrapper class FileToZlibWrapper
{ {
public: public:
static zlib_filefunc_def CreateFunctions32ForFile(FileAPI::IFile* file); static zlib_filefunc_def CreateFunctions32ForFile(std::iostream* stream);
static zlib_filefunc_def CreateFunctions32ForFile(std::istream* stream);
static zlib_filefunc_def CreateFunctions32ForFile(std::ostream* stream);
}; };

View File

@ -0,0 +1,103 @@
// ReSharper disable CppHidingFunction
// ReSharper disable IdentifierTypo
// ReSharper disable CppInconsistentNaming
#pragma once
// #include <fstream>
//
// #include "ObjStream.h"
//
// template <class Elem, class Traits>
// class basic_fobjbuf final : public basic_objbuf<Elem, Traits>, public std::basic_filebuf<Elem, Traits>
// {
// public:
// using myfb = std::basic_filebuf<Elem, Traits>;
//
// explicit basic_fobjbuf(myfb* fb)
// {
// m_fb.swap(*fb);
// }
//
// _NODISCARD bool is_open() const override
// {
// return m_fb.is_open();
// }
//
// bool close() override
// {
// return m_fb.close();
// }
//
// private:
// myfb m_fb;
// };
//
// template <class Elem, class Traits>
// class basic_fobjstream final : public basic_objstream<Elem, Traits>
// {
// public:
// using mybase = basic_objstream<Elem, Traits>;
// using myfb = basic_fobjbuf<Elem, Traits>;
//
// using mybase::m_ob;
//
// explicit basic_fobjstream(std::fstream&& stream)
// : mybase(std::make_unique<myfb>(std::move(*stream.rdbuf())))
// {
// // reinterpret_cast<myfb*>(m_ob.get())->swapp(*stream.rdbuf());
// // reinterpret_cast<myfb*>(m_ob.get())->swap(*stream.rdbuf());
// }
//
// basic_fobjstream(const basic_fobjstream& other) = delete;
// basic_fobjstream(basic_fobjstream&& other) noexcept = default;
// basic_fobjstream& operator=(const basic_fobjstream& other) = delete;
// basic_fobjstream& operator=(basic_fobjstream&& other) noexcept = default;
// };
//
// template <class Elem, class Traits>
// class basic_ifobjstream final : public basic_iobjstream<Elem, Traits>
// {
// public:
// using mybase = basic_iobjstream<Elem, Traits>;
// using myfb = basic_fobjbuf<Elem, Traits>;
//
// using mybase::m_ob;
//
// explicit basic_ifobjstream(std::ifstream&& stream)
// : mybase(std::make_unique<myfb>(std::move(*stream.rdbuf())))
// {
// // reinterpret_cast<myfb*>(m_ob.get())->swapp(*stream.rdbuf());
// // m_ob->swapp(*stream.rdbuf());
// }
// ~basic_ifobjstream() = default;
//
// basic_ifobjstream(const basic_ifobjstream& other) = delete;
// basic_ifobjstream(basic_ifobjstream&& other) noexcept = default;
// basic_ifobjstream& operator=(const basic_ifobjstream& other) = delete;
// basic_ifobjstream& operator=(basic_ifobjstream&& other) noexcept = default;
// };
//
// template <class Elem, class Traits>
// class basic_ofobjstream final : public basic_oobjstream<Elem, Traits>
// {
// public:
// using mybase = basic_oobjstream<Elem, Traits>;
// using myfb = basic_fobjbuf<Elem, Traits>;
//
// using mybase::m_ob;
//
// explicit basic_ofobjstream(std::ofstream file)
// : mybase(std::make_unique<myfb>(file.rdbuf()))
// {
// }
//
// basic_ofobjstream(const basic_ofobjstream& other) = delete;
// basic_ofobjstream(basic_ofobjstream&& other) noexcept = default;
// basic_ofobjstream& operator=(const basic_ofobjstream& other) = delete;
// basic_ofobjstream& operator=(basic_ofobjstream&& other) noexcept = default;
// };
//
// using fobjbuf = basic_fobjbuf<char, std::char_traits<char>>;
// using fobjstream = basic_fobjstream<char, std::char_traits<char>>;
// using ifobjstream = basic_ifobjstream<char, std::char_traits<char>>;
// using ofobjstream = basic_ofobjstream<char, std::char_traits<char>>;

View File

@ -0,0 +1,222 @@
// ReSharper disable CppInconsistentNaming
// ReSharper disable IdentifierTypo
#pragma once
#include <cassert>
#include "Utils/ClassUtils.h"
#include <streambuf>
#include <iostream>
#include <memory>
template <class Elem, class Traits>
class basic_objbuf : public std::basic_streambuf<Elem, Traits>
{
public:
_NODISCARD virtual bool is_open() const = 0;
virtual bool close() = 0;
};
template <class Elem, class Traits>
class basic_objstream : public std::basic_iostream<Elem, Traits>
{
public:
using mybase = std::basic_iostream<Elem, Traits>;
using myob = basic_objbuf<Elem, Traits>;
using myios = std::basic_ios<Elem, Traits>;
explicit basic_objstream(std::unique_ptr<myob> objbuf)
: std::basic_iostream<Elem, Traits>(objbuf.get()),
m_ob(std::move(objbuf))
{
assert(m_ob);
}
explicit basic_objstream(basic_objstream<Elem, Traits>&& right) noexcept
: std::basic_iostream<Elem, Traits>(right),
m_ob(std::move(right.m_ob))
{
assert(m_ob != nullptr);
}
basic_objstream(const basic_objstream& other) = delete;
basic_objstream& operator=(const basic_objstream& other) = delete;
~basic_objstream() override
{
if(m_ob)
m_ob->close();
}
void swap(basic_objstream& right) noexcept
{
if (this != _STD addressof(right))
{
mybase::swap(right);
m_ob = std::move(right.m_ob);
}
}
basic_objstream& operator=(basic_objstream&& other) noexcept
{
swap(other);
return *this;
}
// ReSharper disable once CppHidingFunction
_NODISCARD myob* rdbuf() const
{
return const_cast<myob*>(m_ob.get());
}
_NODISCARD bool is_open() const
{
return m_ob->is_open();
}
void close()
{
if (!m_ob->close())
{
myios::setstate(std::ios_base::failbit);
}
}
protected:
std::unique_ptr<myob> m_ob;
};
template <class Elem, class Traits>
class basic_iobjstream : public std::basic_istream<Elem, Traits>
{
public:
using mybase = std::basic_istream<Elem, Traits>;
using myob = basic_objbuf<Elem, Traits>;
using myios = std::basic_ios<Elem, Traits>;
explicit basic_iobjstream(std::unique_ptr<myob> objbuf)
: std::basic_istream<Elem, Traits>(objbuf.get()),
m_ob(std::move(objbuf))
{
assert(m_ob);
}
explicit basic_iobjstream(basic_iobjstream<Elem, Traits>&& right) noexcept
: std::basic_istream<Elem, Traits>(right),
m_ob(std::move(right.m_ob))
{
assert(m_ob != nullptr);
}
basic_iobjstream(const basic_iobjstream& other) = delete;
basic_iobjstream& operator=(const basic_iobjstream& other) = delete;
~basic_iobjstream() override = default;
void swap(basic_iobjstream& right) noexcept
{
if (this != _STD addressof(right))
{
mybase::swap(right);
m_ob = std::move(right.m_ob);
}
}
basic_iobjstream& operator=(basic_iobjstream&& other) noexcept
{
swap(other);
return *this;
}
// ReSharper disable once CppHidingFunction
_NODISCARD myob* rdbuf() const
{
return const_cast<myob*>(m_ob.get());
}
_NODISCARD bool is_open() const
{
return m_ob->is_open();
}
void close()
{
if (!m_ob->close())
{
myios::setstate(std::ios_base::failbit);
}
}
protected:
std::unique_ptr<myob> m_ob;
};
template <class Elem, class Traits>
class basic_oobjstream : public std::basic_ostream<Elem, Traits>
{
public:
using mybase = std::basic_ostream<Elem, Traits>;
using myob = basic_objbuf<Elem, Traits>;
using myios = std::basic_ios<Elem, Traits>;
explicit basic_oobjstream(std::unique_ptr<myob> objbuf)
: std::basic_ostream<Elem, Traits>(objbuf.get()),
m_ob(std::move(objbuf))
{
assert(m_ob);
}
explicit basic_oobjstream(basic_oobjstream<Elem, Traits>&& right) noexcept
: std::basic_ostream<Elem, Traits>(right),
m_ob(std::move(right.m_ob))
{
assert(m_ob != nullptr);
}
~basic_oobjstream() override = default;
basic_oobjstream(const basic_oobjstream& other) = delete;
basic_oobjstream& operator=(const basic_oobjstream& other) = delete;
void swap(basic_oobjstream& right) noexcept
{
if (this != _STD addressof(right))
{
mybase::swap(right);
m_ob = std::move(right.m_ob);
}
}
basic_oobjstream& operator=(basic_oobjstream&& other) noexcept
{
swap(other);
return *this;
}
// ReSharper disable once CppHidingFunction
_NODISCARD myob* rdbuf() const
{
return const_cast<myob*>(m_ob.get());
}
_NODISCARD bool is_open() const
{
return m_ob->is_open();
}
void close()
{
if (!m_ob->close())
{
myios::setstate(std::ios_base::failbit);
}
}
protected:
std::unique_ptr<myob> m_ob;
};
using objbuf = basic_objbuf<char, std::char_traits<char>>;
using objstream = basic_objstream<char, std::char_traits<char>>;
using iobjstream = basic_iobjstream<char, std::char_traits<char>>;
using oobjstream = basic_oobjstream<char, std::char_traits<char>>;

View File

@ -43,15 +43,14 @@ namespace IW4
Texture* loadedTexture = nullptr; Texture* loadedTexture = nullptr;
IwiLoader loader(zone->GetMemory()); IwiLoader loader(zone->GetMemory());
const std::string imageFileName = "images/" + std::string(image->name) + ".iwi"; const auto imageFileName = "images/" + std::string(image->name) + ".iwi";
auto* filePathImage = searchPath->Open(imageFileName);
if (filePathImage != nullptr)
{ {
loadedTexture = loader.LoadIwi(filePathImage); const auto filePathImage = searchPath->Open(imageFileName);
if (filePathImage != nullptr)
filePathImage->Close(); {
delete filePathImage; loadedTexture = loader.LoadIwi(*filePathImage);
}
} }
if (loadedTexture != nullptr) if (loadedTexture != nullptr)
@ -59,8 +58,8 @@ namespace IW4
image->texture.texture = loadedTexture; image->texture.texture = loadedTexture;
image->cardMemory.platform[0] = 0; image->cardMemory.platform[0] = 0;
const int textureMipCount = loadedTexture->GetMipMapCount(); const auto textureMipCount = loadedTexture->GetMipMapCount();
for (int mipLevel = 0; mipLevel < textureMipCount; mipLevel++) for (auto mipLevel = 0; mipLevel < textureMipCount; mipLevel++)
image->cardMemory.platform[0] += static_cast<int>(loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount()); image->cardMemory.platform[0] += static_cast<int>(loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount());
} }
else else

View File

@ -1,4 +1,5 @@
#include "ObjLoaderT6.h" #include "ObjLoaderT6.h"
#include "Game/T6/GameT6.h" #include "Game/T6/GameT6.h"
#include "Game/T6/GameAssetPoolT6.h" #include "Game/T6/GameAssetPoolT6.h"
#include "ObjContainer/IPak/IPak.h" #include "ObjContainer/IPak/IPak.h"
@ -22,36 +23,32 @@ namespace T6
if (ObjLoading::Configuration.Verbose) if (ObjLoading::Configuration.Verbose)
printf("Trying to load ipak '%s' for zone '%s'\n", ipakName.c_str(), zone->m_name.c_str()); 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 (existingIPak != nullptr)
{ {
if (ObjLoading::Configuration.Verbose) if (ObjLoading::Configuration.Verbose)
printf("Referencing loaded ipak '%s'.\n", ipakName.c_str()); printf("Referencing loaded ipak '%s'.\n", ipakName.c_str());
IPak::Repository.AddContainer(existingIPak, zone); IPak::Repository.AddContainerReference(existingIPak, zone);
return; return;
} }
const std::string ipakFilename = ipakName + ".ipak"; const auto ipakFilename = ipakName + ".ipak";
auto* file = searchPath->Open(ipakFilename); auto file = searchPath->Open(ipakFilename);
if (file && file->IsOpen()) if (file)
{ {
IPak* ipak = new IPak(ipakFilename, file); auto ipak = std::make_unique<IPak>(ipakFilename, std::move(file));
if (ipak->Initialize()) if (ipak->Initialize())
{ {
IPak::Repository.AddContainer(ipak, zone); IPak::Repository.AddContainer(std::move(ipak), zone);
if (ObjLoading::Configuration.Verbose) if (ObjLoading::Configuration.Verbose)
printf("Found and loaded ipak '%s'.\n", ipakFilename.c_str()); printf("Found and loaded ipak '%s'.\n", ipakFilename.c_str());
} }
else else
{ {
delete ipak;
file->Close();
delete file;
printf("Failed to load ipak '%s'!\n", ipakFilename.c_str()); printf("Failed to load ipak '%s'!\n", ipakFilename.c_str());
} }
} }
@ -108,7 +105,7 @@ namespace T6
void ObjLoader::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const void ObjLoader::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const
{ {
auto* assetPoolT6 = dynamic_cast<GameAssetPoolT6*>(zone->m_pools.get()); 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); LoadCommonIPaks(searchPath, zone);
@ -117,9 +114,9 @@ namespace T6
for (auto* keyValuePairsEntry : *assetPoolT6->m_key_value_pairs) for (auto* keyValuePairsEntry : *assetPoolT6->m_key_value_pairs)
{ {
auto* keyValuePairs = keyValuePairsEntry->Asset(); 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) if (variable->namespaceHash == zoneNameHash && variable->keyHash == IPAK_READ_HASH)
{ {
@ -149,14 +146,13 @@ namespace T6
{ {
for (auto* ipak : IPak::Repository) 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(); ipakStream->close();
delete ipakStream;
if (loadedTexture != nullptr) if (loadedTexture != nullptr)
{ {
@ -168,15 +164,14 @@ namespace T6
if (loadedTexture == nullptr) if (loadedTexture == nullptr)
{ {
const std::string imageFileName = "images/" + std::string(image->name) + ".iwi"; const auto imageFileName = "images/" + std::string(image->name) + ".iwi";
auto* filePathImage = searchPath->Open(imageFileName);
if (filePathImage != nullptr)
{ {
loadedTexture = loader.LoadIwi(filePathImage); const auto filePathImage = searchPath->Open(imageFileName);
if (filePathImage)
filePathImage->Close(); {
delete filePathImage; loadedTexture = loader.LoadIwi(*filePathImage);
}
} }
} }
@ -185,8 +180,8 @@ namespace T6
image->texture.texture = loadedTexture; image->texture.texture = loadedTexture;
image->loadedSize = 0; image->loadedSize = 0;
const int textureMipCount = loadedTexture->GetMipMapCount(); const auto textureMipCount = loadedTexture->GetMipMapCount();
for (int mipLevel = 0; mipLevel < textureMipCount; mipLevel++) for (auto mipLevel = 0; mipLevel < textureMipCount; mipLevel++)
image->loadedSize += loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount(); image->loadedSize += loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount();
} }
else else

View File

@ -52,21 +52,22 @@ const ImageFormat* IwiLoader::GetFormat8(int8_t format)
return nullptr; return nullptr;
} }
Texture* IwiLoader::LoadIwi8(FileAPI::IFile* file) Texture* IwiLoader::LoadIwi8(std::istream& stream) const
{ {
iwi8::IwiHeader header{}; 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; return nullptr;
const ImageFormat* format = GetFormat8(header.format); const auto* format = GetFormat8(header.format);
if (format == nullptr) if (format == nullptr)
return nullptr; return nullptr;
uint16_t width = header.dimensions[0]; auto width = header.dimensions[0];
uint16_t height = header.dimensions[1]; auto height = header.dimensions[1];
uint16_t depth = header.dimensions[2]; auto depth = header.dimensions[2];
bool hasMipMaps = !(header.flags & iwi8::IwiFlags::IMG_FLAG_NOMIPMAPS); auto hasMipMaps = !(header.flags & iwi8::IwiFlags::IMG_FLAG_NOMIPMAPS);
Texture* texture; Texture* texture;
if ((header.flags & iwi8::IwiFlags::IMG_FLAG_MAPTYPE_MASK) == iwi8::IwiFlags::IMG_FLAG_MAPTYPE_CUBE) 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(); texture->Allocate();
size_t currentFileSize = sizeof iwi8::IwiHeader + sizeof IwiVersion; auto currentFileSize = sizeof iwi8::IwiHeader + sizeof IwiVersion;
const int mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1; 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; currentFileSize += sizeOfMipLevel;
if (currentMipLevel < static_cast<int>(_countof(iwi8::IwiHeader::fileSizeForPicmip)) if (currentMipLevel < static_cast<int>(_countof(iwi8::IwiHeader::fileSizeForPicmip))
@ -111,7 +112,8 @@ Texture* IwiLoader::LoadIwi8(FileAPI::IFile* file)
return nullptr; 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); printf("Unexpected eof of iwi in mip level %i\n", currentMipLevel);
@ -167,21 +169,22 @@ const ImageFormat* IwiLoader::GetFormat27(int8_t format)
return nullptr; return nullptr;
} }
Texture* IwiLoader::LoadIwi27(FileAPI::IFile* file) Texture* IwiLoader::LoadIwi27(std::istream& stream) const
{ {
iwi27::IwiHeader header{}; 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; return nullptr;
const ImageFormat* format = GetFormat27(header.format); const auto* format = GetFormat27(header.format);
if (format == nullptr) if (format == nullptr)
return nullptr; return nullptr;
uint16_t width = header.dimensions[0]; auto width = header.dimensions[0];
uint16_t height = header.dimensions[1]; auto height = header.dimensions[1];
uint16_t depth = header.dimensions[2]; auto depth = header.dimensions[2];
bool hasMipMaps = !(header.flags & iwi27::IwiFlags::IMG_FLAG_NOMIPMAPS); auto hasMipMaps = !(header.flags & iwi27::IwiFlags::IMG_FLAG_NOMIPMAPS);
Texture* texture; Texture* texture;
if (header.flags & iwi27::IwiFlags::IMG_FLAG_CUBEMAP) if (header.flags & iwi27::IwiFlags::IMG_FLAG_CUBEMAP)
@ -199,12 +202,12 @@ Texture* IwiLoader::LoadIwi27(FileAPI::IFile* file)
texture->Allocate(); texture->Allocate();
size_t currentFileSize = sizeof iwi27::IwiHeader + sizeof IwiVersion; auto currentFileSize = sizeof iwi27::IwiHeader + sizeof IwiVersion;
const int mipMapCount = hasMipMaps ? texture->GetMipMapCount() : 1; 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; currentFileSize += sizeOfMipLevel;
if (currentMipLevel < static_cast<int>(_countof(iwi27::IwiHeader::fileSizeForPicmip)) if (currentMipLevel < static_cast<int>(_countof(iwi27::IwiHeader::fileSizeForPicmip))
@ -216,7 +219,8 @@ Texture* IwiLoader::LoadIwi27(FileAPI::IFile* file)
return nullptr; 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); printf("Unexpected eof of iwi in mip level %i\n", currentMipLevel);
@ -228,11 +232,12 @@ Texture* IwiLoader::LoadIwi27(FileAPI::IFile* file)
return texture; return texture;
} }
Texture* IwiLoader::LoadIwi(FileAPI::IFile* file) Texture* IwiLoader::LoadIwi(std::istream& stream)
{ {
IwiVersion iwiVersion{}; 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; return nullptr;
if (iwiVersion.tag[0] != 'I' if (iwiVersion.tag[0] != 'I'
@ -245,10 +250,10 @@ Texture* IwiLoader::LoadIwi(FileAPI::IFile* file)
switch (iwiVersion.version) switch (iwiVersion.version)
{ {
case 8: case 8:
return LoadIwi8(file); return LoadIwi8(stream);
case 27: case 27:
return LoadIwi27(file); return LoadIwi27(stream);
default: default:
break; break;

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "Utils/FileAPI.h" #include <istream>
#include "Utils/MemoryManager.h" #include "Utils/MemoryManager.h"
#include "Image/Texture.h" #include "Image/Texture.h"
@ -9,13 +9,13 @@ class IwiLoader
MemoryManager* m_memory_manager; MemoryManager* m_memory_manager;
static const ImageFormat* GetFormat8(int8_t format); 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); static const ImageFormat* GetFormat27(int8_t format);
Texture* LoadIwi27(FileAPI::IFile* file); Texture* LoadIwi27(std::istream& stream) const;
public: public:
explicit IwiLoader(MemoryManager* memoryManager); explicit IwiLoader(MemoryManager* memoryManager);
Texture* LoadIwi(FileAPI::IFile* file); Texture* LoadIwi(std::istream& stream);
}; };

View File

@ -1,27 +1,33 @@
#include "IPak.h" #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 <sstream>
#include <vector> #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; ObjContainerRepository<IPak, Zone> IPak::Repository;
class IPak::Impl : public ObjContainerReferenceable 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; static const uint32_t VERSION = 0x50000;
std::string m_path; std::string m_path;
FileAPI::IFile* m_file; std::unique_ptr<std::istream> m_stream;
bool m_initialized; bool m_initialized;
IPakSection* m_index_section; std::unique_ptr<IPakSection> m_index_section;
IPakSection* m_data_section; std::unique_ptr<IPakSection> m_data_section;
std::vector<IPakIndexEntry> m_index_entries; 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) 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); hash = 33 * hash ^ (*pos | 0x20);
} }
@ -39,12 +45,13 @@ class IPak::Impl : public ObjContainerReferenceable
bool ReadIndexSection() bool ReadIndexSection()
{ {
m_file->Goto(m_index_section->offset); m_stream->seekg(m_index_section->offset);
IPakIndexEntry indexEntry{}; IPakIndexEntry indexEntry{};
for (unsigned itemIndex = 0; itemIndex < m_index_section->itemCount; itemIndex++) 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); printf("Unexpected eof when trying to load index entry %u.\n", itemIndex);
return false; return false;
@ -66,7 +73,8 @@ class IPak::Impl : public ObjContainerReferenceable
{ {
IPakSection section{}; IPakSection section{};
if (m_file->Read(&section, sizeof section, 1) != 1) m_stream->read(reinterpret_cast<char*>(&section), sizeof section);
if (m_stream->gcount() != sizeof section)
{ {
printf("Unexpected eof when trying to load section.\n"); printf("Unexpected eof when trying to load section.\n");
return false; return false;
@ -75,11 +83,11 @@ class IPak::Impl : public ObjContainerReferenceable
switch (section.type) switch (section.type)
{ {
case 1: case 1:
m_index_section = new IPakSection(section); m_index_section = std::make_unique<IPakSection>(section);
break; break;
case 2: case 2:
m_data_section = new IPakSection(section); m_data_section = std::make_unique<IPakSection>(section);
break; break;
default: default:
@ -93,7 +101,8 @@ class IPak::Impl : public ObjContainerReferenceable
{ {
IPakHeader header{}; 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"); printf("Unexpected eof when trying to load header.\n");
return false; return false;
@ -136,28 +145,22 @@ class IPak::Impl : public ObjContainerReferenceable
} }
public: public:
Impl(std::string path, FileAPI::IFile* file) Impl(std::string path, std::unique_ptr<std::istream> stream)
: m_stream_manager(file) : 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() ~Impl() override
{ = default;
delete m_index_section;
m_index_section = nullptr;
delete m_data_section;
m_data_section = nullptr;
}
std::string GetName() override std::string GetName() override
{ {
return utils::Path::GetFilenameWithoutExtension(m_path); return fs::path(m_path).filename().replace_extension("").string();
} }
bool Initialize() bool Initialize()
@ -172,7 +175,7 @@ public:
return true; return true;
} }
FileAPI::IFile* GetEntryData(const Hash nameHash, const Hash dataHash) std::unique_ptr<iobjstream> GetEntryData(const Hash nameHash, const Hash dataHash)
{ {
IPakIndexEntryKey wantedKey{}; IPakIndexEntryKey wantedKey{};
wantedKey.nameHash = nameHash; wantedKey.nameHash = nameHash;
@ -182,7 +185,7 @@ public:
{ {
if (entry.key.combinedKey == wantedKey.combinedKey) 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) 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() IPak::~IPak()
@ -221,12 +224,12 @@ std::string IPak::GetName()
return m_impl->GetName(); return m_impl->GetName();
} }
bool IPak::Initialize() const bool IPak::Initialize()
{ {
return m_impl->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); return m_impl->GetEntryData(nameHash, dataHash);
} }

View File

@ -1,8 +1,11 @@
#pragma once #pragma once
#include "Utils/FileAPI.h" #include <istream>
#include "Utils/ClassUtils.h"
#include "ObjContainer/ObjContainerReferenceable.h" #include "ObjContainer/ObjContainerReferenceable.h"
#include "ObjContainer/ObjContainerRepository.h" #include "ObjContainer/ObjContainerRepository.h"
#include "Utils/ObjStream.h"
#include "Zone/Zone.h" #include "Zone/Zone.h"
class IPak final : public ObjContainerReferenceable class IPak final : public ObjContainerReferenceable
@ -15,13 +18,13 @@ public:
static ObjContainerRepository<IPak, Zone> Repository; static ObjContainerRepository<IPak, Zone> Repository;
IPak(std::string path, FileAPI::IFile* file); IPak(std::string path, std::unique_ptr<std::istream> stream);
~IPak(); ~IPak() override;
std::string GetName() override; std::string GetName() override;
bool Initialize() const; bool Initialize();
FileAPI::IFile* GetEntryStream(Hash nameHash, Hash dataHash) const; _NODISCARD std::unique_ptr<iobjstream> GetEntryStream(Hash nameHash, Hash dataHash) const;
static Hash HashString(const std::string& str); static Hash HashString(const std::string& str);
static Hash HashData(const void* data, size_t dataSize); static Hash HashData(const void* data, size_t dataSize);

View File

@ -1,48 +1,47 @@
#include "IPakEntryReadStream.h" #include "IPakEntryReadStream.h"
#include "ObjContainer/IPak/IPakTypes.h"
#include <cassert> #include <cassert>
#include <stdexcept>
#include <minilzo.h> #include <minilzo.h>
#include "ObjContainer/IPak/IPakTypes.h"
using namespace ipak_consts; 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) 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(); lzo_init();
} }
IPakEntryReadStream::~IPakEntryReadStream() IPakEntryReadStream::~IPakEntryReadStream()
{ {
Close(); close();
} }
size_t IPakEntryReadStream::ReadChunks(uint8_t* buffer, const int64_t startPos, const size_t chunkCount) const size_t IPakEntryReadStream::ReadChunks(uint8_t* buffer, const int64_t startPos, const size_t chunkCount) const
{ {
m_stream_manager_actions->StartReading(); m_stream_manager_actions->StartReading();
m_file->Goto(startPos); m_stream.seekg(startPos);
const auto readSize = m_file->Read(buffer, 1, chunkCount * IPAK_CHUNK_SIZE); 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(); m_stream_manager_actions->StopReading();
return readSize / IPAK_CHUNK_SIZE; return readSize / IPAK_CHUNK_SIZE;
@ -66,47 +65,42 @@ bool IPakEntryReadStream::SetChunkBufferWindow(const int64_t startPos, size_t ch
return true; 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 (startPos >= m_buffer_start_pos && startPos < m_buffer_end_pos)
{ {
if (m_buffer_start_pos != startPos) if (m_buffer_start_pos != startPos)
{ {
const int64_t moveEnd = endPos < m_buffer_end_pos ? endPos : m_buffer_end_pos; const auto moveEnd = endPos < m_buffer_end_pos ? endPos : m_buffer_end_pos;
memmove_s(m_chunk_buffer, memmove_s(m_chunk_buffer, IPAK_CHUNK_SIZE * IPAK_CHUNK_COUNT_PER_READ, &m_chunk_buffer[startPos - m_buffer_start_pos],
IPAK_CHUNK_SIZE * IPAK_CHUNK_COUNT_PER_READ,
&m_chunk_buffer[startPos - m_buffer_start_pos],
static_cast<size_t>(moveEnd - startPos)); static_cast<size_t>(moveEnd - startPos));
m_buffer_start_pos = startPos; m_buffer_start_pos = startPos;
} }
if (endPos > m_buffer_end_pos) if (endPos > m_buffer_end_pos)
{ {
const size_t readChunkCount = ReadChunks(&m_chunk_buffer[m_buffer_end_pos - startPos], const auto readChunkCount = ReadChunks(&m_chunk_buffer[m_buffer_end_pos - startPos], m_buffer_end_pos,
m_buffer_end_pos, static_cast<size_t>(endPos - m_buffer_end_pos) / IPAK_CHUNK_SIZE);
static_cast<size_t>(endPos - m_buffer_end_pos) / IPAK_CHUNK_SIZE);
m_buffer_end_pos += static_cast<int64_t>(readChunkCount) * IPAK_CHUNK_SIZE; m_buffer_end_pos += static_cast<int64_t>(readChunkCount) * IPAK_CHUNK_SIZE;
return m_buffer_end_pos == endPos; 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], 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), IPAK_CHUNK_SIZE * IPAK_CHUNK_COUNT_PER_READ - static_cast<size_t>(m_buffer_start_pos - startPos),
m_chunk_buffer, m_chunk_buffer,
static_cast<size_t>(endPos - m_buffer_start_pos)); static_cast<size_t>(endPos - m_buffer_start_pos));
const size_t readChunkCount = ReadChunks(m_chunk_buffer, const auto readChunkCount = ReadChunks(m_chunk_buffer,
startPos, startPos,
static_cast<size_t>(m_buffer_start_pos - startPos) / IPAK_CHUNK_SIZE); static_cast<size_t>(m_buffer_start_pos - startPos) / IPAK_CHUNK_SIZE);
m_buffer_start_pos = startPos; m_buffer_start_pos = startPos;
m_buffer_end_pos = readChunkCount == (m_buffer_start_pos - startPos) / IPAK_CHUNK_SIZE 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; return m_buffer_end_pos == endPos;
} }
const size_t readChunkCount = ReadChunks(m_chunk_buffer, const auto readChunkCount = ReadChunks(m_chunk_buffer, startPos, chunkCount);
startPos,
chunkCount);
m_buffer_start_pos = startPos; m_buffer_start_pos = startPos;
m_buffer_end_pos = startPos + static_cast<int64_t>(readChunkCount) * IPAK_CHUNK_SIZE; 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) if (blockHeader->offset != m_file_head)
{ {
// A matching offset is only relevant if a command contains data. // 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) || 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; return false;
} }
} }
@ -190,8 +182,8 @@ bool IPakEntryReadStream::NextBlock()
const auto chunkStartPos = AlignBackwards<int64_t>(m_pos, IPAK_CHUNK_SIZE); const auto chunkStartPos = AlignBackwards<int64_t>(m_pos, IPAK_CHUNK_SIZE);
const auto blockOffsetInChunk = static_cast<size_t>(m_pos - chunkStartPos); const auto blockOffsetInChunk = static_cast<size_t>(m_pos - chunkStartPos);
const size_t sizeLeftToRead = m_entry_size - m_file_head; const auto 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) auto estimatedChunksToRead = AlignForward(m_entry_size - static_cast<size_t>(m_pos - m_base_pos), IPAK_CHUNK_SIZE)
/ IPAK_CHUNK_SIZE; / IPAK_CHUNK_SIZE;
if (estimatedChunksToRead > IPAK_CHUNK_COUNT_PER_READ) if (estimatedChunksToRead > IPAK_CHUNK_COUNT_PER_READ)
@ -263,18 +255,29 @@ bool IPakEntryReadStream::AdvanceStream()
return true; 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); if (is_open())
const size_t bufferSize = elementCount * elementSize; {
size_t countRead = 0; 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) 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; 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) if (sizeToRead > m_current_command_length - m_current_command_offset)
sizeToRead = m_current_command_length - m_current_command_offset; sizeToRead = m_current_command_length - m_current_command_offset;
if (sizeToRead > 0) if (sizeToRead > 0)
{ {
memcpy_s(&destBuffer[countRead], bufferSize - countRead, memcpy_s(&destBuffer[countRead], static_cast<rsize_t>(count - countRead),
&m_current_command_buffer[m_current_command_offset], sizeToRead); &m_current_command_buffer[m_current_command_offset], static_cast<rsize_t>(sizeToRead));
countRead += sizeToRead; countRead += sizeToRead;
m_current_command_offset += sizeToRead; m_current_command_offset += sizeToRead;
m_file_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. pos_type pos;
assert(false); if (dir == std::ios_base::beg)
throw std::runtime_error("This is not a stream for output!");
}
void IPakEntryReadStream::Skip(const int64_t amount)
{
if (amount > 0)
{ {
const size_t targetOffset = m_file_offset + static_cast<size_t>(amount); pos = off;
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;
}
} }
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, ...) std::streambuf::pos_type IPakEntryReadStream::seekpos(const pos_type pos, std::ios_base::openmode mode)
{
// 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)
{ {
if (pos == 0) if (pos == 0)
{ {
@ -357,34 +385,31 @@ void IPakEntryReadStream::Goto(const int64_t pos)
m_current_command_buffer = nullptr; m_current_command_buffer = nullptr;
m_current_command_length = 0; m_current_command_length = 0;
m_current_command_offset = 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() return pos;
{
// 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);
} }
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);
} }

View File

@ -1,21 +1,22 @@
#pragma once #pragma once
#include "IPakStreamManager.h" #include <istream>
#include "Utils/FileAPI.h"
#include "ObjContainer/IPak/IPakTypes.h"
#include <mutex>
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; static constexpr size_t IPAK_DECOMPRESS_BUFFER_SIZE = 0x8000;
uint8_t* m_chunk_buffer; uint8_t* m_chunk_buffer;
IFile* m_file; std::istream& m_stream;
IPakStreamManagerActions* m_stream_manager_actions; IPakStreamManagerActions* m_stream_manager_actions;
size_t m_file_offset; int64_t m_file_offset;
size_t m_file_head; int64_t m_file_head;
size_t m_entry_size; size_t m_entry_size;
@ -53,16 +54,17 @@ class IPakEntryReadStream final : public FileAPI::IFile
bool AdvanceStream(); bool AdvanceStream();
public: 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; ~IPakEntryReadStream() override;
bool IsOpen() override; _NODISCARD bool is_open() const override;
size_t Read(void* buffer, size_t elementSize, size_t elementCount) override; bool close() override;
size_t Write(const void* data, size_t elementSize, size_t elementCount) override;
void Skip(int64_t amount) override; protected:
size_t Printf(const char* fmt, ...) override; std::streamsize showmanyc() override;
int64_t Pos() override; int_type underflow() override;
void Goto(int64_t pos) override; int_type uflow() override;
void GotoEnd() override; std::streamsize xsgetn(char* ptr, std::streamsize count) override;
void Close() 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;
}; };

View File

@ -1,9 +1,11 @@
#include "IPakStreamManager.h" #include "IPakStreamManager.h"
#include "IPakEntryReadStream.h"
#include "ObjContainer/IPak/IPakTypes.h"
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include "IPakEntryReadStream.h"
#include "ObjContainer/IPak/IPakTypes.h"
using namespace ipak_consts; using namespace ipak_consts;
class IPakStreamManager::Impl final : public IPakStreamManagerActions 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_read_mutex;
std::mutex m_stream_mutex; std::mutex m_stream_mutex;
@ -39,10 +41,9 @@ class IPakStreamManager::Impl final : public IPakStreamManagerActions
std::vector<ChunkBuffer*> m_chunk_buffers; std::vector<ChunkBuffer*> m_chunk_buffers;
public: public:
explicit Impl(FileAPI::IFile* file) explicit Impl(std::istream& stream)
: m_stream(stream)
{ {
m_file = file;
m_chunk_buffers.push_back(new ChunkBuffer()); m_chunk_buffers.push_back(new ChunkBuffer());
} }
@ -55,7 +56,7 @@ public:
for (const auto& openStream : m_open_streams) for (const auto& openStream : m_open_streams)
{ {
openStream.m_stream->Close(); openStream.m_stream->close();
} }
m_open_streams.clear(); m_open_streams.clear();
@ -65,16 +66,15 @@ public:
Impl& operator=(const Impl& other) = delete; Impl& operator=(const Impl& other) = delete;
Impl& operator=(Impl&& other) noexcept = 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(); m_stream_mutex.lock();
ChunkBuffer* reservedChunkBuffer; ChunkBuffer* reservedChunkBuffer;
const auto freeChunkBuffer = std::find_if(m_chunk_buffers.begin(), m_chunk_buffers.end(), const auto freeChunkBuffer = std::find_if(m_chunk_buffers.begin(), m_chunk_buffers.end(), [](ChunkBuffer* chunkBuffer)
[](ChunkBuffer* chunkBuffer) {
{ return chunkBuffer->m_using_stream == nullptr;
return chunkBuffer->m_using_stream == nullptr; });
});
if (freeChunkBuffer == m_chunk_buffers.end()) if (freeChunkBuffer == m_chunk_buffers.end())
{ {
@ -84,15 +84,15 @@ public:
else else
reservedChunkBuffer = *freeChunkBuffer; 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(); m_stream_mutex.unlock();
return stream; return std::make_unique<iobjstream>(std::move(ipakEntryStream));
} }
void StartReading() override void StartReading() override
@ -105,15 +105,14 @@ public:
m_read_mutex.unlock(); m_read_mutex.unlock();
} }
void CloseStream(FileAPI::IFile* stream) override void CloseStream(objbuf* stream) override
{ {
m_stream_mutex.lock(); m_stream_mutex.lock();
const auto openStreamEntry = std::find_if(m_open_streams.begin(), m_open_streams.end(), const auto openStreamEntry = std::find_if(m_open_streams.begin(), m_open_streams.end(), [stream](const ManagedStream& managedStream)
[stream](const ManagedStream& managedStream) {
{ return managedStream.m_stream == stream;
return managedStream.m_stream == stream; });
});
if (openStreamEntry != m_open_streams.end()) 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() IPakStreamManager::~IPakStreamManager()
@ -149,7 +148,7 @@ IPakStreamManager::~IPakStreamManager()
m_impl = nullptr; 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); return m_impl->OpenStream(startPosition, length);
} }

View File

@ -1,8 +1,11 @@
#pragma once #pragma once
#include "Utils/FileAPI.h"
#include <cstdint> #include <cstdint>
#include <mutex> #include <mutex>
#include <istream>
#include "Utils/ClassUtils.h"
#include "Utils/ObjStream.h"
class IPakStreamManagerActions class IPakStreamManagerActions
{ {
@ -10,7 +13,7 @@ public:
virtual void StartReading() = 0; virtual void StartReading() = 0;
virtual void StopReading() = 0; virtual void StopReading() = 0;
virtual void CloseStream(FileAPI::IFile* stream) = 0; virtual void CloseStream(objbuf* stream) = 0;
}; };
class IPakStreamManager class IPakStreamManager
@ -19,7 +22,7 @@ class IPakStreamManager
Impl* m_impl; Impl* m_impl;
public: public:
explicit IPakStreamManager(FileAPI::IFile* file); explicit IPakStreamManager(std::istream& stream);
IPakStreamManager(const IPakStreamManager& other) = delete; IPakStreamManager(const IPakStreamManager& other) = delete;
IPakStreamManager(IPakStreamManager&& other) noexcept = delete; IPakStreamManager(IPakStreamManager&& other) noexcept = delete;
~IPakStreamManager(); ~IPakStreamManager();
@ -27,5 +30,5 @@ public:
IPakStreamManager& operator=(const IPakStreamManager& other) = delete; IPakStreamManager& operator=(const IPakStreamManager& other) = delete;
IPakStreamManager& operator=(IPakStreamManager&& other) noexcept = 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;
}; };

View File

@ -1,6 +1,5 @@
#include "IWD.h" #include "IWD.h"
#include "Utils/PathUtils.h"
#include "ObjLoading.h" #include "ObjLoading.h"
#include "Utils/FileToZlibWrapper.h" #include "Utils/FileToZlibWrapper.h"
@ -8,10 +7,14 @@
#include <filesystem> #include <filesystem>
#include <cassert> #include <cassert>
#include <map> #include <map>
#include <fstream>
#include <memory>
namespace fs = std::filesystem;
ObjContainerRepository<IWD, ISearchPath> IWD::Repository; ObjContainerRepository<IWD, ISearchPath> IWD::Repository;
class IWDFile final : public FileAPI::IFile class IWDFile final : public objbuf
{ {
public: public:
class IParent class IParent
@ -25,99 +28,135 @@ public:
private: private:
IParent* m_parent; IParent* m_parent;
bool m_open; bool m_open;
size_t m_size; int64_t m_size;
unzFile m_container; unzFile m_container;
bool m_peeked;
int_type m_peek_symbol;
public: 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 ~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; return m_open;
} }
size_t Read(void* buffer, const size_t elementSize, const size_t elementCount) override bool close() 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
{ {
unzCloseCurrentFile(m_container); unzCloseCurrentFile(m_container);
m_open = false; m_open = false;
m_parent->OnIWDFileClose(); m_parent->OnIWDFileClose();
return true;
} }
}; };
@ -126,12 +165,12 @@ class IWD::Impl : public ISearchPath, public IObjContainer, public IWDFile::IPar
class IWDEntry class IWDEntry
{ {
public: public:
size_t m_size{}; int64_t m_size{};
unz_file_pos m_file_pos{}; unz_file_pos m_file_pos{};
}; };
std::string m_path; std::string m_path;
FileAPI::IFile* m_file; std::unique_ptr<std::istream> m_stream;
unzFile m_unz_file; unzFile m_unz_file;
IWDFile* m_last_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; std::map<std::string, IWDEntry> m_entry_map;
public: 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 ~Impl() override
@ -152,13 +191,7 @@ public:
if (m_unz_file != nullptr) if (m_unz_file != nullptr)
{ {
unzClose(m_unz_file); unzClose(m_unz_file);
} m_unz_file = nullptr;
if (m_file)
{
m_file->Close();
delete m_file;
m_file = nullptr;
} }
} }
@ -169,7 +202,7 @@ public:
bool Initialize() bool Initialize()
{ {
auto ioFunctions = FileToZlibWrapper::CreateFunctions32ForFile(m_file); auto ioFunctions = FileToZlibWrapper::CreateFunctions32ForFile(m_stream.get());
m_unz_file = unzOpen2("", &ioFunctions); m_unz_file = unzOpen2("", &ioFunctions);
if (m_unz_file == nullptr) if (m_unz_file == nullptr)
@ -181,9 +214,9 @@ public:
auto ret = unzGoToFirstFile(m_unz_file); auto ret = unzGoToFirstFile(m_unz_file);
while (ret == Z_OK) while (ret == Z_OK)
{ {
unz_file_info info; unz_file_info64 info;
char fileNameBuffer[256]; 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::string fileName(fileNameBuffer);
std::filesystem::path path(fileName); std::filesystem::path path(fileName);
@ -207,21 +240,21 @@ public:
return true; 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) if (m_unz_file == nullptr)
{ {
return nullptr; return nullptr;
} }
std::string iwdFilename = fileName; auto iwdFilename = fileName;
std::replace(iwdFilename.begin(), iwdFilename.end(), '\\', '/'); std::replace(iwdFilename.begin(), iwdFilename.end(), '\\', '/');
const auto iwdEntry = m_entry_map.find(iwdFilename); const auto iwdEntry = m_entry_map.find(iwdFilename);
if (iwdEntry != m_entry_map.end()) 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."); 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) 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; return nullptr;
@ -247,24 +282,24 @@ public:
std::string GetName() override 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 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; return;
} }
for(auto& [entryName, entry] : m_entry_map) for (auto& [entryName, entry] : m_entry_map)
{ {
std::filesystem::path entryPath(entryName); 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; continue;
if(options.m_filter_extensions && options.m_extension != entryPath.extension().string()) if (options.m_filter_extensions && options.m_extension != entryPath.extension().string())
continue; continue;
callback(entryName); 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() IWD::~IWD()
@ -302,12 +337,12 @@ IWD& IWD::operator=(IWD&& other) noexcept
return *this; return *this;
} }
bool IWD::Initialize() const bool IWD::Initialize()
{ {
return m_impl->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); return m_impl->Open(fileName);
} }

View File

@ -1,5 +1,9 @@
#pragma once #pragma once
#include <memory>
#include "Utils/ClassUtils.h"
#include "Utils/ObjStream.h"
#include "SearchPath/ISearchPath.h" #include "SearchPath/ISearchPath.h"
#include "ObjContainer/ObjContainerRepository.h" #include "ObjContainer/ObjContainerRepository.h"
@ -11,7 +15,7 @@ class IWD final : public ISearchPath, IObjContainer
public: public:
static ObjContainerRepository<IWD, ISearchPath> Repository; static ObjContainerRepository<IWD, ISearchPath> Repository;
IWD(std::string path, FileAPI::IFile* file); IWD(std::string path, std::unique_ptr<std::istream> stream);
~IWD(); ~IWD();
IWD(const IWD& other) = delete; IWD(const IWD& other) = delete;
@ -23,9 +27,9 @@ public:
* \brief Initializes the IWD container. * \brief Initializes the IWD container.
* \return \c true when initialization was successful. * \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 GetPath() override;
std::string GetName() override; std::string GetName() override;
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override; void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;

View File

@ -7,6 +7,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <set> #include <set>
#include <memory>
template <typename ContainerType, typename ReferencerType> template <typename ContainerType, typename ReferencerType>
class ObjContainerRepository class ObjContainerRepository
@ -14,51 +15,67 @@ class ObjContainerRepository
class ObjContainerEntry class ObjContainerEntry
{ {
public: public:
ContainerType* m_container; std::unique_ptr<ContainerType> m_container;
std::set<ReferencerType*> m_references; 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; std::vector<ObjContainerEntry> m_containers;
public: public:
void AddContainer(ContainerType* container, ReferencerType* referencer) ObjContainerRepository() = default;
{ ~ObjContainerRepository() = default;
auto firstEntry = std::find_if(m_containers.begin(), m_containers.end(), ObjContainerRepository(const ObjContainerRepository& other) = delete;
[container](ObjContainerEntry& entry) -> bool ObjContainerRepository(ObjContainerRepository&& other) noexcept = default;
{ ObjContainerRepository& operator=(const ObjContainerRepository& other) = delete;
return entry.m_container == container; 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); firstEntry->m_references.insert(referencer);
return; return true;
} }
ObjContainerEntry entry(container); return false;
entry.m_references.insert(referencer);
m_containers.push_back(entry);
} }
void RemoveContainerReferences(ReferencerType* referencer) 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); auto foundReference = iEntry->m_references.find(referencer);
if(foundReference != iEntry->m_references.end()) if (foundReference != iEntry->m_references.end())
{ {
iEntry->m_references.erase(foundReference); iEntry->m_references.erase(foundReference);
} }
if(iEntry->m_references.empty()) if (iEntry->m_references.empty())
{ {
delete iEntry->m_container;
iEntry = m_containers.erase(iEntry); iEntry = m_containers.erase(iEntry);
} }
else else
@ -70,14 +87,14 @@ public:
ContainerType* GetContainerByName(const std::string& name) ContainerType* GetContainerByName(const std::string& name)
{ {
auto foundEntry = std::find_if(m_containers.begin(), m_containers.end(), [name](ObjContainerEntry& entry) -> bool auto foundEntry = std::find_if(m_containers.begin(), m_containers.end(), [name](ObjContainerEntry& entry)
{
return entry.m_container->GetName() == name;
});
if(foundEntry != m_containers.end())
{ {
return foundEntry->m_container; return entry.m_container->GetName() == name;
});
if (foundEntry != m_containers.end())
{
return foundEntry->m_container.get();
} }
return nullptr; return nullptr;
@ -86,12 +103,12 @@ public:
TransformIterator<typename std::vector<ObjContainerEntry>::iterator, ObjContainerEntry&, ContainerType*> begin() TransformIterator<typename std::vector<ObjContainerEntry>::iterator, ObjContainerEntry&, ContainerType*> begin()
{ {
return TransformIterator<typename std::vector<ObjContainerEntry>::iterator, ObjContainerEntry&, ContainerType*>( 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() TransformIterator<typename std::vector<ObjContainerEntry>::iterator, ObjContainerEntry&, ContainerType*> end()
{ {
return TransformIterator<typename std::vector<ObjContainerEntry>::iterator, ObjContainerEntry&, ContainerType*>( 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(); });
} }
}; };

View File

@ -1,9 +1,13 @@
#include "ObjLoading.h" #include "ObjLoading.h"
#include <fstream>
#include "IObjLoader.h" #include "IObjLoader.h"
#include "Game/IW4/ObjLoaderIW4.h" #include "Game/IW4/ObjLoaderIW4.h"
#include "Game/T6/ObjLoaderT6.h" #include "Game/T6/ObjLoaderT6.h"
#include "ObjContainer/IWD/IWD.h" #include "ObjContainer/IWD/IWD.h"
#include "SearchPath/SearchPaths.h" #include "SearchPath/SearchPaths.h"
#include "Utils/ObjFileStream.h"
ObjLoading::Configuration_t ObjLoading::Configuration; ObjLoading::Configuration_t ObjLoading::Configuration;
@ -51,29 +55,20 @@ void ObjLoading::UnloadContainersOfZone(Zone* zone)
void ObjLoading::LoadIWDsInSearchPath(ISearchPath* searchPath) void ObjLoading::LoadIWDsInSearchPath(ISearchPath* searchPath)
{ {
searchPath->Find(SearchPathSearchOptions().IncludeSubdirectories(false).FilterExtensions("iwd"), searchPath->Find(SearchPathSearchOptions().IncludeSubdirectories(false).FilterExtensions("iwd"), [searchPath](const std::string& path)
[searchPath](const std::string& path) -> void {
{ auto file = std::make_unique<std::ifstream>(path, std::fstream::in | std::fstream::binary);
auto file = FileAPI::Open(path, FileAPI::Mode::MODE_READ);
if (file.IsOpen()) if (file->is_open())
{ {
auto* fileP = new FileAPI::File(std::move(file)); auto iwd = std::make_unique<IWD>(path, std::move(file));
IWD* iwd = new IWD(path, fileP);
if (iwd->Initialize())
if (iwd->Initialize()) {
{ IWD::Repository.AddContainer(std::move(iwd), searchPath);
IWD::Repository.AddContainer(iwd, searchPath); }
} }
else });
{
delete iwd;
fileP->Close();
delete fileP;
}
}
});
} }
void ObjLoading::UnloadIWDsInSearchPath(ISearchPath* searchPath) void ObjLoading::UnloadIWDsInSearchPath(ISearchPath* searchPath)

View File

@ -1,8 +1,11 @@
#pragma once #pragma once
#include "SearchPathSearchOptions.h"
#include "Utils/FileAPI.h"
#include <functional> #include <functional>
#include <istream>
#include <memory>
#include "Utils/ObjStream.h"
#include "SearchPathSearchOptions.h"
class ISearchPath class ISearchPath
{ {
@ -14,7 +17,7 @@ public:
* \param fileName The relative path to the file to open. * \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. * \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. * \brief Returns the path to the search path.

View File

@ -1,7 +1,11 @@
#include "SearchPathFilesystem.h" #include "SearchPathFilesystem.h"
#include "Utils/PathUtils.h"
#include <filesystem> #include <filesystem>
#include <fstream>
#include "Utils/ObjFileStream.h"
namespace fs = std::filesystem;
SearchPathFilesystem::SearchPathFilesystem(std::string path) SearchPathFilesystem::SearchPathFilesystem(std::string path)
{ {
@ -13,20 +17,19 @@ std::string SearchPathFilesystem::GetPath()
return m_path; 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; return nullptr;
} }
void SearchPathFilesystem::Find(const SearchPathSearchOptions& options, void SearchPathFilesystem::Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback)
const std::function<void(const std::string&)>& callback)
{ {
try try
{ {

View File

@ -1,8 +1,9 @@
#pragma once #pragma once
#include "ISearchPath.h"
#include <string> #include <string>
#include "ISearchPath.h"
class SearchPathFilesystem final : public ISearchPath class SearchPathFilesystem final : public ISearchPath
{ {
std::string m_path; std::string m_path;
@ -10,7 +11,7 @@ class SearchPathFilesystem final : public ISearchPath
public: public:
explicit SearchPathFilesystem(std::string path); 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; std::string GetPath() override;
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override; void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
}; };

View File

@ -5,15 +5,7 @@
SearchPaths::SearchPaths() = default; SearchPaths::SearchPaths() = default;
SearchPaths::~SearchPaths() SearchPaths::~SearchPaths()
{ = default;
for(auto searchPathToFree : m_to_free)
{
delete searchPathToFree;
}
m_to_free.clear();
m_search_paths.clear();
}
SearchPaths::SearchPaths(const SearchPaths& other) SearchPaths::SearchPaths(const SearchPaths& other)
: m_search_paths(other.m_search_paths) : m_search_paths(other.m_search_paths)
@ -41,15 +33,15 @@ SearchPaths& SearchPaths::operator=(SearchPaths&& other) noexcept
return *this; 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) 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); searchPathEntry->Find(options, callback);
} }
} }
void SearchPaths::CommitSearchPath(ISearchPath* searchPath) void SearchPaths::CommitSearchPath(std::unique_ptr<ISearchPath> searchPath)
{ {
m_search_paths.push_back(searchPath); m_search_paths.push_back(searchPath.get());
m_to_free.push_back(searchPath); m_owned_search_paths.emplace_back(std::move(searchPath));
} }
void SearchPaths::IncludeSearchPath(ISearchPath* searchPath) void SearchPaths::IncludeSearchPath(ISearchPath* searchPath)

View File

@ -1,12 +1,13 @@
#pragma once #pragma once
#include "ISearchPath.h"
#include <vector> #include <vector>
#include "ISearchPath.h"
class SearchPaths final : public ISearchPath class SearchPaths final : public ISearchPath
{ {
std::vector<ISearchPath*> m_search_paths; std::vector<ISearchPath*> m_search_paths;
std::vector<ISearchPath*> m_to_free; std::vector<std::unique_ptr<ISearchPath>> m_owned_search_paths;
public: public:
using iterator = std::vector<ISearchPath*>::iterator; using iterator = std::vector<ISearchPath*>::iterator;
@ -14,7 +15,7 @@ public:
SearchPaths(); SearchPaths();
~SearchPaths() override; ~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; std::string GetPath() override;
void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override; void Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback) override;
@ -27,7 +28,7 @@ public:
* \brief Adds a search path that gets deleted upon destruction of the \c SearchPaths object. * \brief Adds a search path that gets deleted upon destruction of the \c SearchPaths object.
* \param searchPath The search path to add. * \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. * \brief Adds a search path that does \b NOT get deleted upon destruction of the \c SearchPaths object.

View File

@ -1,10 +1,10 @@
#pragma once #pragma once
#include "IAssetDumper.h" #include "IAssetDumper.h"
#include "Utils/FileAPI.h"
#include "Utils/PathUtils.h"
#include <cstdio> #include <fstream>
#include <filesystem>
#include <iostream>
template<class T> template<class T>
class AbstractAssetDumper : public IAssetDumper<T> class AbstractAssetDumper : public IAssetDumper<T>
@ -12,7 +12,7 @@ class AbstractAssetDumper : public IAssetDumper<T>
protected: protected:
virtual bool ShouldDump(XAssetInfo<T>* asset) = 0; virtual bool ShouldDump(XAssetInfo<T>* asset) = 0;
virtual std::string GetFileNameForAsset(Zone* zone, XAssetInfo<T>* asset) = 0; virtual std::string GetFileNameForAsset(Zone* zone, XAssetInfo<T>* asset) = 0;
virtual void DumpAsset(Zone* zone, XAssetInfo<T>* asset, FileAPI::File* out) = 0; virtual void DumpAsset(Zone* zone, XAssetInfo<T>* asset, std::ostream& stream) = 0;
public: public:
void DumpPool(Zone* zone, AssetPool<T>* pool, const std::string& basePath) override void DumpPool(Zone* zone, AssetPool<T>* pool, const std::string& basePath) override
@ -25,21 +25,23 @@ public:
continue; continue;
} }
std::string assetFilePath = utils::Path::Combine(basePath, GetFileNameForAsset(zone, assetInfo)); std::filesystem::path assetFilePath(basePath);
assetFilePath.append(GetFileNameForAsset(zone, assetInfo));
FileAPI::DirectoryCreate(utils::Path::GetDirectory(assetFilePath)); auto assetFileFolder(assetFilePath);
assetFileFolder.replace_filename("");
create_directories(assetFileFolder);
auto file = FileAPI::Open(assetFilePath, FileAPI::Mode::MODE_WRITE); std::ofstream file(assetFilePath, std::fstream::out | std::fstream::binary);
if(file.is_open())
if(file.IsOpen())
{ {
DumpAsset(zone, assetInfo, &file); DumpAsset(zone, assetInfo, file);
file.Close(); file.close();
} }
else else
{ {
printf("Failed to open file '%s' to dump asset '%s'\n", assetFilePath.c_str(), assetInfo->m_name.c_str()); std::cout << "Failed to open file '" << assetFilePath.string() << "' to dump asset '" << assetInfo->m_name.c_str() << "'\n";
} }
} }
} }

View File

@ -2,23 +2,21 @@
#include <sstream> #include <sstream>
const std::string CsvWriter::LINE_BREAK = "\n"; CsvWriter::CsvWriter(std::ostream& stream)
: m_stream(stream),
CsvWriter::CsvWriter(FileAPI::IFile* file) m_column_count(0),
m_current_column(0),
m_first_row(true)
{ {
m_file = file;
m_first_row = true;
m_current_column = 0;
m_column_count = 0;
} }
void CsvWriter::WriteColumn(const std::string& value) void CsvWriter::WriteColumn(const std::string& value)
{ {
if (m_current_column++ > 0) if (m_current_column++ > 0)
m_file->Printf(","); m_stream << ",";
bool containsSeparator = false; auto containsSeparator = false;
bool containsQuote = false; auto containsQuote = false;
for (const auto& c : value) for (const auto& c : value)
{ {
if (c == '"') if (c == '"')
@ -35,7 +33,7 @@ void CsvWriter::WriteColumn(const std::string& value)
{ {
std::ostringstream str; std::ostringstream str;
for(const auto& c : value) for (const auto& c : value)
{ {
if (c == '"') if (c == '"')
str << "\"\""; str << "\"\"";
@ -43,15 +41,15 @@ void CsvWriter::WriteColumn(const std::string& value)
str << c; str << c;
} }
m_file->Printf("\"%s\"", str.str().c_str()); m_stream << "\"" << str.str() << "\"";
} }
else if (containsSeparator) else if (containsSeparator)
{ {
m_file->Printf("\"%s\"", value.c_str()); m_stream << "\"" << value << "\"";
} }
else else
{ {
m_file->Printf("%s", value.c_str()); m_stream << value;
} }
} }
@ -64,13 +62,13 @@ void CsvWriter::NextRow()
} }
else else
{ {
while(m_current_column < m_column_count) while (m_current_column < m_column_count)
{ {
m_file->Printf(","); m_stream << ",";
m_current_column++; m_current_column++;
} }
} }
m_file->Printf("\n"); m_stream << "\n";
m_current_column = 0; m_current_column = 0;
} }

View File

@ -1,18 +1,19 @@
#pragma once #pragma once
#include "Utils/FileAPI.h"
#include <string>
#include <ostream>
class CsvWriter class CsvWriter
{ {
static constexpr char SEPARATOR = ','; static constexpr char SEPARATOR = ',';
static const std::string LINE_BREAK;
std::ostream& m_stream;
FileAPI::IFile* m_file;
unsigned m_column_count; unsigned m_column_count;
unsigned m_current_column; unsigned m_current_column;
bool m_first_row; bool m_first_row;
public: public:
explicit CsvWriter(FileAPI::IFile* file); explicit CsvWriter(std::ostream& stream);
void WriteColumn(const std::string& value); void WriteColumn(const std::string& value);
void NextRow(); void NextRow();

View File

@ -1,16 +1,12 @@
#include "StringFileDumper.h" #include "StringFileDumper.h"
#include <regex> #include <regex>
StringFileDumper::StringFileDumper(Zone* zone, FileAPI::File* file) StringFileDumper::StringFileDumper(Zone* zone, std::ostream& stream)
: m_zone(zone),
m_stream(stream),
m_language_caps("ENGLISH"),
m_wrote_header(false)
{ {
m_zone = zone;
m_file = file;
m_config_file = "";
m_notes = "";
m_language_caps = "ENGLISH";
m_wrote_header = false;
} }
void StringFileDumper::SetLanguageName(std::string language) void StringFileDumper::SetLanguageName(std::string language)
@ -31,11 +27,11 @@ void StringFileDumper::SetNotes(std::string notes)
void StringFileDumper::WriteHeader() void StringFileDumper::WriteHeader()
{ {
m_file->Printf("// Dumped from fastfile \"%s\".\n", m_zone->m_name.c_str()); m_stream << "// Dumped from fastfile \"" << m_zone->m_name << "\".\n";
m_file->Printf("// In their original format the strings might have been separated in multiple files.\n"); m_stream << "// In their original format the strings might have been separated in multiple files.\n";
m_file->Printf("VERSION \"1\"\n"); m_stream << "VERSION \"1\"\n";
m_file->Printf("CONFIG \"%s\"\n", m_config_file.c_str()); m_stream << "CONFIG \"" << m_config_file << "\"\n";
m_file->Printf("FILENOTES \"%s\"\n", m_notes.c_str()); m_stream << "FILENOTES \"" << m_notes << "\"\n";
m_wrote_header = true; m_wrote_header = true;
} }
@ -45,13 +41,13 @@ void StringFileDumper::WriteLocalizeEntry(const std::string& reference, const st
if (!m_wrote_header) if (!m_wrote_header)
WriteHeader(); WriteHeader();
m_file->Printf("\n"); m_stream << "\n";
m_file->Printf("REFERENCE %s\n", reference.c_str()); m_stream << "REFERENCE " << reference <<"\n";
const std::string escapedValue = std::regex_replace(value, std::regex("\n"), "\\n"); const auto escapedValue = std::regex_replace(value, std::regex("\n"), "\\n");
const std::string valueSpacing = std::string(15 - m_language_caps.length(), ' '); const auto valueSpacing = std::string(15 - m_language_caps.length(), ' ');
m_file->Printf("LANG_%s%s\"%s\"\n", m_language_caps.c_str(), valueSpacing.c_str(), escapedValue.c_str()); m_stream << "LANG_" << m_language_caps << valueSpacing << "\"" << escapedValue << "\"\n";
} }
void StringFileDumper::Finalize() void StringFileDumper::Finalize()
@ -59,5 +55,5 @@ void StringFileDumper::Finalize()
if (!m_wrote_header) if (!m_wrote_header)
WriteHeader(); WriteHeader();
m_file->Printf("\nENDMARKER"); m_stream << "\nENDMARKER";
} }

View File

@ -1,12 +1,13 @@
#pragma once #pragma once
#include <ostream>
#include "Zone/Zone.h" #include "Zone/Zone.h"
#include "Utils/FileAPI.h"
class StringFileDumper class StringFileDumper
{ {
Zone* m_zone; Zone* m_zone;
FileAPI::File* m_file; std::ostream& m_stream;
std::string m_config_file; std::string m_config_file;
std::string m_notes; std::string m_notes;
@ -17,7 +18,7 @@ class StringFileDumper
void WriteHeader(); void WriteHeader();
public: public:
StringFileDumper(Zone* zone, FileAPI::File* file); StringFileDumper(Zone* zone, std::ostream& stream);
void SetConfigFile(std::string configFile); void SetConfigFile(std::string configFile);
void SetNotes(std::string notes); void SetNotes(std::string notes);

View File

@ -15,8 +15,8 @@ std::string AssetDumperAddonMapEnts::GetFileNameForAsset(Zone* zone, XAssetInfo<
return asset->m_name; return asset->m_name;
} }
void AssetDumperAddonMapEnts::DumpAsset(Zone* zone, XAssetInfo<AddonMapEnts>* asset, FileAPI::File* out) void AssetDumperAddonMapEnts::DumpAsset(Zone* zone, XAssetInfo<AddonMapEnts>* asset, std::ostream& stream)
{ {
const auto* addonMapEnts = asset->Asset(); const auto* addonMapEnts = asset->Asset();
out->Write(addonMapEnts->entityString, 1, std::max(addonMapEnts->numEntityChars - 1, 0)); stream.write(addonMapEnts->entityString, std::max(addonMapEnts->numEntityChars - 1, 0));
} }

View File

@ -10,6 +10,6 @@ namespace IW4
protected: protected:
bool ShouldDump(XAssetInfo<AddonMapEnts>* asset) override; bool ShouldDump(XAssetInfo<AddonMapEnts>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<AddonMapEnts>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<AddonMapEnts>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<AddonMapEnts>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<AddonMapEnts>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -42,8 +42,8 @@ std::string AssetDumperGfxImage::GetFileNameForAsset(Zone* zone, XAssetInfo<GfxI
return "images/" + asset->m_name + m_writer->GetFileExtension(); return "images/" + asset->m_name + m_writer->GetFileExtension();
} }
void AssetDumperGfxImage::DumpAsset(Zone* zone, XAssetInfo<GfxImage>* asset, FileAPI::File* out) void AssetDumperGfxImage::DumpAsset(Zone* zone, XAssetInfo<GfxImage>* asset, std::ostream& stream)
{ {
const auto* image = asset->Asset(); const auto* image = asset->Asset();
m_writer->DumpImage(out, image->texture.texture); m_writer->DumpImage(stream, image->texture.texture);
} }

View File

@ -13,7 +13,7 @@ namespace IW4
protected: protected:
bool ShouldDump(XAssetInfo<GfxImage>* asset) override; bool ShouldDump(XAssetInfo<GfxImage>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<GfxImage>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<GfxImage>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<GfxImage>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<GfxImage>* asset, std::ostream& stream) override;
public: public:
AssetDumperGfxImage(); AssetDumperGfxImage();

View File

@ -14,9 +14,9 @@ std::string AssetDumperLoadedSound::GetFileNameForAsset(Zone* zone, XAssetInfo<L
return "sound/" + asset->m_name; return "sound/" + asset->m_name;
} }
void AssetDumperLoadedSound::DumpWavPcm(Zone* zone, const LoadedSound* asset, FileAPI::File* out) void AssetDumperLoadedSound::DumpWavPcm(Zone* zone, const LoadedSound* asset, std::ostream& stream)
{ {
const uint32_t riffMasterChunkSize = sizeof WAV_CHUNK_ID_RIFF const auto riffMasterChunkSize = sizeof WAV_CHUNK_ID_RIFF
+ sizeof uint32_t + sizeof uint32_t
+ sizeof WAV_WAVE_ID + sizeof WAV_WAVE_ID
+ sizeof WavChunkHeader + sizeof WavChunkHeader
@ -24,16 +24,16 @@ void AssetDumperLoadedSound::DumpWavPcm(Zone* zone, const LoadedSound* asset, Fi
+ sizeof WavChunkHeader + sizeof WavChunkHeader
+ sizeof asset->sound.info.data_len; + sizeof asset->sound.info.data_len;
out->Write(&WAV_CHUNK_ID_RIFF, sizeof WAV_CHUNK_ID_RIFF, 1); stream.write(reinterpret_cast<const char*>(&WAV_CHUNK_ID_RIFF), sizeof WAV_CHUNK_ID_RIFF);
out->Write(&riffMasterChunkSize, sizeof riffMasterChunkSize, 1); stream.write(reinterpret_cast<const char*>(&riffMasterChunkSize), sizeof riffMasterChunkSize);
out->Write(&WAV_WAVE_ID, sizeof WAV_WAVE_ID, 1); stream.write(reinterpret_cast<const char*>(&WAV_WAVE_ID), sizeof WAV_WAVE_ID);
const WavChunkHeader formatChunkHeader const WavChunkHeader formatChunkHeader
{ {
WAV_CHUNK_ID_FMT, WAV_CHUNK_ID_FMT,
sizeof WavFormatChunkPcm sizeof WavFormatChunkPcm
}; };
out->Write(&formatChunkHeader, sizeof formatChunkHeader, 1); stream.write(reinterpret_cast<const char*>(&formatChunkHeader), sizeof formatChunkHeader);
WavFormatChunkPcm formatChunk WavFormatChunkPcm formatChunk
{ {
@ -44,24 +44,24 @@ void AssetDumperLoadedSound::DumpWavPcm(Zone* zone, const LoadedSound* asset, Fi
static_cast<uint16_t>(asset->sound.info.block_size), static_cast<uint16_t>(asset->sound.info.block_size),
static_cast<uint16_t>(asset->sound.info.bits) static_cast<uint16_t>(asset->sound.info.bits)
}; };
out->Write(&formatChunk, sizeof formatChunk, 1); stream.write(reinterpret_cast<const char*>(&formatChunk), sizeof formatChunk);
const WavChunkHeader dataChunkHeader const WavChunkHeader dataChunkHeader
{ {
WAV_CHUNK_ID_DATA, WAV_CHUNK_ID_DATA,
asset->sound.info.data_len asset->sound.info.data_len
}; };
out->Write(&dataChunkHeader, sizeof dataChunkHeader, 1); stream.write(reinterpret_cast<const char*>(&dataChunkHeader), sizeof dataChunkHeader);
out->Write(asset->sound.data, 1, asset->sound.info.data_len); stream.write(asset->sound.data, asset->sound.info.data_len);
} }
void AssetDumperLoadedSound::DumpAsset(Zone* zone, XAssetInfo<LoadedSound>* asset, FileAPI::File* out) void AssetDumperLoadedSound::DumpAsset(Zone* zone, XAssetInfo<LoadedSound>* asset, std::ostream& stream)
{ {
const auto* loadedSound = asset->Asset(); const auto* loadedSound = asset->Asset();
switch (static_cast<WavFormat>(loadedSound->sound.info.format)) switch (static_cast<WavFormat>(loadedSound->sound.info.format))
{ {
case WavFormat::PCM: case WavFormat::PCM:
DumpWavPcm(zone, loadedSound, out); DumpWavPcm(zone, loadedSound, stream);
break; break;
default: default:

View File

@ -7,10 +7,10 @@ namespace IW4
{ {
class AssetDumperLoadedSound final : public AbstractAssetDumper<LoadedSound> class AssetDumperLoadedSound final : public AbstractAssetDumper<LoadedSound>
{ {
static void DumpWavPcm(Zone* zone, const LoadedSound* asset, FileAPI::File* out); static void DumpWavPcm(Zone* zone, const LoadedSound* asset, std::ostream& stream);
protected: protected:
bool ShouldDump(XAssetInfo<LoadedSound>* asset) override; bool ShouldDump(XAssetInfo<LoadedSound>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<LoadedSound>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<LoadedSound>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<LoadedSound>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<LoadedSound>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -1,25 +1,35 @@
#include "AssetDumperLocalizeEntry.h" #include "AssetDumperLocalizeEntry.h"
#include <fstream>
#include <filesystem>
#include "Dumping/Localize/LocalizeCommon.h" #include "Dumping/Localize/LocalizeCommon.h"
#include "Dumping/Localize/StringFileDumper.h" #include "Dumping/Localize/StringFileDumper.h"
using namespace IW4; using namespace IW4;
namespace fs = std::filesystem;
void AssetDumperLocalizeEntry::DumpPool(Zone* zone, AssetPool<LocalizeEntry>* pool, const std::string& basePath) void AssetDumperLocalizeEntry::DumpPool(Zone* zone, AssetPool<LocalizeEntry>* pool, const std::string& basePath)
{ {
if (pool->m_asset_lookup.empty()) if (pool->m_asset_lookup.empty())
return; return;
const std::string language = LocalizeCommon::GetNameOfLanguage(zone->m_language); const auto language = LocalizeCommon::GetNameOfLanguage(zone->m_language);
const std::string stringsPath = utils::Path::Combine(basePath, language + "/localizedstrings"); fs::path stringsPath(basePath);
stringsPath.append(language);
stringsPath.append("/localizedstrings");
FileAPI::DirectoryCreate(stringsPath); create_directories(stringsPath);
FileAPI::File stringFile = FileAPI::Open(utils::Path::Combine(stringsPath, zone->m_name + ".str"), FileAPI::Mode::MODE_WRITE); auto stringFilePath(stringsPath);
stringFilePath.append(zone->m_name);
stringFilePath.append(".str");
if (stringFile.IsOpen()) std::ofstream stringFile(stringFilePath, std::fstream::out | std::ofstream::binary);
if (stringFile.is_open())
{ {
StringFileDumper stringFileDumper(zone, &stringFile); StringFileDumper stringFileDumper(zone, stringFile);
stringFileDumper.SetLanguageName(language); stringFileDumper.SetLanguageName(language);
@ -28,14 +38,14 @@ void AssetDumperLocalizeEntry::DumpPool(Zone* zone, AssetPool<LocalizeEntry>* po
stringFileDumper.SetNotes(""); stringFileDumper.SetNotes("");
for (auto localizeEntry : *pool) for (auto* localizeEntry : *pool)
{ {
stringFileDumper.WriteLocalizeEntry(localizeEntry->m_name, localizeEntry->Asset()->value); stringFileDumper.WriteLocalizeEntry(localizeEntry->m_name, localizeEntry->Asset()->value);
} }
stringFileDumper.Finalize(); stringFileDumper.Finalize();
stringFile.Close(); stringFile.close();
} }
else else
{ {

View File

@ -14,7 +14,7 @@ std::string AssetDumperRawFile::GetFileNameForAsset(Zone* zone, XAssetInfo<RawFi
return asset->m_name; return asset->m_name;
} }
void AssetDumperRawFile::DumpAsset(Zone* zone, XAssetInfo<RawFile>* asset, FileAPI::File* out) void AssetDumperRawFile::DumpAsset(Zone* zone, XAssetInfo<RawFile>* asset, std::ostream& stream)
{ {
const auto* rawFile = asset->Asset(); const auto* rawFile = asset->Asset();
if (rawFile->compressedLen > 0) if (rawFile->compressedLen > 0)
@ -52,13 +52,13 @@ void AssetDumperRawFile::DumpAsset(Zone* zone, XAssetInfo<RawFile>* asset, FileA
return; return;
} }
out->Write(buffer, 1, sizeof buffer - zs.avail_out); stream.write(reinterpret_cast<char*>(buffer), sizeof buffer - zs.avail_out);
} }
inflateEnd(&zs); inflateEnd(&zs);
} }
else if (rawFile->len > 0) else if (rawFile->len > 0)
{ {
out->Write(rawFile->data.buffer, 1, rawFile->len); stream.write(rawFile->data.buffer, rawFile->len);
} }
} }

View File

@ -10,6 +10,6 @@ namespace IW4
protected: protected:
bool ShouldDump(XAssetInfo<RawFile>* asset) override; bool ShouldDump(XAssetInfo<RawFile>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<RawFile>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<RawFile>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<RawFile>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<RawFile>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -14,14 +14,14 @@ std::string AssetDumperStringTable::GetFileNameForAsset(Zone* zone, XAssetInfo<S
return asset->m_name; return asset->m_name;
} }
void AssetDumperStringTable::DumpAsset(Zone* zone, XAssetInfo<StringTable>* asset, FileAPI::File* out) void AssetDumperStringTable::DumpAsset(Zone* zone, XAssetInfo<StringTable>* asset, std::ostream& stream)
{ {
const auto* stringTable = asset->Asset(); const auto* stringTable = asset->Asset();
CsvWriter csv(out); CsvWriter csv(stream);
for (int row = 0; row < stringTable->rowCount; row++) for (auto row = 0; row < stringTable->rowCount; row++)
{ {
for (int column = 0; column < stringTable->columnCount; column++) for (auto column = 0; column < stringTable->columnCount; column++)
{ {
const auto* cell = &stringTable->values[column + row * stringTable->columnCount]; const auto* cell = &stringTable->values[column + row * stringTable->columnCount];
csv.WriteColumn(cell->string); csv.WriteColumn(cell->string);

View File

@ -10,6 +10,6 @@ namespace IW4
protected: protected:
bool ShouldDump(XAssetInfo<StringTable>* asset) override; bool ShouldDump(XAssetInfo<StringTable>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<StringTable>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<StringTable>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<StringTable>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<StringTable>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -240,7 +240,7 @@ std::string AssetDumperVehicle::GetFileNameForAsset(Zone* zone, XAssetInfo<Vehic
return "vehicles/" + asset->m_name; return "vehicles/" + asset->m_name;
} }
void AssetDumperVehicle::DumpAsset(Zone* zone, XAssetInfo<VehicleDef>* asset, FileAPI::File* out) void AssetDumperVehicle::DumpAsset(Zone* zone, XAssetInfo<VehicleDef>* asset, std::ostream& stream)
{ {
InfoStringFromVehicleConverter converter(asset->Asset(), vehicle_fields, _countof(vehicle_fields), [asset](const scr_string_t scrStr) -> std::string InfoStringFromVehicleConverter converter(asset->Asset(), vehicle_fields, _countof(vehicle_fields), [asset](const scr_string_t scrStr) -> std::string
{ {
@ -253,5 +253,5 @@ void AssetDumperVehicle::DumpAsset(Zone* zone, XAssetInfo<VehicleDef>* asset, Fi
const auto infoString = converter.Convert(); const auto infoString = converter.Convert();
const auto stringValue = infoString.ToString("VEHICLEFILE"); const auto stringValue = infoString.ToString("VEHICLEFILE");
out->Write(stringValue.c_str(), 1, stringValue.length()); stream.write(stringValue.c_str(), stringValue.size());
} }

View File

@ -13,6 +13,6 @@ namespace IW4
protected: protected:
bool ShouldDump(XAssetInfo<VehicleDef>* asset) override; bool ShouldDump(XAssetInfo<VehicleDef>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<VehicleDef>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<VehicleDef>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<VehicleDef>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<VehicleDef>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -1162,7 +1162,7 @@ std::string AssetDumperWeapon::GetFileNameForAsset(Zone* zone, XAssetInfo<Weapon
return "weapons/" + asset->m_name; return "weapons/" + asset->m_name;
} }
void AssetDumperWeapon::DumpAsset(Zone* zone, XAssetInfo<WeaponCompleteDef>* asset, FileAPI::File* out) void AssetDumperWeapon::DumpAsset(Zone* zone, XAssetInfo<WeaponCompleteDef>* asset, std::ostream& stream)
{ {
auto* fullDef = new WeaponFullDef; auto* fullDef = new WeaponFullDef;
memset(fullDef, 0, sizeof WeaponFullDef); memset(fullDef, 0, sizeof WeaponFullDef);
@ -1179,7 +1179,7 @@ void AssetDumperWeapon::DumpAsset(Zone* zone, XAssetInfo<WeaponCompleteDef>* ass
const auto infoString = converter.Convert(); const auto infoString = converter.Convert();
const auto stringValue = infoString.ToString("WEAPONFILE"); const auto stringValue = infoString.ToString("WEAPONFILE");
out->Write(stringValue.c_str(), 1, stringValue.length()); stream.write(stringValue.c_str(), stringValue.size());
delete fullDef; delete fullDef;
} }

View File

@ -14,6 +14,6 @@ namespace IW4
protected: protected:
bool ShouldDump(XAssetInfo<WeaponCompleteDef>* asset) override; bool ShouldDump(XAssetInfo<WeaponCompleteDef>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<WeaponCompleteDef>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<WeaponCompleteDef>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<WeaponCompleteDef>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<WeaponCompleteDef>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -241,8 +241,8 @@ class AssetDumperFontIconInternal
} }
public: public:
explicit AssetDumperFontIconInternal(FileAPI::IFile* file) explicit AssetDumperFontIconInternal(std::ostream& stream)
: m_csv(file) : m_csv(stream)
{ {
} }
@ -265,8 +265,8 @@ std::string AssetDumperFontIcon::GetFileNameForAsset(Zone* zone, XAssetInfo<Font
return asset->m_name; return asset->m_name;
} }
void AssetDumperFontIcon::DumpAsset(Zone* zone, XAssetInfo<FontIcon>* asset, FileAPI::File* out) void AssetDumperFontIcon::DumpAsset(Zone* zone, XAssetInfo<FontIcon>* asset, std::ostream& stream)
{ {
AssetDumperFontIconInternal dumper(out); AssetDumperFontIconInternal dumper(stream);
dumper.DumpFontIcon(asset->Asset()); dumper.DumpFontIcon(asset->Asset());
} }

View File

@ -10,6 +10,6 @@ namespace T6
protected: protected:
bool ShouldDump(XAssetInfo<FontIcon>* asset) override; bool ShouldDump(XAssetInfo<FontIcon>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<FontIcon>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<FontIcon>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<FontIcon>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<FontIcon>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -42,8 +42,8 @@ std::string AssetDumperGfxImage::GetFileNameForAsset(Zone* zone, XAssetInfo<GfxI
return "images/" + asset->m_name + m_writer->GetFileExtension(); return "images/" + asset->m_name + m_writer->GetFileExtension();
} }
void AssetDumperGfxImage::DumpAsset(Zone* zone, XAssetInfo<GfxImage>* asset, FileAPI::File* out) void AssetDumperGfxImage::DumpAsset(Zone* zone, XAssetInfo<GfxImage>* asset, std::ostream& stream)
{ {
const auto* image = asset->Asset(); const auto* image = asset->Asset();
m_writer->DumpImage(out, image->texture.texture); m_writer->DumpImage(stream, image->texture.texture);
} }

View File

@ -13,7 +13,7 @@ namespace T6
protected: protected:
bool ShouldDump(XAssetInfo<GfxImage>* asset) override; bool ShouldDump(XAssetInfo<GfxImage>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<GfxImage>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<GfxImage>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<GfxImage>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<GfxImage>* asset, std::ostream& stream) override;
public: public:
AssetDumperGfxImage(); AssetDumperGfxImage();

View File

@ -1,25 +1,35 @@
#include "AssetDumperLocalizeEntry.h" #include "AssetDumperLocalizeEntry.h"
#include <fstream>
#include <filesystem>
#include "Dumping/Localize/LocalizeCommon.h" #include "Dumping/Localize/LocalizeCommon.h"
#include "Dumping/Localize/StringFileDumper.h" #include "Dumping/Localize/StringFileDumper.h"
using namespace T6; using namespace T6;
namespace fs = std::filesystem;
void AssetDumperLocalizeEntry::DumpPool(Zone* zone, AssetPool<LocalizeEntry>* pool, const std::string& basePath) void AssetDumperLocalizeEntry::DumpPool(Zone* zone, AssetPool<LocalizeEntry>* pool, const std::string& basePath)
{ {
if (pool->m_asset_lookup.empty()) if (pool->m_asset_lookup.empty())
return; return;
const std::string language = LocalizeCommon::GetNameOfLanguage(zone->m_language); const auto language = LocalizeCommon::GetNameOfLanguage(zone->m_language);
const std::string stringsPath = utils::Path::Combine(basePath, language + "/localizedstrings"); fs::path stringsPath(basePath);
stringsPath.append(language);
stringsPath.append("/localizedstrings");
FileAPI::DirectoryCreate(stringsPath); create_directories(stringsPath);
FileAPI::File stringFile = FileAPI::Open(utils::Path::Combine(stringsPath, zone->m_name + ".str"), FileAPI::Mode::MODE_WRITE); auto stringFilePath(stringsPath);
stringFilePath.append(zone->m_name);
stringFilePath.append(".str");
if(stringFile.IsOpen()) std::ofstream stringFile(stringFilePath, std::fstream::out | std::ofstream::binary);
if(stringFile.is_open())
{ {
StringFileDumper stringFileDumper(zone, &stringFile); StringFileDumper stringFileDumper(zone, stringFile);
stringFileDumper.SetLanguageName(language); stringFileDumper.SetLanguageName(language);
@ -28,14 +38,14 @@ void AssetDumperLocalizeEntry::DumpPool(Zone* zone, AssetPool<LocalizeEntry>* po
stringFileDumper.SetNotes(""); stringFileDumper.SetNotes("");
for(auto localizeEntry : *pool) for(auto* localizeEntry : *pool)
{ {
stringFileDumper.WriteLocalizeEntry(localizeEntry->m_name, localizeEntry->Asset()->value); stringFileDumper.WriteLocalizeEntry(localizeEntry->m_name, localizeEntry->Asset()->value);
} }
stringFileDumper.Finalize(); stringFileDumper.Finalize();
stringFile.Close(); stringFile.close();
} }
else else
{ {

View File

@ -138,7 +138,7 @@ std::string AssetDumperPhysConstraints::GetFileNameForAsset(Zone* zone, XAssetIn
return "physconstraints/" + asset->m_name; return "physconstraints/" + asset->m_name;
} }
void AssetDumperPhysConstraints::DumpAsset(Zone* zone, XAssetInfo<PhysConstraints>* asset, FileAPI::File* out) void AssetDumperPhysConstraints::DumpAsset(Zone* zone, XAssetInfo<PhysConstraints>* asset, std::ostream& stream)
{ {
assert(asset->Asset()->count <= 4); assert(asset->Asset()->count <= 4);
@ -153,5 +153,5 @@ void AssetDumperPhysConstraints::DumpAsset(Zone* zone, XAssetInfo<PhysConstraint
const auto infoString = converter.Convert(); const auto infoString = converter.Convert();
const auto stringValue = infoString.ToString("PHYSCONSTRAINTS"); const auto stringValue = infoString.ToString("PHYSCONSTRAINTS");
out->Write(stringValue.c_str(), 1, stringValue.length()); stream.write(stringValue.c_str(), stringValue.size());
} }

View File

@ -12,6 +12,6 @@ namespace T6
protected: protected:
bool ShouldDump(XAssetInfo<PhysConstraints>* asset) override; bool ShouldDump(XAssetInfo<PhysConstraints>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<PhysConstraints>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<PhysConstraints>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<PhysConstraints>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<PhysConstraints>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -86,7 +86,7 @@ std::string AssetDumperPhysPreset::GetFileNameForAsset(Zone* zone, XAssetInfo<Ph
return "physic/" + asset->m_name; return "physic/" + asset->m_name;
} }
void AssetDumperPhysPreset::DumpAsset(Zone* zone, XAssetInfo<PhysPreset>* asset, FileAPI::File* out) void AssetDumperPhysPreset::DumpAsset(Zone* zone, XAssetInfo<PhysPreset>* asset, std::ostream& stream)
{ {
auto* physPresetInfo = new PhysPresetInfo; auto* physPresetInfo = new PhysPresetInfo;
CopyToPhysPresetInfo(asset->Asset(), physPresetInfo); CopyToPhysPresetInfo(asset->Asset(), physPresetInfo);
@ -102,7 +102,7 @@ void AssetDumperPhysPreset::DumpAsset(Zone* zone, XAssetInfo<PhysPreset>* asset,
const auto infoString = converter.Convert(); const auto infoString = converter.Convert();
const auto stringValue = infoString.ToString("PHYSIC"); const auto stringValue = infoString.ToString("PHYSIC");
out->Write(stringValue.c_str(), 1, stringValue.length()); stream.write(stringValue.c_str(), stringValue.size());
delete physPresetInfo; delete physPresetInfo;
} }

View File

@ -14,6 +14,6 @@ namespace T6
protected: protected:
bool ShouldDump(XAssetInfo<PhysPreset>* asset) override; bool ShouldDump(XAssetInfo<PhysPreset>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<PhysPreset>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<PhysPreset>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<PhysPreset>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<PhysPreset>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -12,8 +12,8 @@ std::string AssetDumperQdb::GetFileNameForAsset(Zone* zone, XAssetInfo<Qdb>* ass
return asset->m_name; return asset->m_name;
} }
void AssetDumperQdb::DumpAsset(Zone* zone, XAssetInfo<Qdb>* asset, FileAPI::File* out) void AssetDumperQdb::DumpAsset(Zone* zone, XAssetInfo<Qdb>* asset, std::ostream& stream)
{ {
const auto* qdb = asset->Asset(); const auto* qdb = asset->Asset();
out->Write(qdb->buffer, 1, qdb->len); stream.write(qdb->buffer, qdb->len);
} }

View File

@ -10,6 +10,6 @@ namespace T6
protected: protected:
bool ShouldDump(XAssetInfo<Qdb>* asset) override; bool ShouldDump(XAssetInfo<Qdb>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<Qdb>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<Qdb>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<Qdb>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<Qdb>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -12,8 +12,8 @@ std::string AssetDumperRawFile::GetFileNameForAsset(Zone* zone, XAssetInfo<RawFi
return asset->m_name; return asset->m_name;
} }
void AssetDumperRawFile::DumpAsset(Zone* zone, XAssetInfo<RawFile>* asset, FileAPI::File* out) void AssetDumperRawFile::DumpAsset(Zone* zone, XAssetInfo<RawFile>* asset, std::ostream& stream)
{ {
const auto* rawFile = asset->Asset(); const auto* rawFile = asset->Asset();
out->Write(rawFile->buffer, 1, rawFile->len); stream.write(rawFile->buffer, rawFile->len);
} }

View File

@ -10,6 +10,6 @@ namespace T6
protected: protected:
bool ShouldDump(XAssetInfo<RawFile>* asset) override; bool ShouldDump(XAssetInfo<RawFile>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<RawFile>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<RawFile>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<RawFile>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<RawFile>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -12,8 +12,8 @@ std::string AssetDumperScriptParseTree::GetFileNameForAsset(Zone* zone, XAssetIn
return asset->m_name; return asset->m_name;
} }
void AssetDumperScriptParseTree::DumpAsset(Zone* zone, XAssetInfo<ScriptParseTree>* asset, FileAPI::File* out) void AssetDumperScriptParseTree::DumpAsset(Zone* zone, XAssetInfo<ScriptParseTree>* asset, std::ostream& stream)
{ {
const auto* scriptParseTree = asset->Asset(); const auto* scriptParseTree = asset->Asset();
out->Write(scriptParseTree->buffer, 1, scriptParseTree->len); stream.write(scriptParseTree->buffer, scriptParseTree->len);
} }

View File

@ -10,6 +10,6 @@ namespace T6
protected: protected:
bool ShouldDump(XAssetInfo<ScriptParseTree>* asset) override; bool ShouldDump(XAssetInfo<ScriptParseTree>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<ScriptParseTree>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<ScriptParseTree>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<ScriptParseTree>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<ScriptParseTree>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -12,8 +12,8 @@ std::string AssetDumperSlug::GetFileNameForAsset(Zone* zone, XAssetInfo<Slug>* a
return asset->m_name; return asset->m_name;
} }
void AssetDumperSlug::DumpAsset(Zone* zone, XAssetInfo<Slug>* asset, FileAPI::File* out) void AssetDumperSlug::DumpAsset(Zone* zone, XAssetInfo<Slug>* asset, std::ostream& stream)
{ {
const auto* slug = asset->Asset(); const auto* slug = asset->Asset();
out->Write(slug->buffer, 1, slug->len); stream.write(slug->buffer, slug->len);
} }

View File

@ -10,6 +10,6 @@ namespace T6
protected: protected:
bool ShouldDump(XAssetInfo<Slug>* asset) override; bool ShouldDump(XAssetInfo<Slug>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<Slug>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<Slug>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<Slug>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<Slug>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -14,14 +14,14 @@ std::string AssetDumperStringTable::GetFileNameForAsset(Zone* zone, XAssetInfo<S
return asset->m_name; return asset->m_name;
} }
void AssetDumperStringTable::DumpAsset(Zone* zone, XAssetInfo<StringTable>* asset, FileAPI::File* out) void AssetDumperStringTable::DumpAsset(Zone* zone, XAssetInfo<StringTable>* asset, std::ostream& stream)
{ {
const auto* stringTable = asset->Asset(); const auto* stringTable = asset->Asset();
CsvWriter csv(out); CsvWriter csv(stream);
for(int row = 0; row < stringTable->rowCount; row++) for(auto row = 0; row < stringTable->rowCount; row++)
{ {
for(int column = 0; column < stringTable->columnCount; column++) for(auto column = 0; column < stringTable->columnCount; column++)
{ {
const auto* cell = &stringTable->values[column + row * stringTable->columnCount]; const auto* cell = &stringTable->values[column + row * stringTable->columnCount];
csv.WriteColumn(cell->string); csv.WriteColumn(cell->string);

View File

@ -10,6 +10,6 @@ namespace T6
protected: protected:
bool ShouldDump(XAssetInfo<StringTable>* asset) override; bool ShouldDump(XAssetInfo<StringTable>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<StringTable>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<StringTable>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<StringTable>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<StringTable>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -85,7 +85,7 @@ std::string AssetDumperTracer::GetFileNameForAsset(Zone* zone, XAssetInfo<Tracer
return "tracer/" + asset->m_name; return "tracer/" + asset->m_name;
} }
void AssetDumperTracer::DumpAsset(Zone* zone, XAssetInfo<TracerDef>* asset, FileAPI::File* out) void AssetDumperTracer::DumpAsset(Zone* zone, XAssetInfo<TracerDef>* asset, std::ostream& stream)
{ {
InfoStringFromTracerConverter converter(asset->Asset(), tracer_fields, _countof(tracer_fields), [asset](const scr_string_t scrStr) -> std::string InfoStringFromTracerConverter converter(asset->Asset(), tracer_fields, _countof(tracer_fields), [asset](const scr_string_t scrStr) -> std::string
{ {
@ -98,7 +98,7 @@ void AssetDumperTracer::DumpAsset(Zone* zone, XAssetInfo<TracerDef>* asset, File
const auto infoString = converter.Convert(); const auto infoString = converter.Convert();
const auto stringValue = infoString.ToString("TRACER"); const auto stringValue = infoString.ToString("TRACER");
out->Write(stringValue.c_str(), 1, stringValue.length()); stream.write(stringValue.c_str(), stringValue.size());
} }
//void AssetDumperTracer::CheckFields() //void AssetDumperTracer::CheckFields()

View File

@ -12,6 +12,6 @@ namespace T6
protected: protected:
bool ShouldDump(XAssetInfo<TracerDef>* asset) override; bool ShouldDump(XAssetInfo<TracerDef>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<TracerDef>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<TracerDef>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<TracerDef>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<TracerDef>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -680,7 +680,7 @@ std::string AssetDumperVehicle::GetFileNameForAsset(Zone* zone, XAssetInfo<Vehic
return "vehicles/" + asset->m_name; return "vehicles/" + asset->m_name;
} }
void AssetDumperVehicle::DumpAsset(Zone* zone, XAssetInfo<VehicleDef>* asset, FileAPI::File* out) void AssetDumperVehicle::DumpAsset(Zone* zone, XAssetInfo<VehicleDef>* asset, std::ostream& stream)
{ {
InfoStringFromVehicleConverter converter(asset->Asset(), vehicle_fields, _countof(vehicle_fields), [asset](const scr_string_t scrStr) -> std::string InfoStringFromVehicleConverter converter(asset->Asset(), vehicle_fields, _countof(vehicle_fields), [asset](const scr_string_t scrStr) -> std::string
{ {
@ -693,5 +693,5 @@ void AssetDumperVehicle::DumpAsset(Zone* zone, XAssetInfo<VehicleDef>* asset, Fi
const auto infoString = converter.Convert(); const auto infoString = converter.Convert();
const auto stringValue = infoString.ToString("VEHICLEFILE"); const auto stringValue = infoString.ToString("VEHICLEFILE");
out->Write(stringValue.c_str(), 1, stringValue.length()); stream.write(stringValue.c_str(), stringValue.size());
} }

View File

@ -12,6 +12,6 @@ namespace T6
protected: protected:
bool ShouldDump(XAssetInfo<VehicleDef>* asset) override; bool ShouldDump(XAssetInfo<VehicleDef>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<VehicleDef>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<VehicleDef>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<VehicleDef>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<VehicleDef>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -1620,7 +1620,7 @@ std::string AssetDumperWeapon::GetFileNameForAsset(Zone* zone, XAssetInfo<Weapon
return "weapons/" + asset->m_name; return "weapons/" + asset->m_name;
} }
void AssetDumperWeapon::DumpAsset(Zone* zone, XAssetInfo<WeaponVariantDef>* asset, FileAPI::File* out) void AssetDumperWeapon::DumpAsset(Zone* zone, XAssetInfo<WeaponVariantDef>* asset, std::ostream& stream)
{ {
auto* fullDef = new WeaponFullDef; auto* fullDef = new WeaponFullDef;
memset(fullDef, 0, sizeof WeaponFullDef); memset(fullDef, 0, sizeof WeaponFullDef);
@ -1637,7 +1637,7 @@ void AssetDumperWeapon::DumpAsset(Zone* zone, XAssetInfo<WeaponVariantDef>* asse
const auto infoString = converter.Convert(); const auto infoString = converter.Convert();
const auto stringValue = infoString.ToString("WEAPONFILE"); const auto stringValue = infoString.ToString("WEAPONFILE");
out->Write(stringValue.c_str(), 1, stringValue.length()); stream.write(stringValue.c_str(), stringValue.size());
delete fullDef; delete fullDef;
} }

View File

@ -14,6 +14,6 @@ namespace T6
protected: protected:
bool ShouldDump(XAssetInfo<WeaponVariantDef>* asset) override; bool ShouldDump(XAssetInfo<WeaponVariantDef>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<WeaponVariantDef>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<WeaponVariantDef>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<WeaponVariantDef>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<WeaponVariantDef>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -183,7 +183,7 @@ std::string AssetDumperZBarrier::GetFileNameForAsset(Zone* zone, XAssetInfo<ZBar
return "zbarrier/" + asset->m_name; return "zbarrier/" + asset->m_name;
} }
void AssetDumperZBarrier::DumpAsset(Zone* zone, XAssetInfo<ZBarrierDef>* asset, FileAPI::File* out) void AssetDumperZBarrier::DumpAsset(Zone* zone, XAssetInfo<ZBarrierDef>* asset, std::ostream& stream)
{ {
InfoStringFromZBarrierConverter converter(asset->Asset(), zbarrier_fields, _countof(zbarrier_fields), [asset](const scr_string_t scrStr) -> std::string InfoStringFromZBarrierConverter converter(asset->Asset(), zbarrier_fields, _countof(zbarrier_fields), [asset](const scr_string_t scrStr) -> std::string
{ {
@ -196,7 +196,7 @@ void AssetDumperZBarrier::DumpAsset(Zone* zone, XAssetInfo<ZBarrierDef>* asset,
const auto infoString = converter.Convert(); const auto infoString = converter.Convert();
const auto stringValue = infoString.ToString("ZBARRIER"); const auto stringValue = infoString.ToString("ZBARRIER");
out->Write(stringValue.c_str(), 1, stringValue.length()); stream.write(stringValue.c_str(), stringValue.size());
} }
//void AssetDumperZBarrier::CheckFields() //void AssetDumperZBarrier::CheckFields()

View File

@ -12,6 +12,6 @@ namespace T6
protected: protected:
bool ShouldDump(XAssetInfo<ZBarrierDef>* asset) override; bool ShouldDump(XAssetInfo<ZBarrierDef>* asset) override;
std::string GetFileNameForAsset(Zone* zone, XAssetInfo<ZBarrierDef>* asset) override; std::string GetFileNameForAsset(Zone* zone, XAssetInfo<ZBarrierDef>* asset) override;
void DumpAsset(Zone* zone, XAssetInfo<ZBarrierDef>* asset, FileAPI::File* out) override; void DumpAsset(Zone* zone, XAssetInfo<ZBarrierDef>* asset, std::ostream& stream) override;
}; };
} }

View File

@ -15,7 +15,7 @@ const std::map<ImageFormatId, ImageFormatId> DDS_CONVERSION_TABLE
class DdsWriterInternal class DdsWriterInternal
{ {
FileAPI::IFile* m_file; std::ostream& m_stream;
Texture* m_texture; Texture* m_texture;
std::unique_ptr<Texture> m_converted_texture; std::unique_ptr<Texture> m_converted_texture;
bool m_use_dx10_extension; bool m_use_dx10_extension;
@ -190,8 +190,8 @@ public:
return ".dds"; return ".dds";
} }
DdsWriterInternal(FileAPI::IFile* file, Texture* texture) DdsWriterInternal(std::ostream& stream, Texture* texture)
: m_file(file), : m_stream(stream),
m_texture(texture), m_texture(texture),
m_use_dx10_extension(false) m_use_dx10_extension(false)
{ {
@ -204,24 +204,24 @@ public:
DDS_HEADER header{}; DDS_HEADER header{};
PopulateDdsHeader(header); PopulateDdsHeader(header);
constexpr uint32_t magic = MakeFourCc('D', 'D', 'S', ' '); constexpr auto magic = MakeFourCc('D', 'D', 'S', ' ');
m_file->Write(&magic, sizeof magic, 1); m_stream.write(reinterpret_cast<const char*>(&magic), sizeof magic);
m_file->Write(&header, sizeof header, 1); m_stream.write(reinterpret_cast<const char*>(&header), sizeof header);
if (m_use_dx10_extension) if (m_use_dx10_extension)
{ {
DDS_HEADER_DXT10 dxt10{}; DDS_HEADER_DXT10 dxt10{};
PopulateDxt10Header(dxt10); PopulateDxt10Header(dxt10);
m_file->Write(&dxt10, sizeof dxt10, 1); m_stream.write(reinterpret_cast<const char*>(&dxt10), sizeof dxt10);
} }
const int mipCount = m_texture->HasMipMaps() ? m_texture->GetMipMapCount() : 1; const auto mipCount = m_texture->HasMipMaps() ? m_texture->GetMipMapCount() : 1;
for (auto mipLevel = 0; mipLevel < mipCount; mipLevel++) for (auto mipLevel = 0; mipLevel < mipCount; mipLevel++)
{ {
const auto* buffer = m_texture->GetBufferForMipLevel(mipLevel); const auto* buffer = m_texture->GetBufferForMipLevel(mipLevel);
const auto mipLevelSize = m_texture->GetSizeOfMipLevel(mipLevel) * m_texture->GetFaceCount(); const auto mipLevelSize = m_texture->GetSizeOfMipLevel(mipLevel) * m_texture->GetFaceCount();
m_file->Write(buffer, 1, mipLevelSize); m_stream.write(reinterpret_cast<const char*>(buffer), mipLevelSize);
} }
} }
}; };
@ -239,8 +239,8 @@ std::string DdsWriter::GetFileExtension()
return DdsWriterInternal::GetFileExtension(); return DdsWriterInternal::GetFileExtension();
} }
void DdsWriter::DumpImage(FileAPI::IFile* file, Texture* texture) void DdsWriter::DumpImage(std::ostream& stream, Texture* texture)
{ {
DdsWriterInternal internal(file, texture); DdsWriterInternal internal(stream, texture);
internal.DumpImage(); internal.DumpImage();
} }

View File

@ -8,5 +8,5 @@ public:
bool SupportsImageFormat(const ImageFormat * imageFormat) override; bool SupportsImageFormat(const ImageFormat * imageFormat) override;
std::string GetFileExtension() override; std::string GetFileExtension() override;
void DumpImage(FileAPI::IFile* file, Texture* texture) override; void DumpImage(std::ostream& stream, Texture* texture) override;
}; };

View File

@ -1,9 +1,10 @@
#pragma once #pragma once
#include "Image/Texture.h" #include <ostream>
#include "Utils/FileAPI.h"
#include <string> #include <string>
#include "Image/Texture.h"
class IImageWriter class IImageWriter
{ {
public: public:
@ -11,5 +12,5 @@ public:
virtual bool SupportsImageFormat(const ImageFormat* imageFormat) = 0; virtual bool SupportsImageFormat(const ImageFormat* imageFormat) = 0;
virtual std::string GetFileExtension() = 0; virtual std::string GetFileExtension() = 0;
virtual void DumpImage(FileAPI::IFile* file, Texture* texture) = 0; virtual void DumpImage(std::ostream& stream, Texture* texture) = 0;
}; };

View File

@ -1,5 +1,6 @@
#include "IwiWriter27.h" #include "IwiWriter27.h"
#include <cassert> #include <cassert>
#include <ostream>
using namespace iwi27; using namespace iwi27;
@ -52,7 +53,7 @@ std::string IwiWriter::GetFileExtension()
return ".iwi"; return ".iwi";
} }
void IwiWriter::WriteVersion(FileAPI::IFile* file) void IwiWriter::WriteVersion(std::ostream& stream)
{ {
IwiVersion version{}; IwiVersion version{};
version.tag[0] = 'I'; version.tag[0] = 'I';
@ -60,7 +61,7 @@ void IwiWriter::WriteVersion(FileAPI::IFile* file)
version.tag[2] = 'i'; version.tag[2] = 'i';
version.version = 27; version.version = 27;
file->Write(&version, sizeof IwiVersion, 1); stream.write(reinterpret_cast<char*>(&version), sizeof IwiVersion);
} }
void IwiWriter::FillHeader2D(IwiHeader* header, Texture2D* texture) void IwiWriter::FillHeader2D(IwiHeader* header, Texture2D* texture)
@ -86,12 +87,11 @@ void IwiWriter::FillHeader3D(IwiHeader* header, Texture3D* texture)
header->flags |= IMG_FLAG_VOLMAP; header->flags |= IMG_FLAG_VOLMAP;
} }
void IwiWriter::DumpImage(FileAPI::IFile* file, Texture* texture) void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
{ {
assert(file != nullptr);
assert(texture != nullptr); assert(texture != nullptr);
WriteVersion(file); WriteVersion(stream);
IwiHeader header{}; IwiHeader header{};
header.flags = 0; header.flags = 0;
@ -102,39 +102,44 @@ void IwiWriter::DumpImage(FileAPI::IFile* file, Texture* texture)
if (!texture->HasMipMaps()) if (!texture->HasMipMaps())
header.flags |= IMG_FLAG_NOMIPMAPS; header.flags |= IMG_FLAG_NOMIPMAPS;
for (signed char& i : header.maxGlossForMip) for (auto& i : header.maxGlossForMip)
i = 0; i = 0;
size_t currentFileSize = sizeof IwiVersion + sizeof IwiHeader; auto currentFileSize = sizeof IwiVersion + sizeof IwiHeader;
const int textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1; const auto textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1;
for (int currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--) for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
{ {
const size_t mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
currentFileSize += mipLevelSize; currentFileSize += mipLevelSize;
if(currentMipLevel < static_cast<int>(_countof(iwi27::IwiHeader::fileSizeForPicmip))) if (currentMipLevel < static_cast<int>(_countof(iwi27::IwiHeader::fileSizeForPicmip)))
header.fileSizeForPicmip[currentMipLevel] = currentFileSize; header.fileSizeForPicmip[currentMipLevel] = currentFileSize;
} }
if(auto* texture2D = dynamic_cast<Texture2D*>(texture)) if (auto* texture2D = dynamic_cast<Texture2D*>(texture))
{ {
FillHeader2D(&header, texture2D); FillHeader2D(&header, texture2D);
} }
else if(auto* textureCube = dynamic_cast<TextureCube*>(texture)) else if (auto* textureCube = dynamic_cast<TextureCube*>(texture))
{ {
FillHeaderCube(&header, textureCube); FillHeaderCube(&header, textureCube);
} }
else if(auto* texture3D = dynamic_cast<Texture3D*>(texture)) else if (auto* texture3D = dynamic_cast<Texture3D*>(texture))
{ {
FillHeader3D(&header, texture3D); FillHeader3D(&header, texture3D);
} }
else
file->Write(&header, sizeof IwiHeader, 1);
for (int currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
{ {
const size_t mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); assert(false);
file->Write(texture->GetBufferForMipLevel(currentMipLevel), 1, mipLevelSize); return;
}
stream.write(reinterpret_cast<char*>(&header), sizeof IwiHeader);
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
{
const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
stream.write(reinterpret_cast<char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize);
} }
} }

View File

@ -9,7 +9,7 @@ namespace iwi27
{ {
static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat); static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat);
static void WriteVersion(FileAPI::IFile* file); static void WriteVersion(std::ostream& stream);
static void FillHeader2D(IwiHeader* header, Texture2D* texture); static void FillHeader2D(IwiHeader* header, Texture2D* texture);
static void FillHeaderCube(IwiHeader* header, TextureCube* texture); static void FillHeaderCube(IwiHeader* header, TextureCube* texture);
static void FillHeader3D(IwiHeader* header, Texture3D* texture); static void FillHeader3D(IwiHeader* header, Texture3D* texture);
@ -25,6 +25,6 @@ namespace iwi27
bool SupportsImageFormat(const ImageFormat* imageFormat) override; bool SupportsImageFormat(const ImageFormat* imageFormat) override;
std::string GetFileExtension() override; std::string GetFileExtension() override;
void DumpImage(FileAPI::IFile* file, Texture* texture) override; void DumpImage(std::ostream& stream, Texture* texture) override;
}; };
} }

View File

@ -40,7 +40,7 @@ IwiFormat IwiWriter::GetIwiFormatForImageFormat(const ImageFormat* imageFormat)
} }
} }
void IwiWriter::WriteVersion(FileAPI::IFile* file) void IwiWriter::WriteVersion(std::ostream& stream)
{ {
IwiVersion version{}; IwiVersion version{};
version.tag[0] = 'I'; version.tag[0] = 'I';
@ -48,7 +48,7 @@ void IwiWriter::WriteVersion(FileAPI::IFile* file)
version.tag[2] = 'i'; version.tag[2] = 'i';
version.version = 8; version.version = 8;
file->Write(&version, sizeof IwiVersion, 1); stream.write(reinterpret_cast<char*>(&version), sizeof IwiVersion);
} }
void IwiWriter::FillHeader2D(IwiHeader* header, Texture2D* texture) void IwiWriter::FillHeader2D(IwiHeader* header, Texture2D* texture)
@ -84,12 +84,11 @@ std::string IwiWriter::GetFileExtension()
return ".iwi"; return ".iwi";
} }
void IwiWriter::DumpImage(FileAPI::IFile* file, Texture* texture) void IwiWriter::DumpImage(std::ostream& stream, Texture* texture)
{ {
assert(file != nullptr);
assert(texture != nullptr); assert(texture != nullptr);
WriteVersion(file); WriteVersion(stream);
IwiHeader header{}; IwiHeader header{};
header.flags = 0; header.flags = 0;
@ -99,12 +98,12 @@ void IwiWriter::DumpImage(FileAPI::IFile* file, Texture* texture)
if (!texture->HasMipMaps()) if (!texture->HasMipMaps())
header.flags |= IMG_FLAG_NOMIPMAPS; header.flags |= IMG_FLAG_NOMIPMAPS;
size_t currentFileSize = sizeof IwiVersion + sizeof IwiHeader; auto currentFileSize = sizeof IwiVersion + sizeof IwiHeader;
const int textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1; const auto textureMipCount = texture->HasMipMaps() ? texture->GetMipMapCount() : 1;
for (int currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--) for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
{ {
const size_t mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
currentFileSize += mipLevelSize; currentFileSize += mipLevelSize;
if (currentMipLevel < static_cast<int>(_countof(iwi27::IwiHeader::fileSizeForPicmip))) if (currentMipLevel < static_cast<int>(_countof(iwi27::IwiHeader::fileSizeForPicmip)))
@ -123,12 +122,17 @@ void IwiWriter::DumpImage(FileAPI::IFile* file, Texture* texture)
{ {
FillHeader3D(&header, texture3D); FillHeader3D(&header, texture3D);
} }
else
file->Write(&header, sizeof iwi27::IwiHeader, 1);
for (int currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
{ {
const size_t mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount(); assert(false);
file->Write(texture->GetBufferForMipLevel(currentMipLevel), 1, mipLevelSize); return;
}
stream.write(reinterpret_cast<char*>(&header), sizeof IwiHeader);
for (auto currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
{
const auto mipLevelSize = texture->GetSizeOfMipLevel(currentMipLevel) * texture->GetFaceCount();
stream.write(reinterpret_cast<char*>(texture->GetBufferForMipLevel(currentMipLevel)), mipLevelSize);
} }
} }

View File

@ -9,7 +9,7 @@ namespace iwi8
{ {
static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat); static IwiFormat GetIwiFormatForImageFormat(const ImageFormat* imageFormat);
static void WriteVersion(FileAPI::IFile* file); static void WriteVersion(std::ostream& stream);
static void FillHeader2D(IwiHeader* header, Texture2D* texture); static void FillHeader2D(IwiHeader* header, Texture2D* texture);
static void FillHeaderCube(IwiHeader* header, TextureCube* texture); static void FillHeaderCube(IwiHeader* header, TextureCube* texture);
static void FillHeader3D(IwiHeader* header, Texture3D* texture); static void FillHeader3D(IwiHeader* header, Texture3D* texture);
@ -25,6 +25,6 @@ namespace iwi8
bool SupportsImageFormat(const ImageFormat* imageFormat) override; bool SupportsImageFormat(const ImageFormat* imageFormat) override;
std::string GetFileExtension() override; std::string GetFileExtension() override;
void DumpImage(FileAPI::IFile* file, Texture* texture) override; void DumpImage(std::ostream& stream, Texture* texture) override;
}; };
} }

View File

@ -2,28 +2,28 @@
const std::string AbstractZoneDefWriter::META_DATA_KEY_GAME = "game"; const std::string AbstractZoneDefWriter::META_DATA_KEY_GAME = "game";
AbstractZoneDefWriter::AbstractZoneDefWriter(Zone* zone, FileAPI::IFile* file) AbstractZoneDefWriter::AbstractZoneDefWriter(Zone* zone, std::ostream& stream)
: m_zone(zone),
m_stream(stream)
{ {
m_zone = zone;
m_file = file;
} }
void AbstractZoneDefWriter::EmptyLine() const void AbstractZoneDefWriter::EmptyLine() const
{ {
m_file->Printf("\n"); m_stream << "\n";
} }
void AbstractZoneDefWriter::WriteComment(const std::string& comment) const void AbstractZoneDefWriter::WriteComment(const std::string& comment) const
{ {
m_file->Printf("// %s\n", comment.c_str()); m_stream << "// " << comment << "\n";
} }
void AbstractZoneDefWriter::WriteMetaData(const std::string& metaDataKey, const std::string& metaDataValue) const void AbstractZoneDefWriter::WriteMetaData(const std::string& metaDataKey, const std::string& metaDataValue) const
{ {
m_file->Printf(">%s,%s\n", metaDataKey.c_str(), metaDataValue.c_str()); m_stream << ">" << metaDataKey << "," << metaDataValue << "\n";
} }
void AbstractZoneDefWriter::WriteEntry(const std::string& entryKey, const std::string& entryValue) const void AbstractZoneDefWriter::WriteEntry(const std::string& entryKey, const std::string& entryValue) const
{ {
m_file->Printf("%s,%s\n", entryKey.c_str(), entryValue.c_str()); m_stream << entryKey << "," << entryValue << "\n";
} }

View File

@ -1,12 +1,14 @@
#pragma once #pragma once
#include "Utils/FileAPI.h"
#include <ostream>
#include "Zone/Zone.h" #include "Zone/Zone.h"
class AbstractZoneDefWriter class AbstractZoneDefWriter
{ {
protected: protected:
Zone* m_zone; Zone* m_zone;
FileAPI::IFile* m_file; std::ostream& m_stream;
static const std::string META_DATA_KEY_GAME; static const std::string META_DATA_KEY_GAME;
@ -15,7 +17,7 @@ protected:
void WriteMetaData(const std::string& metaDataKey, const std::string& metaDataValue) const; void WriteMetaData(const std::string& metaDataKey, const std::string& metaDataValue) const;
void WriteEntry(const std::string& entryKey, const std::string& entryValue) const; void WriteEntry(const std::string& entryKey, const std::string& entryValue) const;
AbstractZoneDefWriter(Zone* zone, FileAPI::IFile* file); AbstractZoneDefWriter(Zone* zone, std::ostream& stream);
public: public:
virtual void WriteZoneDef() = 0; virtual void WriteZoneDef() = 0;
@ -25,5 +27,5 @@ class IZoneDefWriter
{ {
public: public:
virtual bool CanHandleZone(Zone* zone) const = 0; virtual bool CanHandleZone(Zone* zone) const = 0;
virtual void WriteZoneDef(Zone* zone, FileAPI::IFile* file) const = 0; virtual void WriteZoneDef(Zone* zone, std::ostream& stream) const = 0;
}; };

View File

@ -42,8 +42,8 @@ namespace IW4
} }
public: public:
ZoneDefWriterInternal(Zone* zone, FileAPI::IFile* file) ZoneDefWriterInternal(Zone* zone, std::ostream& stream)
: AbstractZoneDefWriter(zone, file) : AbstractZoneDefWriter(zone, stream)
{ {
} }
@ -63,8 +63,8 @@ bool ZoneDefWriter::CanHandleZone(Zone* zone) const
return zone->m_game == &g_GameIW4; return zone->m_game == &g_GameIW4;
} }
void ZoneDefWriter::WriteZoneDef(Zone* zone, FileAPI::IFile* file) const void ZoneDefWriter::WriteZoneDef(Zone* zone, std::ostream& stream) const
{ {
ZoneDefWriterInternal writer(zone, file); ZoneDefWriterInternal writer(zone, stream);
writer.WriteZoneDef(); writer.WriteZoneDef();
} }

View File

@ -8,6 +8,6 @@ namespace IW4
{ {
public: public:
bool CanHandleZone(Zone* zone) const override; bool CanHandleZone(Zone* zone) const override;
void WriteZoneDef(Zone* zone, FileAPI::IFile* file) const override; void WriteZoneDef(Zone* zone, std::ostream& stream) const override;
}; };
} }

View File

@ -80,8 +80,8 @@ namespace T6
} }
public: public:
ZoneDefWriterInternal(Zone* zone, FileAPI::IFile* file) ZoneDefWriterInternal(Zone* zone, std::ostream& stream)
: AbstractZoneDefWriter(zone, file) : AbstractZoneDefWriter(zone, stream)
{ {
} }
@ -117,8 +117,8 @@ bool ZoneDefWriter::CanHandleZone(Zone* zone) const
return zone->m_game == &g_GameT6; return zone->m_game == &g_GameT6;
} }
void ZoneDefWriter::WriteZoneDef(Zone* zone, FileAPI::IFile* file) const void ZoneDefWriter::WriteZoneDef(Zone* zone, std::ostream& stream) const
{ {
ZoneDefWriterInternal writer(zone, file); ZoneDefWriterInternal writer(zone, stream);
writer.WriteZoneDef(); writer.WriteZoneDef();
} }

View File

@ -8,6 +8,6 @@ namespace T6
{ {
public: public:
bool CanHandleZone(Zone* zone) const override; bool CanHandleZone(Zone* zone) const override;
void WriteZoneDef(Zone* zone, FileAPI::IFile* file) const override; void WriteZoneDef(Zone* zone, std::ostream& stream) const override;
}; };
} }

View File

@ -3,13 +3,13 @@
#include <set> #include <set>
#include <regex> #include <regex>
#include <filesystem> #include <filesystem>
#include <fstream>
#include "Utils/ClassUtils.h"
#include "Utils/Arguments/ArgumentParser.h" #include "Utils/Arguments/ArgumentParser.h"
#include "ZoneLoading.h" #include "ZoneLoading.h"
#include "ObjWriting.h" #include "ObjWriting.h"
#include "ContentLister/ContentPrinter.h" #include "ContentLister/ContentPrinter.h"
#include "Utils/PathUtils.h"
#include "Utils/FileAPI.h"
#include "ObjLoading.h" #include "ObjLoading.h"
#include "SearchPath/SearchPaths.h" #include "SearchPath/SearchPaths.h"
#include "SearchPath/SearchPathFilesystem.h" #include "SearchPath/SearchPathFilesystem.h"
@ -19,6 +19,9 @@
#include "Game/IW4/ZoneDefWriterIW4.h" #include "Game/IW4/ZoneDefWriterIW4.h"
#include "Game/T6/ZoneDefWriterT6.h" #include "Game/T6/ZoneDefWriterT6.h"
#include "Utils/ObjFileStream.h"
namespace fs = std::filesystem;
const IZoneDefWriter* const ZONE_DEF_WRITERS[] const IZoneDefWriter* const ZONE_DEF_WRITERS[]
{ {
@ -33,7 +36,7 @@ class Unlinker::Impl
SearchPathFilesystem* m_last_zone_search_path; SearchPathFilesystem* m_last_zone_search_path;
std::set<std::string> m_absolute_search_paths; std::set<std::string> m_absolute_search_paths;
bool ShouldLoadObj() const _NODISCARD bool ShouldLoadObj() const
{ {
return m_args.m_task != UnlinkerArgs::ProcessingTask::LIST; return m_args.m_task != UnlinkerArgs::ProcessingTask::LIST;
} }
@ -80,7 +83,7 @@ class Unlinker::Impl
SearchPaths GetSearchPathsForZone(const std::string& zonePath) SearchPaths GetSearchPathsForZone(const std::string& zonePath)
{ {
SearchPaths searchPathsForZone; SearchPaths searchPathsForZone;
const std::string absoluteZoneDirectory = absolute(std::filesystem::path(zonePath).remove_filename()).string(); const auto absoluteZoneDirectory = fs::absolute(std::filesystem::path(zonePath).remove_filename()).string();
if (m_last_zone_search_path != nullptr && m_last_zone_search_path->GetPath() == absoluteZoneDirectory) if (m_last_zone_search_path != nullptr && m_last_zone_search_path->GetPath() == absoluteZoneDirectory)
{ {
@ -115,19 +118,19 @@ class Unlinker::Impl
{ {
for (const auto& path : m_args.m_user_search_paths) for (const auto& path : m_args.m_user_search_paths)
{ {
std::string absolutePath = std::filesystem::absolute(path).string(); auto absolutePath = fs::absolute(path);
if (!FileAPI::DirectoryExists(absolutePath)) if (!fs::is_directory(absolutePath))
{ {
printf("Could not find directory of search path: \"%s\"\n", path.c_str()); printf("Could not find directory of search path: \"%s\"\n", path.c_str());
return false; return false;
} }
auto* searchPath = new SearchPathFilesystem(absolutePath); auto searchPath = std::make_unique<SearchPathFilesystem>(absolutePath.string());
LoadSearchPath(searchPath); LoadSearchPath(searchPath.get());
m_search_paths.CommitSearchPath(searchPath); m_search_paths.CommitSearchPath(std::move(searchPath));
m_absolute_search_paths.insert(absolutePath); m_absolute_search_paths.insert(absolutePath.string());
} }
if (m_args.m_verbose) if (m_args.m_verbose)
@ -161,23 +164,26 @@ class Unlinker::Impl
} }
else if (m_args.m_task == UnlinkerArgs::ProcessingTask::DUMP) else if (m_args.m_task == UnlinkerArgs::ProcessingTask::DUMP)
{ {
const std::string outputFolderPath = m_args.GetOutputFolderPathForZone(zone); const auto outputFolderPath = m_args.GetOutputFolderPathForZone(zone);
FileAPI::DirectoryCreate(outputFolderPath); fs::create_directories(outputFolderPath);
const std::string zoneDefinitionFileFolder = utils::Path::Combine(outputFolderPath, "zone_source"); fs::path zoneDefinitionFileFolder(outputFolderPath);
FileAPI::DirectoryCreate(zoneDefinitionFileFolder); zoneDefinitionFileFolder.append("zone_source");
fs::create_directories(zoneDefinitionFileFolder);
FileAPI::File zoneDefinitionFile = FileAPI::Open( auto zoneDefinitionFilePath(zoneDefinitionFileFolder);
utils::Path::Combine(zoneDefinitionFileFolder, zone->m_name + ".zone"), zoneDefinitionFilePath.append(zone->m_name);
FileAPI::Mode::MODE_WRITE); zoneDefinitionFilePath.replace_extension(".zone");
if (zoneDefinitionFile.IsOpen()) std::ofstream zoneDefinitionFile(zoneDefinitionFilePath, std::fstream::out | std::fstream::binary);
if (zoneDefinitionFile.is_open())
{ {
for (auto zoneDefWriter : ZONE_DEF_WRITERS) for (const auto* zoneDefWriter : ZONE_DEF_WRITERS)
{ {
if (zoneDefWriter->CanHandleZone(zone)) if (zoneDefWriter->CanHandleZone(zone))
{ {
zoneDefWriter->WriteZoneDef(zone, &zoneDefinitionFile); zoneDefWriter->WriteZoneDef(zone, zoneDefinitionFile);
break; break;
} }
} }
@ -189,7 +195,7 @@ class Unlinker::Impl
return false; return false;
} }
zoneDefinitionFile.Close(); zoneDefinitionFile.close();
} }
return true; return true;
@ -214,18 +220,18 @@ public:
for (const auto& zonePath : m_args.m_zones_to_load) for (const auto& zonePath : m_args.m_zones_to_load)
{ {
if (!FileAPI::FileExists(zonePath)) if (!fs::is_regular_file(zonePath))
{ {
printf("Could not find file \"%s\".\n", zonePath.c_str()); printf("Could not find file \"%s\".\n", zonePath.c_str());
continue; continue;
} }
std::string absoluteZoneDirectory = absolute(std::filesystem::path(zonePath).remove_filename()).string(); auto absoluteZoneDirectory = absolute(std::filesystem::path(zonePath).remove_filename()).string();
SearchPaths searchPathsForZone = GetSearchPathsForZone(absoluteZoneDirectory); auto searchPathsForZone = GetSearchPathsForZone(absoluteZoneDirectory);
searchPathsForZone.IncludeSearchPath(&m_search_paths); searchPathsForZone.IncludeSearchPath(&m_search_paths);
Zone* zone = ZoneLoading::LoadZone(zonePath); auto* zone = ZoneLoading::LoadZone(zonePath);
if (zone == nullptr) if (zone == nullptr)
{ {
printf("Failed to load zone \"%s\".\n", zonePath.c_str()); printf("Failed to load zone \"%s\".\n", zonePath.c_str());

View File

@ -10,13 +10,15 @@
#define _CPP_VERSION 0 #define _CPP_VERSION 0
#endif #endif
#ifndef _NODISCARD #ifdef _NODISCARD
#undef _NODISCARD
#endif
#if _CPP_VERSION >= 201703L #if _CPP_VERSION >= 201703L
#define _NODISCARD [[nodiscard]] #define _NODISCARD [[nodiscard]]
#else #else
#define _NODISCARD #define _NODISCARD
#endif #endif
#endif
template <class T> template <class T>
struct Movable struct Movable

View File

@ -1,145 +0,0 @@
#include "FileAPI.h"
#include <cstdarg>
#include <cstdio>
#include <filesystem>
bool FileAPI::FileExists(const std::string& fileName)
{
return std::filesystem::exists(fileName);
}
uint64_t FileAPI::FileSize(const std::string& fileName)
{
return std::filesystem::file_size(fileName);
}
bool FileAPI::DirectoryCreate(const std::string& directoryPath)
{
return std::filesystem::create_directories(directoryPath);
}
bool FileAPI::DirectoryExists(const std::string& directoryName)
{
return std::filesystem::is_directory(directoryName);
}
FileAPI::File FileAPI::Open(const std::string& filename, const Mode mode)
{
const char* modeStr;
switch (mode)
{
default:
case Mode::MODE_READ:
modeStr = "rb";
break;
case Mode::MODE_WRITE:
modeStr = "wb";
break;
}
FILE* handle;
if (fopen_s(&handle, filename.c_str(), modeStr) != 0)
{
return File(nullptr);
}
return File(handle);
}
FileAPI::File::File()
{
this->m_handle = nullptr;
}
FileAPI::File::File(void* handle)
{
this->m_handle = handle;
}
FileAPI::File::File(File&& f) noexcept
{
m_handle = f.m_handle;
f.m_handle = nullptr;
}
FileAPI::File::~File()
{
this->Close();
}
FileAPI::File& FileAPI::File::operator=(File&& f) noexcept
{
m_handle = f.m_handle;
f.m_handle = nullptr;
return *this;
}
bool FileAPI::File::IsOpen()
{
return this->m_handle != nullptr;
}
size_t FileAPI::File::Read(void* buffer, const size_t elementSize, const size_t elementCount)
{
if (!this->IsOpen())
return 0;
return fread(buffer, elementSize, elementCount, static_cast<FILE*>(m_handle));
}
size_t FileAPI::File::Write(const void* data, const size_t elementSize, const size_t elementCount)
{
if (!this->IsOpen())
return 0;
return fwrite(data, elementSize, elementCount, static_cast<FILE*>(m_handle));
}
void FileAPI::File::Skip(const int64_t amount)
{
if (!this->IsOpen())
return;
_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, ...)
{
va_list ap;
if (!this->IsOpen())
return 0;
va_start(ap, fmt);
const int result = vfprintf(static_cast<FILE*>(m_handle), fmt, ap);
va_end(ap);
return result;
}
int64_t FileAPI::File::Pos()
{
return _ftelli64(static_cast<FILE*>(m_handle));
}
void FileAPI::File::Goto(const int64_t pos)
{
_fseeki64(static_cast<FILE*>(m_handle), pos, SEEK_SET);
}
void FileAPI::File::Close()
{
if (this->m_handle != nullptr)
{
fclose(static_cast<FILE*>(m_handle));
this->m_handle = nullptr;
}
}

View File

@ -1,63 +0,0 @@
#pragma once
#include <cstdint>
#include <string>
class FileAPI
{
public:
enum class Mode
{
MODE_READ = 0,
MODE_WRITE = 1
};
class IFile
{
public:
virtual ~IFile() = default;
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(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;
};
class File final : public IFile
{
void* m_handle;
public:
File();
explicit File(void* handle);
File(File&) = delete;
File(File&& f) noexcept;
~File() override;
File& operator=(File&) = delete;
File& operator=(File&& f) noexcept;
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;
};
static bool FileExists(const std::string& fileName);
static uint64_t FileSize(const std::string& fileName);
static bool DirectoryCreate(const std::string& directoryPath);
static bool DirectoryExists(const std::string& directoryName);
static File Open(const std::string& filename, Mode mode);
};

View File

@ -1,41 +0,0 @@
#include "PathUtils.h"
#include <filesystem>
namespace utils
{
std::string Path::GetFilename(const std::string& pathInput)
{
const std::filesystem::path path(pathInput);
return path.filename().string();
}
std::string Path::GetFilenameWithoutExtension(const std::string& pathInput)
{
const std::filesystem::path path(pathInput);
return path.filename().replace_extension().string();
}
std::string Path::GetExtension(const std::string& pathInput)
{
const std::filesystem::path path(pathInput);
return path.extension().string();
}
std::string Path::GetDirectory(const std::string& pathInput)
{
std::filesystem::path path(pathInput);
return path.remove_filename().string();
}
std::string Path::Combine(const std::string& p1, const std::string& p2)
{
std::filesystem::path path(p1);
return path.append(p2).string();
}
}

View File

@ -1,16 +0,0 @@
#pragma once
#include <string>
namespace utils
{
class Path
{
public:
static std::string GetFilename(const std::string& pathInput);
static std::string GetFilenameWithoutExtension(const std::string& pathInput);
static std::string GetExtension(const std::string& pathInput);
static std::string GetDirectory(const std::string& pathInput);
static std::string Combine(const std::string& p1, const std::string& p2);
};
}

View File

@ -1,16 +1,17 @@
#include "LoadingFileStream.h" #include "LoadingFileStream.h"
LoadingFileStream::LoadingFileStream(FileAPI::File* file) LoadingFileStream::LoadingFileStream(std::istream& stream)
: m_stream(stream)
{ {
m_file = file;
} }
size_t LoadingFileStream::Load(void* buffer, const size_t length) size_t LoadingFileStream::Load(void* buffer, const size_t length)
{ {
return m_file->Read(buffer, 1, length); m_stream.read(static_cast<char*>(buffer), length);
return static_cast<size_t>(m_stream.gcount());
} }
int64_t LoadingFileStream::Pos() int64_t LoadingFileStream::Pos()
{ {
return m_file->Pos(); return m_stream.tellg();
} }

View File

@ -1,13 +1,15 @@
#pragma once #pragma once
#include <istream>
#include "ILoadingStream.h" #include "ILoadingStream.h"
#include "Utils/FileAPI.h"
class LoadingFileStream final : public ILoadingStream class LoadingFileStream final : public ILoadingStream
{ {
FileAPI::File* m_file; std::istream& m_stream;
public: public:
explicit LoadingFileStream(FileAPI::File* file); explicit LoadingFileStream(std::istream& stream);
size_t Load(void* buffer, size_t length) override; size_t Load(void* buffer, size_t length) override;
int64_t Pos() override; int64_t Pos() override;

View File

@ -1,5 +1,7 @@
#include "StepDumpData.h" #include "StepDumpData.h"
#include <fstream>
StepDumpData::StepDumpData(const unsigned int dumpCount) StepDumpData::StepDumpData(const unsigned int dumpCount)
{ {
m_dump_count = dumpCount; m_dump_count = dumpCount;
@ -10,7 +12,7 @@ void StepDumpData::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream)
uint8_t tempBuffer[128]; uint8_t tempBuffer[128];
unsigned int dumpedBytes = 0; unsigned int dumpedBytes = 0;
FileAPI::File tempFile = FileAPI::Open("dump.dat", FileAPI::Mode::MODE_WRITE); std::ofstream tempFile("dump.dat", std::fstream::out | std::fstream::binary);
while (dumpedBytes < m_dump_count) while (dumpedBytes < m_dump_count)
{ {
@ -25,14 +27,14 @@ void StepDumpData::PerformStep(ZoneLoader* zoneLoader, ILoadingStream* stream)
toDump = sizeof(tempBuffer); toDump = sizeof(tempBuffer);
} }
const size_t loadedSize = stream->Load(tempBuffer, toDump); const auto loadedSize = stream->Load(tempBuffer, toDump);
dumpedBytes += loadedSize; dumpedBytes += loadedSize;
if (loadedSize == 0) if (loadedSize == 0)
break; break;
tempFile.Write(tempBuffer, 1, loadedSize); tempFile.write(reinterpret_cast<char*>(tempBuffer), loadedSize);
} }
tempFile.Close(); tempFile.close();
} }

View File

@ -12,13 +12,13 @@ ZoneLoader::ZoneLoader(Zone* zone)
ZoneLoader::~ZoneLoader() ZoneLoader::~ZoneLoader()
{ {
for(auto step : m_steps) for(auto* step : m_steps)
{ {
delete step; delete step;
} }
m_steps.clear(); m_steps.clear();
for(auto processor : m_processors) for(auto* processor : m_processors)
{ {
delete processor; delete processor;
} }
@ -27,9 +27,9 @@ ZoneLoader::~ZoneLoader()
ILoadingStream* ZoneLoader::BuildLoadingChain(ILoadingStream* rootStream) ILoadingStream* ZoneLoader::BuildLoadingChain(ILoadingStream* rootStream)
{ {
ILoadingStream* currentStream = rootStream; auto* currentStream = rootStream;
for(auto processor : m_processors) for(auto* processor : m_processors)
{ {
processor->SetBaseStream(currentStream); processor->SetBaseStream(currentStream);
@ -74,14 +74,14 @@ void ZoneLoader::RemoveStreamProcessor(StreamProcessor* streamProcessor)
} }
} }
Zone* ZoneLoader::LoadZone(FileAPI::File* file) Zone* ZoneLoader::LoadZone(std::istream& stream)
{ {
LoadingFileStream fileStream(file); LoadingFileStream fileStream(stream);
ILoadingStream* endStream = BuildLoadingChain(&fileStream); auto* endStream = BuildLoadingChain(&fileStream);
try try
{ {
for(auto step : m_steps) for(auto* step : m_steps)
{ {
step->PerformStep(this, endStream); step->PerformStep(this, endStream);

View File

@ -3,10 +3,10 @@
#include "ILoadingStep.h" #include "ILoadingStep.h"
#include "Zone/Zone.h" #include "Zone/Zone.h"
#include "Zone/XBlock.h" #include "Zone/XBlock.h"
#include "Utils/FileAPI.h"
#include "StreamProcessor.h" #include "StreamProcessor.h"
#include <vector> #include <vector>
#include <istream>
class ILoadingStep; class ILoadingStep;
@ -33,5 +33,5 @@ public:
void RemoveStreamProcessor(StreamProcessor* streamProcessor); void RemoveStreamProcessor(StreamProcessor* streamProcessor);
Zone* LoadZone(FileAPI::File* file); Zone* LoadZone(std::istream& stream);
}; };

View File

@ -1,8 +1,14 @@
#include "ZoneLoading.h" #include "ZoneLoading.h"
#include "Utils/PathUtils.h" #include <filesystem>
#include <fstream>
#include <iostream>
#include "Game/IW4/ZoneLoaderFactoryIW4.h" #include "Game/IW4/ZoneLoaderFactoryIW4.h"
#include "Game/T6/ZoneLoaderFactoryT6.h" #include "Game/T6/ZoneLoaderFactoryT6.h"
#include "Utils/ObjFileStream.h"
namespace fs = std::filesystem;
IZoneLoaderFactory* ZoneLoaderFactories[] IZoneLoaderFactory* ZoneLoaderFactories[]
{ {
@ -12,17 +18,22 @@ IZoneLoaderFactory* ZoneLoaderFactories[]
Zone* ZoneLoading::LoadZone(const std::string& path) Zone* ZoneLoading::LoadZone(const std::string& path)
{ {
std::string zoneName = utils::Path::GetFilenameWithoutExtension(path); auto zoneName = fs::path(path).filename().replace_extension("").string();
FileAPI::File file = FileAPI::Open(path, FileAPI::Mode::MODE_READ); std::ifstream file(path, std::fstream::in | std::fstream::binary);
if(!file.IsOpen()) if(!file.is_open())
{ {
printf("Could not open file '%s'.\n", path.c_str()); printf("Could not open file '%s'.\n", path.c_str());
return nullptr; return nullptr;
} }
ZoneHeader header{}; ZoneHeader header{};
file.Read(&header, sizeof(ZoneHeader), 1); file.read(reinterpret_cast<char*>(&header), sizeof header);
if(file.gcount() != sizeof header)
{
std::cout << "Failed to read zone header from file '" << path << "'.\n";
return nullptr;
}
ZoneLoader* zoneLoader = nullptr; ZoneLoader* zoneLoader = nullptr;
for(auto* factory : ZoneLoaderFactories) for(auto* factory : ZoneLoaderFactories)
@ -39,8 +50,9 @@ Zone* ZoneLoading::LoadZone(const std::string& path)
return nullptr; return nullptr;
} }
Zone* loadedZone = zoneLoader->LoadZone(&file); auto* loadedZone = zoneLoader->LoadZone(file);
delete zoneLoader;
file.Close(); file.close();
return loadedZone; return loadedZone;
} }