use std::{
ffi::{c_int, c_ulong, c_void},
io::Write,
ptr::null_mut,
slice,
};
use crate::{PdfiumResult, pdfium_types::FPDF_FILEWRITE};
#[repr(C)]
pub struct PdfiumWriter<W: Write + 'static> {
custom_file_write: CustomFileWrite<W>,
pdfium_writer: Box<W>,
}
impl<W: Write + 'static> PdfiumWriter<W> {
pub(crate) fn new(writer: W) -> Box<Self> {
let custom_file_write = CustomFileWrite {
version: 1,
write_block: Some(write_callback),
pdfium_writer: null_mut(),
};
let mut pdfium_writer = Box::new(PdfiumWriter {
custom_file_write,
pdfium_writer: Box::new(writer),
});
let pdfium_writer_ptr: *const PdfiumWriter<W> = pdfium_writer.as_ref();
pdfium_writer.as_mut().custom_file_write.pdfium_writer =
pdfium_writer_ptr as *mut PdfiumWriter<W>;
pdfium_writer
}
pub(crate) fn flush(&mut self) -> PdfiumResult<()> {
self.pdfium_writer.flush()?;
Ok(())
}
pub(crate) fn take_writer(self) -> Box<W> {
self.pdfium_writer
}
}
impl<W: Write + 'static> From<&mut PdfiumWriter<W>> for *mut FPDF_FILEWRITE {
fn from(value: &mut PdfiumWriter<W>) -> Self {
&mut value.custom_file_write as *mut CustomFileWrite<W> as *mut FPDF_FILEWRITE
}
}
#[repr(C)]
struct CustomFileWrite<W: Write + 'static> {
pub version: ::std::os::raw::c_int,
pub write_block: Option<
unsafe extern "C" fn(
p_this: *mut CustomFileWrite<W>,
p_data: *const c_void,
size: c_ulong,
) -> c_int,
>,
pdfium_writer: *mut PdfiumWriter<W>,
}
extern "C" fn write_callback(
p_this: *mut CustomFileWrite<impl Write + 'static>,
p_data: *const c_void,
size: c_ulong,
) -> c_int {
unsafe {
match (*(*p_this).pdfium_writer)
.pdfium_writer
.write_all(slice::from_raw_parts(p_data as *const u8, size as usize))
{
Ok(()) => 1,
Err(_) => 0,
}
}
}