Skip to main content

pdf_objects/
types.rs

1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::error::{PdfError, PdfResult};
6
7pub type PdfDictionary = BTreeMap<String, PdfValue>;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
10pub struct ObjectRef {
11    pub object_number: u32,
12    pub generation: u16,
13}
14
15impl ObjectRef {
16    pub const fn new(object_number: u32, generation: u16) -> Self {
17        Self {
18            object_number,
19            generation,
20        }
21    }
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
25pub struct PdfString(pub Vec<u8>);
26
27impl PdfString {
28    pub fn to_lossy_string(&self) -> String {
29        String::from_utf8_lossy(&self.0).into_owned()
30    }
31}
32
33#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
34pub enum PdfValue {
35    Null,
36    Bool(bool),
37    Integer(i64),
38    Number(f64),
39    Name(String),
40    String(PdfString),
41    Array(Vec<PdfValue>),
42    Dictionary(PdfDictionary),
43    Reference(ObjectRef),
44}
45
46impl PdfValue {
47    pub fn as_name(&self) -> Option<&str> {
48        match self {
49            PdfValue::Name(value) => Some(value.as_str()),
50            _ => None,
51        }
52    }
53
54    pub fn as_bool(&self) -> Option<bool> {
55        match self {
56            PdfValue::Bool(value) => Some(*value),
57            _ => None,
58        }
59    }
60
61    pub fn as_integer(&self) -> Option<i64> {
62        match self {
63            PdfValue::Integer(value) => Some(*value),
64            PdfValue::Number(value) if value.fract() == 0.0 => Some(*value as i64),
65            _ => None,
66        }
67    }
68
69    pub fn as_number(&self) -> Option<f64> {
70        match self {
71            PdfValue::Integer(value) => Some(*value as f64),
72            PdfValue::Number(value) => Some(*value),
73            _ => None,
74        }
75    }
76
77    pub fn as_array(&self) -> Option<&[PdfValue]> {
78        match self {
79            PdfValue::Array(values) => Some(values),
80            _ => None,
81        }
82    }
83
84    pub fn as_dictionary(&self) -> Option<&PdfDictionary> {
85        match self {
86            PdfValue::Dictionary(dictionary) => Some(dictionary),
87            _ => None,
88        }
89    }
90}
91
92#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
93pub struct PdfStream {
94    pub dict: PdfDictionary,
95    pub data: Vec<u8>,
96}
97
98#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
99pub enum PdfObject {
100    Value(PdfValue),
101    Stream(PdfStream),
102}
103
104#[derive(Debug, Clone, PartialEq)]
105pub enum XrefEntry {
106    Free,
107    Uncompressed {
108        offset: usize,
109        generation: u16,
110    },
111    Compressed {
112        stream_object_number: u32,
113        index: u32,
114    },
115}
116
117#[derive(Debug, Clone)]
118pub struct PdfFile {
119    pub version: String,
120    pub objects: BTreeMap<ObjectRef, PdfObject>,
121    pub trailer: PdfDictionary,
122    pub max_object_number: u32,
123}
124
125impl PdfFile {
126    pub fn get_object(&self, object_ref: ObjectRef) -> PdfResult<&PdfObject> {
127        self.objects.get(&object_ref).ok_or_else(|| {
128            PdfError::MissingObject(format!(
129                "{} {}",
130                object_ref.object_number, object_ref.generation
131            ))
132        })
133    }
134
135    pub fn get_object_mut(&mut self, object_ref: ObjectRef) -> PdfResult<&mut PdfObject> {
136        self.objects.get_mut(&object_ref).ok_or_else(|| {
137            PdfError::MissingObject(format!(
138                "{} {}",
139                object_ref.object_number, object_ref.generation
140            ))
141        })
142    }
143
144    pub fn get_value(&self, object_ref: ObjectRef) -> PdfResult<&PdfValue> {
145        match self.get_object(object_ref)? {
146            PdfObject::Value(value) => Ok(value),
147            PdfObject::Stream(_) => Err(PdfError::Corrupt(format!(
148                "expected value object at {} {}",
149                object_ref.object_number, object_ref.generation
150            ))),
151        }
152    }
153
154    pub fn get_dictionary(&self, object_ref: ObjectRef) -> PdfResult<&PdfDictionary> {
155        match self.get_value(object_ref)? {
156            PdfValue::Dictionary(dictionary) => Ok(dictionary),
157            _ => Err(PdfError::Corrupt(format!(
158                "expected dictionary at {} {}",
159                object_ref.object_number, object_ref.generation
160            ))),
161        }
162    }
163
164    pub fn resolve<'a>(&'a self, value: &'a PdfValue) -> PdfResult<&'a PdfValue> {
165        match value {
166            PdfValue::Reference(object_ref) => self.get_value(*object_ref),
167            _ => Ok(value),
168        }
169    }
170
171    pub fn resolve_dict<'a>(&'a self, value: &'a PdfValue) -> PdfResult<&'a PdfDictionary> {
172        self.resolve(value)?
173            .as_dictionary()
174            .ok_or_else(|| PdfError::Corrupt("expected dictionary value".to_string()))
175    }
176
177    pub fn allocate_object_ref(&mut self) -> ObjectRef {
178        self.max_object_number += 1;
179        ObjectRef::new(self.max_object_number, 0)
180    }
181
182    pub fn insert_object(&mut self, object_ref: ObjectRef, object: PdfObject) {
183        self.max_object_number = self.max_object_number.max(object_ref.object_number);
184        self.objects.insert(object_ref, object);
185    }
186}