1use super::encryption::*;
2use super::types::*;
3use crate::ext::io::*;
4use crate::scripts::base::*;
5use crate::types::*;
6use crate::utils::encoding::*;
7use anyhow::Result;
8use rand::Rng;
9use std::io::{Seek, Write};
10
11struct MListEntry<T> {
12 back: *mut MListEntry<T>,
13 next: *mut MListEntry<T>,
14 data: T,
15}
16
17struct MList<T> {
18 head: *mut MListEntry<T>,
19 depth: usize,
20}
21
22impl<T> MList<T> {
23 pub fn new() -> Self {
24 Self {
25 head: std::ptr::null_mut(),
26 depth: 0,
27 }
28 }
29
30 pub fn push(&mut self, data: T, way: bool) -> usize {
31 let entry = Box::new(MListEntry {
32 back: std::ptr::null_mut(),
33 next: std::ptr::null_mut(),
34 data,
35 });
36 let entry_ptr = Box::into_raw(entry);
37 if self.head.is_null() {
38 self.head = entry_ptr;
39 unsafe {
40 (*self.head).back = self.head;
41 (*self.head).next = self.head;
42 }
43 } else {
44 if way {
45 unsafe {
46 (*(*self.head).back).next = entry_ptr;
47 (*entry_ptr).back = (*self.head).back;
48 (*entry_ptr).next = self.head;
49 (*self.head).back = entry_ptr;
50 }
51 } else {
52 unsafe {
53 (*(*self.head).back).next = entry_ptr;
54 (*entry_ptr).back = (*self.head).back;
55 (*entry_ptr).next = self.head;
56 (*self.head).back = entry_ptr;
57 self.head = entry_ptr;
58 }
59 }
60 }
61 self.depth += 1;
62 self.depth
63 }
64
65 pub fn pop(&mut self, way: bool) -> Option<T> {
66 if self.head.is_null() {
67 return None;
68 }
69 if self.depth > 0 {
70 self.depth -= 1;
71 let ret;
72 if way {
73 unsafe {
74 ret = (*self.head).back;
75 (*(*ret).back).next = (*ret).next;
76 (*self.head).back = (*ret).back;
77 }
78 } else {
79 unsafe {
80 ret = self.head;
81 (*(*ret).back).next = (*ret).next;
82 (*(*ret).next).back = (*ret).back;
83 self.head = (*ret).next;
84 }
85 }
86 if self.depth == 0 {
87 self.head = std::ptr::null_mut();
88 }
89 let boxed = unsafe { Box::from_raw(ret) };
90 return Some(boxed.data);
91 }
92 None
93 }
94}
95
96impl<T> Drop for MList<T> {
97 fn drop(&mut self) {
98 if self.head.is_null() {
99 return;
100 }
101 let mut current = self.head;
102 loop {
103 unsafe {
104 let next = (*current).next;
105 let _ = Box::from_raw(current);
106 if next == self.head {
107 break;
108 }
109 current = next;
110 }
111 }
112 }
113}
114
115pub struct QliePackArchiveWriterV31<T: Write + Seek> {
116 writer: T,
117 encryption: Encryption31,
118 qkey: QlieKey,
119 header: QlieHeader,
120 hash: QlieHash14,
121 has_key_file: bool,
122 entries: Vec<QlieEntry>,
123 key: u32,
124 common_key: Option<Vec<u8>>,
125 compress_files: bool,
126}
127
128struct FilenameEntry {
129 name: Vec<u16>,
130 hash: u32,
131 index: u32,
132}
133
134fn get_pos(hash: u32, count: u32) -> u32 {
135 let v = (hash as u16 as u32)
136 .wrapping_add(hash >> 8)
137 .wrapping_add(hash >> 16);
138 v % count
139}
140
141impl<T: Write + Seek> QliePackArchiveWriterV31<T> {
142 pub fn new(writer: T, files: &[&str], config: &ExtraConfig) -> Result<Self> {
143 let has_key_file = files.iter().any(|f| *f == QLIE_KEY_FILE);
144 let mut file_count = files.len() as u32;
145 if !has_key_file {
146 if config.qlie_pack_keyfile.is_none() {
147 anyhow::bail!(
148 "Qlie Pack Archive key file is required but not provided. Put a key file named '{}' in the directory or specify the path using '--qlie-pack-keyfile' option.",
149 QLIE_KEY_FILE
150 );
151 }
152 file_count += 1;
154 }
155 let header = QlieHeader {
156 signature: *b"FilePackVer3.1\x00\x00",
157 file_count,
158 index_offset: 0,
159 };
160 let encryption = Encryption31::new();
161 let mut qkey = QlieKey {
162 signature: *QLIE_KEY_SIGNATURE,
163 hash_size: 0,
164 key: [0; 0x400],
165 };
166 rand::rng().fill(&mut qkey.key[..0x100]);
167 let key = encryption.compute_hash(&qkey.key[..0x100])? & 0xFFFFFFF;
168 encrypt(&mut qkey.signature, key)?;
169 let mut entries = Vec::new();
170 let mut list = Vec::with_capacity(256);
171 for _ in 0..256 {
172 list.push(MList::<FilenameEntry>::new());
173 }
174 let key_entry = QlieEntry {
175 name: QLIE_KEY_FILE.to_string(),
176 ..Default::default()
177 };
178 entries.push(key_entry);
179 let key_filename: Vec<_> = QLIE_KEY_FILE.encode_utf16().collect();
180 let key_hash = encryption.compute_name_hash(&key_filename)?;
181 let key_name_entry = FilenameEntry {
182 name: key_filename,
183 hash: key_hash,
184 index: 0,
185 };
186 let pos = get_pos(key_hash, 256);
187 list[pos as usize].push(key_name_entry, true);
188 for name in files {
189 if *name == QLIE_KEY_FILE {
190 continue;
191 }
192 let filename: Vec<_> = name.encode_utf16().collect();
193 let name_hash = encryption.compute_name_hash(&filename)?;
194 let entry = QlieEntry {
195 name: name.to_string(),
196 ..Default::default()
197 };
198 entries.push(entry);
199 let name_entry = FilenameEntry {
200 name: filename,
201 hash: name_hash,
202 index: (entries.len() - 1) as u32,
203 };
204 let pos = get_pos(name_hash, 256);
205 list[pos as usize].push(name_entry, true);
206 }
207 let mut hash_data = MemWriter::new();
208 for mut list in list {
209 hash_data.write_u32(list.depth as u32)?;
210 while let Some(entry) = list.pop(false) {
211 hash_data.write_u16(entry.name.len() as u16)?;
212 hash_data.write_struct(&entry.name, false, Encoding::Utf16LE, &None)?;
213 hash_data.write_u64(entry.index as u64 * 4)?;
214 hash_data.write_u32(entry.hash)?;
215 }
216 }
217 for i in 0..file_count {
218 hash_data.write_u32(i)?;
219 }
220 let mut hash_data = hash_data.into_inner();
221 encrypt(&mut hash_data, 0x0428)?;
222 let hash = QlieHash14 {
223 signature: *HASH_VER_1_4_SIGNATURE,
224 table_size: 256,
225 file_count: header.file_count,
226 index_size: header.file_count * 4,
227 hash_data_size: hash_data.len() as u32,
228 is_compressed: 0,
229 unk: [0; 32],
230 hash_data,
231 };
232 qkey.hash_size = hash.hash_data_size + 68;
233 let mut inner = Self {
234 writer,
235 encryption,
236 qkey,
237 header,
238 hash,
239 has_key_file,
240 entries,
241 key,
242 common_key: None,
243 compress_files: config.qlie_pack_compress_files,
244 };
245 if !has_key_file {
246 let key_path = config.qlie_pack_keyfile.as_ref().unwrap();
247 let key_data = std::fs::read(key_path)?;
248 inner.write_key(key_data)?;
249 }
250 Ok(inner)
251 }
252
253 fn write_key(&mut self, key_data: Vec<u8>) -> Result<()> {
254 let entry = &mut self.entries[0];
255 entry.size = key_data.len() as u32;
256 entry.offset = self.writer.stream_position()?;
257 entry.unpacked_size = entry.size;
258 entry.is_packed = 0;
259 entry.is_encrypted = 1;
260 self.common_key = Some(get_common_key(&key_data)?);
261 let hasher = Encryption31Hasher::new();
262 let size = entry.size;
263 let compute = EntryWriter {
264 entry,
265 inner: &mut self.writer,
266 hasher,
267 };
268 let mut encryptor =
269 Encryption31EncryptV1::new(compute, size, QLIE_KEY_FILE.to_string(), self.key)?;
270 encryptor.write_all(&key_data)?;
271 Ok(())
272 }
273}
274
275struct Writer<'a> {
276 inner: Box<dyn Write + 'a>,
277 mem: MemWriter,
278}
279
280impl std::fmt::Debug for Writer<'_> {
281 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
282 f.debug_struct("Writer").field("mem", &self.mem).finish()
283 }
284}
285
286impl<'a> Write for Writer<'a> {
287 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
288 self.mem.write(buf)
289 }
290
291 fn flush(&mut self) -> std::io::Result<()> {
292 self.mem.flush()
293 }
294}
295
296impl<'a> Seek for Writer<'a> {
297 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
298 self.mem.seek(pos)
299 }
300
301 fn stream_position(&mut self) -> std::io::Result<u64> {
302 self.mem.stream_position()
303 }
304
305 fn rewind(&mut self) -> std::io::Result<()> {
306 self.mem.rewind()
307 }
308}
309
310impl<'a> Drop for Writer<'a> {
311 fn drop(&mut self) {
312 let _ = self.inner.write_all(&self.mem.data);
313 let _ = self.inner.flush();
314 }
315}
316
317struct Writer2<'a, T: Write + Seek> {
318 inner: &'a mut QliePackArchiveWriterV31<T>,
319 entry_idx: usize,
320 mem: MemWriter,
321 is_v1: bool,
322 compress_file: bool,
323}
324
325impl<'a, T: Write + Seek> Writer2<'a, T> {
326 fn close(&mut self) -> Result<()> {
327 let entry = &mut self.inner.entries[self.entry_idx];
328 entry.size = self.mem.data.len() as u32;
329 entry.offset = self.inner.writer.stream_position()?;
330 entry.unpacked_size = entry.size;
331 entry.is_packed = 0;
332 let hasher = Encryption31Hasher::new();
333 let size = entry.size;
334 let compute = EntryWriter {
335 entry,
336 inner: &mut self.inner.writer,
337 hasher,
338 };
339 if self.is_v1 {
340 compute.entry.is_encrypted = 1;
341 let name = compute.entry.name.clone();
342 let mut encryptor = Encryption31EncryptV1::new(compute, size, name, self.inner.key)?;
343 encryptor.write_all(&self.mem.data)?;
344 self.inner.common_key = Some(get_common_key(&self.mem.data)?);
345 } else {
346 compute.entry.is_encrypted = 2;
347 let data = if self.compress_file {
348 let compressed = compress(&self.mem.data)?;
349 if compressed.len() >= self.mem.data.len() {
350 let mut nw = MemWriter::new();
351 std::mem::swap(&mut self.mem, &mut nw);
352 nw.into_inner()
353 } else {
354 compute.entry.is_packed = 1;
355 compute.entry.size = compressed.len() as u32;
356 compressed
364 }
365 } else {
366 let mut nw = MemWriter::new();
367 std::mem::swap(&mut self.mem, &mut nw);
368 nw.into_inner()
369 };
370 let name = compute.entry.name.clone();
371 let common_key = self
372 .inner
373 .common_key
374 .as_ref()
375 .ok_or_else(|| anyhow::anyhow!("Common key is not available"))?;
376 let mut encryptor = Encryption31EncryptV2::new(
377 compute,
378 data.len() as u32,
379 name,
380 self.inner.key,
381 common_key.to_vec(),
382 )?;
383 encryptor.write_all(&data)?;
384 }
385 Ok(())
386 }
387}
388
389impl<T: Write + Seek> std::fmt::Debug for Writer2<'_, T> {
390 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
391 f.debug_struct("Writer").field("mem", &self.mem).finish()
392 }
393}
394
395impl<'a, T: Write + Seek> Write for Writer2<'a, T> {
396 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
397 self.mem.write(buf)
398 }
399
400 fn flush(&mut self) -> std::io::Result<()> {
401 self.mem.flush()
402 }
403}
404
405impl<'a, T: Write + Seek> Seek for Writer2<'a, T> {
406 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
407 self.mem.seek(pos)
408 }
409
410 fn stream_position(&mut self) -> std::io::Result<u64> {
411 self.mem.stream_position()
412 }
413
414 fn rewind(&mut self) -> std::io::Result<()> {
415 self.mem.rewind()
416 }
417}
418
419impl<'a, T: Write + Seek> Drop for Writer2<'a, T> {
420 fn drop(&mut self) {
421 let _ = self.close();
422 }
423}
424
425struct EntryWriter<'a, T: Write> {
426 entry: &'a mut QlieEntry,
427 inner: T,
428 hasher: Encryption31Hasher,
429}
430
431impl<'a, T: Write> Write for EntryWriter<'a, T> {
432 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
433 let writed = self.inner.write(buf)?;
434 self.hasher
435 .update(&buf[..writed])
436 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
437 Ok(writed)
438 }
439
440 fn flush(&mut self) -> std::io::Result<()> {
441 self.inner.flush()
442 }
443}
444
445impl<'a, T: Write> Drop for EntryWriter<'a, T> {
446 fn drop(&mut self) {
447 if let Ok(hash) = self.hasher.finalize() {
448 self.entry.hash = hash;
449 }
450 }
451}
452
453impl<T: Write + Seek> Archive for QliePackArchiveWriterV31<T> {
454 fn prelist<'a>(&'a self) -> Result<Option<Box<dyn Iterator<Item = Result<String>> + 'a>>> {
455 if !self.has_key_file {
456 Ok(None)
457 } else {
458 let iter = std::iter::once(Ok(QLIE_KEY_FILE.to_string()));
459 Ok(Some(Box::new(iter)))
460 }
461 }
462
463 fn new_file<'a>(
464 &'a mut self,
465 name: &str,
466 size: Option<u64>,
467 ) -> Result<Box<dyn WriteSeek + 'a>> {
468 let inner = self.new_file_non_seek(name, size)?;
469 Ok(Box::new(Writer {
470 inner,
471 mem: MemWriter::new(),
472 }))
473 }
474
475 fn new_file_non_seek<'a>(
476 &'a mut self,
477 name: &str,
478 size: Option<u64>,
479 ) -> Result<Box<dyn Write + 'a>> {
480 if self.common_key.is_none() {
481 if name != QLIE_KEY_FILE {
482 anyhow::bail!("Common key is not available before writing key file");
483 }
484 let entry_idx = self
485 .entries
486 .iter()
487 .position(|e| e.name == name)
488 .ok_or_else(|| anyhow::anyhow!("File {} not found in entries", name))?;
489 return Ok(Box::new(Writer2 {
490 inner: self,
491 entry_idx,
492 mem: MemWriter::new(),
493 is_v1: true,
494 compress_file: false,
496 }));
497 }
498 if size.is_none() || self.compress_files {
499 let entry_idx = self
500 .entries
501 .iter()
502 .position(|e| e.name == name)
503 .ok_or_else(|| anyhow::anyhow!("File {} not found in entries", name))?;
504 let compress_file = self.compress_files;
505 return Ok(Box::new(Writer2 {
506 inner: self,
507 entry_idx,
508 mem: MemWriter::new(),
509 is_v1: false,
510 compress_file,
511 }));
512 }
513 let entry_idx = self
514 .entries
515 .iter()
516 .position(|e| e.name == name)
517 .ok_or_else(|| anyhow::anyhow!("File {} not found in entries", name))?;
518 let entry = &mut self.entries[entry_idx];
519 entry.size = size.unwrap() as u32;
520 entry.offset = self.writer.stream_position()?;
521 entry.unpacked_size = entry.size;
522 entry.is_packed = 0;
523 entry.is_encrypted = 2;
524 let common_key = self
525 .common_key
526 .as_ref()
527 .ok_or_else(|| anyhow::anyhow!("Common key is not available"))?;
528 let hasher = Encryption31Hasher::new();
529 let size = entry.size;
530 let compute = EntryWriter {
531 entry,
532 inner: &mut self.writer,
533 hasher,
534 };
535 let encryptor = Encryption31EncryptV2::new(
536 compute,
537 size,
538 name.to_string(),
539 self.key,
540 common_key.to_vec(),
541 )?;
542 Ok(Box::new(encryptor))
543 }
544
545 fn write_header(&mut self) -> Result<()> {
546 self.header.index_offset = self.writer.stream_position()?;
547 for entry in &self.entries {
548 let name_length = entry.name.encode_utf16().count() as u16;
549 self.writer.write_u16(name_length)?;
550 let mut encoded = encode_string(Encoding::Utf16LE, &entry.name, true)?;
551 self.encryption
552 .encrypt_name(&mut encoded, self.key as i32)?;
553 self.writer.write_all(&encoded)?;
554 self.writer.write_u64(entry.offset)?;
555 self.writer.write_u32(entry.size)?;
556 self.writer.write_u32(entry.unpacked_size)?;
557 self.writer.write_u32(entry.is_packed)?;
558 self.writer.write_u32(entry.is_encrypted)?;
559 self.writer.write_u32(entry.hash)?;
560 }
561 self.writer
562 .write_struct(&self.hash, false, Encoding::Utf8, &None)?;
563 self.writer
564 .write_struct(&self.qkey, false, Encoding::Utf8, &None)?;
565 self.writer
566 .write_struct(&self.header, false, Encoding::Utf8, &None)?;
567 Ok(())
568 }
569}
570
571#[test]
572fn test_drop_mlist() {
573 use std::sync::Arc;
574 use std::sync::atomic::{AtomicI32, Ordering};
575 let t = Arc::new(AtomicI32::new(0));
576 struct Test {
577 value: i32,
578 t: Arc<AtomicI32>,
579 }
580
581 impl Test {
582 fn new(value: i32, t: Arc<AtomicI32>) -> Self {
583 Self { value, t }
584 }
585 }
586
587 impl Drop for Test {
588 fn drop(&mut self) {
589 self.t.fetch_add(self.value, Ordering::SeqCst);
590 }
591 }
592 {
593 let mut list: MList<Test> = MList::new();
594 list.push(Test::new(1, t.clone()), true);
595 list.push(Test::new(2, t.clone()), true);
596 list.push(Test::new(3, t.clone()), true);
597 }
598 let v = t.load(Ordering::SeqCst);
599 assert_eq!(v, 6);
600}
601
602#[test]
603fn test_mlist() {
604 let mut list = MList::new();
605 list.push(1, true);
606 list.push(2, true);
607 list.push(3, true);
608 assert_eq!(list.depth, 3);
609 assert_eq!(list.pop(false), Some(1));
610 assert_eq!(list.depth, 2);
611 assert_eq!(list.pop(false), Some(2));
612 assert_eq!(list.depth, 1);
613 assert_eq!(list.pop(false), Some(3));
614 assert_eq!(list.depth, 0);
615 assert_eq!(list.pop(false), None);
616}