use crate::error::GmsslError;
use libc::{c_char, c_int, c_void, size_t, FILE};
use std::ffi::CString;
use std::io;
use std::ptr;
pub(crate) unsafe fn file_from_bytes(data: &[u8]) -> Result<*mut FILE, GmsslError> {
let mode = CString::new("rb").unwrap();
let fp = libc::fmemopen(data.as_ptr() as *mut c_void, data.len(), mode.as_ptr());
if fp.is_null() {
Err(GmsslError::IoError(io::Error::last_os_error()))
} else {
Ok(fp)
}
}
pub(crate) unsafe fn collect_to_bytes<F>(writer: F) -> Result<Vec<u8>, GmsslError>
where
F: FnOnce(*mut FILE) -> c_int,
{
let mut buf: *mut c_char = ptr::null_mut();
let mut size: size_t = 0;
let _mode = CString::new("wb").unwrap();
let fp = libc::open_memstream(&mut buf, &mut size);
if fp.is_null() {
return Err(GmsslError::IoError(io::Error::last_os_error()));
}
let ret = writer(fp);
libc::fclose(fp);
if ret != 1 {
if !buf.is_null() {
libc::free(buf as *mut c_void);
}
return Err(GmsslError::LibraryError("PEM write failed"));
}
let result = if size > 0 && !buf.is_null() {
std::slice::from_raw_parts(buf as *const u8, size).to_vec()
} else {
Vec::new()
};
libc::free(buf as *mut c_void);
Ok(result)
}
pub(crate) unsafe fn file_open_read(path: &str) -> Result<*mut FILE, GmsslError> {
let c_path = CString::new(path).map_err(|_| {
GmsslError::InvalidInput("path contains NUL byte")
})?;
let c_mode = CString::new("rb").unwrap();
let fp = libc::fopen(c_path.as_ptr(), c_mode.as_ptr());
if fp.is_null() {
Err(GmsslError::IoError(io::Error::last_os_error()))
} else {
Ok(fp)
}
}
pub(crate) unsafe fn file_open_write(path: &str) -> Result<*mut FILE, GmsslError> {
let c_path = CString::new(path).map_err(|_| {
GmsslError::InvalidInput("path contains NUL byte")
})?;
let c_mode = CString::new("wb").unwrap();
let fp = libc::fopen(c_path.as_ptr(), c_mode.as_ptr());
if fp.is_null() {
Err(GmsslError::IoError(io::Error::last_os_error()))
} else {
Ok(fp)
}
}
pub(crate) fn read_pem_data<F>(pem_data: &[u8], f: F) -> Result<c_int, GmsslError>
where
F: FnOnce(*mut FILE) -> c_int,
{
unsafe {
let fp = file_from_bytes(pem_data)?;
let ret = f(fp);
libc::fclose(fp);
Ok(ret)
}
}
pub(crate) unsafe fn collect_der<F>(max_size: usize, f: F) -> Result<Vec<u8>, GmsslError>
where
F: FnOnce(*mut *mut u8, *mut size_t) -> c_int,
{
let mut buf = vec![0u8; max_size];
let start = buf.as_mut_ptr();
let mut ptr: *mut u8 = start;
let mut len: size_t = max_size;
let ret = f(&mut ptr, &mut len);
if ret != 1 {
return Err(GmsslError::LibraryError("DER encoding failed"));
}
let written = (ptr as usize).saturating_sub(start as usize);
buf.truncate(written);
Ok(buf)
}
pub(crate) unsafe fn parse_der<T, F>(data: &[u8], f: F) -> Result<T, GmsslError>
where
F: FnOnce(*mut T, *mut *const u8, *mut size_t) -> c_int,
{
let mut result = std::mem::MaybeUninit::<T>::uninit();
let mut ptr: *const u8 = data.as_ptr();
let mut len: size_t = data.len();
let ret = f(result.as_mut_ptr(), &mut ptr, &mut len);
if ret != 1 {
return Err(GmsslError::LibraryError("DER decoding failed"));
}
Ok(result.assume_init())
}