Skip to content

Instantly share code, notes, and snippets.

@incertia
Created February 8, 2023 00:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save incertia/bbd9157e4293dbe0241754273af1585b to your computer and use it in GitHub Desktop.
Save incertia/bbd9157e4293dbe0241754273af1585b to your computer and use it in GitHub Desktop.
oodle network decompression in rust
use ffi_opaque::opaque;
opaque! {
struct OodleNetwork1UDP_StateCompacted;
struct OodleNetwork1UDP_State;
struct OodleNetwork1_Shared;
}
#[link(name = "oo2netlinux64", kind = "static")]
extern "C" {
fn OodleNetwork1UDP_State_Size() -> libc::intptr_t;
fn OodleNetwork1UDP_State_Uncompact_ForVersion(
to: *mut OodleNetwork1UDP_State,
from: *const OodleNetwork1UDP_StateCompacted,
version: i32
) -> bool;
fn OodleNetwork1_Shared_Size(htbits: i32) -> usize;
fn OodleNetwork1_Shared_SetWindow(
data: *mut OodleNetwork1_Shared,
htbits: i32,
window: *const libc::c_void,
window_size: i32
) -> ();
fn OodleNetwork1UDP_Decode(
state: *const OodleNetwork1UDP_State,
shared: *const OodleNetwork1_Shared,
comp: *const libc::c_void,
comp_len: libc::intptr_t,
raw: *mut libc::c_void,
raw_len: libc::intptr_t
) -> bool;
}
pub struct Oodle {
_dict: Vec<u8>,
state: *mut OodleNetwork1UDP_State,
shared: *mut OodleNetwork1_Shared,
}
unsafe impl Send for Oodle {}
unsafe impl Sync for Oodle {}
impl Oodle {
pub fn new(state: &[u8]) -> Option<Self> {
// magic number check
let magic = u32::from_le_bytes(state[..4].try_into().ok()?);
if magic != 0x11235801 {
return None;
}
let htbits = i32::from_le_bytes(state[8..12].try_into().ok()?);
let dict_size = u32::from_le_bytes(state[12..16].try_into().ok()?) as usize;
let version = i32::from_le_bytes(state[16..20].try_into().ok()?);
let _dict_complen = u32::from_le_bytes(state[20..24].try_into().ok()?);
let statecompacted_size = i32::from_le_bytes(state[24..28].try_into().ok()?) as usize;
let _statecompacted_complen = i32::from_le_bytes(state[28..32].try_into().ok()?);
let mut dict = Vec::with_capacity(dict_size);
let mut on1udpnew_compacted = Vec::with_capacity(statecompacted_size);
unsafe {
dict.set_len(dict_size);
dict.as_mut_slice().copy_from_slice(&state[32..32 + dict_size]);
on1udpnew_compacted.set_len(statecompacted_size as usize);
on1udpnew_compacted.as_mut_slice().copy_from_slice(&state[32 + dict_size..32 + dict_size + statecompacted_size]);
};
let state = unsafe { libc::malloc(OodleNetwork1UDP_State_Size() as usize) as *mut OodleNetwork1UDP_State };
let uncompact_result = unsafe {
OodleNetwork1UDP_State_Uncompact_ForVersion(
state,
on1udpnew_compacted.as_ptr() as *const OodleNetwork1UDP_StateCompacted,
version
)
};
if !uncompact_result {
return None;
}
let shared_size = unsafe { OodleNetwork1_Shared_Size(htbits) };
let shared = unsafe { libc::malloc(shared_size) as *mut OodleNetwork1_Shared };
unsafe {
OodleNetwork1_Shared_SetWindow(shared, htbits, dict.as_ptr() as *const libc::c_void, dict_size as i32);
}
Some(Self {
_dict: dict,
state,
shared,
})
}
pub fn decode(&self, comp: &[u8]) -> Option<Vec<u8>> {
match comp {
[o1, o2, o3, o4, data @ ..] => {
let out_len = u32::from_le_bytes([*o1, *o2, *o3, *o4]);
let mut out = Vec::with_capacity(out_len as usize);
let result = unsafe { OodleNetwork1UDP_Decode(
self.state,
self.shared,
data.as_ptr() as *const libc::c_void,
data.len() as isize,
out.as_mut_ptr() as *mut libc::c_void,
out_len as isize
) };
if result {
unsafe {
out.set_len(out_len as usize);
}
Some(out)
} else {
None
}
},
_ => None,
}
}
}
impl Drop for Oodle {
fn drop(&mut self) {
unsafe {
libc::free(self.shared as *mut libc::c_void);
libc::free(self.state as *mut libc::c_void);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment