rust_unreal_unpak/pak/
pak_file.rs

1use std::path::Path;
2
3use thiserror::Error;
4use tokio::{fs::File, io::AsyncReadExt};
5
6use super::pak_reader::{PakReader, PakReaderError};
7use std::collections::HashMap;
8use crate::pak::pak_reader::PakEntry;
9
10#[derive(Error, Debug)]
11pub enum PakError {
12    #[error("Error opening or reading file: {0}")]
13    FileError(#[from] std::io::Error),
14    #[error("Error parsing the pak file: {0}")]
15    ReaderError(#[from] PakReaderError),
16}
17
18#[derive(Debug)]
19pub struct PakInfo {
20    pub encryption_index_guid: Vec<u8>,
21    pub is_encrypted: bool,
22    pub magic: u32,
23    pub version: i32,
24    pub sub_version: i32,
25    pub index_offset: i64,
26    pub index_size: i64,
27    pub index_hash: Vec<u8>,
28    pub index_frozen: u8,
29    pub compression_methods: Vec<String>
30}
31
32#[derive(Debug)]
33pub struct PakCompressionBlock {
34    pub compression_start: i64,
35    pub compression_end: i64
36}
37
38#[derive(Debug)]
39pub struct PakFile {
40    pub info: PakInfo,
41    pub mount_point: String,
42    pub file_indexes: HashMap<String, PakEntry>,
43    reader: PakReader
44}
45
46impl PakFile {
47    // Open the file and pass it to the from_file
48    pub async fn from_path(path: &Path) -> Result<Self, PakError> {
49        match File::open(path).await {
50            Ok(file) => Self::from_file(file).await,
51            Err(err) => Err(PakError::FileError(err)),
52        }
53    }
54
55    // Read the buffer from the file, and pass it into from_memory which reads the content
56    pub async fn from_file(mut file: File) -> Result<Self, PakError> {
57        let mut buffer = Vec::new();
58        match file.read_to_end(&mut buffer).await {
59            Ok(_) => Self::from_memory(buffer).await,
60            Err(e) => Err(PakError::FileError(e)),
61        }
62    }
63
64    // Parse the PAK from memory, into the pak struct, with respective reader
65    pub async fn from_memory(buffer: Vec<u8>) -> Result<Self, PakError> {
66        let mut reader = PakReader::new(buffer);
67
68        let pak_info = reader.get_pak_info().await?;
69        let (mount_point, indexes) = reader.get_pak_entries(&pak_info).await?;
70
71        Ok(Self {
72            info: pak_info,
73            mount_point: mount_point,
74            file_indexes: indexes,
75            reader: reader
76        })
77    }
78
79    pub async fn get_entry_data<T: Into<String>>(&mut self, index: T) -> Result<Option<Vec<u8>>, PakError> {
80        let entry = self.file_indexes.get(&index.into());
81        if let Some(pak_entry) = entry {
82            Ok(Some(self.reader.get_pak_entry_data(pak_entry).await?))
83        } else {
84            Ok(None)
85        }
86    }
87
88}