diff --git a/src/Linker/Linker.cpp b/src/Linker/Linker.cpp index c6d2940e..42090924 100644 --- a/src/Linker/Linker.cpp +++ b/src/Linker/Linker.cpp @@ -9,6 +9,7 @@ #include "LinkerSearchPaths.h" #include "ObjContainer/IPak/IPakWriter.h" #include "ObjContainer/IWD/IWD.h" +#include "ObjContainer/IWD/IWDWriter.h" #include "ObjLoading.h" #include "ObjWriting.h" #include "SearchPath/SearchPaths.h" @@ -45,7 +46,7 @@ enum class ProjectType NONE, FASTFILE, IPAK, - + IWD, MAX }; @@ -53,7 +54,7 @@ constexpr const char* PROJECT_TYPE_NAMES[static_cast(ProjectType::MAX) "none", "fastfile", "ipak", -}; + "iwd"}; class LinkerImpl final : public Linker { @@ -462,6 +463,32 @@ class LinkerImpl final : public Linker return true; } + bool BuildIWD(const std::string& projectName, const ZoneDefinition& zoneDefinition, SearchPaths& assetSearchPaths) const + { + const fs::path iwdFolderPath(m_args.GetOutputFolderPathForProject(projectName)); + auto iwdFilePath(iwdFolderPath); + const auto iwdFileName = zoneDefinition.m_name + ".iwd"; + iwdFilePath.append(iwdFileName); + + fs::create_directories(iwdFolderPath); + + const auto iwdWriter = IWDWriter::Create(iwdFilePath.string(), &assetSearchPaths); + for (const auto& assetEntry : zoneDefinition.m_assets) + { + iwdWriter->AddFile(assetEntry.m_asset_name); + } + + if (!iwdWriter->Write()) + { + std::cout << "Writing iwd failed." << std::endl; + return false; + } + + std::cout << "Created iwd \"" << iwdFilePath.string() << "\"\n"; + + return true; + } + bool BuildReferencedTargets(const std::string& projectName, const std::string& targetName, const ZoneDefinition& zoneDefinition) { return std::all_of(zoneDefinition.m_targets_to_build.begin(), @@ -512,6 +539,10 @@ class LinkerImpl final : public Linker result = BuildIPak(projectName, *zoneDefinition, assetSearchPaths); break; + case ProjectType::IWD: + result = BuildIWD(projectName, *zoneDefinition, assetSearchPaths); + break; + default: assert(false); result = false; diff --git a/src/ObjWriting/ObjContainer/IWD/IWDWriter.cpp b/src/ObjWriting/ObjContainer/IWD/IWDWriter.cpp index e69de29b..e75c947e 100644 --- a/src/ObjWriting/ObjContainer/IWD/IWDWriter.cpp +++ b/src/ObjWriting/ObjContainer/IWD/IWDWriter.cpp @@ -0,0 +1,105 @@ +#include "IWDWriter.h" + +#include +#include +#include "../minizip/zip.h" + +class IWDWriterImpl final : public IWDWriter +{ +public: + explicit IWDWriterImpl(const std::string& iwdFileName, ISearchPath* assetSearchPath) + : m_filename(iwdFileName), + m_asset_search_path(assetSearchPath), + m_files(0) + { + m_zipfile = zipOpen(m_filename.c_str(), APPEND_STATUS_CREATE); + if (!m_zipfile) + { + throw std::runtime_error("Error creating IWD file: \"" + m_filename + "\""); + } + } + + void AddFile(std::string fileName) override + { + m_files.emplace_back(std::move(fileName)); + } + + bool AddFileToArchive(const std::string& fileName, const std::unique_ptr& fileData, const size_t& fileSize) + { + zip_fileinfo zi = {}; + + if (zipOpenNewFileInZip(m_zipfile, fileName.c_str(), &zi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION) != ZIP_OK) + { + zipClose(m_zipfile, NULL); + throw std::runtime_error( "Could not open new file in IWD \"" + fileName + "\"\n"); + } + + if (zipWriteInFileInZip(m_zipfile, fileData.get(), fileSize) != ZIP_OK) + { + zipClose(m_zipfile, NULL); + throw std::runtime_error("Could not write file data to IWD \"" + fileName + "\"\n"); + } + + if (zipCloseFileInZip(m_zipfile) != ZIP_OK) + { + zipClose(m_zipfile, NULL); + throw std::runtime_error("Could not close file in IWD \"" + fileName + "\"\n"); + } + + return true; + } + + std::unique_ptr ReadFileDataFromSearchPath(const std::string& fileName, size_t& fileSize) const + { + const auto openFile = m_asset_search_path->Open(fileName); + if (!openFile.IsOpen()) + { + std::cerr << "Could not open file for writing to IWD \"" << fileName << "\"\n"; + return nullptr; + } + + fileSize = static_cast(openFile.m_length); + auto fileData = std::make_unique(fileSize); + openFile.m_stream->read(fileData.get(), fileSize); + + return fileData; + } + + bool WriteFileData(const std::string& fileName) + { + size_t fileSize; + const auto fileData = ReadFileDataFromSearchPath(fileName, fileSize); + if (!fileData) + return false; + + AddFileToArchive(fileName, fileData, fileSize); + + return true; + } + + bool Write() override + { + const auto result = std::all_of(m_files.begin(), + m_files.end(), + [this](const std::string& fileName) + { + return WriteFileData(fileName); + }); + + zipClose(m_zipfile, NULL); + return result; + } + +private: + const std::string m_filename; + + ISearchPath* m_asset_search_path; + std::vector m_files; + + zipFile m_zipfile; +}; + +std::unique_ptr IWDWriter::Create(const std::string& iwdFileName, ISearchPath* assetSearchPath) +{ + return std::make_unique(iwdFileName, assetSearchPath); +} diff --git a/src/ObjWriting/ObjContainer/IWD/IWDWriter.h b/src/ObjWriting/ObjContainer/IWD/IWDWriter.h index e69de29b..bc72ed4f 100644 --- a/src/ObjWriting/ObjContainer/IWD/IWDWriter.h +++ b/src/ObjWriting/ObjContainer/IWD/IWDWriter.h @@ -0,0 +1,24 @@ +#pragma once +#include "SearchPath/ISearchPath.h" + +#include +#include + +class IWDWriter +{ +public: + static constexpr auto USE_COMPRESSION = true; + + IWDWriter() = default; + virtual ~IWDWriter() = default; + + IWDWriter(const IWDWriter& other) = default; + IWDWriter(IWDWriter&& other) noexcept = default; + IWDWriter& operator=(const IWDWriter& other) = default; + IWDWriter& operator=(IWDWriter&& other) noexcept = default; + + virtual void AddFile(std::string fileName) = 0; + virtual bool Write() = 0; + + static std::unique_ptr Create(const std::string& iwdFileName, ISearchPath* assetSearchPath); +}; \ No newline at end of file