From f2c2255d532b5bbe0d5ecb4b411561d7cfce33df Mon Sep 17 00:00:00 2001 From: spuds <71292624+bananaturtlesandwich@users.noreply.github.com> Date: Wed, 16 Aug 2023 22:13:03 +0100 Subject: [PATCH] add compression and oodle features --- repak/Cargo.toml | 19 ++++++++++++------- repak/src/entry.rs | 16 ++++++++++++++-- repak/src/error.rs | 13 +++++++++---- repak/src/lib.rs | 3 +++ repak/src/pak.rs | 2 +- repak_cli/Cargo.toml | 2 +- 6 files changed, 40 insertions(+), 15 deletions(-) diff --git a/repak/Cargo.toml b/repak/Cargo.toml index 532a01e..5c31a19 100644 --- a/repak/Cargo.toml +++ b/repak/Cargo.toml @@ -6,19 +6,24 @@ license.workspace = true version.workspace = true edition.workspace = true +[features] +default = ["compression"] +compression = ["dep:flate2", "dep:zstd"] +oodle = ["dep:libloading", "dep:ureq", "dep:once_cell", "dep:hex-literal", "dep:hex"] + [dependencies] byteorder = "1.4" aes = "0.8" -flate2 = "1.0" +flate2 = { version = "1.0", optional = true } +zstd = { version = "0.12", optional = true } thiserror = "1.0" sha1 = "0.10.5" strum = { workspace = true } -libloading = "0.7.4" -ureq = "2.6.2" -hex-literal = "0.4.1" -hex = { workspace = true } -once_cell = "1.17.1" -zstd = "0.12.3" +libloading = { version = "0.7", optional = true } +ureq = { version = "2.6", optional = true } +once_cell = { version = "1.17", optional = true} +hex-literal = { version = "0.4", optional = true } +hex = { workspace = true, optional = true } [dev-dependencies] base64 = { workspace = true } diff --git a/repak/src/entry.rs b/repak/src/entry.rs index df1a8fc..71b5af2 100644 --- a/repak/src/entry.rs +++ b/repak/src/entry.rs @@ -350,6 +350,7 @@ impl Entry { None => vec![0..data.len()], }; + #[cfg(feature = "compression")] macro_rules! decompress { ($decompressor: ty) => { for range in ranges { @@ -359,14 +360,18 @@ impl Entry { } match self.compression.map(|c| compression[c as usize]) { - None => buf.write_all(&data)?, + None | Some(Compression::None) => buf.write_all(&data)?, + #[cfg(feature = "compression")] Some(Compression::Zlib) => decompress!(flate2::read::ZlibDecoder<&[u8]>), + #[cfg(feature = "compression")] Some(Compression::Gzip) => decompress!(flate2::read::GzDecoder<&[u8]>), + #[cfg(feature = "compression")] Some(Compression::Zstd) => { for range in ranges { io::copy(&mut zstd::stream::read::Decoder::new(&data[range])?, buf)?; } } + #[cfg(feature = "oodle")] Some(Compression::Oodle) => { #[cfg(not(target_os = "windows"))] return Err(super::Error::Oodle); @@ -472,18 +477,25 @@ impl Entry { buf.write_all(&decompressed)?; } } - _ => todo!(), + #[cfg(not(feature = "oodle"))] + Some(Compression::Oodle) => return Err(super::Error::Oodle), + #[cfg(not(feature = "compression"))] + _ => return Err(super::Error::Compression), } buf.flush()?; Ok(()) } } +#[cfg(feature = "oodle")] use once_cell::sync::Lazy; +#[cfg(feature = "oodle")] static OODLE: Lazy> = Lazy::new(|| get_oodle().map_err(|e| e.to_string())); +#[cfg(feature = "oodle")] static OODLE_HASH: [u8; 20] = hex_literal::hex!("4bcc73614cb8fd2b0bce8d0f91ee5f3202d9d624"); +#[cfg(feature = "oodle")] fn get_oodle() -> Result { use sha1::{Digest, Sha1}; diff --git a/repak/src/error.rs b/repak/src/error.rs index affffae..a961fad 100644 --- a/repak/src/error.rs +++ b/repak/src/error.rs @@ -9,6 +9,13 @@ pub enum Error { #[error("expect 256 bit AES key as base64 or hex string")] Aes, + // feature errors + #[error("enable the compression feature to read compressed paks")] + Compression, + + #[error("enable the oodle feature to read oodle paks")] + Oodle, + // std errors #[error("io error: {0}")] Io(#[from] std::io::Error), @@ -22,6 +29,7 @@ pub enum Error { #[error("utf16 conversion: {0}")] Utf16(#[from] std::string::FromUtf16Error), + #[cfg(feature = "oodle")] #[error("ureq error: {0}")] Ureq(#[from] Box), // boxed because ureq::Error is quite large @@ -35,9 +43,6 @@ pub enum Error { #[error("found magic of {0:#x} instead of {:#x}", super::MAGIC)] Magic(u32), - #[error("Oodle compression only supported on Windows (or WINE)")] - Oodle, - #[error("Could not load oo2core_9_win64.dll")] OodleFailed, @@ -72,7 +77,7 @@ pub enum Error { OsString(std::ffi::OsString), #[error("{0}version unsupported or is encrypted (possibly missing --aes-key?)")] - UnsuportedOrEncrypted(String), + UnsupportedOrEncrypted(String), #[error("{0}")] Other(String), diff --git a/repak/src/lib.rs b/repak/src/lib.rs index 5b64447..e66c4e0 100644 --- a/repak/src/lib.rs +++ b/repak/src/lib.rs @@ -7,6 +7,9 @@ mod pak; pub use {error::*, pak::*}; +#[cfg(all(feature = "oodle", not(target_os = "windows")))] +compile_error!("Oodle compression only supported on Windows (or WINE)"); + pub const MAGIC: u32 = 0x5A6F12E1; #[derive( diff --git a/repak/src/pak.rs b/repak/src/pak.rs index 7b4a738..deaaec2 100644 --- a/repak/src/pak.rs +++ b/repak/src/pak.rs @@ -96,7 +96,7 @@ impl PakReader { Err(err) => writeln!(log, "trying version {} failed: {}", ver, err)?, } } - Err(super::Error::UnsuportedOrEncrypted(log)) + Err(super::Error::UnsupportedOrEncrypted(log)) } pub fn new( diff --git a/repak_cli/Cargo.toml b/repak_cli/Cargo.toml index 3a1709b..0c3ef14 100644 --- a/repak_cli/Cargo.toml +++ b/repak_cli/Cargo.toml @@ -19,6 +19,6 @@ indicatif = { version = "0.17.3", features = ["rayon"] } path-clean = "0.1.0" path-slash = "0.2.1" rayon = "1.6.1" -repak = { version = "0.1.7", path = "../repak" } +repak = { version = "0.1.7", path = "../repak", features = ["oodle"] } sha2 = "0.10.7" strum = { workspace = true }