use crate::bindgen::FPDF_DOCUMENT;
use crate::bindings::PdfiumLibraryBindings;
use crate::error::PdfiumError;
use bitflags::bitflags;
use std::os::raw::c_int;
bitflags! {
struct FpdfPermissions: u32 {
const RESERVED_BIT_1 = 0b00000000000000000000000000000001;
const RESERVED_BIT_2 = 0b00000000000000000000000000000010;
const CAN_PRINT_BIT_3 = 0b00000000000000000000000000000100;
const CAN_MODIFY_BIT_4 = 0b00000000000000000000000000001000;
const CAN_EXTRACT_TEXT_AND_GRAPHICS_BIT_5 = 0b00000000000000000000000000010000;
const CAN_ANNOTATE_AND_FORM_FILL_BIT_6 = 0b00000000000000000000000000100000;
const RESERVED_BIT_7 = 0b00000000000000000000000001000000;
const RESERVED_BIT_8 = 0b00000000000000000000000010000000;
const V3_CAN_FORM_FILL_BIT_9 = 0b00000000000000000000000100000000;
const V3_CAN_EXTRACT_TEXT_AND_GRAPHICS_BIT_10 = 0b00000000000000000000001000000000;
const V3_CAN_ASSEMBLE_DOCUMENT_BIT_11 = 0b00000000000000000000010000000000;
const V3_CAN_PRINT_HIGH_QUALITY_BIT_12 = 0b00000000000000000000100000000000;
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum PdfSecurityHandlerRevision {
Unprotected,
Revision2,
Revision3,
Revision4,
}
impl PdfSecurityHandlerRevision {
pub(crate) fn from_pdfium(value: c_int) -> Option<Self> {
match value {
-1 => Some(PdfSecurityHandlerRevision::Unprotected),
2 => Some(PdfSecurityHandlerRevision::Revision2),
3 => Some(PdfSecurityHandlerRevision::Revision3),
4 => Some(PdfSecurityHandlerRevision::Revision4),
_ => None,
}
}
}
pub struct PdfPermissions<'a> {
document_handle: FPDF_DOCUMENT,
bindings: &'a dyn PdfiumLibraryBindings,
}
impl<'a> PdfPermissions<'a> {
#[inline]
pub(crate) fn from_pdfium(
document_handle: FPDF_DOCUMENT,
bindings: &'a dyn PdfiumLibraryBindings,
) -> Self {
Self {
document_handle,
bindings,
}
}
#[inline]
pub fn bindings(&self) -> &'a dyn PdfiumLibraryBindings {
self.bindings
}
#[inline]
fn get_permissions_bits(&self) -> FpdfPermissions {
FpdfPermissions::from_bits_truncate(
self.bindings().FPDF_GetDocPermissions(self.document_handle) as u32,
)
}
pub fn security_handler_revision(&self) -> Result<PdfSecurityHandlerRevision, PdfiumError> {
PdfSecurityHandlerRevision::from_pdfium(
self.bindings()
.FPDF_GetSecurityHandlerRevision(self.document_handle),
)
.ok_or(PdfiumError::UnknownPdfSecurityHandlerRevision)
}
pub fn can_print_high_quality(&self) -> Result<bool, PdfiumError> {
let permissions = self.get_permissions_bits();
let result = match self.security_handler_revision()? {
PdfSecurityHandlerRevision::Unprotected => true,
PdfSecurityHandlerRevision::Revision2 => {
permissions.contains(FpdfPermissions::CAN_PRINT_BIT_3)
}
PdfSecurityHandlerRevision::Revision3 | PdfSecurityHandlerRevision::Revision4 => {
permissions.contains(FpdfPermissions::CAN_PRINT_BIT_3)
&& permissions.contains(FpdfPermissions::V3_CAN_PRINT_HIGH_QUALITY_BIT_12)
}
};
Ok(result)
}
pub fn can_print_only_low_quality(&self) -> Result<bool, PdfiumError> {
let permissions = self.get_permissions_bits();
let result = match self.security_handler_revision()? {
PdfSecurityHandlerRevision::Unprotected | PdfSecurityHandlerRevision::Revision2 => {
false
}
PdfSecurityHandlerRevision::Revision3 | PdfSecurityHandlerRevision::Revision4 => {
permissions.contains(FpdfPermissions::CAN_PRINT_BIT_3)
&& !permissions.contains(FpdfPermissions::V3_CAN_PRINT_HIGH_QUALITY_BIT_12)
}
};
Ok(result)
}
pub fn can_assemble_document(&self) -> Result<bool, PdfiumError> {
let permissions = self.get_permissions_bits();
let result = match self.security_handler_revision()? {
PdfSecurityHandlerRevision::Unprotected => true,
PdfSecurityHandlerRevision::Revision2 => {
permissions.contains(FpdfPermissions::CAN_MODIFY_BIT_4)
}
PdfSecurityHandlerRevision::Revision3 | PdfSecurityHandlerRevision::Revision4 => {
permissions.contains(FpdfPermissions::V3_CAN_ASSEMBLE_DOCUMENT_BIT_11)
}
};
Ok(result)
}
pub fn can_modify_document_content(&self) -> Result<bool, PdfiumError> {
let permissions = self.get_permissions_bits();
let result = match self.security_handler_revision()? {
PdfSecurityHandlerRevision::Unprotected => true,
_ => permissions.contains(FpdfPermissions::CAN_MODIFY_BIT_4),
};
Ok(result)
}
pub fn can_extract_text_and_graphics(&self) -> Result<bool, PdfiumError> {
let permissions = self.get_permissions_bits();
let result = match self.security_handler_revision()? {
PdfSecurityHandlerRevision::Unprotected => true,
PdfSecurityHandlerRevision::Revision2 => {
permissions.contains(FpdfPermissions::CAN_EXTRACT_TEXT_AND_GRAPHICS_BIT_5)
}
PdfSecurityHandlerRevision::Revision3 | PdfSecurityHandlerRevision::Revision4 => {
permissions.contains(FpdfPermissions::V3_CAN_EXTRACT_TEXT_AND_GRAPHICS_BIT_10)
}
};
Ok(result)
}
pub fn can_fill_existing_interactive_form_fields(&self) -> Result<bool, PdfiumError> {
let permissions = self.get_permissions_bits();
let result = match self.security_handler_revision()? {
PdfSecurityHandlerRevision::Unprotected => true,
PdfSecurityHandlerRevision::Revision2 => {
permissions.contains(FpdfPermissions::CAN_ANNOTATE_AND_FORM_FILL_BIT_6)
}
PdfSecurityHandlerRevision::Revision3 | PdfSecurityHandlerRevision::Revision4 => {
permissions.contains(FpdfPermissions::V3_CAN_FORM_FILL_BIT_9)
}
};
Ok(result)
}
pub fn can_create_new_interactive_form_fields(&self) -> Result<bool, PdfiumError> {
let permissions = self.get_permissions_bits();
let result = match self.security_handler_revision()? {
PdfSecurityHandlerRevision::Unprotected => true,
_ => {
permissions.contains(FpdfPermissions::CAN_MODIFY_BIT_4)
&& permissions.contains(FpdfPermissions::CAN_ANNOTATE_AND_FORM_FILL_BIT_6)
}
};
Ok(result)
}
pub fn can_add_or_modify_text_annotations(&self) -> Result<bool, PdfiumError> {
let permissions = self.get_permissions_bits();
let result = match self.security_handler_revision()? {
PdfSecurityHandlerRevision::Unprotected => true,
_ => permissions.contains(FpdfPermissions::CAN_ANNOTATE_AND_FORM_FILL_BIT_6),
};
Ok(result)
}
}