use crate::{
PdfiumAction, PdfiumDestination,
document::PdfiumDocument,
error::{PdfiumError, PdfiumResult},
lib,
pdfium_types::{BookmarkHandle, FPDF_BOOKMARK, Handle},
};
#[derive(Debug, Clone)]
pub struct PdfiumBookmark {
handle: BookmarkHandle,
level: Option<u32>,
}
impl PdfiumBookmark {
pub(crate) fn new_from_handle(handle: FPDF_BOOKMARK) -> PdfiumResult<Self> {
if handle.is_null() {
Err(PdfiumError::NullHandle)
} else {
Ok(Self {
handle: Handle::new(handle, None), level: None,
})
}
}
pub(crate) fn null() -> Self {
Self {
handle: Handle::new(std::ptr::null_mut(), None),
level: None,
}
}
#[allow(dead_code)]
pub(crate) fn is_null(&self) -> bool {
self.handle.handle().is_null()
}
pub fn title(&self) -> PdfiumResult<String> {
let lib = lib();
let buf_len = lib.FPDFBookmark_GetTitle(self, None, 0);
if buf_len == 0 {
return Err(PdfiumError::InvokationFailed);
}
let mut buffer = vec![0u8; buf_len as usize];
lib.FPDFBookmark_GetTitle(self, Some(&mut buffer), buf_len);
let utf16_codes: Vec<_> = buffer[..buffer.len().saturating_sub(2)]
.chunks_exact(2)
.map(|pair| u16::from_le_bytes([pair[0], pair[1]])) .collect();
Ok(String::from_utf16_lossy(&utf16_codes))
}
pub fn count(&self) -> i32 {
lib().FPDFBookmark_GetCount(self)
}
pub fn level(&self) -> Option<u32> {
self.level
}
pub(crate) fn set_level(&mut self, level: u32) {
self.level = Some(level);
}
pub fn dest(&self, document: &PdfiumDocument) -> PdfiumResult<PdfiumDestination> {
lib().FPDFBookmark_GetDest(document, self)
}
pub fn first_child(&self, document: &PdfiumDocument) -> Option<PdfiumBookmark> {
lib().FPDFBookmark_GetFirstChild(document, self).ok()
}
pub fn next_sibling(&self, document: &PdfiumDocument) -> Option<PdfiumBookmark> {
lib().FPDFBookmark_GetNextSibling(document, self).ok()
}
pub fn action(&self) -> Option<PdfiumAction> {
lib().FPDFBookmark_GetAction(self).ok()
}
}
impl From<&PdfiumBookmark> for FPDF_BOOKMARK {
fn from(bookmark: &PdfiumBookmark) -> Self {
bookmark.handle.handle()
}
}