1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
pub(crate) mod internal {
// We want to make the PdfPageAnnotationPrivate trait private while providing a blanket
// implementation of PdfPageAnnotationCommon for any type T where T: PdfPageAnnotationPrivate.
// Rust complains, however, that by doing so we are leaking the private trait outside
// the crate.
// Instead of making the PdfPageAnnotationPrivate trait private, we leave it public but place it
// inside this pub(crate) module in order to prevent it from being visible outside the crate.
use crate::bindgen::{FPDF_ANNOTATION, FPDF_OBJECT_STRING, FPDF_WCHAR, FS_RECTF};
use crate::bindings::PdfiumLibraryBindings;
use crate::error::PdfiumError;
use crate::page::PdfRect;
use crate::page_annotation::PdfPageAnnotationCommon;
use crate::page_annotation_objects::PdfPageAnnotationObjects;
use crate::utils::mem::create_byte_buffer;
use crate::utils::utf16le::get_string_from_pdfium_utf16le_bytes;
/// Internal crate-specific functionality common to all [PdfPageAnnotation] objects.
pub trait PdfPageAnnotationPrivate<'a>: PdfPageAnnotationCommon {
/// Returns the internal `FPDF_ANNOTATION` handle for this [PdfPageAnnotation].
fn handle(&self) -> &FPDF_ANNOTATION;
/// Returns the [PdfiumLibraryBindings] used by this [PdfPageAnnotation].
fn bindings(&self) -> &dyn PdfiumLibraryBindings;
/// Returns the string value associated with the given key in the annotation dictionary
/// of this [PdfPageAnnotation], if any.
fn get_string_value(&self, key: &str) -> Option<String> {
if !self
.bindings()
.is_true(self.bindings().FPDFAnnot_HasKey(*self.handle(), key))
{
// The key does not exist.
return None;
}
if self.bindings().FPDFAnnot_GetValueType(*self.handle(), key) as u32
!= FPDF_OBJECT_STRING
{
// The key exists, but the value associated with the key is not a string.
return None;
}
// Retrieving the string value from Pdfium is a two-step operation. First, we call
// FPDFAnot_GetStringValue() with a null buffer; this will retrieve the length of
// the value in bytes, assuming the key exists. If the length is zero, then there
// is no such key, or the key's value is not a string.
// If the length is non-zero, then we reserve a byte buffer of the given
// length and call FPDFAnot_GetStringValue() again with a pointer to the buffer;
// this will write the string value into the buffer.
let buffer_length = self.bindings().FPDFAnnot_GetStringValue(
*self.handle(),
key,
std::ptr::null_mut(),
0,
);
if buffer_length <= 2 {
// A buffer length of 2 indicates that the string value for the given key is
// an empty UTF16-LE string, so there is no point in retrieving it.
return None;
}
let mut buffer = create_byte_buffer(buffer_length as usize);
let result = self.bindings().FPDFAnnot_GetStringValue(
*self.handle(),
key,
buffer.as_mut_ptr() as *mut FPDF_WCHAR,
buffer_length,
);
assert_eq!(result, buffer_length);
Some(get_string_from_pdfium_utf16le_bytes(buffer).unwrap_or_default())
}
/// Internal implementation of [PdfPageAnnotationCommon::name()].
#[inline]
fn name_impl(&self) -> Option<String> {
self.get_string_value("NM")
}
/// Internal implementation of [PdfPageAnnotationCommon::bounds()].
#[inline]
fn bounds_impl(&self) -> Result<PdfRect, PdfiumError> {
let mut rect = FS_RECTF {
left: 0_f32,
bottom: 0_f32,
right: 0_f32,
top: 0_f32,
};
let result = self.bindings().FPDFAnnot_GetRect(*self.handle(), &mut rect);
PdfRect::from_pdfium_as_result(result, rect, self.bindings())
}
/// Internal implementation of [PdfPageAnnotationCommon::contents()].
#[inline]
fn contents_impl(&self) -> Option<String> {
self.get_string_value("Contents")
}
/// Internal implementation of [PdfPageAnnotationCommon::creator()].
#[inline]
fn creator_impl(&self) -> Option<String> {
self.get_string_value("T")
}
/// Internal implementation of [PdfPageAnnotationCommon::creation_date()].
#[inline]
fn creation_date_impl(&self) -> Option<String> {
self.get_string_value("CreationDate")
}
/// Internal implementation of [PdfPageAnnotationCommon::modification_date()].
#[inline]
fn modification_date_impl(&self) -> Option<String> {
self.get_string_value("M")
}
/// Internal implementation of [PdfPageAnnotationCommon::objects()].
fn objects_impl(&self) -> &PdfPageAnnotationObjects;
/// Internal mutable accessor available for all [PdfPageAnnotation] types.
/// This differs from the public interface, which makes mutable page object access
/// available only for the ink annotation and stamp annotation types, since those
/// are the only annotation types for which Pdfium itself supports adding or removing
/// page objects.
fn objects_mut_impl(&mut self) -> &mut PdfPageAnnotationObjects<'a>;
}
}