mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-06 17:35:40 +00:00
84 lines
2.6 KiB
Rust
84 lines
2.6 KiB
Rust
//! `.Pak` extractor
|
|
|
|
// Features
|
|
#![feature(array_value_iter)]
|
|
|
|
// Modules
|
|
mod cli;
|
|
mod logger;
|
|
|
|
// Imports
|
|
use anyhow::Context;
|
|
use dcb_io::{pak, PakFileReader};
|
|
use std::path::Path;
|
|
|
|
|
|
fn main() -> Result<(), anyhow::Error> {
|
|
// Initialize the logger
|
|
logger::init();
|
|
|
|
// Get all data from cli
|
|
let cli::CliData { input_file, output_dir } = cli::CliData::new();
|
|
|
|
// Try to extract the filesystem
|
|
self::extract_file(&input_file, &output_dir).context("Unable to extract `pak` file")?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Extracts a `.pak` file to `output_dir`.
|
|
fn extract_file(input_file: &Path, output_dir: &Path) -> Result<(), anyhow::Error> {
|
|
// Open the file and parse a `pak` filesystem from it.
|
|
let mut input_file = std::fs::File::open(input_file).context("Unable to open input file")?;
|
|
let mut pak_fs = PakFileReader::new(&mut input_file);
|
|
|
|
// Try to create the output directory
|
|
self::try_create_folder(output_dir)?;
|
|
|
|
// Then read all entries
|
|
while let Some(entry) = pak_fs.next_entry().context("Unable to read entry")? {
|
|
// Get the filename
|
|
let filename = entry.header().id;
|
|
|
|
// Get the extension
|
|
let extension = match entry.header().kind {
|
|
pak::header::Kind::Model3DSet => "M3D",
|
|
pak::header::Kind::Unknown1 => "UN1",
|
|
pak::header::Kind::GameScript => "MSD",
|
|
pak::header::Kind::Animation2D => "A2D",
|
|
pak::header::Kind::Unknown2 => "UN2",
|
|
pak::header::Kind::FileContents => "BIN",
|
|
pak::header::Kind::AudioSeq => "SEQ",
|
|
pak::header::Kind::AudioVh => "VH",
|
|
pak::header::Kind::AudioVb => "VB",
|
|
};
|
|
|
|
let path = output_dir.join(format!("{}.{}", filename, extension));
|
|
|
|
log::info!("{} ({} bytes)", path.display(), entry.header().size);
|
|
|
|
// Seek the file and read it's size at most
|
|
let mut contents = entry.contents();
|
|
|
|
// Then create the output file and copy.
|
|
if path.exists() {
|
|
log::warn!("Overriding file {}", path.display());
|
|
}
|
|
let mut output_file = std::fs::File::create(&path).with_context(|| format!("Unable to create file {}", path.display()))?;
|
|
std::io::copy(&mut contents, &mut output_file).with_context(|| format!("Unable to write file {}", path.display()))?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Attempts to create a folder. Returns `Ok` if it already exists.
|
|
#[allow(clippy::create_dir)] // We only want to create a single level
|
|
fn try_create_folder(path: impl AsRef<std::path::Path>) -> Result<(), anyhow::Error> {
|
|
match std::fs::create_dir(&path) {
|
|
// If it already exists, ignore
|
|
Ok(_) => Ok(()),
|
|
Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => Ok(()),
|
|
Err(err) => Err(err).with_context(|| format!("Unable to create directory {}", path.as_ref().display())),
|
|
}
|
|
}
|