use std::alloc::Layout;
use std::alloc::{self};
use std::os::raw::c_void;
use std::ptr;
const ALIGN: usize = std::mem::align_of::<usize>();
fn align_up(size: usize, align: usize) -> usize {
(size + align - 1) & !(align - 1)
}
pub extern "C" fn zalloc(
_ptr: *mut c_void,
items: u32,
item_size: u32,
) -> *mut c_void {
let size = match (items as usize)
.checked_mul(item_size as usize)
.map(|size| align_up(size, ALIGN))
.and_then(|i| i.checked_add(std::mem::size_of::<usize>()))
{
Some(i) => i,
None => return ptr::null_mut(),
};
let layout = match Layout::from_size_align(size, ALIGN) {
Ok(layout) => layout,
Err(_) => return ptr::null_mut(),
};
unsafe {
let ptr = alloc::alloc(layout) as *mut usize;
if ptr.is_null() {
return ptr as *mut c_void;
}
*ptr = size;
ptr.add(1) as *mut c_void
}
}
pub extern "C" fn zfree(_ptr: *mut c_void, address: *mut c_void) {
unsafe {
let ptr = (address as *mut usize).offset(-1);
let size = *ptr;
let layout = Layout::from_size_align_unchecked(size, ALIGN);
alloc::dealloc(ptr as *mut u8, layout)
}
}
pub extern "C" fn brotli_alloc(
_opaque: *mut brotli::ffi::broccoli::c_void,
size: usize,
) -> *mut brotli::ffi::broccoli::c_void {
let total_size = match size
.checked_add(std::mem::size_of::<usize>())
.map(|size| align_up(size, ALIGN))
{
Some(i) => i,
None => return ptr::null_mut(),
};
let layout = match Layout::from_size_align(total_size, ALIGN) {
Ok(layout) => layout,
Err(_) => return ptr::null_mut(),
};
unsafe {
let ptr = alloc::alloc(layout) as *mut usize;
if ptr.is_null() {
return ptr as *mut brotli::ffi::broccoli::c_void;
}
*ptr = total_size;
ptr.add(1) as *mut brotli::ffi::broccoli::c_void
}
}
pub extern "C" fn brotli_free(
_opaque: *mut brotli::ffi::broccoli::c_void,
address: *mut brotli::ffi::broccoli::c_void,
) {
if address.is_null() {
return;
}
unsafe {
let ptr = (address as *mut usize).offset(-1);
let size = *ptr;
let layout = Layout::from_size_align_unchecked(size, ALIGN);
alloc::dealloc(ptr as *mut u8, layout)
}
}