Files
unixtract/src/main.rs
T

100 lines
2.7 KiB
Rust
Raw Normal View History

2025-09-27 00:31:18 +02:00
mod formats;
mod keys;
mod utils;
2025-09-27 00:31:18 +02:00
2025-09-11 20:26:51 +02:00
use clap::Parser;
use std::path::{PathBuf};
2025-10-07 21:43:49 +02:00
use std::io::{self};
use std::fs::{self, File};
2026-02-05 15:18:26 +01:00
use crate::formats::{Format, get_registry};
2025-09-11 20:26:51 +02:00
#[derive(Parser, Debug)]
struct Args {
input_target: String,
2026-02-05 19:38:50 +01:00
output_directory: Option<String>,
2025-09-11 20:26:51 +02:00
}
pub enum InputTarget {
File(File),
Directory(PathBuf),
}
pub struct AppContext {
pub input: InputTarget,
pub output_dir: PathBuf,
2026-02-05 15:18:26 +01:00
}
impl AppContext {
pub fn file(&self) -> Option<&File> {
match &self.input {
InputTarget::File(f) => Some(f),
_ => None,
}
}
pub fn dir(&self) -> Option<&PathBuf> {
match &self.input {
InputTarget::Directory(p) => Some(p),
_ => None,
}
}
}
2026-02-05 15:18:26 +01:00
2025-09-11 20:26:51 +02:00
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("unixtract Firmware extractor");
2025-09-11 20:26:51 +02:00
let args = Args::parse();
2026-02-05 19:38:50 +01:00
let target_path_str = args.input_target;
println!("Input target: {}", target_path_str);
let target_path = PathBuf::from(&target_path_str);
let output_path_str = if args.output_directory.is_some() {
args.output_directory.unwrap()
} else {
2026-02-05 19:38:50 +01:00
format!("_{}", target_path.file_name().and_then(|s| s.to_str()).unwrap())
};
println!("Output directory: {}", output_path_str);
2026-02-05 19:38:50 +01:00
let output_directory_path = PathBuf::from(&output_path_str);
2025-09-11 20:26:51 +02:00
2026-02-05 19:38:50 +01:00
if output_directory_path.exists() {
if output_directory_path.is_dir() {
let is_empty = fs::read_dir(&output_directory_path)?.next().is_none();
2025-10-07 21:43:49 +02:00
if !is_empty {
println!("\nWarning: Output folder already exists and is NOT empty! Files may be overwritten!");
2025-10-07 21:43:49 +02:00
println!("Press Enter if you want to continue...");
io::stdin().read_line(&mut String::new())?;
}
}
}
2026-02-05 15:18:26 +01:00
let app_ctx;
if target_path.is_file() {
let file = File::open(&target_path)?;
app_ctx = AppContext {
input: InputTarget::File(file),
output_dir: output_directory_path,
};
} else if target_path.is_dir() {
app_ctx = AppContext {
input: InputTarget::Directory(target_path),
output_dir: output_directory_path,
};
} else {
return Err("Invalid input path!".into());
}
2026-02-05 15:18:26 +01:00
2026-02-05 19:38:50 +01:00
let formats: Vec<Format> = get_registry();
println!("Loaded {} formats!", formats.len());
2026-02-05 15:18:26 +01:00
for format in formats {
2026-02-05 18:53:35 +01:00
if let Some(ctx) = (format.detector_func)(&app_ctx)? {
println!("\n{} detected!", format.name);
(format.extractor_func)(&app_ctx, ctx)?;
2026-02-05 15:18:26 +01:00
return Ok(());
2025-09-11 20:26:51 +02:00
}
}
2026-02-05 15:18:26 +01:00
println!("\nInput format not recognized!");
2025-09-11 20:26:51 +02:00
Ok(())
}