From 6c0ef1ce7b4bbdd1079ed919d8043b4dcf69ebd7 Mon Sep 17 00:00:00 2001 From: spuds <71292624+bananaturtlesandwich@users.noreply.github.com> Date: Wed, 20 Sep 2023 08:02:16 +0100 Subject: [PATCH] download in repak-cli --- Cargo.toml | 2 +- repak/Cargo.toml | 7 ++--- repak/src/lib.rs | 3 +- repak_cli/Cargo.toml | 8 +++++- repak_cli/src/main.rs | 67 ++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 75 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 63d145d..41d7c06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,8 @@ edition = "2021" [workspace.dependencies] aes = "0.8.2" base64 = "0.21.0" -hex = "0.4.3" strum = { version = "0.24", features = ["derive"] } +sha1 = "0.10" # generated by 'cargo dist init' [profile.dist] diff --git a/repak/Cargo.toml b/repak/Cargo.toml index c149198..a7b66c2 100644 --- a/repak/Cargo.toml +++ b/repak/Cargo.toml @@ -14,16 +14,13 @@ encryption = ["dep:aes"] [dependencies] byteorder = "1.4" -aes = { version = "0.8", optional = true } +aes = { workspace = true, optional = true } flate2 = { version = "1.0", optional = true } zstd = { version = "0.12", optional = true } thiserror = "1.0" -sha1 = "0.10.5" +sha1 = { workspace = true } strum = { workspace = true } [dev-dependencies] base64 = { workspace = true } paste = "1.0.11" - -[package.metadata.cargo-all-features] -denylist = ["oodle"] diff --git a/repak/src/lib.rs b/repak/src/lib.rs index eabf15c..9884bfe 100644 --- a/repak/src/lib.rs +++ b/repak/src/lib.rs @@ -9,7 +9,8 @@ pub use {error::*, pak::*}; pub const MAGIC: u32 = 0x5A6F12E1; -type DECOMPRESS = fn( +#[cfg(feature = "oodle")] +pub type DECOMPRESS = fn( compBuf: *mut u8, compBufSize: usize, rawBuf: *mut u8, diff --git a/repak_cli/Cargo.toml b/repak_cli/Cargo.toml index b31338b..b8c9f71 100644 --- a/repak_cli/Cargo.toml +++ b/repak_cli/Cargo.toml @@ -12,6 +12,12 @@ path = "src/main.rs" [target.'cfg(windows)'.dependencies] repak = { path = "../repak", features = ["oodle"] } +sha1 = { workspace = true } +ureq = "2.6" +once_cell = "1.17" +hex-literal = "0.4" +libloading = "0.7" + [target.'cfg(not(windows))'.dependencies] repak = { path = "../repak" } @@ -19,7 +25,7 @@ repak = { path = "../repak" } aes = { workspace = true } base64 = { workspace = true } clap = { version = "4.1.4", features = ["derive"] } -hex = { workspace = true } +hex = "0.4.3" indicatif = { version = "0.17.3", features = ["rayon"] } path-clean = "0.1.0" path-slash = "0.2.1" diff --git a/repak_cli/src/main.rs b/repak_cli/src/main.rs index fcd8b9f..6e798c1 100644 --- a/repak_cli/src/main.rs +++ b/repak_cli/src/main.rs @@ -118,7 +118,7 @@ enum Action { Info(ActionInfo), /// List .pak files List(ActionList), - /// List .pka files and the SHA256 of their contents. Useful for finding differences between paks + /// List .pak files and the SHA256 of their contents. Useful for finding differences between paks HashList(ActionHashList), /// Unpack .pak file Unpack(ActionUnpack), @@ -248,6 +248,12 @@ fn hash_list(aes_key: Option, action: ActionHashList) -> Result<(), let hashes: std::sync::Arc, Vec>>> = Default::default(); + use std::ops::Deref; + let lib = match OODLE.deref() { + Ok(lib) => lib, + Err(e) => return Err(repak::Error::Other(e.clone())), + }; + let oodle_decompress = unsafe { lib.get(b"OodleLZ_Decompress") }.unwrap(); full_paths.par_iter().zip(stripped).try_for_each_init( || (hashes.clone(), File::open(&action.input)), @@ -255,10 +261,11 @@ fn hash_list(aes_key: Option, action: ActionHashList) -> Result<(), use sha2::Digest; let mut hasher = sha2::Sha256::new(); - pak.read_file( + pak.read_file_with_oodle( path, &mut BufReader::new(file.as_ref().unwrap()), &mut hasher, + &oodle_decompress, )?; let hash = hasher.finalize(); hashes @@ -354,6 +361,12 @@ fn unpack(aes_key: Option, action: ActionUnpack) -> Result<(), repa let progress = indicatif::ProgressBar::new(entries.len() as u64) .with_style(indicatif::ProgressStyle::with_template(STYLE).unwrap()); + use std::ops::Deref; + let lib = match OODLE.deref() { + Ok(lib) => lib, + Err(e) => return Err(repak::Error::Other(e.clone())), + }; + let decompress = unsafe { lib.get(b"OodleLZ_Decompress") }.unwrap(); entries.par_iter().try_for_each_init( || (progress.clone(), File::open(input)), |(progress, file), entry| -> Result<(), repak::Error> { @@ -361,13 +374,14 @@ fn unpack(aes_key: Option, action: ActionUnpack) -> Result<(), repa progress.println(format!("unpacking {}", entry.entry_path)); } fs::create_dir_all(&entry.out_dir)?; - pak.read_file( + pak.read_file_with_oodle( &entry.entry_path, &mut BufReader::new( file.as_ref() .map_err(|e| repak::Error::Other(format!("error reading pak: {e}")))?, ), &mut fs::File::create(&entry.out_path)?, + &decompress, )?; progress.inc(1); Ok(()) @@ -463,6 +477,51 @@ fn get(aes_key: Option, args: ActionGet) -> Result<(), repak::Error })?; use std::io::Write; - std::io::stdout().write_all(&pak.get(&file.to_slash_lossy(), &mut reader)?)?; + use std::ops::Deref; + let lib = match OODLE.deref() { + Ok(lib) => lib, + Err(e) => return Err(repak::Error::Other(e.clone())), + }; + std::io::stdout().write_all(&pak.get_with_oodle( + &file.to_slash_lossy(), + &mut reader, + &unsafe { lib.get(b"OodleLZ_Decompress") }.unwrap(), + )?)?; Ok(()) } + +#[cfg(windows)] +use once_cell::sync::Lazy; +#[cfg(windows)] +static OODLE: Lazy> = + Lazy::new(|| get_oodle().map_err(|e| e.to_string())); +#[cfg(windows)] +static OODLE_HASH: [u8; 20] = hex_literal::hex!("4bcc73614cb8fd2b0bce8d0f91ee5f3202d9d624"); + +#[cfg(windows)] +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(|e| repak::Error::Other(e.to_string()))? + .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(|| { + repak::Error::Other(format!( + "oodle hash mismatch expected: {} got: {} ", + hex::encode(OODLE_HASH), + hex::encode(hash) + )) + })?; + + unsafe { libloading::Library::new(oodle) }.map_err(|_| repak::Error::OodleFailed) +}