Skip to content

Commit aac24b5

Browse files
committed
Performance improvements
1 parent 2e5d373 commit aac24b5

File tree

1 file changed

+65
-57
lines changed

1 file changed

+65
-57
lines changed

src/lib.rs

Lines changed: 65 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//!A decrypter implementation for rpgm-archive-decrypter. Not intended for use in other applications; but can be.
22
3+
use arrayvec::ArrayVec;
34
#[cfg(feature = "rayon")]
45
use rayon::prelude::*;
56
#[cfg(feature = "rayon")]
@@ -23,12 +24,10 @@ enum SeekFrom {
2324

2425
impl std::fmt::Display for Engine {
2526
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26-
let variant_name: &str = match self {
27-
Engine::Older => "XP/VX",
28-
Engine::VXAce => "VXAce",
29-
};
30-
31-
write!(f, "{}", variant_name)
27+
match self {
28+
Engine::Older => write!(f, "XP/VX"),
29+
Engine::VXAce => write!(f, "VXAce"),
30+
}
3231
}
3332
}
3433

@@ -44,22 +43,26 @@ impl VecWalker {
4443
VecWalker { data, pos: 0, len }
4544
}
4645

46+
#[inline]
4747
pub fn advance(&mut self, bytes: usize) -> &[u8] {
4848
self.pos += bytes;
4949
&self.data[self.pos - bytes..self.pos]
5050
}
5151

