From 97cfdb32e77a7d417b4e3137e1cb14558afa1ad2 Mon Sep 17 00:00:00 2001 From: Lukas Cone Date: Wed, 9 Oct 2024 22:37:56 +0200 Subject: [PATCH] add dlc_extract --- 3rd_party/spike | 2 +- toolset/CMakeLists.txt | 1 + toolset/dlc_extract/CMakeLists.txt | 21 ++++++ toolset/dlc_extract/dlc_extract.cpp | 107 ++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 toolset/dlc_extract/CMakeLists.txt create mode 100644 toolset/dlc_extract/dlc_extract.cpp diff --git a/3rd_party/spike b/3rd_party/spike index 4c8e10f..214b800 160000 --- a/3rd_party/spike +++ b/3rd_party/spike @@ -1 +1 @@ -Subproject commit 4c8e10fb751b7b9e7e1792e413e61ca378990c6d +Subproject commit 214b8002e787f3ca49116af473019b4780bb9918 diff --git a/toolset/CMakeLists.txt b/toolset/CMakeLists.txt index 962b887..9165082 100644 --- a/toolset/CMakeLists.txt +++ b/toolset/CMakeLists.txt @@ -34,6 +34,7 @@ add_spike_subdir(udas_extract) add_spike_subdir(obb_extract) add_spike_subdir(lmt_to_gltf) add_spike_subdir(sdl_conv) +add_spike_subdir(dlc_extract) if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Release") add_spike_subdir(dev) diff --git a/toolset/dlc_extract/CMakeLists.txt b/toolset/dlc_extract/CMakeLists.txt new file mode 100644 index 0000000..68c114d --- /dev/null +++ b/toolset/dlc_extract/CMakeLists.txt @@ -0,0 +1,21 @@ +project(DLCExtract) + +build_target( + NAME + dlc_extract + TYPE + ESMODULE + VERSION + 1 + SOURCES + dlc_extract.cpp + LINKS + revil-interface + INCLUDES + ${CMAKE_SOURCE_DIR}/src/ + AUTHOR + "Lukas Cone" + DESCR + "DLC Archive Extractor" + START_YEAR + 2024) diff --git a/toolset/dlc_extract/dlc_extract.cpp b/toolset/dlc_extract/dlc_extract.cpp new file mode 100644 index 0000000..c93ec91 --- /dev/null +++ b/toolset/dlc_extract/dlc_extract.cpp @@ -0,0 +1,107 @@ +/* DLCExtract + Copyright(C) 2024 Lukas Cone + + This program is free software : you can redistribute it and / or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program.If not, see . +*/ + +#include "hfs.hpp" +#include "project.h" +#include "spike/app_context.hpp" +#include "spike/except.hpp" +#include "spike/io/binreader_stream.hpp" +#include + +std::string_view filters[]{ + ".dat$", +}; + +static AppInfo_s appInfo{ + .filteredLoad = true, + .header = DLCExtract_DESC " v" DLCExtract_VERSION ", " DLCExtract_COPYRIGHT + "Lukas Cone", + .filters = filters, +}; + +AppInfo_s *AppInitModule() { return &appInfo; } + +void AppProcessFile(AppContext *ctx) { + std::stringstream backup; + BinReaderRef_e rd(ctx->GetStream()); + uint32 id; + rd.Push(); + rd.Read(id); + + if (id == SFHID) { + rd.Pop(); + backup = ProcessHFS(rd); + rd = BinReaderRef_e(backup); + rd.Push(); + rd.Read(id); + } + + if (id != CompileFourCC("DLC")) { + rd.SwapEndian(true); + rd.Pop(); + rd.Read(id); + if (id != CompileFourCC("DLC")) { + throw es::InvalidHeaderError(id); + } + } + + uint8 version; + rd.Read(version); + + if (version != 3) { + throw es::InvalidVersionError(version); + } + + std::string name; + rd.ReadString(name); + + struct File { + std::string path; + uint32 offset; + }; + + std::vector files; + rd.ReadContainerLambda(files, [](BinReaderRef_e rd, File &file) { + rd.ReadContainer(file.path); + rd.Read(file.offset); + }); + + auto ectx = ctx->ExtractContext(); + + if (ectx->RequiresFolders()) { + for (auto &f : files) { + AFileInfo finf(f.path); + ectx->AddFolderPath(std::string(finf.GetFolder())); + } + + ectx->GenerateFolders(); + } + + std::string buffer; + const size_t arSize = rd.GetSize(); + + for (size_t curFile = 1; auto &f : files) { + rd.Seek(f.offset); + const size_t fileEnd = + curFile >= files.size() ? arSize : files.at(curFile).offset; + const size_t fileSize = fileEnd - f.offset; + rd.ReadContainer(buffer, fileSize); + ectx->NewFile(f.path); + ectx->SendData(buffer); + curFile++; + } +}