Added a new command option archive-encoding

This commit is contained in:
2025-06-03 10:24:23 +08:00
parent 3e1c7c28fb
commit 9b4f6e4e6e
7 changed files with 98 additions and 20 deletions

View File

@@ -3,7 +3,7 @@ use clap::{ArgAction, ArgGroup, Parser, Subcommand};
/// Tools for export and import scripts /// Tools for export and import scripts
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[clap(group = ArgGroup::new("encodingg").multiple(false), group = ArgGroup::new("output_encodingg").multiple(false))] #[clap(group = ArgGroup::new("encodingg").multiple(false), group = ArgGroup::new("output_encodingg").multiple(false), group = ArgGroup::new("archive_encodingg").multiple(false))]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
pub struct Arg { pub struct Arg {
#[arg(short = 't', long, value_enum, global = true)] #[arg(short = 't', long, value_enum, global = true)]
@@ -38,6 +38,25 @@ pub struct Arg {
)] )]
/// Output code page /// Output code page
pub output_code_page: Option<u32>, pub output_code_page: Option<u32>,
#[arg(
short = 'a',
long,
value_enum,
global = true,
group = "archive_encodingg"
)]
/// Archive filename encoding
pub archive_encoding: Option<TextEncoding>,
#[cfg(windows)]
#[arg(
short = 'A',
long,
value_enum,
global = true,
group = "archive_encodingg"
)]
/// Archive code page
pub archive_code_page: Option<u32>,
#[arg(long, value_enum, global = true)] #[arg(long, value_enum, global = true)]
/// Circus Game /// Circus Game
pub circus_mes_type: Option<CircusMesType>, pub circus_mes_type: Option<CircusMesType>,

View File

@@ -34,6 +34,33 @@ fn get_encoding(
builder.default_encoding() builder.default_encoding()
} }
fn get_archived_encoding(
arg: &args::Arg,
builder: &Box<dyn scripts::ScriptBuilder + Send + Sync>,
encoding: types::Encoding,
) -> types::Encoding {
match &arg.encoding {
Some(enc) => {
return match enc {
&types::TextEncoding::Default => builder.default_encoding(),
&types::TextEncoding::Auto => types::Encoding::Auto,
&types::TextEncoding::Cp932 => types::Encoding::Cp932,
&types::TextEncoding::Utf8 => types::Encoding::Utf8,
&types::TextEncoding::Gb2312 => types::Encoding::Gb2312,
};
}
None => {}
}
#[cfg(windows)]
match &arg.code_page {
Some(code_page) => {
return types::Encoding::CodePage(*code_page);
}
None => {}
}
builder.default_archive_encoding().unwrap_or(encoding)
}
fn get_output_encoding(arg: &args::Arg) -> types::Encoding { fn get_output_encoding(arg: &args::Arg) -> types::Encoding {
match &arg.output_encoding { match &arg.output_encoding {
Some(enc) => { Some(enc) => {
@@ -96,8 +123,14 @@ 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 archive_encoding = get_archived_encoding(arg, builder, encoding);
return Ok(( return Ok((
builder.build_script_from_file(filename, encoding, config)?, builder.build_script_from_file(
filename,
encoding,
archive_encoding,
config,
)?,
builder, builder,
)); ));
} }
@@ -123,8 +156,9 @@ 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 archive_encoding = get_archived_encoding(arg, builder, encoding);
return Ok(( return Ok((
builder.build_script_from_file(filename, encoding, config)?, builder.build_script_from_file(filename, encoding, archive_encoding, config)?,
builder, builder,
)); ));
} }
@@ -153,8 +187,9 @@ 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 archive_encoding = get_archived_encoding(arg, builder, encoding);
return Ok(( return Ok((
builder.build_script_from_file(filename, encoding, config)?, builder.build_script_from_file(filename, encoding, archive_encoding, config)?,
builder, builder,
)); ));
} }
@@ -194,8 +229,9 @@ pub fn parse_script_from_archive(
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 archive_encoding = get_archived_encoding(arg, builder, encoding);
return Ok(( return Ok((
builder.build_script(file.data().to_vec(), encoding, config)?, builder.build_script(file.data().to_vec(), encoding, archive_encoding, config)?,
builder, builder,
)); ));
} }
@@ -218,8 +254,9 @@ pub fn parse_script_from_archive(
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 archive_encoding = get_archived_encoding(arg, builder, encoding);
return Ok(( return Ok((
builder.build_script(file.data().to_vec(), encoding, config)?, builder.build_script(file.data().to_vec(), encoding, archive_encoding, config)?,
builder, builder,
)); ));
} }

