From c595331dd02a878911bde6754509d0dcc55b0361 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Tue, 7 Apr 2026 22:16:31 +0800 Subject: [PATCH] Add force extract flag --- src/args.rs | 4 ++++ src/main.rs | 2 ++ src/scripts/kirikiri/archive/xp3/mod.rs | 20 +++++++++++++++----- src/types.rs | 3 +++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/args.rs b/src/args.rs index f711935..2dcaf66 100644 --- a/src/args.rs +++ b/src/args.rs @@ -728,6 +728,10 @@ pub struct Arg { /// Print/write debug information for Kirikiri XP3 archive when extracting archive to specifiy location. /// This is used to find correct configuration for unknown XP3 archives. pub xp3_debug_archive: bool, + #[cfg(feature = "kirikiri-arc")] + #[arg(long, global = true)] + /// Force extract encrypted files in Kirikiri XP3 archive without decryption. + pub xp3_force_extract: bool, #[command(subcommand)] /// Command pub command: Command, diff --git a/src/main.rs b/src/main.rs index 7b94b1e..c478a25 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3395,6 +3395,8 @@ fn main() { xp3_game_title: arg.xp3_game_title.clone(), #[cfg(feature = "kirikiri-arc")] xp3_debug_archive: arg.xp3_debug_archive, + #[cfg(feature = "kirikiri-arc")] + xp3_force_extract: arg.xp3_force_extract, }); match &arg.command { args::Command::Export { input, output } => { diff --git a/src/scripts/kirikiri/archive/xp3/mod.rs b/src/scripts/kirikiri/archive/xp3/mod.rs index b5179db..374053d 100644 --- a/src/scripts/kirikiri/archive/xp3/mod.rs +++ b/src/scripts/kirikiri/archive/xp3/mod.rs @@ -162,6 +162,7 @@ pub struct Xp3Archive { archive: archive::Xp3Archive, decrypt_simple_crypt: bool, decompress_mdf: bool, + force_extract: bool, } impl Xp3Archive { @@ -185,6 +186,7 @@ impl Xp3Archive { archive, decrypt_simple_crypt: config.xp3_simple_crypt, decompress_mdf: config.xp3_mdf_decompress, + force_extract: config.xp3_force_extract, }) } } @@ -222,16 +224,20 @@ impl Script for Xp3Archive { .ok_or(anyhow::anyhow!("Index out of bounds: {}", index))? .clone(); let crypt = self.archive.crypt.clone(); - if index.is_encrypted() && !crypt.decrypt_supported() { - return Err(anyhow::anyhow!( - "The archive is encrypted with a method that is not supported by the current crypt implementation. You may need to specify a game title by using --xp3-game-title ." - )); + let skip_decrypt = index.is_encrypted() && !crypt.decrypt_supported(); + if skip_decrypt { + if !self.force_extract { + return Err(anyhow::anyhow!( + "The archive is encrypted with a method that is not supported by the current crypt implementation. You may need to specify a game title by using --xp3-game-title <title>." + )); + } } let mut entry = Entry::new( self.archive.inner.clone(), index, self.archive.base_offset, crypt, + skip_decrypt, ); let mut header = [0u8; 16]; let header_len = entry.read(&mut header)?; @@ -305,6 +311,7 @@ struct Entry { base_offset: u64, entries_pos: Vec<u64>, script_type: Option<ScriptType>, + skip_decrypt: bool, } #[automatically_derived] @@ -320,6 +327,7 @@ impl std::fmt::Debug for Entry { .field("base_offset", &self.base_offset) .field("entries_pos", &self.entries_pos) .field("script_type", &self.script_type) + .field("skip_decrypt", &self.skip_decrypt) .finish() } } @@ -330,6 +338,7 @@ impl Entry { index: archive::Xp3Entry, base_offset: u64, crypt: Arc<Box<dyn Crypt>>, + skip_decrypt: bool, ) -> Self { let mut pos = 0; let entries_pos = index @@ -351,6 +360,7 @@ impl Entry { base_offset, crypt, crypt_stream: None, + skip_decrypt, } } } @@ -407,7 +417,7 @@ impl Read for Entry { let seg_pos = self.entries_pos[seg_index]; let skip_pos = self.pos - seg_pos; let read_size = seg.archived_size; - if self.index.is_encrypted() { + if !self.skip_decrypt && self.index.is_encrypted() { if seg.is_compressed || !self.crypt.decrypt_seek_supported() { let mut cache: Box<dyn Read> = if seg.is_compressed { let mut inner = diff --git a/src/types.rs b/src/types.rs index 7c5aef2..f97ebbe 100644 --- a/src/types.rs +++ b/src/types.rs @@ -642,6 +642,9 @@ pub struct ExtraConfig { /// Print debug information for Kirikiri XP3 archive when extracting archive to stdout. /// This is used to find correct configuration for unknown XP3 archives. pub xp3_debug_archive: bool, + #[cfg(feature = "kirikiri-arc")] + /// Force extract encrypted files in Kirikiri XP3 archive without decryption. + pub xp3_force_extract: bool, } #[cfg(feature = "artemis")]