diff --git a/repak/Cargo.toml b/repak/Cargo.toml index a7b66c2..45d5dd4 100644 --- a/repak/Cargo.toml +++ b/repak/Cargo.toml @@ -20,6 +20,7 @@ zstd = { version = "0.12", optional = true } thiserror = "1.0" sha1 = { workspace = true } strum = { workspace = true } +once_cell = "1.18" [dev-dependencies] base64 = { workspace = true } diff --git a/repak/src/entry.rs b/repak/src/entry.rs index 184dee6..475f5a3 100644 --- a/repak/src/entry.rs +++ b/repak/src/entry.rs @@ -307,7 +307,6 @@ impl Entry { compression: &[Compression], #[allow(unused)] key: &super::Key, buf: &mut W, - #[allow(unused)] oodle: super::Oodle, ) -> Result<(), super::Error> { reader.seek(io::SeekFrom::Start(self.offset))?; Entry::read(reader, version)?; @@ -377,7 +376,7 @@ impl Entry { } #[cfg(feature = "oodle")] Some(Compression::Oodle) => unsafe { - let super::Oodle::Some(oodle) = oodle else { + let Some(ref oodle) = super::OODLE else { return Err(super::Error::OodleFailed); }; let mut decompressed = vec![0; self.uncompressed as usize]; diff --git a/repak/src/lib.rs b/repak/src/lib.rs index 34e3ace..887e3bf 100644 --- a/repak/src/lib.rs +++ b/repak/src/lib.rs @@ -10,7 +10,10 @@ pub use {error::*, pak::*}; pub const MAGIC: u32 = 0x5A6F12E1; #[cfg(feature = "oodle")] -pub type DECOMPRESS = unsafe extern "C" fn( +static mut OODLE: Option> = None; + +#[cfg(feature = "oodle")] +pub type Decompress = unsafe extern "C" fn( compBuf: *mut u8, compBufSize: usize, rawBuf: *mut u8, @@ -155,7 +158,7 @@ impl From for Key { #[cfg(feature = "oodle")] pub(crate) enum Oodle<'func> { - Some(&'func DECOMPRESS), + Some(&'func Decompress), None, } diff --git a/repak/src/pak.rs b/repak/src/pak.rs index bdaf5b8..6d35780 100644 --- a/repak/src/pak.rs +++ b/repak/src/pak.rs @@ -4,6 +4,46 @@ use byteorder::{ReadBytesExt, WriteBytesExt, LE}; use std::collections::BTreeMap; use std::io::{self, Read, Seek, Write}; +#[derive(Debug)] +pub struct PakBuilder { + key: super::Key, +} + +impl PakBuilder { + pub fn new() -> Self { + Self { + key: super::Key::None, + } + } + #[cfg(feature = "encryption")] + pub fn key(&mut self, key: aes::Aes256) { + self.key = super::Key::Some(key) + } + #[cfg(feature = "oodle")] + pub fn oodle(&mut self, oodle: fn() -> super::Decompress) { + unsafe { super::OODLE = Some(once_cell::sync::Lazy::new(oodle)) } + } + pub fn reader(self, reader: &mut R) -> Result { + PakReader::new_any_inner(reader, self.key) + } + pub fn reader_with_version( + self, + reader: &mut R, + version: super::Version, + ) -> Result { + PakReader::new_inner(reader, version, self.key) + } + pub fn writer( + self, + writer: W, + version: super::Version, + mount_point: String, + path_hash_seed: Option, + ) -> PakWriter { + PakWriter::new_inner(writer, self.key, version, mount_point, path_hash_seed) + } +} + #[derive(Debug)] pub struct PakReader { pak: Pak, @@ -83,29 +123,6 @@ fn decrypt(key: &super::Key, bytes: &mut [u8]) -> Result<(), super::Error> { } impl PakReader { - pub fn new_any(reader: &mut R) -> Result { - Self::new_any_inner(reader, super::Key::None) - } - - #[cfg(feature = "encryption")] - pub fn new_any_with_key( - reader: &mut R, - key: aes::Aes256, - ) -> Result { - Self::new_any_inner(reader, key.into()) - } - - #[cfg(feature = "encryption")] - pub fn new_any_with_optional_key( - reader: &mut R, - key: Option, - ) -> Result { - match key { - Some(key) => Self::new_any_with_key(reader, key), - None => Self::new_any(reader), - } - } - fn new_any_inner( reader: &mut R, key: super::Key, @@ -122,34 +139,6 @@ impl PakReader { Err(super::Error::UnsupportedOrEncrypted(log)) } - pub fn new( - reader: &mut R, - version: super::Version, - ) -> Result { - Self::new_inner(reader, version, super::Key::None) - } - - #[cfg(feature = "encryption")] - pub fn new_with_key( - reader: &mut R, - version: super::Version, - key: aes::Aes256, - ) -> Result { - Self::new_inner(reader, version, key.into()) - } - - #[cfg(feature = "encryption")] - pub fn new_with_optional_key( - reader: &mut R, - version: super::Version, - key: Option, - ) -> Result { - match key { - Some(key) => Self::new_with_key(reader, version, key), - None => Self::new(reader, version), - } - } - fn new_inner( reader: &mut R, version: super::Version, @@ -180,18 +169,6 @@ impl PakReader { Ok(data) } - #[cfg(feature = "oodle")] - pub fn get_with_oodle( - &self, - path: &str, - reader: &mut R, - oodle: &super::DECOMPRESS, - ) -> Result, super::Error> { - let mut data = Vec::new(); - self.read_file_with_oodle(path, reader, &mut data, oodle)?; - Ok(data) - } - pub fn read_file( &self, path: &str, @@ -205,28 +182,6 @@ impl PakReader { &self.pak.compression, &self.key, writer, - super::Oodle::None, - ), - None => Err(super::Error::MissingEntry(path.to_owned())), - } - } - - #[cfg(feature = "oodle")] - pub fn read_file_with_oodle( - &self, - path: &str, - reader: &mut R, - writer: &mut W, - oodle: &super::DECOMPRESS, - ) -> Result<(), super::Error> { - match self.pak.index.entries().get(path) { - Some(entry) => entry.read_file( - reader, - self.pak.version, - &self.pak.compression, - &self.key, - writer, - super::Oodle::Some(oodle), ), None => Err(super::Error::MissingEntry(path.to_owned())), } @@ -250,48 +205,6 @@ impl PakReader { } impl PakWriter { - pub fn new( - writer: W, - version: Version, - mount_point: String, - path_hash_seed: Option, - ) -> Self { - PakWriter { - pak: Pak::new(version, mount_point, path_hash_seed), - writer, - key: super::Key::None, - } - } - - #[cfg(feature = "encryption")] - pub fn new_with_key( - writer: W, - key: aes::Aes256, - version: Version, - mount_point: String, - path_hash_seed: Option, - ) -> Self { - PakWriter { - pak: Pak::new(version, mount_point, path_hash_seed), - writer, - key: key.into(), - } - } - - #[cfg(feature = "encryption")] - pub fn new_with_optional_key( - writer: W, - key: Option, - version: Version, - mount_point: String, - path_hash_seed: Option, - ) -> Self { - match key { - Some(key) => Self::new_with_key(writer, key, version, mount_point, path_hash_seed), - None => Self::new(writer, version, mount_point, path_hash_seed), - } - } - fn new_inner( writer: W, key: super::Key,