diff --git a/msg_tool_xp3data/crypt.json b/msg_tool_xp3data/crypt.json index f81088b..0bda33f 100644 --- a/msg_tool_xp3data/crypt.json +++ b/msg_tool_xp3data/crypt.json @@ -1974,6 +1974,11 @@ "$type": "HashCrypt", "Title": "双性の姫君 ~ふたなり姉妹と魔王の求愛~" }, + "Specialite!": { + "$type": "StripeCrypt", + "Key": 175, + "Title": "すぺしゃりて!" + }, "Suiheisen made Nan Mile?": { "$type": "CxEncryption", "Mask": 610, diff --git a/src/scripts/kirikiri/archive/xp3/crypt/mod.rs b/src/scripts/kirikiri/archive/xp3/crypt/mod.rs index 6bc5aa6..c59d0fe 100644 --- a/src/scripts/kirikiri/archive/xp3/crypt/mod.rs +++ b/src/scripts/kirikiri/archive/xp3/crypt/mod.rs @@ -176,6 +176,10 @@ enum CryptType { seed: u32, }, HaikuoCrypt, + #[serde(rename_all = "PascalCase")] + StripeCrypt { + key: u8, + }, } #[derive(Clone, Debug, Deserialize)] @@ -276,6 +280,7 @@ impl Schema { CryptType::HibikiCrypt => Box::new(HibikiCrypt::new(self.base.clone())), CryptType::AkabeiCrypt { seed } => Box::new(AkabeiCrypt::new(self.base.clone(), *seed)), CryptType::HaikuoCrypt => Box::new(HaikuoCrypt::new(self.base.clone())), + CryptType::StripeCrypt { key } => Box::new(StripeCrypt::new(self.base.clone(), *key)), }) } } @@ -604,45 +609,54 @@ impl Read for HashCryptReader { } } -#[derive(Debug)] -pub struct XorCrypt { - base: BaseSchema, - key: u8, +macro_rules! seek_crypt_key_base_impl { + ($crypt:ident, $reader:ident, $typ:ty) => { + #[derive(Debug)] + pub struct $crypt { + base: BaseSchema, + key: $typ, + } + impl $crypt { + pub fn new(base: BaseSchema, key: $typ) -> Self { + Self { base, key } + } + } + impl Crypt for $crypt { + base_schema_impl!(); + fn decrypt_supported(&self) -> bool { + true + } + fn decrypt_seek_supported(&self) -> bool { + true + } + fn decrypt<'a>( + &self, + _entry: &Xp3Entry, + cur_seg: &Segment, + stream: Box, + ) -> Result> { + Ok(Box::new($reader::new(stream, cur_seg, self.key))) + } + fn decrypt_with_seek<'a>( + &self, + _entry: &Xp3Entry, + cur_seg: &Segment, + stream: Box, + ) -> Result> { + Ok(Box::new($reader::new(stream, cur_seg, self.key))) + } + } + }; } -impl XorCrypt { - pub fn new(base: BaseSchema, key: u8) -> Self { - Self { base, key } - } +macro_rules! seek_crypt_key_impl { + ($crypt:ident, $reader:ident<$t:ident>, $typ:ty) => { + seek_crypt_key_base_impl!($crypt, $reader, $typ); + seek_reader_key_impl!($reader<$t>, $typ); + }; } -impl Crypt for XorCrypt { - base_schema_impl!(); - fn decrypt_supported(&self) -> bool { - true - } - fn decrypt_seek_supported(&self) -> bool { - true - } - fn decrypt<'a>( - &self, - _entry: &Xp3Entry, - cur_seg: &Segment, - stream: Box, - ) -> Result> { - Ok(Box::new(XorCryptReader::new(stream, cur_seg, self.key))) - } - fn decrypt_with_seek<'a>( - &self, - _entry: &Xp3Entry, - cur_seg: &Segment, - stream: Box, - ) -> Result> { - Ok(Box::new(XorCryptReader::new(stream, cur_seg, self.key))) - } -} - -seek_reader_key_impl!(XorCryptReader, u8); +seek_crypt_key_impl!(XorCrypt, XorCryptReader, u8); impl Read for XorCryptReader { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { @@ -1164,6 +1178,20 @@ impl Read for HaikuoCryptReader { } } +seek_crypt_key_impl!(StripeCrypt, StripeCryptReader, u8); + +impl Read for StripeCryptReader { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let readed = self.inner.read(buf)?; + for t in (&mut buf[..readed]).iter_mut() { + *t ^= self.key; + w!(*t += 1); + } + self.pos += readed as u64; + Ok(readed) + } +} + #[test] fn test_deserialize_crypt() { for (key, schema) in CRYPT_SCHEMA.iter() {