Skip to main content

pdfium_render/pdf/action/
uri.rs

1//! Defines the [PdfActionUri] struct, exposing functionality related to a single
2//! action of type `PdfActionType::Uri`.
3
4use crate::bindgen::{FPDF_ACTION, FPDF_DOCUMENT};
5use crate::error::PdfiumError;
6use crate::pdf::action::private::internal::PdfActionPrivate;
7use crate::pdfium::PdfiumLibraryBindingsAccessor;
8use crate::utils::mem::create_byte_buffer;
9use std::ffi::{c_void, CString};
10use std::marker::PhantomData;
11
12pub struct PdfActionUri<'a> {
13    handle: FPDF_ACTION,
14    document: FPDF_DOCUMENT,
15    lifetime: PhantomData<&'a FPDF_ACTION>,
16}
17
18impl<'a> PdfActionUri<'a> {
19    #[inline]
20    pub(crate) fn from_pdfium(handle: FPDF_ACTION, document: FPDF_DOCUMENT) -> Self {
21        PdfActionUri {
22            handle,
23            document,
24            lifetime: PhantomData,
25        }
26    }
27
28    /// Returns the URI path associated with this [PdfActionUri], if any.
29    pub fn uri(&self) -> Result<String, PdfiumError> {
30        // Retrieving the URI path from Pdfium is a two-step operation. First, we call
31        // FPDFAction_GetURIPath() with a null buffer; this will retrieve the length of
32        // the path in bytes. If the length is zero, then there is no path associated
33        // with this action.
34
35        // If the length is non-zero, then we reserve a byte buffer of the given
36        // length and call FPDFAction_GetURIPath() again with a pointer to the buffer;
37        // this will write the path to the buffer as an array of 7-bit ASCII characters.
38
39        let buffer_length = unsafe {
40            self.bindings().FPDFAction_GetURIPath(
41                self.document,
42                self.handle,
43                std::ptr::null_mut(),
44                0,
45            )
46        };
47
48        if buffer_length == 0 {
49            // There is no URI path for this action.
50
51            return Err(PdfiumError::NoUriForAction);
52        }
53
54        let mut buffer = create_byte_buffer(buffer_length as usize);
55
56        let result = unsafe {
57            self.bindings().FPDFAction_GetURIPath(
58                self.document,
59                self.handle,
60                buffer.as_mut_ptr() as *mut c_void,
61                buffer_length,
62            )
63        };
64
65        assert_eq!(result, buffer_length);
66
67        if let Ok(result) = CString::from_vec_with_nul(buffer) {
68            result
69                .into_string()
70                .map_err(PdfiumError::CStringConversionError)
71        } else {
72            Err(PdfiumError::NoUriForAction)
73        }
74    }
75}
76
77impl<'a> PdfActionPrivate<'a> for PdfActionUri<'a> {
78    #[inline]
79    fn handle(&self) -> &FPDF_ACTION {
80        &self.handle
81    }
82}
83
84impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfActionUri<'a> {}
85
86#[cfg(feature = "thread_safe")]
87unsafe impl<'a> Send for PdfActionUri<'a> {}
88
89#[cfg(feature = "thread_safe")]
90unsafe impl<'a> Sync for PdfActionUri<'a> {}