Skip to main content

rpgmad_lib/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![warn(clippy::all, clippy::pedantic)]
3#![allow(clippy::needless_doctest_main)]
4#![allow(clippy::cast_possible_truncation)]
5#![allow(clippy::cast_possible_wrap)]
6#![allow(clippy::cast_sign_loss)]
7#![allow(clippy::deref_addrof)]
8#![allow(invalid_reference_casting)]
9#![doc = include_str!("../README.md")]
10
11use core::{
12    default::Default,
13    iter::{self, Iterator},
14};
15#[cfg(feature = "serde")]
16use serde::{Deserialize, Serialize};
17use strum_macros::{Display, EnumIs};
18use thiserror::Error;
19
20fn memcpy(dst: &mut [u8], src: &[u8]) {
21    unsafe {
22        core::ptr::copy_nonoverlapping(
23            src.as_ptr(),
24            dst.as_mut_ptr(),
25            src.len(),
26        );
27    }
28}
29
30enum SeekFrom {
31    Start(u64),
32    Current(i64),
33}
34
35macro_rules! sizeof {
36    ($t:ty) => {{ core::mem::size_of::<$t>() }};
37}
38
39const ARCHIVE_HEADER: &[u8; 7] = b"RGSSAD\0";
40
41const OLDER_DECRYPTION_KEY: u32 = 0xDEAD_CAFE;
42const ENCRYPTION_KEY: u32 = 0;
43
44pub const XP_RGSSAD_EXT: &str = "rgssad";
45pub const VX_RGSS2A_EXT: &str = "rgss2a";
46pub const VXACE_RGSS3A_EXT: &str = "rgss3a";
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, 0])"
53    )]
54    InvalidHeader([u8; 7]),
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, Clone, Copy, PartialEq)]
62pub enum Engine {
63    #[strum(to_string = "XP/VX")]
64    Older = 1,
65    #[strum(to_string = "VXAce")]
66    VXAce = 3,
67}
68
69/// Struct representing decrypted file.
70///
71/// # Fields
72/// - `path` - Represents path to the decrypted file. For example, graphics files are stored in Graphics/DIR, e.g. Graphics/Actors/Actor1.png.
73///
74/// Note, that `path` is represented by [`&[u8]`] because it may contain non-UTF-8 sequences, e.g. Japanese Shift JIS text. In that case, it's up to you how to handle the path.
75///
76/// - `data` - Represents content of the file.
77pub struct ArchiveEntry<'a> {
78    pub path: &'a [u8],
79    pub data: &'a [u8],
80}
81
82/// A struct responsible for decrypting and extracting files from encrypted game archives.
83pub struct Decrypter<'a> {
84    engine: Engine,
85    key: u32,
86    key_bytes: [u8; sizeof!(u32)],
87
88    // Decryption members
89    data: &'a mut [u8],
90    pos: usize,
91    len: usize,
92}
93
94impl<'a> Decrypter<'a> {
95    /// Creates a new [`Decrypter`] with empty buffer.
96    #[must_use]
97    pub fn new() -> Self {
98        Self {
99            engine: Engine::Older,
100            key: OLDER_DECRYPTION_KEY,
101            key_bytes: OLDER_DECRYPTION_KEY.to_le_bytes(),
102
103            data: &mut [],
104            pos: 0,
105            len: 0,
106        }
107    }
108
109    #[inline]
110    fn update_key(&mut self, new_key: u32) {
111        self.key = new_key;
112        self.key_bytes = new_key.to_le_bytes();
113    }
114
115    #[inline]
116    fn update_key_older(&mut self) {
117        self.update_key(self.key.wrapping_mul(7).wrapping_add(3));
118    }
119
120    #[inline]
121    fn update_key_vxace(&mut self) {
122        self.update_key(self.key.wrapping_mul(9).wrapping_add(3));
123    }
124
125    #[inline]
126    #[track_caller]
127    fn read_bytes(&mut self, count: usize) -> &[u8] {
128        self.pos += count;
129        &self.data[self.pos - count..self.pos]
130    }
131
132    #[inline]
133    fn read_u32(&mut self) -> u32 {
134        let chunk = self.read_bytes(sizeof!(u32));
135        u32::from_le_bytes(unsafe {
136            *chunk.as_ptr().cast::<[u8; sizeof!(u32)]>()
137        })
138    }
139
140    #[inline]
141    fn read_byte(&mut self) -> u8 {
142        self.pos += 1;
143        self.data[self.pos - 1]
144    }
145
146    #[inline]
147    fn seek_byte(&mut self, from: SeekFrom) {
148        self.pos = match from {
149            SeekFrom::Start(offset) => offset as usize,
150            SeekFrom::Current(offset) => self.pos + offset as usize,
151        };
152    }
153
154    #[inline]
155    /// Decrypts u32 if `u32` is encrypted, encrypts u32 if `u32` is decrypted.
156    fn xor_u32_vxace(&self, u32: u32) -> u32 {
157        u32 ^ self.key
158    }
159
160    #[inline]
161    /// Decrypts u32 if `u32` is encrypted, encrypts u32 if `u32` is decrypted.
162    fn xor_u32_older(&mut self, u32: u32) -> u32 {
163        let decrypted = u32 ^ self.key;
164
165        if self.engine.is_older() {
166            self.update_key_older();
167        }
168
169        decrypted
170    }
171
172    #[inline]
173    /// Decrypts path if `path_data` is encrypted, encrypts path if `path_data` is decrypted.
174    fn xor_path_vxace(&mut self, path_data: &mut [u8]) {
175        for (idx, byte) in
176            (unsafe { &*(path_data as *mut [u8]) }).iter().enumerate()
177        {
178            // Compiler is smart and can optimize this modulo into `& 0b11`.
179            // Since modulo is more self-descriptive, let it be here.
180            path_data[idx] = byte ^ self.key_bytes[idx % 4];
181        }
182    }
183
184    #[inline]
185    /// Decrypts path if `path_data` is encrypted, encrypts path if `path_data` is decrypted.
186    fn xor_path_older(&mut self, path_data: &mut [u8]) {
187        for (idx, byte) in
188            (unsafe { &*(path_data as *mut [u8]) }).iter().enumerate()
189        {
190            path_data[idx] = byte ^ self.key as u8;
191            self.update_key_older();
192        }
193    }
194
195    #[inline]
196    /// Decrypts data if `data` is encrypted, encrypts data if `data` is decrypted.
197    fn xor_data(mut key: u32, data: &mut [u8]) {
198        let mut key_bytes = key.to_le_bytes();
199        let mut key_byte_pos = 0;
200
201        // Decrypting data
202        for (idx, data_byte) in
203            (unsafe { &*(data as *mut [u8]) }).iter().enumerate()
204        {
205            if key_byte_pos == 4 {
206                key_byte_pos = 0;
207                key = key.wrapping_mul(7).wrapping_add(3);
208                key_bytes = key.to_le_bytes();
209            }
210
211            data[idx] = data_byte ^ key_bytes[key_byte_pos];
212            key_byte_pos += 1;
213        }
214    }
215
216    #[inline]
217    fn parse_header(&mut self) -> Result<(), ExtractError> {
218        let header = self.read_bytes(ARCHIVE_HEADER.len());
219
220        if header != ARCHIVE_HEADER {
221            return Err(ExtractError::InvalidHeader(unsafe {
222                *header.as_ptr().cast::<[u8; 7]>()
223            }));
224        }
225
226        let engine_type = self.read_byte();
227
228        self.engine = match engine_type {
229            1 => Engine::Older,
230            3 => Engine::VXAce,
231            _ => {
232                return Err(ExtractError::InvalidEngine(engine_type));
233            }
234        };
235
236        Ok(())
237    }
238
239    #[inline]
240    #[track_caller]
241    fn decrypt_entries(&'a mut self) -> impl Iterator<Item = ArchiveEntry<'a>> {
242        if self.engine.is_vx_ace() {
243            // Default key is not ever used and overwritten.
244            let key = self.read_u32();
245            self.update_key(key);
246            self.update_key_vxace();
247        }
248
249        iter::from_fn(move  || {
250            let mut u32: u32;
251
252            if self.engine.is_vx_ace() {
253                u32 = self.read_u32();
254                let data_offset = self.xor_u32_vxace(u32) as u64;
255
256                // End of data
257                if data_offset == 0 {
258                    return None;
259                }
260
261                u32 = self.read_u32();
262                let data_size = self.xor_u32_vxace(u32) as usize;
263
264                u32 = self.read_u32();
265                let entry_key = self.xor_u32_vxace(u32);
266
267                u32 = self.read_u32();
268                let path_size = self.xor_u32_vxace(u32) as usize;
269
270                let path_data = unsafe {
271                    &mut *(self.read_bytes(path_size) as *const [u8]
272                        as *mut [u8])
273                };
274
275                self.xor_path_vxace(path_data);
276
277                // Store current position
278                let prev_pos = self.pos;
279
280                // Read data
281                self.seek_byte(SeekFrom::Start(data_offset));
282
283                let entry_data = unsafe {
284                    &mut *(self.read_bytes(data_size) as *const [u8]
285                        as *mut [u8])
286                };
287                Self::xor_data(entry_key, entry_data);
288
289                let entry = ArchiveEntry {
290                    path: path_data,
291                    data: entry_data,
292                };
293
294                // Restore position
295                self.seek_byte(SeekFrom::Start(prev_pos as u64));
296
297                Some(entry)
298            } else {
299                // End of data
300                if self.pos == self.len {
301                    return None;
302                }
303
304                u32 = self.read_u32();
305                let path_size = self.xor_u32_older(u32) as usize;
306
307                let path_data = unsafe {
308                    &mut *(self.read_bytes(path_size) as *const [u8]
309                        as *mut [u8])
310                };
311
312                self.xor_path_older(path_data);
313
314                u32 = self.read_u32();
315                let data_size = self.xor_u32_older(u32) as usize;
316                let data_offset = self.pos as u64;
317                let entry_key = self.key;
318
319                // Skip data block
320                self.seek_byte(SeekFrom::Current(data_size as i64));
321
322                // Store current position
323                let prev_pos = self.pos;
324
325                // Seek back to the data and read it
326                self.seek_byte(SeekFrom::Start(data_offset));
327
328                let entry_data = unsafe {
329                    &mut *(self.read_bytes(data_size) as *const [u8]
330                        as *mut [u8])
331                };
332                Self::xor_data(entry_key, entry_data);
333
334                let entry = ArchiveEntry {
335                    path: path_data,
336                    data: entry_data,
337                };
338
339                // Restore position
340                self.seek_byte(SeekFrom::Start(prev_pos as u64));
341
342                Some(entry)
343            }
344        })
345    }
346
347    fn encrypt_entries(
348        &mut self,
349        entries: &[ArchiveEntry],
350        archive_buffer: &mut [u8],
351    ) {
352        let mut offset = 8;
353
354        if self.engine.is_vx_ace() {
355            self.update_key(ENCRYPTION_KEY);
356
357            memcpy(&mut archive_buffer[offset..], &self.key_bytes);
358            offset += 4;
359
360            self.update_key_vxace();
361        }
362
363        if self.engine.is_vx_ace() {
364            // First we write metadata: content size, key, path size and path itself
365            for entry in entries {
366                // Placeholder offset, we'll modify it later
367                memcpy(&mut archive_buffer[offset..], &0u32.to_le_bytes());
368                offset += 4;
369
370                let data_size = entry.data.len() as u32;
371                let encoded_data_size = self.xor_u32_vxace(data_size);
372                memcpy(
373                    &mut archive_buffer[offset..],
374                    &encoded_data_size.to_le_bytes(),
375                );
376                offset += 4;
377
378                // self.key ^ self.key = 0
379                memcpy(
380                    &mut archive_buffer[offset..],
381                    &ENCRYPTION_KEY.to_le_bytes(),
382                );
383                offset += 4;
384
385                let path_size = entry.path.len() as u32;
386                let encoded_path_size = self.xor_u32_vxace(path_size);
387                memcpy(
388                    &mut archive_buffer[offset..],
389                    &encoded_path_size.to_le_bytes(),
390                );
391                offset += 4;
392
393                memcpy(&mut archive_buffer[offset..], entry.path);
394                self.xor_path_vxace(&mut archive_buffer[offset..]);
395                offset += entry.path.len();
396            }
397
398            // Write the key, when decrypthing it will be xor'd against itself which will produce 0, and decryption will stop.
399            memcpy(&mut archive_buffer[offset..], &self.key.to_le_bytes());
400            offset += 4;
401
402            let mut placeholder_offset = 12;
403
404            // Write the actual contents and modify the offsets with the offsets of the contents
405            for entry in entries {
406                let data_offset = offset as u32;
407                let encrypted_data_offset = self.xor_u32_vxace(data_offset);
408
409                archive_buffer[placeholder_offset..placeholder_offset + 4]
410                    .copy_from_slice(&encrypted_data_offset.to_le_bytes());
411
412                placeholder_offset += 16 + entry.path.len();
413
414                memcpy(&mut archive_buffer[offset..], entry.data);
415                Self::xor_data(self.key, &mut archive_buffer[offset..]);
416                offset += entry.data.len();
417            }
418        } else {
419            for entry in entries {
420                let path_size = entry.path.len() as u32;
421
422                let encoded_path_size = self.xor_u32_older(path_size);
423                memcpy(
424                    &mut archive_buffer[offset..],
425                    &encoded_path_size.to_le_bytes(),
426                );
427
428                memcpy(&mut archive_buffer[offset..], entry.path);
429                offset += entry.path.len();
430
431                self.xor_path_older(&mut archive_buffer[offset..]);
432
433                let data_size = entry.data.len() as u32;
434                let encoded_data_size = self.xor_u32_older(data_size);
435                memcpy(
436                    &mut archive_buffer[offset..],
437                    &encoded_data_size.to_le_bytes(),
438                );
439                offset += 4;
440
441                memcpy(&mut archive_buffer[offset..], entry.data);
442                Self::xor_data(self.key, &mut archive_buffer[offset..]);
443                offset += entry.data.len();
444            }
445        }
446    }
447
448    fn reset(&mut self, data: &'a mut [u8]) {
449        self.len = data.len();
450        self.data = data;
451        self.pos = 0;
452
453        self.engine = Engine::Older;
454        self.key = OLDER_DECRYPTION_KEY;
455        self.key_bytes = OLDER_DECRYPTION_KEY.to_le_bytes();
456    }
457
458    /// Returns an iterator over decrypted [`ArchiveEntry`] entries.
459    ///
460    /// # Parameters
461    /// - `archive_data`: The content of the archive file. This data is modified in-place, and requires to be a mutable reference.
462    ///
463    /// # Returns
464    /// - [`Iterator<Item = ArchiveEntry>`] if files were successfully decrypted.
465    /// - [`ExtractError`] otherwise.
466    ///
467    /// # Errors
468    ///
469    /// - [`ExtractError::InvalidHeader`] for invalid header.
470    /// - [`ExtractError::InvalidEngine`] for invalid header engine type byte.
471    ///
472    /// # Example
473    /// ```no_run
474    /// use rpgmad_lib::Decrypter;
475    /// use std::{path::PathBuf, fs::{read, write, create_dir_all}};
476    ///
477    /// let mut data = read("C:/Game/Game.rgss3a").unwrap();
478    /// let mut decrypter = Decrypter::new();
479    /// let decrypted_entries = decrypter.decrypt(&mut data).unwrap();
480    ///
481    /// for entry in decrypted_entries {
482    ///     let path = String::from_utf8_lossy(&entry.path);
483    ///     let output_path = PathBuf::from("C:/Game").join(path.as_ref());
484    ///
485    ///     if let Some(parent) = output_path.parent() {
486    ///         create_dir_all(parent).unwrap();
487    ///     }
488    ///
489    ///     write(output_path, entry.data).unwrap();
490    /// }
491    /// ```
492    #[inline]
493    pub fn decrypt(
494        &'a mut self,
495        archive_data: &'a mut [u8],
496    ) -> Result<impl Iterator<Item = ArchiveEntry<'a>>, ExtractError> {
497        self.reset(archive_data);
498        self.parse_header()?;
499        Ok(self.decrypt_entries())
500    }
501
502    /// Returns the size for the encrypted buffer of archive entries in bytes.
503    ///
504    /// It's necessary to use this function to get the buffer size for the encrypted buffer before actually encrypting the data with [`Decrypter::encrypt`].
505    ///
506    /// # Parameters
507    ///
508    /// - `archive_entries`: Archive entries to encrypt.
509    /// - `engine`: Target archive engine.
510    ///
511    /// # Example
512    /// See [`Decrypter::encrypt`].
513    ///
514    pub fn encrypted_buffer_size(
515        archive_entries: &[ArchiveEntry],
516        engine: Engine,
517    ) -> usize {
518        let mut buf_size: usize = ARCHIVE_HEADER.len();
519
520        // Engine byte
521        buf_size += 1;
522
523        if engine.is_vx_ace() {
524            buf_size += 4;
525        }
526
527        for entry in archive_entries {
528            if engine.is_vx_ace() {
529                // Offset
530                buf_size += sizeof!(u32);
531
532                // Data size
533                buf_size += sizeof!(u32);
534
535                // Key
536                buf_size += sizeof!(u32);
537
538                // Path size
539                buf_size += sizeof!(u32);
540            } else {
541                // Path size
542                buf_size += sizeof!(u32);
543
544                // Data size
545                buf_size += sizeof!(u32);
546            }
547
548            buf_size += entry.data.len();
549            buf_size += entry.path.len();
550        }
551
552        if engine.is_vx_ace() {
553            // Stop offset int
554            buf_size += sizeof!(u32);
555
556            // VX Ace actually writes the full entry before the stop offset, although this data is not ever used when decrypting and discarded.
557            buf_size += sizeof!(u32) * 3;
558        }
559
560        buf_size
561    }
562
563    /// Writes encrypted archive data to `archive_buffer`.
564    ///
565    /// `archive_buffer` must be manually pre-allocated by you. You must use the size that [`Decrypter::encrypted_buffer_size`] function returns. This is done this way for `no_std` compatibility.
566    ///
567    /// # Parameters
568    /// - `archive_entries`: Archive entries to encrypt.
569    /// - `engine`: Target archive engine.
570    /// - `archive_buffer`: Buffer to write encrypted data into.
571    ///
572    /// # Example
573    /// ```no_run
574    /// use rpgmad_lib::{Decrypter, Engine, ArchiveEntry};
575    /// use std::{fs::{read, write}, borrow::Cow};
576    ///
577    /// let data = read("Graphics/Tilesets/Tileset1.png").unwrap();
578    /// let archive_entries = [ArchiveEntry {
579    ///     path: b"Graphics/Tilesets/Tileset1.png",
580    ///     data: &data,
581    /// }];
582    ///
583    /// let encrypted_buffer_size = Decrypter::encrypted_buffer_size(&archive_entries, Engine::VXAce);
584    /// let mut archive_buffer = Vec::new();
585    /// archive_buffer.resize(encrypted_buffer_size, 0);
586    ///
587    /// Decrypter::new().encrypt(&archive_entries, Engine::VXAce, &mut archive_buffer);
588    /// write("./Game.rgss3a", archive_buffer).unwrap();
589    /// ```
590    #[must_use]
591    #[inline]
592    pub fn encrypt(
593        &mut self,
594        archive_entries: &[ArchiveEntry],
595        engine: Engine,
596        archive_buffer: &mut [u8],
597    ) {
598        memcpy(archive_buffer, ARCHIVE_HEADER);
599        archive_buffer[7] = engine as u8;
600
601        self.engine = engine;
602        self.encrypt_entries(archive_entries, archive_buffer);
603    }
604}
605
606impl Default for Decrypter<'_> {
607    /// Returns a new [`Decrypter`] with default parameters.
608    ///
609    /// Equivalent to calling [`Decrypter::new`].
610    fn default() -> Self {
611        Self::new()
612    }
613}