Skip to main content

pdfium_render/pdf/document/
catalog.rs

1//! Defines the [PdfCatalog] struct, exposing internal properties related to the
2//! document catalog for a single [PdfDocument].
3
4use crate::bindgen::FPDF_DOCUMENT;
5use crate::error::PdfiumError;
6use crate::pdfium::PdfiumLibraryBindingsAccessor;
7use crate::utils::{mem::create_byte_buffer, utf16le::get_string_from_pdfium_utf16le_bytes};
8use std::marker::PhantomData;
9
10#[cfg(any(
11    feature = "pdfium_future",
12    feature = "pdfium_8125",
13    feature = "pdfium_7881",
14    feature = "pdfium_7763"
15))]
16use std::ffi::c_ushort;
17
18#[cfg(doc)]
19use crate::pdf::document::PdfDocument;
20
21/// The internal catalog properties for a single [PdfDocument].
22pub struct PdfCatalog<'a> {
23    document_handle: FPDF_DOCUMENT,
24    lifetime: PhantomData<&'a FPDF_DOCUMENT>,
25}
26
27impl<'a> PdfCatalog<'a> {
28    #[inline]
29    pub(crate) fn from_pdfium(document_handle: FPDF_DOCUMENT) -> Self {
30        Self {
31            document_handle,
32            lifetime: PhantomData,
33        }
34    }
35
36    /// Returns the internal `FPDF_DOCUMENT` handle of the `PdfDocument` containing
37    /// this [PdfCatalog] instance.
38    #[inline]
39    pub(crate) fn document_handle(&self) -> FPDF_DOCUMENT {
40        self.document_handle
41    }
42
43    /// Returns `true` if the containing [PdfDocument] is a tagged PDF.
44    ///
45    /// A PDF is considered "tagged" if it includes structural elements and metadata
46    /// that can be used to facilitate content extraction and processing by tooling;
47    /// in other words, the PDF contains data above and beyond that required merely for
48    /// rendering.
49    ///
50    /// For more information on tagged PDFs, see The PDF Reference, Sixth Edition,
51    /// section 10.7, starting on page 883.
52    #[inline]
53    pub fn is_tagged(&self) -> bool {
54        self.bindings()
55            .is_true(unsafe { self.bindings().FPDFCatalog_IsTagged(self.document_handle()) })
56    }
57
58    #[cfg(any(
59        feature = "pdfium_future",
60        feature = "pdfium_8125",
61        feature = "pdfium_7881",
62        feature = "pdfium_7763"
63    ))]
64    /// Returns the language set in the catalog of the containing [PdfDocument], if any.
65    pub fn get_language(&self) -> Result<String, PdfiumError> {
66        // Retrieving the bookmark title from Pdfium is a two-step operation. First, we call
67        // FPDFBookmark_GetTitle() with a null buffer; this will retrieve the length of
68        // the bookmark title in bytes. If the length is zero, then there is no title.
69
70        // If the length is non-zero, then we reserve a byte buffer of the given
71        // length and call FPDFBookmark_GetTitle() again with a pointer to the buffer;
72        // this will write the bookmark title to the buffer in UTF16-LE format.
73
74        let buffer_length = unsafe {
75            self.bindings()
76                .FPDFCatalog_GetLanguage(self.document_handle(), std::ptr::null_mut(), 0)
77        };
78
79        if buffer_length == 0 {
80            // An error occurred.
81
82            return Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure);
83        }
84
85        if buffer_length == 2 {
86            // No language is set.
87
88            return Err(PdfiumError::NoLanguageSetInDocumentCatalog);
89        }
90
91        let mut buffer = create_byte_buffer(buffer_length as usize);
92
93        let result = unsafe {
94            self.bindings().FPDFCatalog_GetLanguage(
95                self.document_handle(),
96                buffer.as_mut_ptr() as *mut c_ushort,
97                buffer_length,
98            )
99        };
100
101        assert_eq!(result, buffer_length);
102
103        get_string_from_pdfium_utf16le_bytes(buffer)
104            .ok_or(PdfiumError::NoLanguageSetInDocumentCatalog)
105    }
106
107    #[cfg(any(
108        feature = "pdfium_future",
109        feature = "pdfium_8125",
110        feature = "pdfium_7881",
111        feature = "pdfium_7763",
112        feature = "pdfium_7543",
113        feature = "pdfium_7350",
114        feature = "pdfium_7215",
115        feature = "pdfium_7123",
116        feature = "pdfium_6996",
117        feature = "pdfium_6721",
118        feature = "pdfium_6666"
119    ))]
120    /// Sets the language of the containing [PdfDocument] to the given value.
121    pub fn set_language(&mut self, language: impl ToString) -> Result<(), PdfiumError> {
122        if self.bindings().is_true(unsafe {
123            self.bindings()
124                .FPDFCatalog_SetLanguage_str(self.document_handle(), language.to_string().as_str())
125        }) {
126            Ok(())
127        } else {
128            Err(PdfiumError::PdfiumFunctionReturnValueIndicatedFailure)
129        }
130    }
131}
132
133impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfCatalog<'a> {}
134
135#[cfg(feature = "thread_safe")]
136unsafe impl<'a> Send for PdfCatalog<'a> {}
137
138#[cfg(feature = "thread_safe")]
139unsafe impl<'a> Sync for PdfCatalog<'a> {}