use crate::{
PdfiumStructElementAttr, PdfiumStructTree,
error::{PdfiumError, PdfiumResult},
lib,
pdfium_types::{FPDF_STRUCTELEMENT, Handle, StructElementHandle},
};
#[derive(Debug, Clone)]
pub struct PdfiumStructElement {
handle: StructElementHandle,
owner: Option<PdfiumStructTree>,
}
impl PdfiumStructElement {
pub(crate) fn new_from_handle(handle: FPDF_STRUCTELEMENT) -> PdfiumResult<Self> {
if handle.is_null() {
Err(PdfiumError::NullHandle)
} else {
Ok(Self {
handle: Handle::new(handle, None),
owner: None,
})
}
}
pub(crate) fn set_owner(&mut self, owner: PdfiumStructTree) {
self.owner = Some(owner);
}
pub fn count_children(&self) -> i32 {
lib().FPDF_StructElement_CountChildren(self)
}
pub fn child(&self, index: i32) -> PdfiumResult<PdfiumStructElement> {
let mut child = lib().FPDF_StructElement_GetChildAtIndex(self, index)?;
if let Some(owner) = &self.owner {
child.set_owner(owner.clone());
}
Ok(child)
}
pub fn element_type(&self) -> Option<String> {
let len = lib().FPDF_StructElement_GetType(self, None, 0);
if len > 0 {
let mut buffer = vec![0u8; len as usize];
lib().FPDF_StructElement_GetType(self, Some(&mut buffer), len);
let u16_buffer: Vec<u16> = buffer
.chunks_exact(2)
.map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
.take_while(|&c| c != 0)
.collect();
Some(String::from_utf16_lossy(&u16_buffer))
} else {
None
}
}
pub fn actual_text(&self) -> Option<String> {
let len = lib().FPDF_StructElement_GetActualText(self, None, 0);
if len > 0 {
let mut buffer = vec![0u8; len as usize];
lib().FPDF_StructElement_GetActualText(self, Some(&mut buffer), len);
let u16_buffer: Vec<u16> = buffer
.chunks_exact(2)
.map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
.take_while(|&c| c != 0)
.collect();
Some(String::from_utf16_lossy(&u16_buffer))
} else {
None
}
}
pub fn alt_text(&self) -> Option<String> {
let len = lib().FPDF_StructElement_GetAltText(self, None, 0);
if len > 0 {
let mut buffer = vec![0u8; len as usize];
lib().FPDF_StructElement_GetAltText(self, Some(&mut buffer), len);
let u16_buffer: Vec<u16> = buffer
.chunks_exact(2)
.map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
.take_while(|&c| c != 0)
.collect();
Some(String::from_utf16_lossy(&u16_buffer))
} else {
None
}
}
pub fn title(&self) -> Option<String> {
let len = lib().FPDF_StructElement_GetTitle(self, None, 0);
if len > 0 {
let mut buffer = vec![0u8; len as usize];
lib().FPDF_StructElement_GetTitle(self, Some(&mut buffer), len);
let u16_buffer: Vec<u16> = buffer
.chunks_exact(2)
.map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
.take_while(|&c| c != 0)
.collect();
Some(String::from_utf16_lossy(&u16_buffer))
} else {
None
}
}
pub fn id(&self) -> Option<String> {
let len = lib().FPDF_StructElement_GetID(self, None, 0);
if len > 0 {
let mut buffer = vec![0u8; len as usize];
lib().FPDF_StructElement_GetID(self, Some(&mut buffer), len);
let u16_buffer: Vec<u16> = buffer
.chunks_exact(2)
.map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
.take_while(|&c| c != 0)
.collect();
Some(String::from_utf16_lossy(&u16_buffer))
} else {
None
}
}
pub fn lang(&self) -> Option<String> {
let len = lib().FPDF_StructElement_GetLang(self, None, 0);
if len > 0 {
let mut buffer = vec![0u8; len as usize];
lib().FPDF_StructElement_GetLang(self, Some(&mut buffer), len);
let u16_buffer: Vec<u16> = buffer
.chunks_exact(2)
.map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
.take_while(|&c| c != 0)
.collect();
Some(String::from_utf16_lossy(&u16_buffer))
} else {
None
}
}
pub fn obj_type(&self) -> Option<String> {
let len = lib().FPDF_StructElement_GetObjType(self, None, 0);
if len > 0 {
let mut buffer = vec![0u8; len as usize];
lib().FPDF_StructElement_GetObjType(self, Some(&mut buffer), len);
let u16_buffer: Vec<u16> = buffer
.chunks_exact(2)
.map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
.take_while(|&c| c != 0)
.collect();
Some(String::from_utf16_lossy(&u16_buffer))
} else {
None
}
}
pub fn string_attribute(&self, attr_name: &str) -> Option<String> {
let c_attr_name = std::ffi::CString::new(attr_name).ok()?;
let len = lib().FPDF_StructElement_GetStringAttribute(self, &c_attr_name, None, 0);
if len > 0 {
let mut buffer = vec![0u8; len as usize];
lib().FPDF_StructElement_GetStringAttribute(self, &c_attr_name, Some(&mut buffer), len);
let u16_buffer: Vec<u16> = buffer
.chunks_exact(2)
.map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
.take_while(|&c| c != 0)
.collect();
Some(String::from_utf16_lossy(&u16_buffer))
} else {
None
}
}
pub fn marked_content_id(&self) -> Option<i32> {
let id = lib().FPDF_StructElement_GetMarkedContentID(self);
if id == -1 { None } else { Some(id) }
}
pub fn marked_content_id_count(&self) -> Option<usize> {
let count = lib().FPDF_StructElement_GetMarkedContentIdCount(self);
if count == -1 {
None
} else {
Some(count as usize)
}
}
pub fn marked_content_id_at_index(&self, index: usize) -> Option<i32> {
let id = lib().FPDF_StructElement_GetMarkedContentIdAtIndex(self, index as i32);
if id == -1 { None } else { Some(id) }
}
pub fn child_marked_content_id(&self, index: i32) -> Option<i32> {
let id = lib().FPDF_StructElement_GetChildMarkedContentID(self, index);
if id == -1 { None } else { Some(id) }
}
pub fn parent(&self) -> Option<PdfiumStructElement> {
let mut parent = lib().FPDF_StructElement_GetParent(self).ok()?;
if let Some(owner) = &self.owner {
parent.set_owner(owner.clone());
}
Some(parent)
}
pub fn attribute_count(&self) -> i32 {
lib().FPDF_StructElement_GetAttributeCount(self)
}
pub fn attribute_at_index(&self, index: i32) -> PdfiumResult<PdfiumStructElementAttr> {
let mut attr = lib().FPDF_StructElement_GetAttributeAtIndex(self, index)?;
attr.set_owner(self.clone());
Ok(attr)
}
}
impl From<&PdfiumStructElement> for FPDF_STRUCTELEMENT {
fn from(struct_element: &PdfiumStructElement) -> Self {
struct_element.handle.handle()
}
}