mirror of
https://github.com/xavo95/repak.git
synced 2025-01-18 19:04:07 +00:00
Implement Oodle decompression (Windows only)
This commit is contained in:
parent
d3d0b23a31
commit
89abdf5297
2 changed files with 118 additions and 26 deletions
|
@ -13,6 +13,7 @@ flate2 = "1.0"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
sha1 = "0.10.5"
|
sha1 = "0.10.5"
|
||||||
strum = { workspace = true }
|
strum = { workspace = true }
|
||||||
|
libloading = "0.7.4"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
base64 = { workspace = true }
|
base64 = { workspace = true }
|
||||||
|
|
|
@ -335,41 +335,132 @@ impl Entry {
|
||||||
}
|
}
|
||||||
data.truncate(self.compressed as usize);
|
data.truncate(self.compressed as usize);
|
||||||
}
|
}
|
||||||
macro_rules! decompress {
|
|
||||||
($decompressor: ty) => {
|
let ranges = match &self.blocks {
|
||||||
match &self.blocks {
|
Some(blocks) => blocks
|
||||||
Some(blocks) => {
|
.iter()
|
||||||
for block in blocks {
|
.map(
|
||||||
io::copy(
|
|block| match version.version_major() >= VersionMajor::RelativeChunkOffsets {
|
||||||
&mut <$decompressor>::new(
|
|
||||||
&data[match version.version_major()
|
|
||||||
>= VersionMajor::RelativeChunkOffsets
|
|
||||||
{
|
|
||||||
true => {
|
true => {
|
||||||
(block.start - (data_offset - self.offset)) as usize
|
(block.start - (data_offset - self.offset)) as usize
|
||||||
..(block.end - (data_offset - self.offset)) as usize
|
..(block.end - (data_offset - self.offset)) as usize
|
||||||
}
|
}
|
||||||
false => {
|
false => {
|
||||||
(block.start - data_offset) as usize
|
(block.start - data_offset) as usize..(block.end - data_offset) as usize
|
||||||
..(block.end - data_offset) as usize
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
),
|
|
||||||
buf,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
io::copy(&mut flate2::read::ZlibDecoder::new(data.as_slice()), buf)?;
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
None => vec![0..data.len()],
|
||||||
|
};
|
||||||
|
|
||||||
|
macro_rules! decompress {
|
||||||
|
($decompressor: ty) => {
|
||||||
|
for range in ranges {
|
||||||
|
io::copy(&mut <$decompressor>::new(&data[range]), buf)?;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.compression.map(|c| compression[c as usize]) {
|
match self.compression.map(|c| compression[c as usize]) {
|
||||||
None => buf.write_all(&data)?,
|
None => buf.write_all(&data)?,
|
||||||
Some(Compression::Zlib) => decompress!(flate2::read::ZlibDecoder<&[u8]>),
|
Some(Compression::Zlib) => decompress!(flate2::read::ZlibDecoder<&[u8]>),
|
||||||
Some(Compression::Gzip) => decompress!(flate2::read::GzDecoder<&[u8]>),
|
Some(Compression::Gzip) => decompress!(flate2::read::GzDecoder<&[u8]>),
|
||||||
Some(Compression::Oodle) => todo!("Oodle compression"),
|
Some(Compression::Oodle) => {
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
return Err(super::Error::Other(
|
||||||
|
"Oodle compression only supported on Windows (or WINE)",
|
||||||
|
));
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
unsafe {
|
||||||
|
let lib = libloading::Library::new("oo2core_9_win64.dll").map_err(|_| {
|
||||||
|
super::Error::Other(
|
||||||
|
"Could not find oo2core_9_win64.dll for Oodle compression",
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
/*
|
||||||
|
let set_printf: libloading::Symbol<
|
||||||
|
unsafe extern "C" fn(
|
||||||
|
unsafe extern "C" fn(
|
||||||
|
i32,
|
||||||
|
*const std::ffi::c_char,
|
||||||
|
i32,
|
||||||
|
*const std::ffi::c_char,
|
||||||
|
...
|
||||||
|
) -> std::ffi::c_int,
|
||||||
|
),
|
||||||
|
> = lib.get(b"OodleCore_Plugins_SetPrintf").unwrap();
|
||||||
|
|
||||||
|
pub unsafe extern "C" fn printf(
|
||||||
|
a: i32,
|
||||||
|
b: *const std::ffi::c_char,
|
||||||
|
c: i32,
|
||||||
|
str: *const std::ffi::c_char,
|
||||||
|
mut args: ...
|
||||||
|
) -> std::ffi::c_int {
|
||||||
|
use printf_compat::{format, output};
|
||||||
|
let mut s = String::new();
|
||||||
|
let bytes_written = format(str, args.as_va_list(), output::fmt_write(&mut s));
|
||||||
|
print!("[OODLE]: {}", s);
|
||||||
|
bytes_written
|
||||||
|
}
|
||||||
|
|
||||||
|
set_printf(printf);
|
||||||
|
*/
|
||||||
|
|
||||||
|
let func: libloading::Symbol<
|
||||||
|
extern "C" fn(
|
||||||
|
compBuf: *mut u8,
|
||||||
|
compBufSize: usize,
|
||||||
|
rawBuf: *mut u8,
|
||||||
|
rawLen: usize,
|
||||||
|
fuzzSafe: u32,
|
||||||
|
checkCRC: u32,
|
||||||
|
verbosity: u32,
|
||||||
|
decBufBase: u64,
|
||||||
|
decBufSize: usize,
|
||||||
|
fpCallback: u64,
|
||||||
|
callbackUserData: u64,
|
||||||
|
decoderMemory: u64,
|
||||||
|
decoderMemorySize: usize,
|
||||||
|
threadPhase: u32,
|
||||||
|
) -> i32,
|
||||||
|
> = lib.get(b"OodleLZ_Decompress").unwrap();
|
||||||
|
|
||||||
|
let mut decompressed = vec![0; self.uncompressed as usize];
|
||||||
|
|
||||||
|
// merge all blocks into one (assuming no odd bytes) in between
|
||||||
|
// oodle does not like decompressing blocks individually
|
||||||
|
let buffer = &mut data[ranges[0].start..ranges[ranges.len() - 1].end];
|
||||||
|
let out = func(
|
||||||
|
buffer.as_mut_ptr(),
|
||||||
|
buffer.len(),
|
||||||
|
decompressed.as_mut_ptr(),
|
||||||
|
decompressed.len(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0, //verbose 3
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
3,
|
||||||
|
);
|
||||||
|
if out == 0 {
|
||||||
|
return Err(super::Error::Other("decompression failed"));
|
||||||
|
} else {
|
||||||
|
assert_eq!(
|
||||||
|
out as u64, self.uncompressed,
|
||||||
|
"Unexpected decompressed bytes"
|
||||||
|
);
|
||||||
|
buf.write_all(&decompressed)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
buf.flush()?;
|
buf.flush()?;
|
||||||
|
|
Loading…
Reference in a new issue