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