use crate::bindgen::FPDF_SIGNATURE;
use crate::error::{PdfiumError, PdfiumInternalError};
use crate::pdfium::PdfiumLibraryBindingsAccessor;
use crate::utils::mem::create_byte_buffer;
use crate::utils::utf16le::get_string_from_pdfium_utf16le_bytes;
use std::ffi::{c_uint, CString};
use std::marker::PhantomData;
use std::os::raw::{c_char, c_void};
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum PdfSignatureModificationDetectionPermission {
Mdp1,
Mdp2,
Mdp3,
}
impl PdfSignatureModificationDetectionPermission {
#[inline]
pub(crate) fn from_pdfium(raw: c_uint) -> Result<Self, PdfiumError> {
match raw {
0 => Err(PdfiumError::PdfiumLibraryInternalError(
PdfiumInternalError::Unknown,
)),
1 => Ok(PdfSignatureModificationDetectionPermission::Mdp1),
2 => Ok(PdfSignatureModificationDetectionPermission::Mdp2),
3 => Ok(PdfSignatureModificationDetectionPermission::Mdp3),
_ => Err(PdfiumError::UnknownPdfSignatureModificationDetectionPermissionLevel),
}
}
}
pub struct PdfSignature<'a> {
handle: FPDF_SIGNATURE,
lifetime: PhantomData<&'a FPDF_SIGNATURE>,
}
impl<'a> PdfSignature<'a> {
#[inline]
pub(crate) fn from_pdfium(handle: FPDF_SIGNATURE) -> Self {
PdfSignature {
handle,
lifetime: PhantomData,
}
}
pub fn bytes(&self) -> Vec<u8> {
let buffer_length = unsafe {
self.bindings()
.FPDFSignatureObj_GetContents(self.handle, std::ptr::null_mut(), 0)
};
if buffer_length == 0 {
return Vec::new();
}
let mut buffer = create_byte_buffer(buffer_length as usize);
let result = unsafe {
self.bindings().FPDFSignatureObj_GetContents(
self.handle,
buffer.as_mut_ptr() as *mut c_void,
buffer_length,
)
};
assert_eq!(result, buffer_length);
buffer
}
pub fn reason(&self) -> Option<String> {
let buffer_length = unsafe {
self.bindings()
.FPDFSignatureObj_GetReason(self.handle, std::ptr::null_mut(), 0)
};
if buffer_length == 0 {
return None;
}
let mut buffer = create_byte_buffer(buffer_length as usize);
let result = unsafe {
self.bindings().FPDFSignatureObj_GetReason(
self.handle,
buffer.as_mut_ptr() as *mut c_void,
buffer_length,
)
};
assert_eq!(result, buffer_length);
get_string_from_pdfium_utf16le_bytes(buffer)
}
pub fn signing_date(&self) -> Option<String> {
let buffer_length = unsafe {
self.bindings()
.FPDFSignatureObj_GetTime(self.handle, std::ptr::null_mut(), 0)
};
if buffer_length == 0 {
return None;
}
let mut buffer = create_byte_buffer(buffer_length as usize);
let result = unsafe {
self.bindings().FPDFSignatureObj_GetTime(
self.handle,
buffer.as_mut_ptr() as *mut c_char,
buffer_length,
)
};
assert_eq!(result, buffer_length);
if let Ok(result) = CString::from_vec_with_nul(buffer) {
result.into_string().ok()
} else {
None
}
}
pub fn modification_detection_permission(
&self,
) -> Result<PdfSignatureModificationDetectionPermission, PdfiumError> {
PdfSignatureModificationDetectionPermission::from_pdfium(unsafe {
self.bindings()
.FPDFSignatureObj_GetDocMDPPermission(self.handle)
})
}
}
impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfSignature<'a> {}
#[cfg(feature = "thread_safe")]
unsafe impl<'a> Send for PdfSignature<'a> {}
#[cfg(feature = "thread_safe")]
unsafe impl<'a> Sync for PdfSignature<'a> {}