View File

@@ -4,6 +4,10 @@ use anyhow::Result;
pub trait ScriptBuilder: std::fmt::Debug { pub trait ScriptBuilder: std::fmt::Debug {
fn default_encoding(&self) -> Encoding; fn default_encoding(&self) -> Encoding;
fn default_archive_encoding(&self) -> Option<Encoding> {
None
}
fn default_patched_encoding(&self) -> Encoding { fn default_patched_encoding(&self) -> Encoding {
self.default_encoding() self.default_encoding()
} }
@@ -12,6 +16,7 @@ pub trait ScriptBuilder: std::fmt::Debug {
&self, &self,
buf: Vec<u8>, buf: Vec<u8>,
encoding: Encoding, encoding: Encoding,
archive_encoding: Encoding,
config: &ExtraConfig, config: &ExtraConfig,
) -> Result<Box<dyn Script>>; ) -> Result<Box<dyn Script>>;
@@ -19,10 +24,11 @@ pub trait ScriptBuilder: std::fmt::Debug {
&self, &self,
filename: &str, filename: &str,
encoding: Encoding, encoding: Encoding,
archive_encoding: Encoding,
config: &ExtraConfig, config: &ExtraConfig,
) -> Result<Box<dyn Script>> { ) -> Result<Box<dyn Script>> {
let data = crate::utils::files::read_file(filename)?; let data = crate::utils::files::read_file(filename)?;
self.build_script(data, encoding, config) self.build_script(data, encoding, archive_encoding, config)
} }
fn extensions(&self) -> &'static [&'static str]; fn extensions(&self) -> &'static [&'static str];

View File

