mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-06 21:08:48 +08:00
Add support to unpack archive files
This commit is contained in:
@@ -132,12 +132,20 @@ pub enum Command {
|
||||
},
|
||||
/// Import to script
|
||||
Import(ImportArgs),
|
||||
/// Pack files to archive
|
||||
Pack {
|
||||
/// Input directory
|
||||
input: String,
|
||||
/// Output archive file
|
||||
output: Option<String>,
|
||||
},
|
||||
/// Unpack archive to directory
|
||||
Unpack {
|
||||
/// Input archive file
|
||||
input: String,
|
||||
/// Output directory
|
||||
output: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
pub fn parse_args() -> Arg {
|
||||
|
||||
101
src/main.rs
101
src/main.rs
@@ -975,6 +975,73 @@ pub fn pack_archive(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn unpack_archive(
|
||||
filename: &str,
|
||||
arg: &args::Arg,
|
||||
config: &types::ExtraConfig,
|
||||
output: &Option<String>,
|
||||
is_dir: bool,
|
||||
) -> anyhow::Result<types::ScriptResult> {
|
||||
eprintln!("Unpacking {}", filename);
|
||||
let mut script = parse_script(filename, arg, config)?.0;
|
||||
if !script.is_archive() {
|
||||
return Ok(types::ScriptResult::Ignored);
|
||||
}
|
||||
let odir = match output.as_ref() {
|
||||
Some(output) => {
|
||||
let mut pb = std::path::PathBuf::from(output);
|
||||
let filename = std::path::PathBuf::from(filename);
|
||||
if is_dir {
|
||||
if let Some(fname) = filename.file_name() {
|
||||
pb.push(fname);
|
||||
}
|
||||
}
|
||||
pb.to_string_lossy().into_owned()
|
||||
}
|
||||
None => {
|
||||
let mut pb = std::path::PathBuf::from(filename);
|
||||
pb.set_extension("");
|
||||
pb.to_string_lossy().into_owned()
|
||||
}
|
||||
};
|
||||
if !std::fs::exists(&odir)? {
|
||||
std::fs::create_dir_all(&odir)?;
|
||||
}
|
||||
for f in script.iter_archive_mut()? {
|
||||
let f = f?;
|
||||
let out_path = std::path::PathBuf::from(&odir).join(f.name());
|
||||
match utils::files::make_sure_dir_exists(&out_path) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"Error creating parent directory for {}: {}",
|
||||
out_path.display(),
|
||||
e
|
||||
);
|
||||
COUNTER.inc_error();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
match utils::files::write_file(&out_path) {
|
||||
Ok(mut fi) => match fi.write_all(f.data()) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
eprintln!("Error writing to file {}: {}", out_path.display(), e);
|
||||
COUNTER.inc_error();
|
||||
continue;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
eprintln!("Error writing file {}: {}", out_path.display(), e);
|
||||
COUNTER.inc_error();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
COUNTER.inc(types::ScriptResult::Ok);
|
||||
}
|
||||
Ok(types::ScriptResult::Ok)
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref COUNTER: utils::counter::Counter = utils::counter::Counter::new();
|
||||
}
|
||||
@@ -1089,6 +1156,40 @@ fn main() {
|
||||
eprintln!("Error packing archive: {}", e);
|
||||
}
|
||||
}
|
||||
args::Command::Unpack { input, output } => {
|
||||
let (scripts, is_dir) = utils::files::collect_arc_files(input, arg.recursive).unwrap();
|
||||
if is_dir {
|
||||
match &output {
|
||||
Some(output) => {
|
||||
let op = std::path::Path::new(output);
|
||||
if op.exists() {
|
||||
if !op.is_dir() {
|
||||
eprintln!("Output path is not a directory");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
std::fs::create_dir_all(op).unwrap();
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
for script in scripts.iter() {
|
||||
let re = unpack_archive(&script, &arg, &cfg, output, is_dir);
|
||||
match re {
|
||||
Ok(s) => {
|
||||
COUNTER.inc(s);
|
||||
}
|
||||
Err(e) => {
|
||||
COUNTER.inc_error();
|
||||
eprintln!("Error unpacking {}: {}", script, e);
|
||||
if arg.backtrace {
|
||||
eprintln!("Backtrace: {}", e.backtrace());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
eprintln!("{}", std::ops::Deref::deref(&COUNTER));
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use crate::scripts::{ALL_EXTS, ARCHIVE_EXTS};
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::Path;
|
||||
|
||||
use crate::scripts::ALL_EXTS;
|
||||
|
||||
pub fn find_files(path: &str, recursive: bool, no_ext_filter: bool) -> io::Result<Vec<String>> {
|
||||
let mut result = Vec::new();
|
||||
let dir_path = Path::new(&path);
|
||||
@@ -36,6 +35,35 @@ pub fn find_files(path: &str, recursive: bool, no_ext_filter: bool) -> io::Resul
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn find_arc_files(path: &str, recursive: bool) -> io::Result<Vec<String>> {
|
||||
let mut result = Vec::new();
|
||||
let dir_path = Path::new(&path);
|
||||
|
||||
if dir_path.is_dir() {
|
||||
for entry in fs::read_dir(dir_path)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
|
||||
if path.is_file()
|
||||
&& path.extension().map_or(false, |ext| {
|
||||
ARCHIVE_EXTS.contains(&ext.to_string_lossy().to_lowercase())
|
||||
})
|
||||
{
|
||||
if let Some(path_str) = path.to_str() {
|
||||
result.push(path_str.to_string());
|
||||
}
|
||||
} else if recursive && path.is_dir() {
|
||||
if let Some(path_str) = path.to_str() {
|
||||
let mut sub_files = find_arc_files(&path_str.to_string(), recursive)?;
|
||||
result.append(&mut sub_files);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn collect_files(
|
||||
path: &str,
|
||||
recursive: bool,
|
||||
@@ -54,6 +82,20 @@ pub fn collect_files(
|
||||
))
|
||||
}
|
||||
|
||||
pub fn collect_arc_files(path: &str, recursive: bool) -> io::Result<(Vec<String>, bool)> {
|
||||
let pa = Path::new(path);
|
||||
if pa.is_dir() {
|
||||
return Ok((find_arc_files(path, recursive)?, true));
|
||||
}
|
||||
if pa.is_file() {
|
||||
return Ok((vec![path.to_string()], false));
|
||||
}
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
format!("Path {} is neither a file nor a directory", pa.display()),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn read_file<F: AsRef<Path> + ?Sized>(f: &F) -> io::Result<Vec<u8>> {
|
||||
let mut content = Vec::new();
|
||||
if f.as_ref() == Path::new("-") {
|
||||
|
||||
Reference in New Issue
Block a user