add compression and oodle features

This commit is contained in:
spuds 2023-08-16 22:13:03 +01:00
parent 03dd3a63ed
commit f2c2255d53
No known key found for this signature in database
GPG key ID: 0B6CA6068E827C8F
6 changed files with 40 additions and 15 deletions

View file

@ -6,19 +6,24 @@ license.workspace = true
version.workspace = true version.workspace = true
edition.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] [dependencies]
byteorder = "1.4" byteorder = "1.4"
aes = "0.8" aes = "0.8"
flate2 = "1.0" flate2 = { version = "1.0", optional = true }
zstd = { version = "0.12", optional = true }
thiserror = "1.0" thiserror = "1.0"
sha1 = "0.10.5" sha1 = "0.10.5"
strum = { workspace = true } strum = { workspace = true }
libloading = "0.7.4" libloading = { version = "0.7", optional = true }
ureq = "2.6.2" ureq = { version = "2.6", optional = true }
hex-literal = "0.4.1" once_cell = { version = "1.17", optional = true}
hex = { workspace = true } hex-literal = { version = "0.4", optional = true }
once_cell = "1.17.1" hex = { workspace = true, optional = true }
zstd = "0.12.3"
[dev-dependencies] [dev-dependencies]
base64 = { workspace = true } base64 = { workspace = true }

View file

@ -350,6 +350,7 @@ impl Entry {
None => vec![0..data.len()], None => vec![0..data.len()],
}; };
#[cfg(feature = "compression")]
macro_rules! decompress { macro_rules! decompress {
($decompressor: ty) => { ($decompressor: ty) => {
for range in ranges { for range in ranges {
@ -359,14 +360,18 @@ impl Entry {
} }
match self.compression.map(|c| compression[c as usize]) { 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]>), Some(Compression::Zlib) => decompress!(flate2::read::ZlibDecoder<&[u8]>),
#[cfg(feature = "compression")]
Some(Compression::Gzip) => decompress!(flate2::read::GzDecoder<&[u8]>), Some(Compression::Gzip) => decompress!(flate2::read::GzDecoder<&[u8]>),
#[cfg(feature = "compression")]
Some(Compression::Zstd) => { Some(Compression::Zstd) => {
for range in ranges { for range in ranges {
io::copy(&mut zstd::stream::read::Decoder::new(&data[range])?, buf)?; io::copy(&mut zstd::stream::read::Decoder::new(&data[range])?, buf)?;
} }
} }
#[cfg(feature = "oodle")]
Some(Compression::Oodle) => { Some(Compression::Oodle) => {
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
return Err(super::Error::Oodle); return Err(super::Error::Oodle);
@ -472,18 +477,25 @@ impl Entry {
buf.write_all(&decompressed)?; 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()?; buf.flush()?;
Ok(()) Ok(())
} }
} }
#[cfg(feature = "oodle")]
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
#[cfg(feature = "oodle")]
static OODLE: Lazy<Result<libloading::Library, String>> = static OODLE: Lazy<Result<libloading::Library, String>> =
Lazy::new(|| get_oodle().map_err(|e| e.to_string())); Lazy::new(|| get_oodle().map_err(|e| e.to_string()));
#[cfg(feature = "oodle")]
static OODLE_HASH: [u8; 20] = hex_literal::hex!("4bcc73614cb8fd2b0bce8d0f91ee5f3202d9d624"); static OODLE_HASH: [u8; 20] = hex_literal::hex!("4bcc73614cb8fd2b0bce8d0f91ee5f3202d9d624");
#[cfg(feature = "oodle")]
fn get_oodle() -> Result<libloading::Library, super::Error> { fn get_oodle() -> Result<libloading::Library, super::Error> {
use sha1::{Digest, Sha1}; use sha1::{Digest, Sha1};

View file

@ -9,6 +9,13 @@ pub enum Error {
#[error("expect 256 bit AES key as base64 or hex string")] #[error("expect 256 bit AES key as base64 or hex string")]
Aes, 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 // std errors
#[error("io error: {0}")] #[error("io error: {0}")]
Io(#[from] std::io::Error), Io(#[from] std::io::Error),
@ -22,6 +29,7 @@ pub enum Error {
#[error("utf16 conversion: {0}")] #[error("utf16 conversion: {0}")]
Utf16(#[from] std::string::FromUtf16Error), Utf16(#[from] std::string::FromUtf16Error),
#[cfg(feature = "oodle")]
#[error("ureq error: {0}")] #[error("ureq error: {0}")]
Ureq(#[from] Box<ureq::Error>), // boxed because ureq::Error is quite large Ureq(#[from] Box<ureq::Error>), // 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)] #[error("found magic of {0:#x} instead of {:#x}", super::MAGIC)]
Magic(u32), Magic(u32),
#[error("Oodle compression only supported on Windows (or WINE)")]
Oodle,
#[error("Could not load oo2core_9_win64.dll")] #[error("Could not load oo2core_9_win64.dll")]
OodleFailed, OodleFailed,
@ -72,7 +77,7 @@ pub enum Error {
OsString(std::ffi::OsString), OsString(std::ffi::OsString),
#[error("{0}version unsupported or is encrypted (possibly missing --aes-key?)")] #[error("{0}version unsupported or is encrypted (possibly missing --aes-key?)")]
UnsuportedOrEncrypted(String), UnsupportedOrEncrypted(String),
#[error("{0}")] #[error("{0}")]
Other(String), Other(String),

View file

@ -7,6 +7,9 @@ mod pak;
pub use {error::*, 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; pub const MAGIC: u32 = 0x5A6F12E1;
#[derive( #[derive(

View file

@ -96,7 +96,7 @@ impl PakReader {
Err(err) => writeln!(log, "trying version {} failed: {}", ver, err)?, Err(err) => writeln!(log, "trying version {} failed: {}", ver, err)?,
} }
} }
Err(super::Error::UnsuportedOrEncrypted(log)) Err(super::Error::UnsupportedOrEncrypted(log))
} }
pub fn new<R: Read + Seek>( pub fn new<R: Read + Seek>(

View file

@ -19,6 +19,6 @@ indicatif = { version = "0.17.3", features = ["rayon"] }
path-clean = "0.1.0" path-clean = "0.1.0"
path-slash = "0.2.1" path-slash = "0.2.1"
rayon = "1.6.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" sha2 = "0.10.7"
strum = { workspace = true } strum = { workspace = true }