mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-25 13:17:06 +08:00
Add mdf decompress support when unpack xp3 archive
This commit is contained in:
@@ -484,6 +484,14 @@ pub struct Arg {
|
|||||||
#[arg(long, global = true, visible_alias = "softpal-idx")]
|
#[arg(long, global = true, visible_alias = "softpal-idx")]
|
||||||
/// Whether to add message index to Softpal src script when exporting.
|
/// Whether to add message index to Softpal src script when exporting.
|
||||||
pub softpal_add_message_index: bool,
|
pub softpal_add_message_index: bool,
|
||||||
|
#[cfg(feature = "kirikiri-arc")]
|
||||||
|
#[arg(long, global = true)]
|
||||||
|
/// Disable decrypt SimpleCrypt files in Kirikiri XP3 archive when extracting.
|
||||||
|
pub xp3_no_simple_crypt: bool,
|
||||||
|
#[cfg(feature = "kirikiri-arc")]
|
||||||
|
#[arg(long, global = true)]
|
||||||
|
/// Disable decompressing mdf files in Kirikiri XP3 archive when extracting.
|
||||||
|
pub xp3_no_mdf_decompress: bool,
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
/// Command
|
/// Command
|
||||||
pub command: Command,
|
pub command: Command,
|
||||||
|
|||||||
@@ -2744,6 +2744,10 @@ fn main() {
|
|||||||
softpal_add_message_index: arg.softpal_add_message_index,
|
softpal_add_message_index: arg.softpal_add_message_index,
|
||||||
#[cfg(feature = "kirikiri")]
|
#[cfg(feature = "kirikiri")]
|
||||||
kirikiri_chat_multilang: !arg.kirikiri_chat_no_multilang,
|
kirikiri_chat_multilang: !arg.kirikiri_chat_no_multilang,
|
||||||
|
#[cfg(feature = "kirikiri-arc")]
|
||||||
|
xp3_simple_crypt: !arg.xp3_no_simple_crypt,
|
||||||
|
#[cfg(feature = "kirikiri-arc")]
|
||||||
|
xp3_mdf_decompress: !arg.xp3_no_mdf_decompress,
|
||||||
});
|
});
|
||||||
match &arg.command {
|
match &arg.command {
|
||||||
args::Command::Export { input, output } => {
|
args::Command::Export { input, output } => {
|
||||||
|
|||||||
@@ -83,11 +83,13 @@ impl ScriptBuilder for Xp3ArchiveBuilder {
|
|||||||
pub struct Xp3Archive<T: Read + Seek + std::fmt::Debug> {
|
pub struct Xp3Archive<T: Read + Seek + std::fmt::Debug> {
|
||||||
reader: Arc<Mutex<T>>,
|
reader: Arc<Mutex<T>>,
|
||||||
entries: Vec<(String, XP3FileIndex)>,
|
entries: Vec<(String, XP3FileIndex)>,
|
||||||
|
decrypt_simple_crypt: bool,
|
||||||
|
decompress_mdf: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Read + Seek + std::fmt::Debug> Xp3Archive<T> {
|
impl<T: Read + Seek + std::fmt::Debug> Xp3Archive<T> {
|
||||||
/// Create a new Kirikiri XP3 Archive
|
/// Create a new Kirikiri XP3 Archive
|
||||||
pub fn new(reader: T, _config: &ExtraConfig) -> Result<Self> {
|
pub fn new(reader: T, config: &ExtraConfig) -> Result<Self> {
|
||||||
let xp3_reader = XP3Reader::open_archive(reader)
|
let xp3_reader = XP3Reader::open_archive(reader)
|
||||||
.map_err(|e| anyhow::anyhow!("Failed to open XP3 archive: {:?}", e))?;
|
.map_err(|e| anyhow::anyhow!("Failed to open XP3 archive: {:?}", e))?;
|
||||||
let entries = xp3_reader
|
let entries = xp3_reader
|
||||||
@@ -106,6 +108,8 @@ impl<T: Read + Seek + std::fmt::Debug> Xp3Archive<T> {
|
|||||||
Ok(Self {
|
Ok(Self {
|
||||||
reader: Arc::new(Mutex::new(xp3_reader.close().1)),
|
reader: Arc::new(Mutex::new(xp3_reader.close().1)),
|
||||||
entries,
|
entries,
|
||||||
|
decrypt_simple_crypt: config.xp3_simple_crypt,
|
||||||
|
decompress_mdf: config.xp3_mdf_decompress,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,7 +147,8 @@ impl<T: Read + Seek + std::fmt::Debug + 'static> Script for Xp3Archive<T> {
|
|||||||
let mut header = [0u8; 16];
|
let mut header = [0u8; 16];
|
||||||
let header_len = entry.read(&mut header)?;
|
let header_len = entry.read(&mut header)?;
|
||||||
entry.rewind()?;
|
entry.rewind()?;
|
||||||
if header_len >= 5
|
if self.decrypt_simple_crypt
|
||||||
|
&& header_len >= 5
|
||||||
&& header[0] == 0xFE
|
&& header[0] == 0xFE
|
||||||
&& header[1] == 0xFE
|
&& header[1] == 0xFE
|
||||||
&& header[3] == 0xFF
|
&& header[3] == 0xFF
|
||||||
@@ -159,6 +164,14 @@ impl<T: Read + Seek + std::fmt::Debug + 'static> Script for Xp3Archive<T> {
|
|||||||
return Ok(Box::new(SimpleCrypt::new(entry, index, crypt)?));
|
return Ok(Box::new(SimpleCrypt::new(entry, index, crypt)?));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if self.decompress_mdf
|
||||||
|
&& header_len >= 4
|
||||||
|
&& &header[0..4] == b"mdf\0"
|
||||||
|
&& entry.index.info().file_size() > 8
|
||||||
|
{
|
||||||
|
let index = entry.index.clone();
|
||||||
|
return Ok(Box::new(MdfEntry::new(entry, index)?));
|
||||||
|
}
|
||||||
Ok(Box::new(entry))
|
Ok(Box::new(entry))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -461,3 +474,30 @@ impl<T: Read + Seek + std::fmt::Debug> Seek for SimpleCrypt<T> {
|
|||||||
self.inner.stream_position()
|
self.inner.stream_position()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct MdfEntry<T: Read + Seek + std::fmt::Debug> {
|
||||||
|
inner: ZlibDecoder<StreamRegion<Entry<T>>>,
|
||||||
|
index: XP3FileIndex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Read + Seek + std::fmt::Debug> MdfEntry<T> {
|
||||||
|
fn new(mut entry: Entry<T>, index: XP3FileIndex) -> Result<Self> {
|
||||||
|
entry.seek(SeekFrom::Start(8))?;
|
||||||
|
let entry = StreamRegion::new(entry, 8, index.info().file_size())?;
|
||||||
|
let inner = ZlibDecoder::new(entry);
|
||||||
|
Ok(Self { inner, index })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Read + Seek + std::fmt::Debug> ArchiveContent for MdfEntry<T> {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
&self.index.info().name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Read + Seek + std::fmt::Debug> Read for MdfEntry<T> {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||||
|
self.inner.read(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -472,6 +472,14 @@ pub struct ExtraConfig {
|
|||||||
/// Enable multi-language support for Kirikiri chat messages. Default is true.
|
/// Enable multi-language support for Kirikiri chat messages. Default is true.
|
||||||
/// Note: This requires [Self::kirikiri_language_index] and [Self::kirikiri_languages] to be set correctly.
|
/// Note: This requires [Self::kirikiri_language_index] and [Self::kirikiri_languages] to be set correctly.
|
||||||
pub kirikiri_chat_multilang: bool,
|
pub kirikiri_chat_multilang: bool,
|
||||||
|
#[cfg(feature = "kirikiri-arc")]
|
||||||
|
#[default(true)]
|
||||||
|
/// Decrypt SimpleCrypt files in Kirikiri XP3 archive when extracting. Default is true.
|
||||||
|
pub xp3_simple_crypt: bool,
|
||||||
|
#[cfg(feature = "kirikiri-arc")]
|
||||||
|
#[default(true)]
|
||||||
|
/// Decompress mdf files in Kirikiri XP3 archive when extracting. Default is true.
|
||||||
|
pub xp3_mdf_decompress: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
|||||||
Reference in New Issue
Block a user