fparkan/nres-cli/src/main.rs

199 lines
5.5 KiB
Rust

extern crate core;
extern crate libnres;
use std::io::Write;
use clap::{Parser, Subcommand};
use miette::{IntoDiagnostic, Result};
#[derive(Parser, Debug)]
#[command(name = "NRes CLI")]
#[command(about, author, version, long_about = None)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand, Debug)]
enum Commands {
/// Check if the "NRes" file can be extract
Check {
/// "NRes" file
file: String,
},
/// Print debugging information on the "NRes" file
#[command(arg_required_else_help = true)]
Debug {
/// "NRes" file
file: String,
/// Filter results by file name
#[arg(long)]
name: Option<String>,
},
/// Extract files or a file from the "NRes" file
#[command(arg_required_else_help = true)]
Extract {
/// "NRes" file
file: String,
/// Overwrite files
#[arg(short, long, default_value_t = false, value_name = "TRUE|FALSE")]
force: bool,
/// Outbound directory
#[arg(short, long, value_name = "DIR")]
out: String,
},
/// Print a list of files in the "NRes" file
#[command(arg_required_else_help = true)]
Ls {
/// "NRes" file
file: String,
},
}
pub fn main() -> Result<()> {
let stdout = console::Term::stdout();
let cli = Cli::parse();
match cli.command {
Commands::Check { file } => command_check(stdout, file)?,
Commands::Debug { file, name } => command_debug(stdout, file, name)?,
Commands::Extract { file, force, out } => command_extract(stdout, file, out, force)?,
Commands::Ls { file } => command_ls(stdout, file)?,
}
Ok(())
}
fn command_check(_stdout: console::Term, file: String) -> Result<()> {
let file = std::fs::File::open(file).into_diagnostic()?;
let list = libnres::reader::get_list(&file).into_diagnostic()?;
let tmp = tempdir::TempDir::new("nres").into_diagnostic()?;
let bar = indicatif::ProgressBar::new(list.len() as u64);
bar.set_style(get_bar_style()?);
for element in list {
bar.set_message(element.get_filename());
let path = tmp.path().join(element.get_filename());
let mut output = std::fs::File::create(path).into_diagnostic()?;
let mut buffer = libnres::reader::get_file(&file, &element).into_diagnostic()?;
output.write_all(&buffer).into_diagnostic()?;
buffer.clear();
bar.inc(1);
}
bar.finish();
Ok(())
}
fn command_debug(stdout: console::Term, file: String, name: Option<String>) -> Result<()> {
let file = std::fs::File::open(file).into_diagnostic()?;
let mut list = libnres::reader::get_list(&file).into_diagnostic()?;
let mut total_files_size: u32 = 0;
let mut total_files_gap: u32 = 0;
let mut total_files: u32 = 0;
for (index, item) in list.iter().enumerate() {
total_files_size += item.size;
total_files += 1;
let mut gap = 0;
if index > 1 {
let previous_item = &list[index - 1];
gap = item.position - (previous_item.position + previous_item.size);
}
total_files_gap += gap;
}
if let Some(name) = name {
list.retain(|item| item.name.contains(&name));
};
for (index, item) in list.iter().enumerate() {
let mut gap = 0;
if index > 1 {
let previous_item = &list[index - 1];
gap = item.position - (previous_item.position + previous_item.size);
}
let text = format!("Index: {};\nGap: {};\nItem: {:#?};\n", index, gap, item);
stdout.write_line(&text).into_diagnostic()?;
}
let text = format!(
"Total files: {};\nTotal files gap: {} (bytes);\nTotal files size: {} (bytes);",
total_files, total_files_gap, total_files_size
);
stdout.write_line(&text).into_diagnostic()?;
Ok(())
}
fn command_extract(_stdout: console::Term, file: String, out: String, force: bool) -> Result<()> {
let file = std::fs::File::open(file).into_diagnostic()?;
let list = libnres::reader::get_list(&file).into_diagnostic()?;
let bar = indicatif::ProgressBar::new(list.len() as u64);
bar.set_style(get_bar_style()?);
for element in list {
bar.set_message(element.get_filename());
let path = format!("{}/{}", out, element.get_filename());
if !force && is_exist_file(&path) {
let message = format!("File \"{}\" exists. Overwrite it?", path);
if !dialoguer::Confirm::new()
.with_prompt(message)
.interact()
.into_diagnostic()?
{
continue;
}
}
let mut output = std::fs::File::create(path).into_diagnostic()?;
let mut buffer = libnres::reader::get_file(&file, &element).into_diagnostic()?;
output.write_all(&buffer).into_diagnostic()?;
buffer.clear();
bar.inc(1);
}
bar.finish();
Ok(())
}
fn command_ls(stdout: console::Term, file: String) -> Result<()> {
let file = std::fs::File::open(file).into_diagnostic()?;
let list = libnres::reader::get_list(&file).into_diagnostic()?;
for element in list {
stdout.write_line(&element.name).into_diagnostic()?;
}
Ok(())
}
fn get_bar_style() -> Result<indicatif::ProgressStyle> {
Ok(
indicatif::ProgressStyle::with_template("[{bar:32}] {pos:>7}/{len:7} {msg}")
.into_diagnostic()?
.progress_chars("=>-"),
)
}
fn is_exist_file(path: &String) -> bool {
let metadata = std::path::Path::new(path);
metadata.exists()
}