Skip to content

Commit

Permalink
Use typed-path in place of std Path/PathBuf
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
encounter committed Oct 5, 2024
1 parent 64d0491 commit 2e524e6
Show file tree
Hide file tree
Showing 35 changed files with 623 additions and 599 deletions.
14 changes: 7 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ publish = false
repository = "https://github.com/encounter/decomp-toolkit"
readme = "README.md"
categories = ["command-line-utilities"]
rust-version = "1.80.0"
rust-version = "1.81"

[[bin]]
name = "dtk"
Expand All @@ -31,6 +31,7 @@ argp = "0.3"
base16ct = "0.2"
base64 = "0.22"
byteorder = "1.5"
typed-path = "0.9"
crossterm = "0.28"
cwdemangle = "1.0"
cwextab = "1.0"
Expand All @@ -57,7 +58,6 @@ object = { version = "0.36", features = ["read_core", "std", "elf", "write_std"]
once_cell = "1.20"
orthrus-ncompress = "0.2"
owo-colors = { version = "4.1", features = ["supports-colors"] }
path-slash = "0.2"
petgraph = { version = "0.6", default-features = false }
ppc750cl = "0.3"
rayon = "1.10"
Expand Down
21 changes: 10 additions & 11 deletions src/cmd/alf.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use std::{
io::{stdout, Write},
path::PathBuf,
};
use std::io::{stdout, Write};

use anyhow::Result;
use argp::FromArgs;
use typed_path::Utf8NativePathBuf;

use crate::{
cmd,
util::{
alf::AlfFile,
file::buf_writer,
path::native_path,
reader::{Endian, FromReader},
},
vfs::open_file,
Expand All @@ -35,21 +34,21 @@ enum SubCommand {
/// Prints information about an alf file. (Same as `dol info`)
#[argp(subcommand, name = "info")]
pub struct InfoArgs {
#[argp(positional)]
#[argp(positional, from_str_fn(native_path))]
/// alf file
file: PathBuf,
file: Utf8NativePathBuf,
}

#[derive(FromArgs, PartialEq, Debug)]
/// Extracts symbol hashes from an alf file.
#[argp(subcommand, name = "hashes")]
pub struct HashesArgs {
#[argp(positional)]
#[argp(positional, from_str_fn(native_path))]
/// alf file
alf_file: PathBuf,
#[argp(positional)]
alf_file: Utf8NativePathBuf,
#[argp(positional, from_str_fn(native_path))]
/// output file
output: Option<PathBuf>,
output: Option<Utf8NativePathBuf>,
}

pub fn run(args: Args) -> Result<()> {
Expand All @@ -64,7 +63,7 @@ fn hashes(args: HashesArgs) -> Result<()> {
let mut file = open_file(&args.alf_file, true)?;
AlfFile::from_reader(file.as_mut(), Endian::Little)?
};
let mut w: Box<dyn Write> = if let Some(output) = args.output {
let mut w: Box<dyn Write> = if let Some(output) = &args.output {
Box::new(buf_writer(output)?)
} else {
Box::new(stdout())
Expand Down
44 changes: 22 additions & 22 deletions src/cmd/ar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ use std::{
collections::{btree_map::Entry, BTreeMap},
fs::File,
io::Write,
path::PathBuf,
};

use anyhow::{anyhow, bail, Context, Result};
use argp::FromArgs;
use object::{Object, ObjectSymbol, SymbolScope};
use typed_path::Utf8NativePathBuf;

use crate::{
util::file::{buf_writer, process_rsp},
util::{
file::{buf_writer, process_rsp},
path::native_path,
},
vfs::open_file,
};

Expand All @@ -33,24 +36,24 @@ enum SubCommand {
/// Creates a static library.
#[argp(subcommand, name = "create")]
pub struct CreateArgs {
#[argp(positional)]
#[argp(positional, from_str_fn(native_path))]
/// output file
out: PathBuf,
#[argp(positional)]
out: Utf8NativePathBuf,
#[argp(positional, from_str_fn(native_path))]
/// input files
files: Vec<PathBuf>,
files: Vec<Utf8NativePathBuf>,
}

#[derive(FromArgs, PartialEq, Eq, Debug)]
/// Extracts a static library.
#[argp(subcommand, name = "extract")]
pub struct ExtractArgs {
#[argp(positional)]
#[argp(positional, from_str_fn(native_path))]
/// input files
files: Vec<PathBuf>,
#[argp(option, short = 'o')]
files: Vec<Utf8NativePathBuf>,
#[argp(option, short = 'o', from_str_fn(native_path))]
/// output directory
out: Option<PathBuf>,
out: Option<Utf8NativePathBuf>,
#[argp(switch, short = 'q')]
/// quiet output
quiet: bool,
Expand All @@ -74,14 +77,13 @@ fn create(args: CreateArgs) -> Result<()> {
let mut identifiers = Vec::with_capacity(files.len());
let mut symbol_table = BTreeMap::new();
for path in &files {
let path_str =
path.to_str().ok_or_else(|| anyhow!("'{}' is not valid UTF-8", path.display()))?;
let identifier = path_str.as_bytes().to_vec();
let unix_path = path.with_unix_encoding();
let identifier = unix_path.as_str().as_bytes().to_vec();
identifiers.push(identifier.clone());

let entries = match symbol_table.entry(identifier) {
Entry::Vacant(e) => e.insert(Vec::new()),
Entry::Occupied(_) => bail!("Duplicate file name '{path_str}'"),
Entry::Occupied(_) => bail!("Duplicate file name '{unix_path}'"),
};
let mut file = open_file(path, false)?;
let obj = object::File::parse(file.map()?)?;
Expand All @@ -102,10 +104,8 @@ fn create(args: CreateArgs) -> Result<()> {
symbol_table,
)?;
for path in files {
let path_str =
path.to_str().ok_or_else(|| anyhow!("'{}' is not valid UTF-8", path.display()))?;
let mut file = File::open(&path)?;
builder.append_file(path_str.as_bytes(), &mut file)?;
builder.append_file(path.as_str().as_bytes(), &mut file)?;
}
builder.into_inner()?.flush()?;
Ok(())
Expand All @@ -118,22 +118,22 @@ fn extract(args: ExtractArgs) -> Result<()> {
// Extract files
let mut num_files = 0;
for path in &files {
let mut out_dir = if let Some(out) = &args.out { out.clone() } else { PathBuf::new() };
let mut out_dir =
if let Some(out) = &args.out { out.clone() } else { Utf8NativePathBuf::new() };
// If there are multiple files, extract to separate directories
if files.len() > 1 {
out_dir
.push(path.with_extension("").file_name().ok_or_else(|| anyhow!("No file name"))?);
}
std::fs::create_dir_all(&out_dir)?;
if !args.quiet {
println!("Extracting {} to {}", path.display(), out_dir.display());
println!("Extracting {} to {}", path, out_dir);
}

let mut file = open_file(path, false)?;
let mut archive = ar::Archive::new(file.map()?);
while let Some(entry) = archive.next_entry() {
let mut entry =
entry.with_context(|| format!("Processing entry in {}", path.display()))?;
let mut entry = entry.with_context(|| format!("Processing entry in {}", path))?;
let file_name = std::str::from_utf8(entry.header().identifier())?;
if !args.quiet && args.verbose {
println!("\t{}", file_name);
Expand All @@ -146,7 +146,7 @@ fn extract(args: ExtractArgs) -> Result<()> {
std::fs::create_dir_all(parent)?;
}
let mut file = File::create(&file_path)
.with_context(|| format!("Failed to create file {}", file_path.display()))?;
.with_context(|| format!("Failed to create file {}", file_path))?;
std::io::copy(&mut entry, &mut file)?;
file.flush()?;

Expand Down
Loading

0 comments on commit 2e524e6

Please sign in to comment.