From 4f995751ce655af3a162b0680be61a74b7f9e6f4 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 27 Mar 2021 16:45:30 +0100 Subject: [PATCH] Add load argument to unlinker to load zones before trying to unlink specified zones this allows to make sure certain ipaks are loaded before dumping --- src/Linker/LinkerArgs.cpp | 1 + src/Unlinker/Unlinker.cpp | 153 ++++++++++++------ src/Unlinker/UnlinkerArgs.cpp | 21 ++- src/Unlinker/UnlinkerArgs.h | 1 + .../Game/IW4/ZoneLoaderFactoryIW4.cpp | 9 +- .../Game/T6/ZoneLoaderFactoryT6.cpp | 10 +- src/ZoneLoading/Loading/ZoneLoader.cpp | 29 ++-- src/ZoneLoading/Loading/ZoneLoader.h | 7 +- src/ZoneLoading/ZoneLoading.cpp | 6 +- src/ZoneLoading/ZoneLoading.h | 2 +- 10 files changed, 158 insertions(+), 81 deletions(-) diff --git a/src/Linker/LinkerArgs.cpp b/src/Linker/LinkerArgs.cpp index 8e3589b8..e19f33d7 100644 --- a/src/Linker/LinkerArgs.cpp +++ b/src/Linker/LinkerArgs.cpp @@ -253,6 +253,7 @@ bool LinkerArgs::ParseArgs(const int argc, const char** argv) return false; } + // -l; --load if (m_argument_parser.IsOptionSpecified(OPTION_LOAD)) m_zones_to_load = m_argument_parser.GetParametersForOption(OPTION_LOAD); diff --git a/src/Unlinker/Unlinker.cpp b/src/Unlinker/Unlinker.cpp index d3710341..425fe675 100644 --- a/src/Unlinker/Unlinker.cpp +++ b/src/Unlinker/Unlinker.cpp @@ -36,6 +36,8 @@ class Unlinker::Impl SearchPathFilesystem* m_last_zone_search_path; std::set m_absolute_search_paths; + std::vector> m_loaded_zones; + _NODISCARD bool ShouldLoadObj() const { return m_args.m_task != UnlinkerArgs::ProcessingTask::LIST; @@ -102,7 +104,7 @@ class Unlinker::Impl LoadSearchPath(m_last_zone_search_path); } - for(auto* iwd : IWD::Repository) + for (auto* iwd : IWD::Repository) { searchPathsForZone.IncludeSearchPath(iwd); } @@ -174,7 +176,7 @@ class Unlinker::Impl } } - if(!result) + if (!result) { printf("Failed to find writer for zone definition file of zone \"%s\".\n", zone->m_name.c_str()); } @@ -228,7 +230,7 @@ class Unlinker::Impl context.m_zone = zone; context.m_base_path = outputFolderPath; - if(m_args.m_use_gdt) + if (m_args.m_use_gdt) { if (!OpenGdtFile(zone, zoneDefinitionFileFolder, gdtStream)) return false; @@ -240,7 +242,7 @@ class Unlinker::Impl ObjWriting::DumpZone(context); - if(m_args.m_use_gdt) + if (m_args.m_use_gdt) { context.m_gdt->EndStream(); gdtStream.close(); @@ -250,6 +252,101 @@ class Unlinker::Impl return true; } + bool LoadZones() + { + for (const auto& zonePath : m_args.m_zones_to_load) + { + if (!fs::is_regular_file(zonePath)) + { + printf("Could not find file \"%s\".\n", zonePath.c_str()); + continue; + } + + auto absoluteZoneDirectory = absolute(std::filesystem::path(zonePath).remove_filename()).string(); + + auto searchPathsForZone = GetSearchPathsForZone(absoluteZoneDirectory); + searchPathsForZone.IncludeSearchPath(&m_search_paths); + + auto zone = ZoneLoading::LoadZone(zonePath); + if (zone == nullptr) + { + printf("Failed to load zone \"%s\".\n", zonePath.c_str()); + return false; + } + + if (m_args.m_verbose) + { + printf("Loaded zone \"%s\"\n", zone->m_name.c_str()); + } + + if (ShouldLoadObj()) + { + ObjLoading::LoadReferencedContainersForZone(&searchPathsForZone, zone.get()); + ObjLoading::LoadObjDataForZone(&searchPathsForZone, zone.get()); + } + + + m_loaded_zones.emplace_back(std::move(zone)); + } + + return true; + } + + void UnloadZones() + { + if (ShouldLoadObj()) + { + for (auto& loadedZone : m_loaded_zones) + { + ObjLoading::UnloadContainersOfZone(loadedZone.get()); + } + } + m_loaded_zones.clear(); + } + + bool UnlinkZones() + { + for (const auto& zonePath : m_args.m_zones_to_unlink) + { + if (!fs::is_regular_file(zonePath)) + { + printf("Could not find file \"%s\".\n", zonePath.c_str()); + continue; + } + + auto absoluteZoneDirectory = absolute(std::filesystem::path(zonePath).remove_filename()).string(); + + auto searchPathsForZone = GetSearchPathsForZone(absoluteZoneDirectory); + searchPathsForZone.IncludeSearchPath(&m_search_paths); + + auto zone = ZoneLoading::LoadZone(zonePath); + if (zone == nullptr) + { + printf("Failed to load zone \"%s\".\n", zonePath.c_str()); + return false; + } + + if (m_args.m_verbose) + { + printf("Loaded zone \"%s\"\n", zone->m_name.c_str()); + } + + if (ShouldLoadObj()) + { + ObjLoading::LoadReferencedContainersForZone(&searchPathsForZone, zone.get()); + ObjLoading::LoadObjDataForZone(&searchPathsForZone, zone.get()); + } + + if (!HandleZone(zone.get())) + return false; + + if (ShouldLoadObj()) + ObjLoading::UnloadContainersOfZone(zone.get()); + } + + return true; + } + public: Impl() { @@ -267,51 +364,13 @@ public: if (!BuildSearchPaths()) return false; - for (const auto& zonePath : m_args.m_zones_to_load) - { - if (!fs::is_regular_file(zonePath)) - { - printf("Could not find file \"%s\".\n", zonePath.c_str()); - continue; - } + if (!LoadZones()) + return false; - auto absoluteZoneDirectory = absolute(std::filesystem::path(zonePath).remove_filename()).string(); + const auto result = UnlinkZones(); - auto searchPathsForZone = GetSearchPathsForZone(absoluteZoneDirectory); - searchPathsForZone.IncludeSearchPath(&m_search_paths); - - auto* zone = ZoneLoading::LoadZone(zonePath); - if (zone == nullptr) - { - printf("Failed to load zone \"%s\".\n", zonePath.c_str()); - return false; - } - - if (m_args.m_verbose) - { - printf("Loaded zone \"%s\"\n", zone->m_name.c_str()); - } - - if (ShouldLoadObj()) - { - ObjLoading::LoadReferencedContainersForZone(&searchPathsForZone, zone); - ObjLoading::LoadObjDataForZone(&searchPathsForZone, zone); - } - - if (!HandleZone(zone)) - { - return false; - } - - if (ShouldLoadObj()) - { - ObjLoading::UnloadContainersOfZone(zone); - } - - delete zone; - } - - return true; + UnloadZones(); + return result; } }; diff --git a/src/Unlinker/UnlinkerArgs.cpp b/src/Unlinker/UnlinkerArgs.cpp index 598e3701..2b6ac195 100644 --- a/src/Unlinker/UnlinkerArgs.cpp +++ b/src/Unlinker/UnlinkerArgs.cpp @@ -29,9 +29,17 @@ const CommandLineOption* const OPTION_MINIMAL_ZONE_FILE = .WithDescription("Minimizes the size of the zone file output by only including assets that are not a dependency of another asset.") .Build(); -const CommandLineOption* const OPTION_LIST = +const CommandLineOption* const OPTION_LOAD = CommandLineOption::Builder::Create() .WithShortName("l") + .WithLongName("load") + .WithDescription("Loads an existing zone before trying to unlink any zone.") + .WithParameter("zonePath") + .Reusable() + .Build(); + +const CommandLineOption* const OPTION_LIST = + CommandLineOption::Builder::Create() .WithLongName("list") .WithDescription("Lists the contents of a zone instead of writing them to the disk.") .Build(); @@ -69,6 +77,7 @@ const CommandLineOption* const COMMAND_LINE_OPTIONS[] OPTION_HELP, OPTION_VERBOSE, OPTION_MINIMAL_ZONE_FILE, + OPTION_LOAD, OPTION_LIST, OPTION_OUTPUT_FOLDER, OPTION_SEARCH_PATH, @@ -146,8 +155,8 @@ bool UnlinkerArgs::ParseArgs(const int argc, const char** argv) return false; } - m_zones_to_load = m_argument_parser.GetArguments(); - const size_t zoneCount = m_zones_to_load.size(); + m_zones_to_unlink = m_argument_parser.GetArguments(); + const size_t zoneCount = m_zones_to_unlink.size(); if (zoneCount < 1) { // No zones to load specified... @@ -162,7 +171,11 @@ bool UnlinkerArgs::ParseArgs(const int argc, const char** argv) // -min; --minimal-zone m_minimal_zone_def = m_argument_parser.IsOptionSpecified(OPTION_MINIMAL_ZONE_FILE); - // -l; --list + // -l; --load + if (m_argument_parser.IsOptionSpecified(OPTION_LOAD)) + m_zones_to_load = m_argument_parser.GetParametersForOption(OPTION_LOAD); + + // --list if (m_argument_parser.IsOptionSpecified(OPTION_LIST)) m_task = ProcessingTask::LIST; diff --git a/src/Unlinker/UnlinkerArgs.h b/src/Unlinker/UnlinkerArgs.h index c07be05b..2f74fa08 100644 --- a/src/Unlinker/UnlinkerArgs.h +++ b/src/Unlinker/UnlinkerArgs.h @@ -31,6 +31,7 @@ public: }; std::vector m_zones_to_load; + std::vector m_zones_to_unlink; std::set m_user_search_paths; ProcessingTask m_task; diff --git a/src/ZoneLoading/Game/IW4/ZoneLoaderFactoryIW4.cpp b/src/ZoneLoading/Game/IW4/ZoneLoaderFactoryIW4.cpp index 9042d6c5..24d325a7 100644 --- a/src/ZoneLoading/Game/IW4/ZoneLoaderFactoryIW4.cpp +++ b/src/ZoneLoading/Game/IW4/ZoneLoaderFactoryIW4.cpp @@ -159,12 +159,13 @@ public: return nullptr; // Create new zone - auto* zone = new Zone(fileName, 0, &g_GameIW4); - zone->m_pools = std::make_unique(zone, 0); + auto zone = std::make_unique(fileName, 0, &g_GameIW4); + auto* zonePtr = zone.get(); + zone->m_pools = std::make_unique(zonePtr, 0); zone->m_language = GetZoneLanguage(fileName); // File is supported. Now setup all required steps for loading this file. - auto* zoneLoader = new ZoneLoader(zone); + auto* zoneLoader = new ZoneLoader(std::move(zone)); SetupBlock(zoneLoader); @@ -185,7 +186,7 @@ public: zoneLoader->AddLoadingStep(std::make_unique()); // Start of the zone content - zoneLoader->AddLoadingStep(std::make_unique(std::make_unique(), zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK)); + zoneLoader->AddLoadingStep(std::make_unique(std::make_unique(), zonePtr, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK)); // Return the fully setup zoneloader return zoneLoader; diff --git a/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.cpp b/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.cpp index de0ed935..b613d2ef 100644 --- a/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.cpp +++ b/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "Game/T6/T6.h" #include "Game/T6/ZoneConstantsT6.h" @@ -178,12 +179,13 @@ public: return nullptr; // Create new zone - auto* zone = new Zone(fileName, 0, &g_GameT6); - zone->m_pools = std::make_unique(zone, 0); + auto zone = std::make_unique(fileName, 0, &g_GameT6); + auto* zonePtr = zone.get(); + zone->m_pools = std::make_unique(zonePtr, 0); zone->m_language = GetZoneLanguage(fileName); // File is supported. Now setup all required steps for loading this file. - auto* zoneLoader = new ZoneLoader(zone); + auto* zoneLoader = new ZoneLoader(std::move(zone)); SetupBlock(zoneLoader); @@ -201,7 +203,7 @@ public: zoneLoader->AddLoadingStep(std::make_unique()); // Start of the zone content - zoneLoader->AddLoadingStep(std::make_unique(std::make_unique(), zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK)); + zoneLoader->AddLoadingStep(std::make_unique(std::make_unique(), zonePtr, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK)); if (isSecure) { diff --git a/src/ZoneLoading/Loading/ZoneLoader.cpp b/src/ZoneLoading/Loading/ZoneLoader.cpp index 2853dc65..22e40748 100644 --- a/src/ZoneLoading/Loading/ZoneLoader.cpp +++ b/src/ZoneLoading/Loading/ZoneLoader.cpp @@ -1,26 +1,27 @@ #include "ZoneLoader.h" -#include "Exception/LoadingException.h" -#include "LoadingFileStream.h" #include -ZoneLoader::ZoneLoader(Zone* zone) +#include "Exception/LoadingException.h" +#include "LoadingFileStream.h" + +ZoneLoader::ZoneLoader(std::unique_ptr zone) + : m_processor_chain_dirty(false), + m_zone(std::move(zone)) { - m_zone = zone; - m_processor_chain_dirty = false; } ILoadingStream* ZoneLoader::BuildLoadingChain(ILoadingStream* rootStream) { auto* currentStream = rootStream; - for(const auto& processor : m_processors) + for (const auto& processor : m_processors) { processor->SetBaseStream(currentStream); currentStream = processor.get(); } - + m_processor_chain_dirty = false; return currentStream; } @@ -50,9 +51,9 @@ void ZoneLoader::AddStreamProcessor(std::unique_ptr streamProce void ZoneLoader::RemoveStreamProcessor(StreamProcessor* streamProcessor) { - for(auto i = m_processors.begin(); i < m_processors.end(); ++i) + for (auto i = m_processors.begin(); i < m_processors.end(); ++i) { - if(i->get() == streamProcessor) + if (i->get() == streamProcessor) { m_processors.erase(i); m_processor_chain_dirty = true; @@ -61,18 +62,18 @@ void ZoneLoader::RemoveStreamProcessor(StreamProcessor* streamProcessor) } } -Zone* ZoneLoader::LoadZone(std::istream& stream) +std::unique_ptr ZoneLoader::LoadZone(std::istream& stream) { LoadingFileStream fileStream(stream); auto* endStream = BuildLoadingChain(&fileStream); try { - for(const auto& step : m_steps) + for (const auto& step : m_steps) { step->PerformStep(this, endStream); - if(m_processor_chain_dirty) + if (m_processor_chain_dirty) { endStream = BuildLoadingChain(&fileStream); } @@ -83,12 +84,10 @@ Zone* ZoneLoader::LoadZone(std::istream& stream) const auto detailedMessage = e.DetailedMessage(); printf("Loading fastfile failed: %s\n", detailedMessage.c_str()); - delete m_zone; - return nullptr; } m_zone->Register(); - return m_zone; + return std::move(m_zone); } diff --git a/src/ZoneLoading/Loading/ZoneLoader.h b/src/ZoneLoading/Loading/ZoneLoader.h index 5a721906..ad0d4689 100644 --- a/src/ZoneLoading/Loading/ZoneLoader.h +++ b/src/ZoneLoading/Loading/ZoneLoader.h @@ -7,6 +7,7 @@ #include #include +#include class ILoadingStep; @@ -17,14 +18,14 @@ class ZoneLoader bool m_processor_chain_dirty; - Zone* m_zone; + std::unique_ptr m_zone; ILoadingStream* BuildLoadingChain(ILoadingStream* rootStream); public: std::vector m_blocks; - explicit ZoneLoader(Zone* zone); + explicit ZoneLoader(std::unique_ptr zone); void AddXBlock(std::unique_ptr block); void AddLoadingStep(std::unique_ptr step); @@ -32,5 +33,5 @@ public: void RemoveStreamProcessor(StreamProcessor* streamProcessor); - Zone* LoadZone(std::istream& stream); + std::unique_ptr LoadZone(std::istream& stream); }; diff --git a/src/ZoneLoading/ZoneLoading.cpp b/src/ZoneLoading/ZoneLoading.cpp index 531f54da..b08714c4 100644 --- a/src/ZoneLoading/ZoneLoading.cpp +++ b/src/ZoneLoading/ZoneLoading.cpp @@ -16,7 +16,7 @@ IZoneLoaderFactory* ZoneLoaderFactories[] new T6::ZoneLoaderFactory() }; -Zone* ZoneLoading::LoadZone(const std::string& path) +std::unique_ptr ZoneLoading::LoadZone(const std::string& path) { auto zoneName = fs::path(path).filename().replace_extension("").string(); std::ifstream file(path, std::fstream::in | std::fstream::binary); @@ -50,9 +50,9 @@ Zone* ZoneLoading::LoadZone(const std::string& path) return nullptr; } - auto* loadedZone = zoneLoader->LoadZone(file); + auto loadedZone = zoneLoader->LoadZone(file); delete zoneLoader; file.close(); - return loadedZone; + return std::move(loadedZone); } \ No newline at end of file diff --git a/src/ZoneLoading/ZoneLoading.h b/src/ZoneLoading/ZoneLoading.h index c99ddf33..3017e115 100644 --- a/src/ZoneLoading/ZoneLoading.h +++ b/src/ZoneLoading/ZoneLoading.h @@ -6,5 +6,5 @@ class ZoneLoading { public: - static Zone* LoadZone(const std::string& path); + static std::unique_ptr LoadZone(const std::string& path); };