1#[cfg(feature = "serde")]
40use serde::{Deserialize, Serialize};
41use std::io::SeekFrom;
42use strum_macros::{Display, EnumIs};
43use thiserror::Error;
44
45const ARCHIVE_HEADER: &[u8; 6] = b"RGSSAD";
46const OLDER_DEFAULT_KEY: u32 = 0xDEADCAFE;
47
48#[derive(Debug, Error)]
49#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
50pub enum ExtractError {
51 #[error(
52 "Invalid archive file header: {0:?}. Expected: RGSSAD ([82, 71, 83, 83, 65, 68])"
53 )]
54 InvalidHeader([u8; 6]),
55 #[error(
56 "Invalid game engine byte: {0}. Expected `1` for XP/VX or `3` for VX Ace."
57 )]
58 InvalidEngine(u8),
59}
60
61#[derive(Debug, Display, EnumIs)]
62enum EngineType {
63 #[strum(to_string = "XP/VX")]
64 Older,
65 #[strum(to_string = "VXAce")]
66 VXAce,
67}
68
69pub struct DecryptedFile {
78 pub path: Vec<u8>,
79 pub content: Vec<u8>,
80}
81
82pub struct Decrypter<'a> {
84 data: &'a [u8],
85 pos: usize,
86 len: usize,
87
88 engine_type: EngineType,
89 key: u32,
90 key_bytes: [u8; 4],
91}
92
93impl<'a> Decrypter<'a> {
94 pub fn new() -> Self {
96 Self {
97 data: &[],
98 pos: 0,
99 len: 0,
100
101 engine_type: EngineType::Older,
102 key: OLDER_DEFAULT_KEY,
103 key_bytes: OLDER_DEFAULT_KEY.to_le_bytes(),
104 }
105 }
106
107 #[inline]
108 fn update_key(&mut self, new_key: u32) {
109 self.key = new_key;
110 self.key_bytes = new_key.to_le_bytes();
111 }
112
113 #[inline]
114 fn read_bytes(&mut self, bytes: usize) -> &[u8] {
115 self.pos += bytes;
116 &self.data[self.pos - bytes..self.pos]
117 }
118
119 #[inline]
120 fn read_int(&mut self) -> i32 {
121 let chunk = self.read_bytes(4);
122 i32::from_le_bytes(unsafe { *(chunk.as_ptr() as *const [u8; 4]) })
123 }
124
125 #[inline]
126 fn read_byte(&mut self) -> u8 {
127 self.pos += 1;
128 self.data[self.pos - 1]
129 }
130
131 #[inline]
132 fn seek_byte(&mut self, from: SeekFrom) {
133 self.pos = match from {
134 SeekFrom::Start(offset) => offset as usize,
135 SeekFrom::Current(offset) => self.pos + offset as usize,
136 _ => unreachable!(),
137 };
138 }
139
140 #[inline]
141 fn decrypt_int(&mut self) -> i32 {
142 let int = self.read_int();
143 let result = int ^ self.key as i32;
144
145 if self.engine_type.is_older() {
146 self.update_key(self.key.wrapping_mul(7).wrapping_add(3));
147 }
148
149 result
150 }
151
152 #[inline]
153 fn decrypt_path(&mut self, path: &mut Vec<u8>, path_size: usize) {
154 let filename_bytes =
155 unsafe { &*(self.read_bytes(path_size) as *const [u8]) };
156
157 if self.engine_type.is_vx_ace() {
158 let mut key_byte_pos = 0;
159
160 for byte in filename_bytes {
161 if key_byte_pos == 4 {
162 key_byte_pos = 0;
163 }
164
165 path.push(byte ^ self.key_bytes[key_byte_pos]);
166 key_byte_pos += 1;
167 }
168 } else {
169 for byte in filename_bytes {
170 path.push(byte ^ self.key as u8);
171 self.update_key(self.key.wrapping_mul(7).wrapping_add(3));
172 }
173 }
174 }
175
176 #[inline]
177 fn parse_header(&mut self) -> Result<(), ExtractError> {
178 let header = self.read_bytes(6);
179
180 if header != ARCHIVE_HEADER {
181 return Err(ExtractError::InvalidHeader(unsafe {
182 *(header.as_ptr() as *const [u8; 6])
183 }));
184 }
185
186 self.seek_byte(SeekFrom::Current(1));
187 let engine_type = self.read_byte();
188
189 self.engine_type = match engine_type {
190 1 => EngineType::Older,
191 3 => EngineType::VXAce,
192 _ => {
193 return Err(ExtractError::InvalidEngine(engine_type));
194 }
195 };
196
197 Ok(())
198 }
199
200 #[inline]
201 fn decrypt_entries(&mut self) -> Vec<DecryptedFile> {
202 if self.engine_type.is_vx_ace() {
203 let key = self.read_int() as u32;
205 self.update_key(key.wrapping_mul(9).wrapping_add(3));
206 }
207
208 let mut entries = Vec::with_capacity(16384);
209 let mut prev_pos: usize;
210
211 loop {
212 let (size, offset, mut key);
213 let mut path;
214
215 match self.engine_type {
216 EngineType::VXAce => {
217 offset = self.decrypt_int() as u64;
218
219 if offset == 0 {
220 break;
221 }
222
223 size = self.decrypt_int();
224 key = self.decrypt_int() as u32;
225
226 let path_size = self.decrypt_int() as usize;
227 path = Vec::with_capacity(path_size);
228 self.decrypt_path(&mut path, path_size);
229 }
230 EngineType::Older => {
231 if self.pos == self.len {
232 break;
233 }
234
235 let path_size = self.decrypt_int() as usize;
236 path = Vec::with_capacity(path_size);
237 self.decrypt_path(&mut path, path_size);
238
239 size = self.decrypt_int();
240 offset = self.pos as u64;
241 key = self.key;
242
243 self.seek_byte(SeekFrom::Current(size as i64));
244 }
245 }
246
247 prev_pos = self.pos;
248
249 let mut key_bytes = key.to_le_bytes();
250 let mut key_byte_pos = 0;
251
252 self.seek_byte(SeekFrom::Start(offset));
253
254 let content = self.read_bytes(size as usize);
255 let mut decrypted = Vec::with_capacity(content.len());
256
257 for byte in content {
258 if key_byte_pos == 4 {
259 key_byte_pos = 0;
260 key = key.wrapping_mul(7).wrapping_add(3);
261 key_bytes = key.to_le_bytes();
262 }
263
264 decrypted.push(byte ^ key_bytes[key_byte_pos]);
265 key_byte_pos += 1;
266 }
267
268 entries.push(DecryptedFile {
269 content: decrypted,
270 path,
271 });
272
273 self.seek_byte(SeekFrom::Start(prev_pos as u64));
274 }
275
276 entries
277 }
278
279 fn reset(&mut self, data: &'a [u8]) {
280 *self = Self::new();
281 self.data = data;
282 self.len = data.len();
283 }
284
285 #[inline]
315 pub fn decrypt(
316 &mut self,
317 data: &'a [u8],
318 ) -> Result<Vec<DecryptedFile>, ExtractError> {
319 self.reset(data);
320 self.parse_header()?;
321 Ok(self.decrypt_entries())
322 }
323}
324
325impl<'a> Default for Decrypter<'a> {
326 fn default() -> Self {
330 Self::new()
331 }
332}
333
334pub fn decrypt_archive(
367 data: &[u8],
368) -> Result<Vec<DecryptedFile>, ExtractError> {
369 Decrypter::new().decrypt(data)
370}