From 054cc48e1565addf6a6016e3e8be901edbfd0b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=A1k?= Date: Sun, 23 Mar 2025 13:52:26 +0100 Subject: [PATCH] ddl_ar tool to work with ddls --- tools/CMakeLists.txt | 3 ++ tools/ddl_ar.cpp | 77 ++++++++++++++++++++++++++++++++++++++++++ tools/ddl_ar.h | 3 ++ tools/ddl_ar_class.cpp | 51 ++++++++++++++++++++++++++++ tools/ddl_ar_class.h | 49 +++++++++++++++++++++++++++ 5 files changed, 183 insertions(+) create mode 100644 tools/CMakeLists.txt create mode 100644 tools/ddl_ar.cpp create mode 100644 tools/ddl_ar.h create mode 100644 tools/ddl_ar_class.cpp create mode 100644 tools/ddl_ar_class.h diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt new file mode 100644 index 0000000..3bbfc37 --- /dev/null +++ b/tools/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(ddl_ar ddl_ar.cpp ddl_ar_class.cpp) + +set_property(TARGET ddl_ar PROPERTY CXX_STANDARD 20) diff --git a/tools/ddl_ar.cpp b/tools/ddl_ar.cpp new file mode 100644 index 0000000..6e01a37 --- /dev/null +++ b/tools/ddl_ar.cpp @@ -0,0 +1,77 @@ +#include "ddl_ar.h" +#include "ddl_ar_class.h" +#include + + +void show_licence_header() { +std::puts("Copyright (c) 2025 Ondrej Novak. All rights reserved.\n" + "This work is licensed under the terms of the MIT license.\n" + "For a copy, see \n"); +} + +void show_short_help() { + + show_licence_header(); + std::puts("Use -h for help"); +} + +void show_help() { + show_licence_header(); + std::puts("ddl_ar -h"); + std::puts("ddl_ar -l"); + std::puts("ddl_ar -x "); + std::puts(""); + std::puts("-h this help\n" + "file.ddl input ddl file\n" + "-l list of files\n" + "-x extract files\n"); +} + +int main(int argc, char **argv) { + if (argc <= 1) { + show_short_help(); + return 1; + } + + std::string_view ddl_file = argv[1]; + if (ddl_file == "-h") { + show_help(); + return 1; + } + + if (argc <= 2) { + show_short_help(); + return 1; + } + + DDLArchive arch; + if (!arch.open(ddl_file)) { + std::cerr << "Failed to read ddl file: " << ddl_file; + return 1; + } + + + std::string_view swch(argv[2]); + if (swch == "-l") { + for (const auto &x: arch.get_directory()) { + std::puts(x.first.c_str()); + } + } else if (swch == "-x") { + std::vector fls; + fls.reserve(argc); + for (int i = 3; i < argc; ++i) fls.push_back(argv[i]); + arch.extract(fls.begin(), fls.end(), [](const DDLArchive::Extracted &x){ + if (!x.found) { + std::cout << "Not found: " << x.name << "\n"; + } else { + std::ofstream out(std::string(x.name), std::ios::out|std::ios::binary); + out.write(x.data.data(), x.data.size()); + std::cout << "Extracted: " << x.name << " (" << x.data.size() << " bytes)\n"; + } + }); + } else { + std::cerr << "Unknown switch " << swch << std::endl; + } + + return 0; +} diff --git a/tools/ddl_ar.h b/tools/ddl_ar.h new file mode 100644 index 0000000..45dcbb0 --- /dev/null +++ b/tools/ddl_ar.h @@ -0,0 +1,3 @@ +#pragma once + + diff --git a/tools/ddl_ar_class.cpp b/tools/ddl_ar_class.cpp new file mode 100644 index 0000000..9194c55 --- /dev/null +++ b/tools/ddl_ar_class.cpp @@ -0,0 +1,51 @@ +#include "ddl_ar_class.h" + + +bool DDLArchive::open(std::filesystem::path ar_file) { + _directory.clear(); + _ar_file = std::move(ar_file); + + std::ifstream f = begin_read(); + if (!f) return false; + f.seekg(4,std::ios::beg); + uint32_t dir_offset; + f.read(reinterpret_cast(&dir_offset), sizeof(dir_offset)); + if (f.gcount() != sizeof(dir_offset)) return false; + uint32_t smallest_offset = std::numeric_limits::max(); + f.seekg(dir_offset, std::ios::beg); + while (f.tellg() < smallest_offset) { + char name[13]; + f.read(name, 12); + if (f.gcount() != 12) return false; + name[12] = 0; + uint32_t offset; + f.read(reinterpret_cast(&offset), 4); + if (f.gcount() != 4) return false; + _directory.emplace(name, FileRec{offset, {}}); + smallest_offset = std::min(offset, smallest_offset); + } + return true; +} + +std::ifstream DDLArchive::begin_read() { + return std::ifstream(_ar_file, std::ios::in|std::ios::binary); +} + +DDLArchive::Extracted DDLArchive::extract_file(std::ifstream &s, + std::string_view fname) { + + auto iter = _directory.find(fname); + if (iter == _directory.end()) { + return {fname, false, {}}; + } + s.seekg(iter->second.offset, std::ios::beg); + uint32_t sz; + s.read(reinterpret_cast(&sz),4); + if (s.gcount() != 4) return {fname, false, {}}; + std::vector data; + data.resize(sz); + s.read(data.data(), sz); + if (s.gcount() != sz) return {fname, false, {}}; + return {fname, true, std::move(data)}; + +} diff --git a/tools/ddl_ar_class.h b/tools/ddl_ar_class.h new file mode 100644 index 0000000..4d252f8 --- /dev/null +++ b/tools/ddl_ar_class.h @@ -0,0 +1,49 @@ +#pragma once +#include +#include +#include +#include +#include + +class DDLArchive { +public: + + struct FileRec { + uint32_t offset; + std::filesystem::path source; + + }; + + + using Directory = std::map >; + bool open(std::filesystem::path ar_file); + const Directory &get_directory() const {return _directory;} + const std::filesystem::path& get_ar_file() const {return _ar_file;} + + struct Extracted { + std::string_view name; + bool found; + std::vector data; + }; + + + template CB> + void extract(Iter from, Iter to, CB &&cb) { + std::ifstream f = begin_read(); + while (from != to) { + std::string_view n = *from; + cb(extract_file(f, n)); + ++from; + } + } + +protected: + + std::filesystem::path _ar_file; + Directory _directory; + + std::ifstream begin_read(); + Extracted extract_file(std::ifstream &s, std::string_view fname); + + +};