@@ -22,6 +22,7 @@ impl ScriptBuilder for BGIScriptBuilder {
&self, &self,
buf: Vec<u8>, buf: Vec<u8>,
encoding: Encoding, encoding: Encoding,
_archive_encoding: Encoding,
config: &ExtraConfig, config: &ExtraConfig,
) -> Result<Box<dyn Script>> { ) -> Result<Box<dyn Script>> {
Ok(Box::new(BGIScript::new(buf, encoding, config)?)) Ok(Box::new(BGIScript::new(buf, encoding, config)?))

View File

@@ -22,6 +22,7 @@ impl ScriptBuilder for CircusMesScriptBuilder {
&self, &self,
buf: Vec<u8>, buf: Vec<u8>,
encoding: Encoding, encoding: Encoding,
_archive_encoding: Encoding,
config: &ExtraConfig, config: &ExtraConfig,
) -> Result<Box<dyn Script>> { ) -> Result<Box<dyn Script>> {
Ok(Box::new(CircusMesScript::new(buf, encoding, config)?)) Ok(Box::new(CircusMesScript::new(buf, encoding, config)?))

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};
@@ -20,15 +20,20 @@ impl ScriptBuilder for EscudeBinArchiveBuilder {
Encoding::Cp932 Encoding::Cp932
} }
fn default_archive_encoding(&self) -> Option<Encoding> {
Some(Encoding::Cp932)
}
fn build_script( fn build_script(
&self, &self,
data: Vec<u8>, data: Vec<u8>,
encoding: Encoding, _encoding: Encoding,
archive_encoding: Encoding,
config: &ExtraConfig, config: &ExtraConfig,
) -> Result<Box<dyn Script>> { ) -> Result<Box<dyn Script>> {
Ok(Box::new(EscudeBinArchive::new( Ok(Box::new(EscudeBinArchive::new(
MemReader::new(data), MemReader::new(data),
encoding, archive_encoding,
config, config,
)?)) )?))
} }
@@ -36,16 +41,25 @@ impl ScriptBuilder for EscudeBinArchiveBuilder {
fn build_script_from_file( fn build_script_from_file(
&self, &self,
filename: &str, filename: &str,
encoding: Encoding, _encoding: Encoding,
archive_encoding: Encoding,
config: &ExtraConfig, config: &ExtraConfig,
) -> Result<Box<dyn Script>> { ) -> Result<Box<dyn Script>> {
if filename == "-" { if filename == "-" {
let data = crate::utils::files::read_file(filename)?; let data = crate::utils::files::read_file(filename)?;
self.build_script(data, encoding, config) Ok(Box::new(EscudeBinArchive::new(
MemReader::new(data),
archive_encoding,
config,
)?))
} else { } else {
let f = std::fs::File::open(filename)?; let f = std::fs::File::open(filename)?;
let reader = std::io::BufReader::new(f); let reader = std::io::BufReader::new(f);
Ok(Box::new(EscudeBinArchive::new(reader, encoding, config)?)) Ok(Box::new(EscudeBinArchive::new(
reader,
archive_encoding,
config,
)?))
} }
} }
@@ -101,11 +115,11 @@ pub struct EscudeBinArchive<T: Read + Seek + std::fmt::Debug> {
file_count: u32, file_count: u32,
name_tbl_len: u32, name_tbl_len: u32,
entries: Vec<BinEntry>, entries: Vec<BinEntry>,
encoding: Encoding, archive_encoding: Encoding,
} }
impl<T: Read + Seek + std::fmt::Debug> EscudeBinArchive<T> { impl<T: Read + Seek + std::fmt::Debug> EscudeBinArchive<T> {
pub fn new(mut reader: T, encoding: Encoding, _config: &ExtraConfig) -> Result<Self> { pub fn new(mut reader: T, archive_encoding: Encoding, _config: &ExtraConfig) -> Result<Self> {
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" {
@@ -131,7 +145,7 @@ impl<T: Read + Seek + std::fmt::Debug> EscudeBinArchive<T> {
file_count, file_count,
name_tbl_len, name_tbl_len,
entries, entries,
encoding, archive_encoding,
}) })
} }
} }
@@ -152,12 +166,11 @@ impl<T: Read + Seek + std::fmt::Debug> Script for EscudeBinArchive<T> {
fn iter_archive<'a>( fn iter_archive<'a>(
&'a mut 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 encoding = self.encoding;
Ok(Box::new(EscudeBinArchiveIterator { Ok(Box::new(EscudeBinArchiveIterator {
entries: self.entries.iter(), entries: self.entries.iter(),
reader: &mut self.reader, reader: &mut self.reader,
encoding,
file_count: self.file_count, file_count: self.file_count,
archive_encoding: self.archive_encoding,
})) }))
} }
} }
@@ -165,8 +178,8 @@ impl<T: Read + Seek + std::fmt::Debug> Script for EscudeBinArchive<T> {
struct EscudeBinArchiveIterator<'a, T: Iterator<Item = &'a BinEntry>, R: Read + Seek> { struct EscudeBinArchiveIterator<'a, T: Iterator<Item = &'a BinEntry>, R: Read + Seek> {
entries: T, entries: T,
reader: &'a mut R, reader: &'a mut R,
encoding: Encoding,
file_count: u32, file_count: u32,
archive_encoding: Encoding,
} }
impl<'a, T: Iterator<Item = &'a BinEntry>, R: Read + Seek> Iterator impl<'a, T: Iterator<Item = &'a BinEntry>, R: Read + Seek> Iterator
@@ -186,7 +199,7 @@ impl<'a, T: Iterator<Item = &'a BinEntry>, R: Read + Seek> Iterator
Ok(name) => name, Ok(name) => name,
Err(e) => return Some(Err(e.into())), Err(e) => return Some(Err(e.into())),
}; };
let name = match decode_to_string(self.encoding, name.as_bytes()) { let name = match decode_to_string(self.archive_encoding, name.as_bytes()) {
Ok(name) => name, Ok(name) => name,
Err(e) => return Some(Err(e.into())), Err(e) => return Some(Err(e.into())),
}; };

View File

@@ -25,6 +25,7 @@ impl ScriptBuilder for EscudeBinScriptBuilder {
&self, &self,
data: Vec<u8>, data: Vec<u8>,
encoding: Encoding, encoding: Encoding,
_archive_encoding: Encoding,
config: &ExtraConfig, config: &ExtraConfig,
) -> Result<Box<dyn Script>> { ) -> Result<Box<dyn Script>> {
Ok(Box::new(EscudeBinScript::new(data, encoding, config)?)) Ok(Box::new(EscudeBinScript::new(data, encoding, config)?))