mirror of
https://github.com/encounter/decomp-toolkit.git
synced 2025-08-07 12:45:53 +00:00
This allows handling path conversions in a more structured way, as well as avoiding needless UTF-8 checks. All argument inputs use `Utf8NativePathBuf`, while all config entries use `Utf8UnixPathBuf`, ensuring that we deserialize/serialize using forward slashes. We can omit `.display()` and lossy UTF-8 conversions since all paths are known valid UTF-8.
111 lines
3.2 KiB
Rust
111 lines
3.2 KiB
Rust
use std::fs;
|
|
|
|
use anyhow::{Context, Result};
|
|
use argp::FromArgs;
|
|
use typed_path::Utf8NativePathBuf;
|
|
|
|
use crate::{
|
|
util::{
|
|
file::process_rsp,
|
|
ncompress::{compress_yaz0, decompress_yaz0},
|
|
path::native_path,
|
|
IntoCow, ToCow,
|
|
},
|
|
vfs::open_file,
|
|
};
|
|
|
|
#[derive(FromArgs, PartialEq, Debug)]
|
|
/// Commands for processing YAZ0-compressed files.
|
|
#[argp(subcommand, name = "yaz0")]
|
|
pub struct Args {
|
|
#[argp(subcommand)]
|
|
command: SubCommand,
|
|
}
|
|
|
|
#[derive(FromArgs, PartialEq, Debug)]
|
|
#[argp(subcommand)]
|
|
enum SubCommand {
|
|
Compress(CompressArgs),
|
|
Decompress(DecompressArgs),
|
|
}
|
|
|
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
|
/// Compresses files using YAZ0.
|
|
#[argp(subcommand, name = "compress")]
|
|
pub struct CompressArgs {
|
|
#[argp(positional, from_str_fn(native_path))]
|
|
/// Files to compress
|
|
files: Vec<Utf8NativePathBuf>,
|
|
#[argp(option, short = 'o', from_str_fn(native_path))]
|
|
/// Output file (or directory, if multiple files are specified).
|
|
/// If not specified, compresses in-place.
|
|
output: Option<Utf8NativePathBuf>,
|
|
}
|
|
|
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
|
/// Decompresses YAZ0-compressed files.
|
|
#[argp(subcommand, name = "decompress")]
|
|
pub struct DecompressArgs {
|
|
#[argp(positional, from_str_fn(native_path))]
|
|
/// YAZ0-compressed files
|
|
files: Vec<Utf8NativePathBuf>,
|
|
#[argp(option, short = 'o', from_str_fn(native_path))]
|
|
/// Output file (or directory, if multiple files are specified).
|
|
/// If not specified, decompresses in-place.
|
|
output: Option<Utf8NativePathBuf>,
|
|
}
|
|
|
|
pub fn run(args: Args) -> Result<()> {
|
|
match args.command {
|
|
SubCommand::Compress(args) => compress(args),
|
|
SubCommand::Decompress(args) => decompress(args),
|
|
}
|
|
}
|
|
|
|
fn compress(args: CompressArgs) -> Result<()> {
|
|
let files = process_rsp(&args.files)?;
|
|
let single_file = files.len() == 1;
|
|
for path in files {
|
|
let data = {
|
|
let mut file = open_file(&path, false)?;
|
|
compress_yaz0(file.map()?)
|
|
};
|
|
let out_path = if let Some(output) = &args.output {
|
|
if single_file {
|
|
output.as_path().to_cow()
|
|
} else {
|
|
output.join(path.file_name().unwrap()).into_cow()
|
|
}
|
|
} else {
|
|
path.as_path().to_cow()
|
|
};
|
|
fs::write(out_path.as_ref(), data)
|
|
.with_context(|| format!("Failed to write '{}'", out_path))?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn decompress(args: DecompressArgs) -> Result<()> {
|
|
let files = process_rsp(&args.files)?;
|
|
let single_file = files.len() == 1;
|
|
for path in files {
|
|
let data = {
|
|
let mut file = open_file(&path, false)?;
|
|
decompress_yaz0(file.map()?)
|
|
.with_context(|| format!("Failed to decompress '{}' using Yaz0", path))?
|
|
};
|
|
let out_path = if let Some(output) = &args.output {
|
|
if single_file {
|
|
output.as_path().to_cow()
|
|
} else {
|
|
output.join(path.file_name().unwrap()).into_cow()
|
|
}
|
|
} else {
|
|
path.as_path().to_cow()
|
|
};
|
|
fs::write(out_path.as_ref(), data)
|
|
.with_context(|| format!("Failed to write '{}'", out_path))?;
|
|
}
|
|
Ok(())
|
|
}
|