2025-09-27 00:31:18 +02:00
|
|
|
mod formats;
|
2025-10-08 15:14:53 +02:00
|
|
|
mod keys;
|
2025-10-30 22:04:59 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2026-02-05 18:53:35 +01:00
|
|
|
pub struct AppContext<'a> {
|
2026-02-05 15:18:26 +01:00
|
|
|
pub file: &'a std::fs::File,
|
|
|
|
|
pub output_dir: &'a str,
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-11 20:26:51 +02:00
|
|
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
2025-10-07 16:00:32 +02:00
|
|
|
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()
|
2025-12-10 20:27:32 +01:00
|
|
|
} else {
|
2026-02-05 19:38:50 +01:00
|
|
|
format!("_{}", target_path.file_name().and_then(|s| s.to_str()).unwrap())
|
2025-12-10 20:27:32 +01:00
|
|
|
};
|
2026-02-05 19:38:50 +01:00
|
|
|
println!("Output directory: {}\n", output_path_str);
|
|
|
|
|
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 {
|
2025-12-10 20:27:32 +01:00
|
|
|
println!("Warning: 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
|
|
|
|
2026-02-05 19:38:50 +01:00
|
|
|
let file = File::open(target_path)?;
|
|
|
|
|
let app_ctx: AppContext = AppContext { file: &file, output_dir: &output_path_str };
|
2026-02-05 15:18:26 +01:00
|
|
|
|
2026-02-05 19:38:50 +01:00
|
|
|
let formats: Vec<Format> = get_registry();
|
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)? {
|
2026-02-05 15:18:26 +01:00
|
|
|
println!("{} detected!", format.name);
|
2026-02-05 18:53:35 +01:00
|
|
|
(format.extractor_func)(&app_ctx, Some(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(())
|
|
|
|
|
}
|