mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-07 13:28:47 +08:00
Use box instead
This commit is contained in:
25
src/scripts/entis_gls/csx/base.rs
Normal file
25
src/scripts/entis_gls/csx/base.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use crate::scripts::base::*;
|
||||
use crate::types::*;
|
||||
use anyhow::Result;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
|
||||
pub trait ECSImage: std::fmt::Debug {
|
||||
fn disasm<'a>(&self, writer: Box<dyn Write + 'a>) -> Result<()>;
|
||||
fn export(&self) -> Result<Vec<Message>>;
|
||||
fn export_multi(&self) -> Result<HashMap<String, Vec<Message>>>;
|
||||
fn export_all(&self) -> Result<Vec<String>>;
|
||||
fn import<'a>(
|
||||
&self,
|
||||
messages: Vec<Message>,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
replacement: Option<&'a ReplacementTable>,
|
||||
) -> Result<()>;
|
||||
fn import_multi<'a>(
|
||||
&self,
|
||||
messages: HashMap<String, Vec<Message>>,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
replacement: Option<&'a ReplacementTable>,
|
||||
) -> Result<()>;
|
||||
fn import_all<'a>(&self, messages: Vec<String>, file: Box<dyn WriteSeek + 'a>) -> Result<()>;
|
||||
}
|
||||
@@ -1,3 +1,177 @@
|
||||
//! Ported from Crsky/EntisGLS_Tools C# project
|
||||
//! Entis GLS CSX Script Support
|
||||
//!
|
||||
//! Ported from Crsky/EntisGLS_Tools C# project
|
||||
//! Original license: GPL-3.0
|
||||
pub mod v1;
|
||||
mod base;
|
||||
mod v1;
|
||||
|
||||
use crate::ext::io::*;
|
||||
use crate::scripts::base::*;
|
||||
use crate::types::*;
|
||||
use crate::utils::encoding::*;
|
||||
use anyhow::Result;
|
||||
use base::ECSImage;
|
||||
use v1::ECSExecutionImageV1;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CSXScriptBuilder {}
|
||||
|
||||
impl CSXScriptBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl ScriptBuilder for CSXScriptBuilder {
|
||||
fn default_encoding(&self) -> Encoding {
|
||||
Encoding::Utf16LE
|
||||
}
|
||||
|
||||
fn build_script(
|
||||
&self,
|
||||
buf: Vec<u8>,
|
||||
_filename: &str,
|
||||
_encoding: Encoding,
|
||||
_archive_encoding: Encoding,
|
||||
config: &ExtraConfig,
|
||||
_archive: Option<&Box<dyn Script>>,
|
||||
) -> Result<Box<dyn Script>> {
|
||||
Ok(Box::new(CSXScript::new(buf, config)?))
|
||||
}
|
||||
|
||||
fn extensions(&self) -> &'static [&'static str] {
|
||||
&["csx"]
|
||||
}
|
||||
|
||||
fn script_type(&self) -> &'static ScriptType {
|
||||
&ScriptType::EntisGlsCsx
|
||||
}
|
||||
|
||||
fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
|
||||
if buf_len >= 8 && &buf[0..8] == b"Entis\x1a\0\0" {
|
||||
Some(30)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CSXScript {
|
||||
img: Box<dyn ECSImage>,
|
||||
disasm: bool,
|
||||
custom_yaml: bool,
|
||||
}
|
||||
|
||||
impl CSXScript {
|
||||
pub fn new(buf: Vec<u8>, config: &ExtraConfig) -> Result<Self> {
|
||||
let reader = MemReader::new(buf);
|
||||
let img = ECSExecutionImageV1::new(reader.to_ref(), config)?;
|
||||
Ok(Self {
|
||||
img: Box::new(img),
|
||||
disasm: config.entis_gls_csx_disasm,
|
||||
custom_yaml: config.custom_yaml,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Script for CSXScript {
|
||||
fn default_output_script_type(&self) -> OutputScriptType {
|
||||
OutputScriptType::Json
|
||||
}
|
||||
|
||||
fn is_output_supported(&self, _output: OutputScriptType) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn default_format_type(&self) -> FormatOptions {
|
||||
FormatOptions::None
|
||||
}
|
||||
|
||||
fn extract_messages(&self) -> Result<Vec<Message>> {
|
||||
self.img.export()
|
||||
}
|
||||
|
||||
fn import_messages<'a>(
|
||||
&'a self,
|
||||
messages: Vec<Message>,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
_filename: &str,
|
||||
_encoding: Encoding,
|
||||
replacement: Option<&'a ReplacementTable>,
|
||||
) -> Result<()> {
|
||||
self.img.import(messages, file, replacement)
|
||||
}
|
||||
|
||||
fn multiple_message_files(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn extract_multiple_messages(&self) -> Result<std::collections::HashMap<String, Vec<Message>>> {
|
||||
self.img.export_multi()
|
||||
}
|
||||
|
||||
fn import_multiple_messages<'a>(
|
||||
&'a self,
|
||||
messages: std::collections::HashMap<String, Vec<Message>>,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
_filename: &str,
|
||||
_encoding: Encoding,
|
||||
replacement: Option<&'a ReplacementTable>,
|
||||
) -> Result<()> {
|
||||
self.img.import_multi(messages, file, replacement)
|
||||
}
|
||||
|
||||
fn custom_output_extension<'a>(&'a self) -> &'a str {
|
||||
if self.disasm {
|
||||
"d.txt"
|
||||
} else if self.custom_yaml {
|
||||
"yaml"
|
||||
} else {
|
||||
"json"
|
||||
}
|
||||
}
|
||||
|
||||
fn custom_export(&self, filename: &std::path::Path, encoding: Encoding) -> Result<()> {
|
||||
if self.disasm {
|
||||
let file = crate::utils::files::write_file(filename)?;
|
||||
let file = std::io::BufWriter::new(file);
|
||||
self.img.disasm(Box::new(file))?;
|
||||
} else {
|
||||
let messages = self.img.export_all()?;
|
||||
let s = if self.custom_yaml {
|
||||
serde_yaml_ng::to_string(&messages)?
|
||||
} else {
|
||||
serde_json::to_string_pretty(&messages)?
|
||||
};
|
||||
let s = encode_string(encoding, &s, false)?;
|
||||
let mut file = crate::utils::files::write_file(filename)?;
|
||||
file.write_all(&s)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn custom_import<'a>(
|
||||
&'a self,
|
||||
custom_filename: &'a str,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
_encoding: Encoding,
|
||||
output_encoding: Encoding,
|
||||
) -> Result<()> {
|
||||
if self.disasm {
|
||||
Err(anyhow::anyhow!(
|
||||
"Importing from disassembly is not supported."
|
||||
))
|
||||
} else {
|
||||
let data = crate::utils::files::read_file(custom_filename)?;
|
||||
let s = decode_to_string(output_encoding, &data, false)?;
|
||||
let messages: Vec<String> = if self.custom_yaml {
|
||||
serde_yaml_ng::from_str(&s)?
|
||||
} else {
|
||||
serde_json::from_str(&s)?
|
||||
};
|
||||
self.img.import_all(messages, file)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use super::super::base::*;
|
||||
use super::disasm::*;
|
||||
use super::types::*;
|
||||
use crate::ext::io::*;
|
||||
@@ -34,7 +35,7 @@ pub struct ECSExecutionImage {
|
||||
}
|
||||
|
||||
impl ECSExecutionImage {
|
||||
pub fn new(mut reader: MemReader, config: &ExtraConfig) -> Result<Self> {
|
||||
pub fn new(mut reader: MemReaderRef<'_>, config: &ExtraConfig) -> Result<Self> {
|
||||
let file_header = EMCFileHeader::unpack(&mut reader, false, Encoding::Utf8)?;
|
||||
// if file_header.signagure != *b"Entis\x1a\0\0" {
|
||||
// return Err(anyhow::anyhow!("Invalid EMC file signature"));
|
||||
@@ -362,8 +363,10 @@ impl ECSExecutionImage {
|
||||
writer.write_all(&data)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn disasm<'a>(&self, writer: Box<dyn Write + 'a>) -> Result<()> {
|
||||
impl ECSImage for ECSExecutionImage {
|
||||
fn disasm<'a>(&self, writer: Box<dyn Write + 'a>) -> Result<()> {
|
||||
let mut disasm = ECSExecutionImageDisassembler::new(
|
||||
self.image.to_ref(),
|
||||
self.ext_const_str.as_ref(),
|
||||
@@ -373,7 +376,7 @@ impl ECSExecutionImage {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn export(&self) -> Result<Vec<Message>> {
|
||||
fn export(&self) -> Result<Vec<Message>> {
|
||||
let mut disasm = ECSExecutionImageDisassembler::new(
|
||||
self.image.to_ref(),
|
||||
self.ext_const_str.as_ref(),
|
||||
@@ -459,7 +462,7 @@ impl ECSExecutionImage {
|
||||
Ok(messages)
|
||||
}
|
||||
|
||||
pub fn export_multi(&self) -> Result<HashMap<String, Vec<Message>>> {
|
||||
fn export_multi(&self) -> Result<HashMap<String, Vec<Message>>> {
|
||||
let mut key = String::from("global");
|
||||
let mut messages = HashMap::new();
|
||||
let mut disasm = ECSExecutionImageDisassembler::new(
|
||||
@@ -576,7 +579,7 @@ impl ECSExecutionImage {
|
||||
Ok(messages)
|
||||
}
|
||||
|
||||
pub fn export_all(&self) -> Result<Vec<String>> {
|
||||
fn export_all(&self) -> Result<Vec<String>> {
|
||||
let mut disasm = ECSExecutionImageDisassembler::new(
|
||||
self.image.to_ref(),
|
||||
self.ext_const_str.as_ref(),
|
||||
@@ -599,7 +602,7 @@ impl ECSExecutionImage {
|
||||
Ok(messages)
|
||||
}
|
||||
|
||||
pub fn import<'a>(
|
||||
fn import<'a>(
|
||||
&self,
|
||||
messages: Vec<Message>,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
@@ -981,7 +984,7 @@ impl ECSExecutionImage {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn import_multi<'a>(
|
||||
fn import_multi<'a>(
|
||||
&self,
|
||||
mut messages: HashMap<String, Vec<Message>>,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
@@ -1388,11 +1391,7 @@ impl ECSExecutionImage {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn import_all<'a>(
|
||||
&self,
|
||||
messages: Vec<String>,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
) -> Result<()> {
|
||||
fn import_all<'a>(&self, messages: Vec<String>, file: Box<dyn WriteSeek + 'a>) -> Result<()> {
|
||||
let mut cloned = self.clone();
|
||||
let mut mess = messages.into_iter();
|
||||
let mut mes = mess.next();
|
||||
|
||||
@@ -4,172 +4,4 @@ mod disasm;
|
||||
mod img;
|
||||
mod types;
|
||||
|
||||
use crate::ext::io::*;
|
||||
use crate::scripts::base::*;
|
||||
use crate::types::*;
|
||||
use crate::utils::encoding::*;
|
||||
use anyhow::Result;
|
||||
use img::ECSExecutionImage;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CSXScriptBuilder {}
|
||||
|
||||
impl CSXScriptBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl ScriptBuilder for CSXScriptBuilder {
|
||||
fn default_encoding(&self) -> Encoding {
|
||||
Encoding::Utf16LE
|
||||
}
|
||||
|
||||
fn build_script(
|
||||
&self,
|
||||
buf: Vec<u8>,
|
||||
_filename: &str,
|
||||
_encoding: Encoding,
|
||||
_archive_encoding: Encoding,
|
||||
config: &ExtraConfig,
|
||||
_archive: Option<&Box<dyn Script>>,
|
||||
) -> Result<Box<dyn Script>> {
|
||||
Ok(Box::new(CSXScript::new(buf, config)?))
|
||||
}
|
||||
|
||||
fn extensions(&self) -> &'static [&'static str] {
|
||||
&["csx"]
|
||||
}
|
||||
|
||||
fn script_type(&self) -> &'static ScriptType {
|
||||
&ScriptType::EntisGlsCsx1
|
||||
}
|
||||
|
||||
fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
|
||||
if buf_len >= 8 && &buf[0..8] == b"Entis\x1a\0\0" {
|
||||
Some(30)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CSXScript {
|
||||
img: ECSExecutionImage,
|
||||
disasm: bool,
|
||||
custom_yaml: bool,
|
||||
}
|
||||
|
||||
impl CSXScript {
|
||||
pub fn new(buf: Vec<u8>, config: &ExtraConfig) -> Result<Self> {
|
||||
let reader = MemReader::new(buf);
|
||||
let img = ECSExecutionImage::new(reader, config)?;
|
||||
Ok(Self {
|
||||
img,
|
||||
disasm: config.entis_gls_csx_disasm,
|
||||
custom_yaml: config.custom_yaml,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Script for CSXScript {
|
||||
fn default_output_script_type(&self) -> OutputScriptType {
|
||||
OutputScriptType::Json
|
||||
}
|
||||
|
||||
fn is_output_supported(&self, _output: OutputScriptType) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn default_format_type(&self) -> FormatOptions {
|
||||
FormatOptions::None
|
||||
}
|
||||
|
||||
fn extract_messages(&self) -> Result<Vec<Message>> {
|
||||
self.img.export()
|
||||
}
|
||||
|
||||
fn import_messages<'a>(
|
||||
&'a self,
|
||||
messages: Vec<Message>,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
_filename: &str,
|
||||
_encoding: Encoding,
|
||||
replacement: Option<&'a ReplacementTable>,
|
||||
) -> Result<()> {
|
||||
self.img.import(messages, file, replacement)
|
||||
}
|
||||
|
||||
fn multiple_message_files(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn extract_multiple_messages(&self) -> Result<std::collections::HashMap<String, Vec<Message>>> {
|
||||
self.img.export_multi()
|
||||
}
|
||||
|
||||
fn import_multiple_messages<'a>(
|
||||
&'a self,
|
||||
messages: std::collections::HashMap<String, Vec<Message>>,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
_filename: &str,
|
||||
_encoding: Encoding,
|
||||
replacement: Option<&'a ReplacementTable>,
|
||||
) -> Result<()> {
|
||||
self.img.import_multi(messages, file, replacement)
|
||||
}
|
||||
|
||||
fn custom_output_extension<'a>(&'a self) -> &'a str {
|
||||
if self.disasm {
|
||||
"d.txt"
|
||||
} else if self.custom_yaml {
|
||||
"yaml"
|
||||
} else {
|
||||
"json"
|
||||
}
|
||||
}
|
||||
|
||||
fn custom_export(&self, filename: &std::path::Path, encoding: Encoding) -> Result<()> {
|
||||
if self.disasm {
|
||||
let file = crate::utils::files::write_file(filename)?;
|
||||
let file = std::io::BufWriter::new(file);
|
||||
self.img.disasm(Box::new(file))?;
|
||||
} else {
|
||||
let messages = self.img.export_all()?;
|
||||
let s = if self.custom_yaml {
|
||||
serde_yaml_ng::to_string(&messages)?
|
||||
} else {
|
||||
serde_json::to_string_pretty(&messages)?
|
||||
};
|
||||
let s = encode_string(encoding, &s, false)?;
|
||||
let mut file = crate::utils::files::write_file(filename)?;
|
||||
file.write_all(&s)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn custom_import<'a>(
|
||||
&'a self,
|
||||
custom_filename: &'a str,
|
||||
file: Box<dyn WriteSeek + 'a>,
|
||||
_encoding: Encoding,
|
||||
output_encoding: Encoding,
|
||||
) -> Result<()> {
|
||||
if self.disasm {
|
||||
Err(anyhow::anyhow!(
|
||||
"Importing from disassembly is not supported."
|
||||
))
|
||||
} else {
|
||||
let data = crate::utils::files::read_file(custom_filename)?;
|
||||
let s = decode_to_string(output_encoding, &data, false)?;
|
||||
let messages: Vec<String> = if self.custom_yaml {
|
||||
serde_yaml_ng::from_str(&s)?
|
||||
} else {
|
||||
serde_json::from_str(&s)?
|
||||
};
|
||||
self.img.import_all(messages, file)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
pub use img::ECSExecutionImage as ECSExecutionImageV1;
|
||||
|
||||
@@ -163,7 +163,7 @@ lazy_static::lazy_static! {
|
||||
#[cfg(feature = "musica-arc")]
|
||||
Box::new(musica::archive::paz::PazArcBuilder::new()),
|
||||
#[cfg(feature = "entis-gls")]
|
||||
Box::new(entis_gls::csx::v1::CSXScriptBuilder::new()),
|
||||
Box::new(entis_gls::csx::CSXScriptBuilder::new()),
|
||||
];
|
||||
/// A list of all script extensions.
|
||||
pub static ref ALL_EXTS: Vec<String> =
|
||||
|
||||
Reference in New Issue
Block a user