use std::{env, fs, path::Path, process};
use walkdir::{DirEntry, WalkDir};
fn main() {
pretty_env_logger::init();
log::debug!("Startup");
let Some(path) = env::args().nth(1) else {
eprintln!("Please provide a path to an hqx file as the first arugment");
process::exit(-1);
};
match fs::metadata(&path) {
Ok(meta) if meta.is_dir() => WalkDir::new(path)
.into_iter()
.filter_entry(|e| !is_hidden(e))
.filter_map(|e| e.ok())
.for_each(|f| match extract_file(f.path()) {
Ok(_) => {}
Err(e) => {
eprintln!(
"Could not fully extract file at {}: {}",
f.path().display(),
e
);
}
}),
Ok(meta) if meta.is_file() => match extract_file(&path) {
Ok(_) => {}
Err(e) => {
eprintln!("Could not extract file at {}", path);
eprintln!("{:?}", e);
process::exit(-3);
}
},
Ok(_) => {
eprintln!("Path is neither file nor directory, skipping analysis…");
}
Err(e) => {
eprintln!("Could not determine if path is a file or directory!");
eprintln!("{:?}", e);
process::exit(-2);
}
}
log::debug!("Shutdown");
}
fn extract_file(path: impl AsRef<Path>) -> Result<(), binhex::Error> {
log::info!("Extracting {}", path.as_ref().display());
let mut archive = match binhex::Archive::open(path.as_ref()) {
Ok(i) => i,
Err(e) => {
eprintln!("Could not open archive at {}", path.as_ref().display());
eprintln!("{:?}", e);
return Err(e);
}
};
if archive.data_len() != 0 {
let output_name = archive.name().replace("/", ":");
let mut input = archive.data_fork()?;
let mut output = std::fs::File::create_new(output_name)?;
std::io::copy(&mut input, &mut output)?;
}
if archive.resource_len() != 0 {
let output_name = format!("{}.rsrc", archive.name().replace("/", ":"));
let mut input = archive.resource_fork()?;
let mut output = std::fs::File::create_new(output_name)?;
std::io::copy(&mut input, &mut output)?;
}
Ok(())
}
fn is_hidden(entry: &DirEntry) -> bool {
entry
.file_name()
.to_str()
.map(|s| s.starts_with(""))
.unwrap_or(false)
}