Add support read archiver from file directly

This commit is contained in:
2025-06-03 09:57:10 +08:00
parent a2248cf529
commit 3e1c7c28fb
3 changed files with 66 additions and 22 deletions

View File

@@ -96,8 +96,10 @@ pub fn parse_script(
for builder in scripts::BUILDER.iter() { for builder in scripts::BUILDER.iter() {
if typ == builder.script_type() { if typ == builder.script_type() {
let encoding = get_encoding(arg, builder); let encoding = get_encoding(arg, builder);
let data = utils::files::read_file(filename)?; return Ok((
return Ok((builder.build_script(data, encoding, config)?, builder)); builder.build_script_from_file(filename, encoding, config)?,
builder,
));
} }
} }
} }
@@ -121,8 +123,10 @@ pub fn parse_script(
if exts_builder.len() == 1 { if exts_builder.len() == 1 {
let builder = exts_builder.first().unwrap(); let builder = exts_builder.first().unwrap();
let encoding = get_encoding(arg, builder); let encoding = get_encoding(arg, builder);
let data = utils::files::read_file(filename)?; return Ok((
return Ok((builder.build_script(data, encoding, config)?, builder)); builder.build_script_from_file(filename, encoding, config)?,
builder,
));
} }
let mut buf = [0u8; 1024]; let mut buf = [0u8; 1024];
let mut size = 0; let mut size = 0;
@@ -149,8 +153,10 @@ pub fn parse_script(
if best_builders.len() == 1 { if best_builders.len() == 1 {
let builder = best_builders.first().unwrap(); let builder = best_builders.first().unwrap();
let encoding = get_encoding(arg, builder); let encoding = get_encoding(arg, builder);
let data = utils::files::read_file(filename)?; return Ok((
return Ok((builder.build_script(data, encoding, config)?, builder)); builder.build_script_from_file(filename, encoding, config)?,
builder,
));
} }
if best_builders.len() > 1 { if best_builders.len() > 1 {
eprintln!( eprintln!(
@@ -236,7 +242,7 @@ pub fn export_script(
is_dir: bool, is_dir: bool,
) -> anyhow::Result<types::ScriptResult> { ) -> anyhow::Result<types::ScriptResult> {
eprintln!("Exporting {}", filename); eprintln!("Exporting {}", filename);
let script = parse_script(filename, arg, config)?.0; let mut script = parse_script(filename, arg, config)?.0;
if script.is_archive() { if script.is_archive() {
let odir = match output.as_ref() { let odir = match output.as_ref() {
Some(output) => { Some(output) => {

View File

@@ -15,6 +15,16 @@ pub trait ScriptBuilder: std::fmt::Debug {
config: &ExtraConfig, config: &ExtraConfig,
) -> Result<Box<dyn Script>>; ) -> Result<Box<dyn Script>>;
fn build_script_from_file(
&self,
filename: &str,
encoding: Encoding,
config: &ExtraConfig,
) -> Result<Box<dyn Script>> {
let data = crate::utils::files::read_file(filename)?;
self.build_script(data, encoding, config)
}
fn extensions(&self) -> &'static [&'static str]; fn extensions(&self) -> &'static [&'static str];
fn is_this_format(&self, _filename: &str, _buf: &[u8], _buf_len: usize) -> Option<u8> { fn is_this_format(&self, _filename: &str, _buf: &[u8], _buf_len: usize) -> Option<u8> {
@@ -22,6 +32,10 @@ pub trait ScriptBuilder: std::fmt::Debug {
} }
fn script_type(&self) -> &'static ScriptType; fn script_type(&self) -> &'static ScriptType;
fn is_archive(&self) -> bool {
false
}
} }
pub trait ArchiveContent { pub trait ArchiveContent {
@@ -64,7 +78,7 @@ pub trait Script: std::fmt::Debug {
} }
fn iter_archive<'a>( fn iter_archive<'a>(
&'a self, &'a mut self,
) -> Result<Box<dyn Iterator<Item = Result<Box<dyn ArchiveContent>>> + 'a>> { ) -> Result<Box<dyn Iterator<Item = Result<Box<dyn ArchiveContent>>> + 'a>> {
Ok(Box::new(std::iter::empty())) Ok(Box::new(std::iter::empty()))
} }

View File

@@ -1,8 +1,8 @@
use super::crypto::*; use super::crypto::*;
use crate::ext::io::*;
use crate::scripts::base::*; use crate::scripts::base::*;
use crate::types::*; use crate::types::*;
use crate::utils::encoding::decode_to_string; use crate::utils::encoding::decode_to_string;
use crate::ext::io::*;
use anyhow::Result; use anyhow::Result;
use std::io::{Read, Seek, SeekFrom}; use std::io::{Read, Seek, SeekFrom};
@@ -26,7 +26,27 @@ impl ScriptBuilder for EscudeBinArchiveBuilder {
encoding: Encoding, encoding: Encoding,
config: &ExtraConfig, config: &ExtraConfig,
) -> Result<Box<dyn Script>> { ) -> Result<Box<dyn Script>> {
Ok(Box::new(EscudeBinArchive::new(data, encoding, config)?)) Ok(Box::new(EscudeBinArchive::new(
MemReader::new(data),
encoding,
config,
)?))
}
fn build_script_from_file(
&self,
filename: &str,
encoding: Encoding,
config: &ExtraConfig,
) -> Result<Box<dyn Script>> {
if filename == "-" {
let data = crate::utils::files::read_file(filename)?;
self.build_script(data, encoding, config)
} else {
let f = std::fs::File::open(filename)?;
let reader = std::io::BufReader::new(f);
Ok(Box::new(EscudeBinArchive::new(reader, encoding, config)?))
}
} }
fn extensions(&self) -> &'static [&'static str] { fn extensions(&self) -> &'static [&'static str] {
@@ -43,6 +63,10 @@ impl ScriptBuilder for EscudeBinArchiveBuilder {
} }
None None
} }
fn is_archive(&self) -> bool {
true
}
} }
#[derive(Debug)] #[derive(Debug)]
@@ -72,17 +96,16 @@ impl ArchiveContent for Entry {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct EscudeBinArchive { pub struct EscudeBinArchive<T: Read + Seek + std::fmt::Debug> {
reader: MemReader, reader: T,
file_count: u32, file_count: u32,
name_tbl_len: u32, name_tbl_len: u32,
entries: Vec<BinEntry>, entries: Vec<BinEntry>,
encoding: Encoding, encoding: Encoding,
} }
impl EscudeBinArchive { impl<T: Read + Seek + std::fmt::Debug> EscudeBinArchive<T> {
pub fn new(data: Vec<u8>, encoding: Encoding, _config: &ExtraConfig) -> Result<Self> { pub fn new(mut reader: T, encoding: Encoding, _config: &ExtraConfig) -> Result<Self> {
let mut reader = MemReader::new(data);
let mut header = [0u8; 8]; let mut header = [0u8; 8];
reader.read_exact(&mut header)?; reader.read_exact(&mut header)?;
if &header != b"ESC-ARC2" { if &header != b"ESC-ARC2" {
@@ -113,7 +136,7 @@ impl EscudeBinArchive {
} }
} }
impl Script for EscudeBinArchive { impl<T: Read + Seek + std::fmt::Debug> Script for EscudeBinArchive<T> {
fn default_output_script_type(&self) -> OutputScriptType { fn default_output_script_type(&self) -> OutputScriptType {
OutputScriptType::Json OutputScriptType::Json
} }
@@ -127,27 +150,28 @@ impl Script for EscudeBinArchive {
} }
fn iter_archive<'a>( fn iter_archive<'a>(
&'a self, &'a mut self,
) -> Result<Box<dyn Iterator<Item = Result<Box<dyn ArchiveContent>>> + 'a>> { ) -> Result<Box<dyn Iterator<Item = Result<Box<dyn ArchiveContent>>> + 'a>> {
let reader = self.reader.to_ref();
let encoding = self.encoding; let encoding = self.encoding;
Ok(Box::new(EscudeBinArchiveIterator { Ok(Box::new(EscudeBinArchiveIterator {
entries: self.entries.iter(), entries: self.entries.iter(),
reader, reader: &mut self.reader,
encoding, encoding,
file_count: self.file_count, file_count: self.file_count,
})) }))
} }
} }
struct EscudeBinArchiveIterator<'a, T: Iterator<Item = &'a BinEntry>> { struct EscudeBinArchiveIterator<'a, T: Iterator<Item = &'a BinEntry>, R: Read + Seek> {
entries: T, entries: T,
reader: MemReaderRef<'a>, reader: &'a mut R,
encoding: Encoding, encoding: Encoding,
file_count: u32, file_count: u32,
} }
impl<'a, T: Iterator<Item = &'a BinEntry>> Iterator for EscudeBinArchiveIterator<'a, T> { impl<'a, T: Iterator<Item = &'a BinEntry>, R: Read + Seek> Iterator
for EscudeBinArchiveIterator<'a, T, R>
{
type Item = Result<Box<dyn ArchiveContent>>; type Item = Result<Box<dyn ArchiveContent>>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {