1#![warn(clippy::all, clippy::pedantic)]
2#![allow(clippy::needless_doctest_main)]
3#![allow(clippy::cast_possible_truncation)]
4#![allow(clippy::cast_possible_wrap)]
5#![allow(clippy::cast_sign_loss)]
6#![allow(clippy::deref_addrof)]
7#![doc = include_str!("../README.md")]
8
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11use std::{borrow::Cow, io::SeekFrom};
12use strum_macros::{Display, EnumIs};
13use thiserror::Error;
14
15macro_rules! sizeof {
16 ($t:ty) => {{ size_of::<$t>() }};
17}
18
19const ARCHIVE_HEADER: &[u8; 7] = b"RGSSAD\0";
20
21const OLDER_DECRYPTION_KEY: u32 = 0xDEAD_CAFE;
22const ENCRYPTION_KEY: u32 = 0;
23
24const MAX_ENTRY_AMOUNT: usize = 16384;
27
28pub const XP_RGSSAD_EXT: &str = "rgssad";
29pub const VX_RGSS2A_EXT: &str = "rgss2a";
30pub const VXACE_RGSS3A_EXT: &str = "rgss3a";
31
32#[derive(Debug, Error)]
33#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
34pub enum ExtractError {
35 #[error(
36 "Invalid archive file header: {0:?}. Expected: RGSSADā ([82, 71, 83, 83, 65, 68, 0])"
37 )]
38 InvalidHeader([u8; 7]),
39 #[error(
40 "Invalid game engine byte: {0}. Expected `1` for XP/VX or `3` for VX Ace."
41 )]
42 InvalidEngine(u8),
43}
44
45#[derive(PartialEq, Debug, Display, EnumIs, Clone, Copy)]
46pub enum Engine {
47 #[strum(to_string = "XP/VX")]
48 Older = 1,
49 #[strum(to_string = "VXAce")]
50 VXAce = 3,
51}
52
53pub struct ArchiveEntry {
62 pub path: Cow<'static, [u8]>,
63 pub data: Vec<u8>,
64}
65
66pub struct Decrypter<'a> {
68 engine: Engine,
69 key: u32,
70 key_bytes: [u8; sizeof!(u32)],
71
72 data: &'a [u8],
74 pos: usize,
75 len: usize,
76}
77
78impl<'a> Decrypter<'a> {
79 #[must_use]
81 pub fn new() -> Self {
82 Self {
83 engine: Engine::Older,
84 key: OLDER_DECRYPTION_KEY,
85 key_bytes: OLDER_DECRYPTION_KEY.to_le_bytes(),
86
87 data: &[],
88 pos: 0,
89 len: 0,
90 }
91 }
92
93 #[inline]
94 fn update_key(&mut self, new_key: u32) {
95 self.key = new_key;
96 self.key_bytes = new_key.to_le_bytes();
97 }
98
99 #[inline]
100 fn update_key_older(&mut self) {
101 self.update_key(self.key.wrapping_mul(7).wrapping_add(3));
102 }
103
104 #[inline]
105 fn update_key_vxace(&mut self) {
106 self.update_key(self.key.wrapping_mul(9).wrapping_add(3));
107 }
108
109 #[inline]
110 fn read_bytes(&mut self, count: usize) -> &[u8] {
111 self.pos += count;
112 &self.data[self.pos - count..self.pos]
113 }
114
115 #[inline]
116 fn read_u32(&mut self) -> u32 {
117 let chunk = self.read_bytes(sizeof!(u32));
118 u32::from_le_bytes(unsafe {
119 *chunk.as_ptr().cast::<[u8; sizeof!(u32)]>()
120 })
121 }
122
123 #[inline]
124 fn read_byte(&mut self) -> u8 {
125 self.pos += 1;
126 self.data[self.pos - 1]
127 }
128
129 #[inline]
130 fn seek_byte(&mut self, from: SeekFrom) {
131 self.pos = match from {
132 SeekFrom::Start(offset) => offset as usize,
133 SeekFrom::Current(offset) => self.pos + offset as usize,
134 SeekFrom::End(_) => unreachable!(),
135 };
136 }
137
138 #[inline]
139 fn xor_u32_vxace(&mut self, u32: u32) -> u32 {
141 u32 ^ self.key
142 }
143
144 #[inline]
145 fn xor_u32_older(&mut self, u32: u32) -> u32 {
147 let decrypted = u32 ^ self.key;
148
149 if self.engine.is_older() {
150 self.update_key_older();
151 }
152
153 decrypted
154 }
155
156 #[inline]
157 fn xor_path_vxace(&mut self, path_data: &[u8], output: &mut Vec<u8>) {
159 for (idx, byte) in path_data.iter().enumerate() {
160 output.push(byte ^ self.key_bytes[idx % 4]);
163 }
164 }
165
166 #[inline]
167 fn xor_path_older(&mut self, path_data: &[u8], output: &mut Vec<u8>) {
169 for byte in path_data {
170 output.push(byte ^ self.key as u8);
171 self.update_key_older();
172 }
173 }
174
175 #[inline]
176 fn xor_data(mut key: u32, data: &[u8], output: &mut Vec<u8>) {
178 let mut key_bytes = key.to_le_bytes();
179 let mut key_byte_pos = 0;
180
181 for data_byte in data {
183 if key_byte_pos == 4 {
184 key_byte_pos = 0;
185 key = key.wrapping_mul(7).wrapping_add(3);
186 key_bytes = key.to_le_bytes();
187 }
188
189 output.push(data_byte ^ key_bytes[key_byte_pos]);
190 key_byte_pos += 1;
191 }
192 }
193
194 #[inline]
195 fn parse_header(&mut self) -> Result<(), ExtractError> {
196 let header = self.read_bytes(ARCHIVE_HEADER.len());
197
198 if header != ARCHIVE_HEADER {
199 return Err(ExtractError::InvalidHeader(unsafe {
200 *header.as_ptr().cast::<[u8; 7]>()
201 }));
202 }
203
204 let engine_type = self.read_byte();
205
206 self.engine = match engine_type {
207 1 => Engine::Older,
208 3 => Engine::VXAce,
209 _ => {
210 return Err(ExtractError::InvalidEngine(engine_type));
211 }
212 };
213
214 Ok(())
215 }
216
217 #[inline]
218 fn decrypt_entries(&mut self) -> Vec<ArchiveEntry> {
219 if self.engine.is_vx_ace() {
220 let key = self.read_u32();
222 self.update_key(key);
223 self.update_key_vxace();
224 }
225
226 let mut entries = Vec::with_capacity(MAX_ENTRY_AMOUNT);
227 let mut u32: u32;
228
229 if self.engine.is_vx_ace() {
230 loop {
231 u32 = self.read_u32();
232 let data_offset = u64::from(self.xor_u32_vxace(u32));
233
234 if data_offset == 0 {
236 break;
237 }
238
239 u32 = self.read_u32();
240 let data_size = self.xor_u32_vxace(u32);
241
242 u32 = self.read_u32();
243 let entry_key = self.xor_u32_vxace(u32);
244
245 u32 = self.read_u32();
246 let path_size = self.xor_u32_vxace(u32) as usize;
247 let mut decrypted_path = Vec::with_capacity(path_size);
248
249 let path_data =
250 unsafe { &*(self.read_bytes(path_size) as *const [u8]) };
251
252 self.xor_path_vxace(path_data, &mut decrypted_path);
253
254 let prev_pos = self.pos;
256
257 self.seek_byte(SeekFrom::Start(data_offset));
259
260 let entry_data = self.read_bytes(data_size as usize);
261 let mut decrypted_data = Vec::with_capacity(data_size as usize);
262 Self::xor_data(entry_key, entry_data, &mut decrypted_data);
263
264 entries.push(ArchiveEntry {
265 path: Cow::Owned(decrypted_path),
266 data: decrypted_data,
267 });
268
269 self.seek_byte(SeekFrom::Start(prev_pos as u64));
271 }
272 } else {
273 loop {
274 if self.pos == self.len {
276 break;
277 }
278
279 u32 = self.read_u32();
280 let path_size = self.xor_u32_older(u32) as usize;
281 let mut decrypted_path = Vec::with_capacity(path_size);
282
283 let path_data =
284 unsafe { &*(self.read_bytes(path_size) as *const [u8]) };
285
286 self.xor_path_older(path_data, &mut decrypted_path);
287
288 u32 = self.read_u32();
289 let data_size = self.xor_u32_older(u32);
290 let data_offset = self.pos as u64;
291 let entry_key = self.key;
292
293 self.seek_byte(SeekFrom::Current(i64::from(data_size)));
295
296 let prev_pos = self.pos;
298
299 self.seek_byte(SeekFrom::Start(data_offset));
301
302 let entry_data = self.read_bytes(data_size as usize);
303 let mut decrypted_data = Vec::with_capacity(data_size as usize);
304 Self::xor_data(entry_key, entry_data, &mut decrypted_data);
305
306 entries.push(ArchiveEntry {
307 path: Cow::Owned(decrypted_path),
308 data: decrypted_data,
309 });
310
311 self.seek_byte(SeekFrom::Start(prev_pos as u64));
313 }
314 }
315
316 entries
317 }
318
319 fn encrypt_entries(
320 &mut self,
321 entries: &[ArchiveEntry],
322 archive_buffer: &mut Vec<u8>,
323 ) {
324 if self.engine.is_vx_ace() {
325 self.update_key(ENCRYPTION_KEY);
326
327 archive_buffer.extend_from_slice(&self.key_bytes);
328 self.update_key_vxace();
329 }
330
331 let mut data_offsets_indices = Vec::with_capacity(entries.len());
333
334 if self.engine.is_vx_ace() {
335 for entry in entries {
337 data_offsets_indices.push(archive_buffer.len());
339 archive_buffer.extend_from_slice(&0u32.to_le_bytes());
340
341 let data_size = entry.data.len() as u32;
342 let encoded_data_size = self.xor_u32_vxace(data_size);
343 archive_buffer
344 .extend_from_slice(&encoded_data_size.to_le_bytes());
345
346 archive_buffer.extend_from_slice(&ENCRYPTION_KEY.to_le_bytes());
348
349 let path_size = entry.path.len() as u32;
350 let encoded_path_size = self.xor_u32_vxace(path_size);
351 archive_buffer
352 .extend_from_slice(&encoded_path_size.to_le_bytes());
353
354 self.xor_path_vxace(&entry.path, archive_buffer);
355 }
356
357 archive_buffer.extend_from_slice(&self.key.to_le_bytes());
359
360 for (idx, entry) in entries.iter().enumerate() {
362 let data_offset = archive_buffer.len() as u32;
363 let encrypted_data_offset = self.xor_u32_vxace(data_offset);
364 let offset_slice_mut = &mut archive_buffer[data_offsets_indices
365 [idx]
366 ..data_offsets_indices[idx] + sizeof!(u32)];
367
368 offset_slice_mut
369 .copy_from_slice(&encrypted_data_offset.to_le_bytes());
370 Self::xor_data(self.key, &entry.data, archive_buffer);
371 }
372 } else {
373 for entry in entries {
374 let path_size = entry.path.len() as u32;
375
376 let encoded_path_size = self.xor_u32_older(path_size);
377 archive_buffer
378 .extend_from_slice(&encoded_path_size.to_le_bytes());
379
380 self.xor_path_older(&entry.path, archive_buffer);
381
382 let data_size = entry.data.len() as u32;
383 let encoded_data_size = self.xor_u32_older(data_size);
384 archive_buffer
385 .extend_from_slice(&encoded_data_size.to_le_bytes());
386
387 Self::xor_data(self.key, &entry.data, archive_buffer);
388 }
389 }
390 }
391
392 fn reset(&mut self, data: &'a [u8]) {
393 self.data = data;
394 self.len = data.len();
395 self.pos = 0;
396
397 self.engine = Engine::Older;
398 self.key = OLDER_DECRYPTION_KEY;
399 self.key_bytes = OLDER_DECRYPTION_KEY.to_le_bytes();
400 }
401
402 #[inline]
436 pub fn decrypt(
437 &mut self,
438 archive_data: &'a [u8],
439 ) -> Result<Vec<ArchiveEntry>, ExtractError> {
440 self.reset(archive_data);
441 self.parse_header()?;
442 Ok(self.decrypt_entries())
443 }
444
445 #[must_use]
467 #[inline]
468 pub fn encrypt(
469 &mut self,
470 archive_entries: &[ArchiveEntry],
471 engine: Engine,
472 ) -> Vec<u8> {
473 let mut buf_size: usize = ARCHIVE_HEADER.len();
474
475 buf_size += 1;
477
478 for entry in archive_entries {
479 if engine.is_vx_ace() {
480 buf_size += sizeof!(u32);
482
483 buf_size += sizeof!(u32);
485
486 buf_size += sizeof!(u32);
488
489 buf_size += sizeof!(u32);
491 } else {
492 buf_size += sizeof!(u32);
494
495 buf_size += sizeof!(u32);
497 }
498
499 buf_size += entry.data.len();
500 buf_size += entry.path.len();
501 }
502
503 if engine.is_vx_ace() {
504 buf_size += sizeof!(u32);
506 }
507
508 let mut archive_buffer = Vec::with_capacity(buf_size);
509
510 archive_buffer.extend_from_slice(ARCHIVE_HEADER);
511 archive_buffer.push(engine as u8);
512
513 self.engine = engine;
514 self.encrypt_entries(archive_entries, &mut archive_buffer);
515
516 archive_buffer
517 }
518}
519
520impl Default for Decrypter<'_> {
521 fn default() -> Self {
525 Self::new()
526 }
527}
528
529pub fn decrypt_archive(
564 archive_data: &[u8],
565) -> Result<Vec<ArchiveEntry>, ExtractError> {
566 Decrypter::new().decrypt(archive_data)
567}
568
569#[must_use]
593pub fn encrypt_archive(
594 archive_entries: &[ArchiveEntry],
595 engine: Engine,
596) -> Vec<u8> {
597 Decrypter::new().encrypt(archive_entries, engine)
598}