use std::{
ffi::{c_int, c_uchar, c_ulong, c_void},
io::{Read, Seek, SeekFrom},
ptr::null_mut,
slice,
};
use crate::pdfium_types::FPDF_FILEACCESS;
#[repr(C)]
pub struct PdfiumReader {
file_access_ptr: FPDF_FILEACCESS,
reader: Box<dyn PdfiumReaderExt>, }
impl PdfiumReader {
pub(crate) fn new<R: Read + Seek + 'static>(mut reader: R) -> Box<Self> {
let content_length = reader.seek(SeekFrom::End(0)).unwrap_or(0) as c_ulong;
let file_access = FPDF_FILEACCESS {
m_FileLen: content_length,
m_GetBlock: Some(read_callback),
m_Param: null_mut(),
};
let mut pdfium_reader = Box::new(PdfiumReader {
file_access_ptr: file_access,
reader: Box::new(reader),
});
let pdfium_reader_ptr: *const PdfiumReader = pdfium_reader.as_ref();
pdfium_reader.as_mut().file_access_ptr.m_Param = pdfium_reader_ptr as *mut c_void;
pdfium_reader
}
}
impl From<&mut PdfiumReader> for *mut FPDF_FILEACCESS {
fn from(value: &mut PdfiumReader) -> Self {
&mut value.file_access_ptr as *mut FPDF_FILEACCESS
}
}
trait PdfiumReaderExt: Read + Seek {}
impl<R: Read + Seek> PdfiumReaderExt for R {}
extern "C" fn read_callback(
param: *mut c_void,
position: c_ulong,
buf: *mut c_uchar,
size: c_ulong,
) -> c_int {
let pdfium_reader: &mut PdfiumReader = unsafe { &mut *(param as *mut PdfiumReader) };
let reader = pdfium_reader.reader.as_mut();
#[allow(clippy::unnecessary_cast)]
let result = match reader.seek(SeekFrom::Start(position as u64)) {
Ok(_) => reader
.read(unsafe { slice::from_raw_parts_mut(buf, size as usize) })
.unwrap_or(0),
Err(_) => 0,
};
result as c_int
}