mirror of
https://github.com/encounter/decomp-toolkit.git
synced 2025-12-17 00:47:08 +00:00
Improvements to REL & map support
- Fix symbols.txt align attribute - Fully support nested RARC files & transparent Yaz0 decompression - Guess symbol visibility for maps without link map - Add module name config - Add manual force_active config - Quiet option for shasum - `symbols_known` and `fill_gaps` config - Allow disabling .comment generation per-unit (`comment:0`) - Various minor fixes - Add `rarc` and `yaz0` commands
This commit is contained in:
109
src/cmd/rarc.rs
Normal file
109
src/cmd/rarc.rs
Normal file
@@ -0,0 +1,109 @@
|
||||
use std::{fs, fs::DirBuilder, path::PathBuf};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use argp::FromArgs;
|
||||
|
||||
use crate::util::{
|
||||
file::{decompress_if_needed, map_file},
|
||||
rarc::{Node, RarcReader},
|
||||
};
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
/// Commands for processing RSO files.
|
||||
#[argp(subcommand, name = "rarc")]
|
||||
pub struct Args {
|
||||
#[argp(subcommand)]
|
||||
command: SubCommand,
|
||||
}
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
#[argp(subcommand)]
|
||||
enum SubCommand {
|
||||
List(ListArgs),
|
||||
Extract(ExtractArgs),
|
||||
}
|
||||
|
||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||
/// Views RARC file information.
|
||||
#[argp(subcommand, name = "list")]
|
||||
pub struct ListArgs {
|
||||
#[argp(positional)]
|
||||
/// RARC file
|
||||
file: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||
/// Extracts RARC file contents.
|
||||
#[argp(subcommand, name = "extract")]
|
||||
pub struct ExtractArgs {
|
||||
#[argp(positional)]
|
||||
/// RARC file
|
||||
file: PathBuf,
|
||||
#[argp(option, short = 'o')]
|
||||
/// output directory
|
||||
output: Option<PathBuf>,
|
||||
}
|
||||
|
||||
pub fn run(args: Args) -> Result<()> {
|
||||
match args.command {
|
||||
SubCommand::List(c_args) => list(c_args),
|
||||
SubCommand::Extract(c_args) => extract(c_args),
|
||||
}
|
||||
}
|
||||
|
||||
fn list(args: ListArgs) -> Result<()> {
|
||||
let file = map_file(&args.file)?;
|
||||
let rarc = RarcReader::new(&mut file.as_reader())?;
|
||||
|
||||
let mut current_path = PathBuf::new();
|
||||
for node in rarc.nodes() {
|
||||
match node {
|
||||
Node::DirectoryBegin { name } => {
|
||||
current_path.push(name.name);
|
||||
}
|
||||
Node::DirectoryEnd { name: _ } => {
|
||||
current_path.pop();
|
||||
}
|
||||
Node::File { name, offset, size } => {
|
||||
let path = current_path.join(name.name);
|
||||
println!("{}: {} bytes, offset {:#X}", path.display(), size, offset);
|
||||
}
|
||||
Node::CurrentDirectory => {}
|
||||
Node::ParentDirectory => {}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn extract(args: ExtractArgs) -> Result<()> {
|
||||
let file = map_file(&args.file)?;
|
||||
let rarc = RarcReader::new(&mut file.as_reader())?;
|
||||
|
||||
let mut current_path = PathBuf::new();
|
||||
for node in rarc.nodes() {
|
||||
match node {
|
||||
Node::DirectoryBegin { name } => {
|
||||
current_path.push(name.name);
|
||||
}
|
||||
Node::DirectoryEnd { name: _ } => {
|
||||
current_path.pop();
|
||||
}
|
||||
Node::File { name, offset, size } => {
|
||||
let file_data = decompress_if_needed(
|
||||
&file.as_slice()[offset as usize..offset as usize + size as usize],
|
||||
)?;
|
||||
let file_path = current_path.join(&name.name);
|
||||
let output_path =
|
||||
args.output.as_ref().map(|p| p.join(&file_path)).unwrap_or_else(|| file_path);
|
||||
if let Some(parent) = output_path.parent() {
|
||||
DirBuilder::new().recursive(true).create(parent)?;
|
||||
}
|
||||
fs::write(&output_path, file_data)
|
||||
.with_context(|| format!("Failed to write file '{}'", output_path.display()))?;
|
||||
}
|
||||
Node::CurrentDirectory => {}
|
||||
Node::ParentDirectory => {}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user