fix: Decompression doesn't work for some bundles

It seems that with the new bundle format, chunks are stored uncompressed
when their compressed size equals the chunk size.
This commit is contained in:
Lucas Schwiderski 2022-12-28 19:41:47 +01:00
parent 2219f4fab3
commit c2ed9275b0
Signed by: lucas
GPG key ID: AA12679AAA6DF4D8
4 changed files with 54 additions and 24 deletions

View file

@ -5,3 +5,7 @@
=== Added
- implement decompilation for `.strings` files
=== Fixed
- fix issue where some bundles couldn't be opened anymore

View file

@ -20,7 +20,7 @@ pub(crate) mod file;
pub use file::BundleFile;
#[derive(Clone, Copy, Debug, PartialEq)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
enum BundleFormat {
F7,
F8,
@ -198,14 +198,19 @@ impl Bundle {
let mut compressed_buffer = vec![0u8; chunk_size];
r.read_exact(&mut compressed_buffer).await?;
if format >= BundleFormat::F8 && chunk_size == CHUNK_SIZE {
decompressed.append(&mut compressed_buffer);
} else {
// TODO: Optimize to not reallocate?
let ctx = ctx.read().await;
let oodle_lib = ctx.oodle.as_ref().unwrap();
let mut raw_buffer = oodle_lib.decompress(
let mut raw_buffer = oodle_lib
.decompress(
&compressed_buffer,
OodleLZ_FuzzSafe::No,
OodleLZ_CheckCRC::No,
)?;
)
.wrap_err_with(|| format!("failed to decompress chunk {chunk_index}"))?;
if unpacked_size_tracked < CHUNK_SIZE {
raw_buffer.resize(unpacked_size_tracked, 0);
@ -216,6 +221,7 @@ impl Bundle {
tracing::trace!(raw_size = raw_buffer.len());
decompressed.append(&mut raw_buffer);
}
Ok(())
}
.instrument(span)

View file

@ -11,6 +11,8 @@ use types::*;
// Hardcoded chunk size of Bitsquid's bundle compression
pub const CHUNK_SIZE: usize = 512 * 1024;
pub const COMPRESSOR: OodleLZ_Compressor = OodleLZ_Compressor::Kraken;
pub const LEVEL: OodleLZ_CompressionLevel = OodleLZ_CompressionLevel::Optimal2;
pub struct Oodle {
lib: Library,
@ -80,7 +82,7 @@ impl Oodle {
};
if ret == 0 {
eyre::bail!("Failed to decompress chunk.");
eyre::bail!("Decompression failed.");
}
Ok(out)
@ -97,18 +99,15 @@ impl Oodle {
// TODO: Query oodle for buffer size
let mut out = vec![0u8; CHUNK_SIZE];
let compressor = OodleLZ_Compressor::Kraken;
let level = OodleLZ_CompressionLevel::Optimal2;
let ret = unsafe {
let compress: Symbol<OodleLZ_Compress> = self.lib.get(b"OodleLZ_Compress\0")?;
compress(
compressor,
COMPRESSOR,
raw.as_ptr() as *const _,
raw.len(),
out.as_mut_ptr() as *mut _,
level,
LEVEL,
ptr::null_mut(),
0,
ptr::null_mut(),
@ -120,11 +119,25 @@ impl Oodle {
tracing::debug!(compressed_size = ret, "Compressed chunk");
if ret == 0 {
eyre::bail!("Failed to compress chunk.");
eyre::bail!("Compression failed.");
}
out.resize(ret as usize, 0);
Ok(out)
}
pub fn get_decode_buffer_size(
&self,
raw_size: usize,
corruption_possible: bool,
) -> Result<usize> {
unsafe {
let f: Symbol<OodleLZ_GetDecodeBufferSize> =
self.lib.get(b"OodleLZ_GetDecodeBufferSize\0")?;
let size = f(COMPRESSOR, raw_size, corruption_possible);
Ok(size)
}
}
}

View file

@ -179,6 +179,13 @@ pub type OodleLZ_Compress = extern "C" fn(
scratch_size: c_size_t,
) -> c_ulonglong;
#[allow(non_camel_case_types)]
pub type OodleLZ_GetDecodeBufferSize = extern "C" fn(
compressor: OodleLZ_Compressor,
raw_size: c_size_t,
corruption_possible: bool,
) -> c_size_t;
#[allow(non_camel_case_types)]
pub type OodleCore_Plugins_SetPrintf =
extern "C" fn(f: t_fp_OodleCore_Plugin_Printf) -> t_fp_OodleCore_Plugin_Printf;