use core::ffi::c_void;
use crate::uefi_protocol::ProtocolInterface;
use mu_rust_helpers::uefi_decompress::{DecompressionAlgorithm, decompress_into_with_algo};
use r_efi::efi;
pub type GetInfoFn =
extern "efiapi" fn(*mut EfiDecompressProtocol, *mut c_void, u32, *mut u32, *mut u32) -> efi::Status;
pub type DecompressFn = extern "efiapi" fn(
*mut EfiDecompressProtocol,
*const c_void,
u32,
*mut c_void,
u32,
*mut c_void,
u32,
) -> efi::Status;
#[repr(C)]
pub struct EfiDecompressProtocol {
get_info: GetInfoFn,
decompress: DecompressFn,
}
impl EfiDecompressProtocol {
pub const fn new() -> Self {
Self { get_info: Self::get_info, decompress: Self::decompress }
}
pub const fn new_with(get_info: GetInfoFn, decompress: DecompressFn) -> Self {
Self { get_info, decompress }
}
extern "efiapi" fn get_info(
_: *mut EfiDecompressProtocol,
src: *mut c_void,
src_size: u32,
dst_size: *mut u32,
scratch_size: *mut u32,
) -> efi::Status {
if src.is_null() | dst_size.is_null() | scratch_size.is_null() {
return efi::Status::INVALID_PARAMETER;
}
if src_size < 8 {
return efi::Status::INVALID_PARAMETER;
}
let compressed_size = unsafe { src.cast::<u32>().read_unaligned() };
if (src_size < compressed_size + 8) || compressed_size.checked_add(8).is_none() {
return efi::Status::INVALID_PARAMETER;
}
unsafe { dst_size.write_volatile(src.cast::<u32>().add(1).read_unaligned()) };
unsafe { scratch_size.cast::<u32>().write_volatile(0) };
efi::Status::SUCCESS
}
extern "efiapi" fn decompress(
_: *mut EfiDecompressProtocol,
source_buffer: *const c_void,
source_size: u32,
destination_buffer: *mut c_void,
destination_size: u32,
_scratch_buffer: *mut c_void,
_scratch_size: u32,
) -> efi::Status {
if source_buffer.is_null() || destination_buffer.is_null() {
log_debug_assert!("EfiDecompressProtocol::decompress called with null pointer");
return efi::Status::INVALID_PARAMETER;
}
let src = unsafe { core::slice::from_raw_parts(source_buffer as *const u8, source_size as usize) };
let dst = unsafe { core::slice::from_raw_parts_mut(destination_buffer as *mut u8, destination_size as usize) };
match decompress_into_with_algo(src, dst, DecompressionAlgorithm::UefiDecompress) {
Ok(()) => efi::Status::SUCCESS,
Err(_) => efi::Status::INVALID_PARAMETER,
}
}
}
impl Default for EfiDecompressProtocol {
fn default() -> Self {
Self::new()
}
}
unsafe impl ProtocolInterface for EfiDecompressProtocol {
const PROTOCOL_GUID: crate::BinaryGuid = crate::BinaryGuid::from_string("D8117CFE-94A6-11D4-9A3A-0090273FC14D");
}