mirror of
https://github.com/ondra-novak/gates_of_skeldal.git
synced 2025-07-05 06:00:33 -04:00
ddl_ar tool to work with ddls
This commit is contained in:
parent
3eb73c4ad1
commit
054cc48e15
5 changed files with 183 additions and 0 deletions
3
tools/CMakeLists.txt
Normal file
3
tools/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
add_executable(ddl_ar ddl_ar.cpp ddl_ar_class.cpp)
|
||||
|
||||
set_property(TARGET ddl_ar PROPERTY CXX_STANDARD 20)
|
77
tools/ddl_ar.cpp
Normal file
77
tools/ddl_ar.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include "ddl_ar.h"
|
||||
#include "ddl_ar_class.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
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 <https://opensource.org/licenses/MIT>\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 <file.ddl> -l");
|
||||
std::puts("ddl_ar <file.ddl> -x <files...>");
|
||||
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<std::string_view> 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;
|
||||
}
|
3
tools/ddl_ar.h
Normal file
3
tools/ddl_ar.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
|
51
tools/ddl_ar_class.cpp
Normal file
51
tools/ddl_ar_class.cpp
Normal file
|
@ -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<char *>(&dir_offset), sizeof(dir_offset));
|
||||
if (f.gcount() != sizeof(dir_offset)) return false;
|
||||
uint32_t smallest_offset = std::numeric_limits<uint32_t>::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<char *>(&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<char *>(&sz),4);
|
||||
if (s.gcount() != 4) return {fname, false, {}};
|
||||
std::vector<char> data;
|
||||
data.resize(sz);
|
||||
s.read(data.data(), sz);
|
||||
if (s.gcount() != sz) return {fname, false, {}};
|
||||
return {fname, true, std::move(data)};
|
||||
|
||||
}
|
49
tools/ddl_ar_class.h
Normal file
49
tools/ddl_ar_class.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
|
||||
class DDLArchive {
|
||||
public:
|
||||
|
||||
struct FileRec {
|
||||
uint32_t offset;
|
||||
std::filesystem::path source;
|
||||
|
||||
};
|
||||
|
||||
|
||||
using Directory = std::map<std::string, FileRec, std::less<> >;
|
||||
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<char> data;
|
||||
};
|
||||
|
||||
|
||||
template<typename Iter, std::invocable<Extracted> 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);
|
||||
|
||||
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue