aboutsummaryrefslogtreecommitdiff
path: root/nres-cli
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2023-09-17 01:45:17 +0300
committerValentin Popov <valentin@popov.link>2023-09-17 01:45:17 +0300
commit0c095125de8840d09cc825dfc241b3e4d3617335 (patch)
treece58f9bc906b08cc094b3d36f9727d6959a76233 /nres-cli
parent4e195ec38657605657dcbcc5b76581cbf5b8c404 (diff)
downloadfparkan-0c095125de8840d09cc825dfc241b3e4d3617335.tar.xz
fparkan-0c095125de8840d09cc825dfc241b3e4d3617335.zip
Перенос старых наработок в новый репозиторий
Diffstat (limited to 'nres-cli')
-rw-r--r--nres-cli/Cargo.toml20
-rw-r--r--nres-cli/README.md6
-rw-r--r--nres-cli/src/main.rs198
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()
+}