use std::{ffi::OsStr, io};
use windows_sys::Win32::{
Foundation::ERROR_SUCCESS,
NetworkManagement::WindowsFilteringPlatform::{
FWP_BYTE_BLOB, FwpmFreeMemory0, FwpmGetAppIdFromFileName0,
},
};
use crate::util::string_to_null_terminated_utf16;
pub struct OwnedByteBlob {
inner: InnerBlob,
}
enum InnerBlob {
Pointer {
blob: *mut FWP_BYTE_BLOB,
},
Vec {
blob: FWP_BYTE_BLOB,
_buf: Box<[u8]>,
},
}
impl OwnedByteBlob {
pub unsafe fn from_raw(blob: *mut FWP_BYTE_BLOB) -> Self {
Self {
inner: InnerBlob::Pointer { blob },
}
}
pub fn as_ptr(&self) -> *const FWP_BYTE_BLOB {
match &self.inner {
InnerBlob::Pointer { blob } => *blob,
InnerBlob::Vec { blob, .. } => blob,
}
}
}
impl<T: AsRef<[u8]>> From<T> for OwnedByteBlob {
fn from(value: T) -> Self {
let value: Box<[u8]> = Box::from(value.as_ref());
let blob = FWP_BYTE_BLOB {
data: value.as_ptr() as _,
size: u32::try_from(value.len()).expect("blob too large"),
};
OwnedByteBlob {
inner: InnerBlob::Vec { blob, _buf: value },
}
}
}
impl Drop for OwnedByteBlob {
fn drop(&mut self) {
if let InnerBlob::Pointer { mut blob } = self.inner {
unsafe { FwpmFreeMemory0(&mut blob as *mut _ as *mut _) };
}
}
}
pub fn app_id_from_filename(app_path: impl AsRef<OsStr>) -> io::Result<OwnedByteBlob> {
let path: Vec<u16> = string_to_null_terminated_utf16(app_path);
let mut blob = std::ptr::null_mut();
let status = unsafe { FwpmGetAppIdFromFileName0(path.as_ptr(), &mut blob) };
if status != ERROR_SUCCESS {
return Err(io::Error::from_raw_os_error(status as i32));
}
Ok(unsafe { OwnedByteBlob::from_raw(blob) })
}