diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index b091620..2a7ecbb 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -5,3 +5,7 @@ === Added - implement decompilation for `.strings` files + +=== Fixed + +- fix issue where some bundles couldn't be opened anymore diff --git a/lib/sdk/src/bundle/mod.rs b/lib/sdk/src/bundle/mod.rs index ca1fd40..86b1e35 100644 --- a/lib/sdk/src/bundle/mod.rs +++ b/lib/sdk/src/bundle/mod.rs @@ -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,24 +198,30 @@ impl Bundle { let mut compressed_buffer = vec![0u8; chunk_size]; r.read_exact(&mut compressed_buffer).await?; - // 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( - &compressed_buffer, - OodleLZ_FuzzSafe::No, - OodleLZ_CheckCRC::No, - )?; - - if unpacked_size_tracked < CHUNK_SIZE { - raw_buffer.resize(unpacked_size_tracked, 0); + if format >= BundleFormat::F8 && chunk_size == CHUNK_SIZE { + decompressed.append(&mut compressed_buffer); } else { - unpacked_size_tracked -= CHUNK_SIZE; + // 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( + &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); + } else { + unpacked_size_tracked -= CHUNK_SIZE; + } + + tracing::trace!(raw_size = raw_buffer.len()); + + decompressed.append(&mut raw_buffer); } - - tracing::trace!(raw_size = raw_buffer.len()); - - decompressed.append(&mut raw_buffer); Ok(()) } .instrument(span) diff --git a/lib/sdk/src/oodle/mod.rs b/lib/sdk/src/oodle/mod.rs index 3f7303c..0dbb114 100644 --- a/lib/sdk/src/oodle/mod.rs +++ b/lib/sdk/src/oodle/mod.rs @@ -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 = 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 { + unsafe { + let f: Symbol = + self.lib.get(b"OodleLZ_GetDecodeBufferSize\0")?; + + let size = f(COMPRESSOR, raw_size, corruption_possible); + Ok(size) + } + } } diff --git a/lib/sdk/src/oodle/types.rs b/lib/sdk/src/oodle/types.rs index ee6c3fb..5d306f8 100644 --- a/lib/sdk/src/oodle/types.rs +++ b/lib/sdk/src/oodle/types.rs @@ -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;