diff options
author | Valentin Popov <valentin@popov.link> | 2023-09-17 01:45:17 +0300 |
---|---|---|
committer | Valentin Popov <valentin@popov.link> | 2023-09-17 01:45:17 +0300 |
commit | 0c095125de8840d09cc825dfc241b3e4d3617335 (patch) | |
tree | ce58f9bc906b08cc094b3d36f9727d6959a76233 /nres-cli | |
parent | 4e195ec38657605657dcbcc5b76581cbf5b8c404 (diff) | |
download | fparkan-0c095125de8840d09cc825dfc241b3e4d3617335.tar.xz fparkan-0c095125de8840d09cc825dfc241b3e4d3617335.zip |
Перенос старых наработок в новый репозиторий
Diffstat (limited to 'nres-cli')
-rw-r--r-- | nres-cli/Cargo.toml | 20 | ||||
-rw-r--r-- | nres-cli/README.md | 6 | ||||
-rw-r--r-- | nres-cli/src/main.rs | 198 |
3 files changed, 224 insertions, 0 deletions
diff --git a/nres-cli/Cargo.toml b/nres-cli/Cargo.toml new file mode 100644 index 0000000..e3b1932 --- /dev/null +++ b/nres-cli/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "nres-cli" +version = "0.2.3" +description = "Console tool for NRes files" +authors = ["Valentin Popov <valentin@popov.link>"] +homepage = "https://git.popov.link/valentineus/fparkan" +repository = "https://git.popov.link/valentineus/fparkan.git" +license = "GPL-2.0" +edition = "2021" +keywords = ["cli", "gamedev", "nres"] + +[dependencies] +byteorder = "1.4" +clap = { version = "4.2", features = ["derive"] } +console = "0.15" +dialoguer = { version = "0.10", features = ["completion"] } +indicatif = "0.17" +libnres = { version = "0.1", path = "../libnres" } +miette = { version = "5.6", features = ["fancy"] } +tempdir = "0.3" diff --git a/nres-cli/README.md b/nres-cli/README.md new file mode 100644 index 0000000..65a6602 --- /dev/null +++ b/nres-cli/README.md @@ -0,0 +1,6 @@ +# Console tool for NRes files (Deprecated) + +## Commands + +- `extract` - Extract game resources from a "NRes" file. +- `ls` - Get a list of files in a "NRes" file. diff --git a/nres-cli/src/main.rs b/nres-cli/src/main.rs new file mode 100644 index 0000000..85086cb --- /dev/null +++ b/nres-cli/src/main.rs @@ -0,0 +1,198 @@ +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() +} |