52-
pub fn read_chunk(&mut self) -> [u8; 4] {
52+
#[inline]
53+
pub fn read_i32(&mut self) -> i32 {
5354
let chunk: &[u8] = self.advance(4);
54-
unsafe { *(chunk.as_ptr() as *const [u8; 4]) }
55+
i32::from_le_bytes(unsafe { *(chunk.as_ptr() as *const [u8; 4]) })
5556
}
5657

58+
#[inline]
5759
pub fn read_byte(&mut self) -> u8 {
5860
self.pos += 1;
5961
self.data[self.pos - 1]
6062
}
6163

62-
pub fn seek(&mut self, offset: usize, seek_from: SeekFrom) {
64+
#[inline]
65+
pub const fn seek(&mut self, offset: usize, seek_from: SeekFrom) {
6366
self.pos = match seek_from {
6467
SeekFrom::Start => offset,
6568
SeekFrom::Current => self.pos + offset,
@@ -77,20 +80,24 @@ struct Archive {
7780
pub struct Decrypter {
7881
walker: UnsafeCell<VecWalker>,
7982
key: u32,
83+
key_bytes: [u8; 4],
8084
engine: Engine,
8185
}
8286

8387
impl Decrypter {
8488
/// Creates a new decrypter for specified archive binary data.
8589
pub fn new(bytes: Vec<u8>) -> Self {
90+
let key: u32 = 0xDEADCAFE;
8691
Self {
8792
walker: UnsafeCell::new(VecWalker::new(bytes)),
88-
key: 0xDEADCAFE,
93+
key,
94+
key_bytes: key.to_le_bytes(),
8995
engine: Engine::Older,
9096
}
9197
}
9298

9399
/// Extracts archive to `output_path`. Does nothing if extracted files already exist and `force` is set to `false`.
100+
#[inline]
94101
pub fn extract<P: AsRef<Path>>(&mut self, output_path: P, force: bool) -> Result<(), &str> {
95102
let walker: &mut VecWalker = unsafe { &mut *self.walker.get() };
96103

@@ -105,21 +112,19 @@ impl Decrypter {
105112
walker.read_byte()
106113
};
107114

108-
self.engine = if version == 1 {
109-
Engine::Older
110-
} else if version == 3 {
111-
Engine::VXAce
112-
} else {
113-
return Err("Unknown archive game engine. Archive is possibly corrupted.");
115+
self.engine = match version {
116+
1 => Engine::Older,
117+
3 => Engine::VXAce,
118+
_ => return Err("Unknown archive game engine. Archive is possibly corrupted."),
114119
};
115120

116-
let archives: Vec<Archive> = self.read_archive();
121+
let archives: ArrayVec<Archive, 2048> = self.read_archive();
117122

118123
#[cfg(feature = "rayon")]
119124
let arc: Arc<Mutex<&mut VecWalker>> = Arc::new(Mutex::new(walker));
120125

121126
#[cfg(feature = "rayon")]
122-
let archives = archives.into_par_iter();
127+
let archives = archives.into_iter().par_bridge();
123128

124129
#[cfg(not(feature = "rayon"))]
125130
let archives = archives.into_iter();
@@ -156,6 +161,13 @@ impl Decrypter {
156161
Ok(())
157162
}
158163

164+
#[inline]
165+
fn update_key(&mut self, new_key: u32) {
166+
self.key = new_key;
167+
self.key_bytes = new_key.to_le_bytes();
168+
}
169+
170+
#[inline]
159171
fn decrypt_archive(data: &[u8], mut key: u32) -> Vec<u8> {
160172
let mut decrypted: Vec<u8> = Vec::with_capacity(data.len());
161173

@@ -176,89 +188,85 @@ impl Decrypter {
176188
decrypted
177189
}
178190

191+
#[inline]
179192
fn decrypt_integer(&mut self, value: i32) -> i32 {
180193
let result: i32 = value ^ self.key as i32;
181194

182195
if self.engine == Engine::Older {
183-
self.key = self.key.wrapping_mul(7).wrapping_add(3);
196+
self.update_key(self.key.wrapping_mul(7).wrapping_add(3));
184197
}
185198

186199
result
187200
}
188201

202+
#[inline]
189203
fn decrypt_filename(&mut self, filename: &[u8]) -> String {
190204
let mut decrypted: Vec<u8> = Vec::with_capacity(filename.len());
191205

192206
if self.engine == Engine::VXAce {
193-
let key_bytes: [u8; 4] = self.key.to_le_bytes();
194207
let mut j: usize = 0;
195208

196209
for item in filename {
197210
if j == 4 {
198211
j = 0;
199212
}
200213

201-
decrypted.push(item ^ key_bytes[j]);
214+
decrypted.push(item ^ self.key_bytes[j]);
202215
j += 1;
203216
}
204217
} else {
205218
for item in filename {
206-
decrypted.push(item ^ (self.key & 0xff) as u8);
207-
self.key = self.key.wrapping_mul(7).wrapping_add(3);
219+
decrypted.push(item ^ self.key as u8);
220+
self.update_key(self.key.wrapping_mul(7).wrapping_add(3));
208221
}
209222
}
210223

224+
//? probably non-utf8 support?
211225
String::from_utf8(decrypted).unwrap()
212226
}
213227

214-
fn read_archive(&mut self) -> Vec<Archive> {
228+
#[inline]
229+
fn read_archive(&mut self) -> ArrayVec<Archive, 2048> {
215230
let walker: &mut VecWalker = unsafe { &mut *self.walker.get() };
216231

217232
if self.engine == Engine::VXAce {
218233
// 0xDEADCAFE key is not ever used and overwritten.
219-
self.key = u32::from_le_bytes(walker.read_chunk())
220-
.wrapping_mul(9)
221-
.wrapping_add(3);
234+
self.update_key((walker.read_i32() as u32).wrapping_mul(9).wrapping_add(3));
222235
}
223236

224-
let mut archives: Vec<Archive> = Vec::with_capacity(1024);
237+
let mut archives: ArrayVec<Archive, 2048> = ArrayVec::new();
225238

226239
loop {
227-
let (filename, size, offset, key) = if self.engine == Engine::VXAce {
228-
let offset: usize =
229-
self.decrypt_integer(i32::from_le_bytes(walker.read_chunk())) as usize;
230-
231-
let size: i32 = self.decrypt_integer(i32::from_le_bytes(walker.read_chunk()));
232-
233-
let key: u32 = self.decrypt_integer(i32::from_le_bytes(walker.read_chunk())) as u32;
234-
235-
let length: i32 = self.decrypt_integer(i32::from_le_bytes(walker.read_chunk()));
236-
237-
if offset == 0 {
238-
break;
240+
let (filename, size, offset, key) = match self.engine {
241+
Engine::VXAce => {
242+
let offset: usize = self.decrypt_integer(walker.read_i32()) as usize;
243+
let size: i32 = self.decrypt_integer(walker.read_i32());
244+
let key: u32 = self.decrypt_integer(walker.read_i32()) as u32;
245+
let length: i32 = self.decrypt_integer(walker.read_i32());
246+
247+
if offset == 0 {
248+
break;
249+
}
250+
251+
let filename: String = self.decrypt_filename(walker.advance(length as usize));
252+
(filename, size, offset, key)
239253
}
254+
Engine::Older => {
255+
let length: i32 = self.decrypt_integer(walker.read_i32());
256+
let filename: String = self.decrypt_filename(walker.advance(length as usize));
257+
let size: i32 = self.decrypt_integer(walker.read_i32());
240258

241-
let filename: String = self.decrypt_filename(walker.advance(length as usize));
242-
243-
(filename, size, offset, key)
244-
} else {
245-
let length: i32 = self.decrypt_integer(i32::from_le_bytes(walker.read_chunk()));
246-
247-
let filename: String = self.decrypt_filename(walker.advance(length as usize));
259+
let offset: usize = walker.pos;
260+
let key: u32 = self.key;
248261

249-
let size: i32 = self.decrypt_integer(i32::from_le_bytes(walker.read_chunk()));
262+
walker.seek(size as usize, SeekFrom::Current);
250263

251-
let offset: usize = walker.pos;
264+
if walker.pos == walker.len {
265+
break;
266+
}
252267

253-
let key: u32 = self.key;
254-
255-
walker.seek(size as usize, SeekFrom::Current);
256-
257-
if walker.pos == walker.len {
258-
break;
268+
(filename, size, offset, key)
259269
}
260-
261-
(filename, size, offset, key)
262270
};
263271

264272
archives.push(Archive {

0 commit comments

Comments
 (0)