From ad22ba9b1a7be31a903516f622b4052c766b56cd Mon Sep 17 00:00:00 2001 From: Truman Kilen Date: Thu, 13 Apr 2023 02:01:19 -0500 Subject: [PATCH] Obtain oodle DLL automatically --- Cargo.toml | 1 + repak/Cargo.toml | 4 ++++ repak/src/entry.rs | 41 ++++++++++++++++++++++++++++++++++++++--- repak/src/error.rs | 12 +++++++++--- repak_cli/Cargo.toml | 2 +- 5 files changed, 53 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5871492..242f984 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ edition = "2021" [workspace.dependencies] aes = "0.8.2" base64 = "0.21.0" +hex = "0.4.3" strum = { version = "0.24", features = ["derive"] } # generated by 'cargo dist init' diff --git a/repak/Cargo.toml b/repak/Cargo.toml index 0a0f371..f4c2cf6 100644 --- a/repak/Cargo.toml +++ b/repak/Cargo.toml @@ -14,6 +14,10 @@ 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" [dev-dependencies] base64 = { workspace = true } diff --git a/repak/src/entry.rs b/repak/src/entry.rs index 95e2d28..97d7c8a 100644 --- a/repak/src/entry.rs +++ b/repak/src/entry.rs @@ -364,12 +364,15 @@ impl Entry { Some(Compression::Gzip) => decompress!(flate2::read::GzDecoder<&[u8]>), Some(Compression::Oodle) => { #[cfg(not(target_os = "windows"))] - return Err(super::Error::Oodle()); + return Err(super::Error::Oodle); #[cfg(target_os = "windows")] unsafe { - let lib = libloading::Library::new("oo2core_9_win64.dll") - .map_err(|_| super::Error::OodleMissing())?; + use std::ops::Deref; + let lib = match OODLE.deref() { + Ok(lib) => Ok(lib), + Err(e) => Err(super::Error::Other(e.to_string())), + }?; /* let set_printf: libloading::Symbol< @@ -459,6 +462,38 @@ impl Entry { } } +use once_cell::sync::Lazy; +static OODLE: Lazy> = + Lazy::new(|| get_oodle().map_err(|e| e.to_string())); +static OODLE_HASH: [u8; 20] = hex_literal::hex!("4bcc73614cb8fd2b0bce8d0f91ee5f3202d9d624"); + +fn get_oodle() -> Result { + use sha1::{Digest, Sha1}; + + let oodle = std::env::current_exe()?.with_file_name("oo2core_9_win64.dll"); + if !oodle.exists() { + let mut data = vec![]; + ureq::get("https://cdn.discordapp.com/attachments/817251677086285848/992648087371792404/oo2core_9_win64.dll") + .call().map_err(Box::new)? + .into_reader().read_to_end(&mut data)?; + + std::fs::write(&oodle, data)?; + } + + let mut hasher = Sha1::new(); + hasher.update(std::fs::read(&oodle)?); + let hash = hasher.finalize(); + (hash[..] == OODLE_HASH).then_some(()).ok_or_else(|| { + super::Error::Other(format!( + "oodle hash mismatch expected: {} got: {} ", + hex::encode(OODLE_HASH), + hex::encode(hash) + )) + })?; + + unsafe { libloading::Library::new(oodle) }.map_err(|_| super::Error::OodleFailed) +} + mod test { #[test] fn test_entry() { diff --git a/repak/src/error.rs b/repak/src/error.rs index d5ea333..a669106 100644 --- a/repak/src/error.rs +++ b/repak/src/error.rs @@ -19,6 +19,9 @@ pub enum Error { #[error("utf16 conversion: {0}")] Utf16(#[from] std::string::FromUtf16Error), + #[error("ureq error: {0}")] + Ureq(#[from] Box), // boxed because ureq::Error is quite large + #[error("bufwriter dereference: {0}")] IntoInner(#[from] std::io::IntoInnerError>>), @@ -30,10 +33,10 @@ pub enum Error { Magic(u32), #[error("Oodle compression only supported on Windows (or WINE)")] - Oodle(), + Oodle, - #[error("Could not find oo2core_9_win64.dll for Oodle compression")] - OodleMissing(), + #[error("Could not load oo2core_9_win64.dll")] + OodleFailed, #[error("No entry found at {0}")] MissingEntry(String), @@ -67,6 +70,9 @@ pub enum Error { #[error("version unsupported or is encrypted (possibly missing --aes-key?)")] UnsuportedOrEncrypted, + + #[error("{0}")] + Other(String), } impl std::fmt::Debug for Error { diff --git a/repak_cli/Cargo.toml b/repak_cli/Cargo.toml index f42f348..9fc13c7 100644 --- a/repak_cli/Cargo.toml +++ b/repak_cli/Cargo.toml @@ -14,7 +14,7 @@ path = "src/main.rs" aes = { workspace = true } base64 = { workspace = true } clap = { version = "4.1.4", features = ["derive"] } -hex = "0.4.3" +hex = { workspace = true } indicatif = { version = "0.17.3", features = ["rayon"] } path-clean = "0.1.0" path-slash = "0.2.1"