diff --git a/ArcFormats/ShiinaRio/WarcEncryption.cs b/ArcFormats/ShiinaRio/WarcEncryption.cs index d03a701c..20dc4e10 100644 --- a/ArcFormats/ShiinaRio/WarcEncryption.cs +++ b/ArcFormats/ShiinaRio/WarcEncryption.cs @@ -975,9 +975,9 @@ namespace GameRes.Formats.ShiinaRio } [Serializable] - public class AdlerCrypt : KeyDecryptBase + public class KeyAdlerCrypt : KeyDecryptBase { - public AdlerCrypt (uint key) : base (key, null) + public KeyAdlerCrypt (uint key) : base (key, null) { } @@ -990,4 +990,140 @@ namespace GameRes.Formats.ShiinaRio data[index + 0x207] ^= (byte)(key >> 24); } } + + [Serializable] + public class AdlerCrypt : IDecryptExtra + { + public void Decrypt (byte[] data, int index, uint length, uint flags) + { + if (length >= 0x400 && (flags & 0x204) == 0x204) + Transform (data, index, 0xFF); + } + + public void Encrypt (byte[] data, int index, uint length, uint flags) + { + if (length >= 0x400 && (flags & 0x104) == 0x104) + Transform (data, index, 0xFF); + } + + void Transform (byte[] data, int index, int length) + { + uint key = Adler32.Compute (data, index, length); + data[index + 0x200] ^= (byte)key; + data[index + 0x201] ^= (byte)(key >> 8); + data[index + 0x202] ^= (byte)(key >> 16); + data[index + 0x203] ^= (byte)(key >> 24); + } + } + + [Serializable] + public class BinboCrypt : IDecryptExtra + { + public void Decrypt (byte[] data, int index, uint length, uint flags) + { + if (length < 0x200) + return; + if ((flags & 0x204) == 0x204) + { + if (0x718E958D == LittleEndian.ToUInt32 (data, index)) + { + var input = new byte[0x200]; + Buffer.BlockCopy (data, index, input, 0, 0x200); + var reader = new LzComp (input, 8); + reader.Unpack (data, index); + } + if (length > 0x200) + data[index + 0x200] ^= (byte)length; + if (length > 0x201) + data[index + 0x201] ^= (byte)(length >> 8); + if (length > 0x202) + data[index + 0x202] ^= (byte)(length >> 16); + if (length > 0x203) + data[index + 0x203] ^= (byte)(length >> 24); + } + } + + public void Encrypt (byte[] data, int index, uint length, uint flags) + { + if (length < 0x200) + return; + if ((flags & 0x104) == 0x104) + { + throw new NotImplementedException(); + } + } + + sealed class LzComp + { + byte[] m_input; + int m_src; + + uint m_bits; + int m_bits_count; + + public LzComp (byte[] input, int index) + { + m_input = input; + m_src = index; + } + + public void Unpack (byte[] output, int dst) + { + FillBitCache(); + while (m_src < m_input.Length) + { + if (GetBit() != 0) + { + output[dst++] = m_input[m_src++]; + continue; + } + int count, offset; + if (GetBit() != 0) + { + count = LittleEndian.ToUInt16 (m_input, m_src); + m_src += 2; + offset = count >> 3 | -0x2000; + count &= 7; + if (count > 0) + { + count += 2; + } + else + { + count = m_input[m_src++]; + if (0 == count) + break; + count += 9; + } + } + else + { + count = GetBit() << 1; + count |= GetBit(); + count += 2; + offset = m_input[m_src++] | -0x100; + } + Binary.CopyOverlapped (output, dst+offset, dst, count); + dst += count; + } + } + + int GetBit () + { + uint v = m_bits >> --m_bits_count; + if (m_bits_count <= 0) + { + FillBitCache(); + } + return (int)(v & 1); + } + + void FillBitCache () + { + m_bits = LittleEndian.ToUInt32 (m_input, m_src); + m_src += 4; + m_bits_count = 32; + } + } + } } diff --git a/supported.html b/supported.html index 0fba3ddc..e1c14646 100644 --- a/supported.html +++ b/supported.html @@ -421,6 +421,7 @@ Enkaku Sousa 2.36 or 2.37
Gensou no Idea ~Oratorio Phantasm Historia~ShiinaRio v2.49
Gohoushi Nurse ~Mayonaka no Kyousei Call~ ShiinaRio v2.50
Helter Skelter ShiinaRio v2.40
+Hin wa Bokura no Fuku no Kami ShiinaRio v2.49
Hitozuma Onna Kyoushi Reika ShiinaRio v2.39
Intruder ShiinaRio v2.49
Itsuka, Dokoka de ~Ano Ameoto no Kioku~2.36 or 2.37
@@ -1068,6 +1069,7 @@ Aneboku ~Onee-chan wa Bijin 3 Shimai~
Aniyome Kyouka-san to Sono Haha Chikako-san
Aru Kazoku no Kankeizu
Chou no Yume ~Futari no Chou~
+Choumajuu! ~Seieki Juuten Dungeon Kouryaku~
Cosplay Ecchi ~Layer Kana no Yuuutsu~
Etsuraku no Tane
Fuka no Jugoku