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_integer(&self) -> Option<i64> {
55        match self {
56            PdfValue::Integer(value) => Some(*value),
57            PdfValue::Number(value) if value.fract() == 0.0 => Some(*value as i64),
58            _ => None,
59        }
60    }
61
62    pub fn as_number(&self) -> Option<f64> {
63        match self {
64            PdfValue::Integer(value) => Some(*value as f64),
65            PdfValue::Number(value) => Some(*value),
66            _ => None,
67        }
68    }
69
70    pub fn as_array(&self) -> Option<&[PdfValue]> {
71        match self {
72            PdfValue::Array(values) => Some(values),
73            _ => None,
74        }
75    }
76
77    pub fn as_dictionary(&self) -> Option<&PdfDictionary> {
78        match self {
79            PdfValue::Dictionary(dictionary) => Some(dictionary),
80            _ => None,
81        }
82    }
83}
84
85#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
86pub struct PdfStream {
87    pub dict: PdfDictionary,
88    pub data: Vec<u8>,
89}
90
91#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
92pub enum PdfObject {
93    Value(PdfValue),
94    Stream(PdfStream),
95}
96
97#[derive(Debug, Clone, PartialEq)]
98pub struct XrefEntry {
99    pub offset: usize,
100    pub generation: u16,
101    pub in_use: bool,
102}
103
104#[derive(Debug, Clone)]
105pub struct PdfFile {
106    pub version: String,
107    pub objects: BTreeMap<ObjectRef, PdfObject>,
108    pub trailer: PdfDictionary,
109    pub max_object_number: u32,
110}
111
112impl PdfFile {
113    pub fn get_object(&self, object_ref: ObjectRef) -> PdfResult<&PdfObject> {
114        self.objects.get(&object_ref).ok_or_else(|| {
115            PdfError::MissingObject(format!(
116                "{} {}",
117                object_ref.object_number, object_ref.generation
118            ))
119        })
120    }
121
122    pub fn get_object_mut(&mut self, object_ref: ObjectRef) -> PdfResult<&mut PdfObject> {
123        self.objects.get_mut(&object_ref).ok_or_else(|| {
124            PdfError::MissingObject(format!(
125                "{} {}",
126                object_ref.object_number, object_ref.generation
127            ))
128        })
129    }
130
131    pub fn get_value(&self, object_ref: ObjectRef) -> PdfResult<&PdfValue> {
132        match self.get_object(object_ref)? {
133            PdfObject::Value(value) => Ok(value),
134            PdfObject::Stream(_) => Err(PdfError::Corrupt(format!(
135                "expected value object at {} {}",
136                object_ref.object_number, object_ref.generation
137            ))),
138        }
139    }
140
141    pub fn get_dictionary(&self, object_ref: ObjectRef) -> PdfResult<&PdfDictionary> {
142        match self.get_value(object_ref)? {
143            PdfValue::Dictionary(dictionary) => Ok(dictionary),
144            _ => Err(PdfError::Corrupt(format!(
145                "expected dictionary at {} {}",
146                object_ref.object_number, object_ref.generation
147            ))),
148        }
149    }
150
151    pub fn resolve<'a>(&'a self, value: &'a PdfValue) -> PdfResult<&'a PdfValue> {
152        match value {
153            PdfValue::Reference(object_ref) => self.get_value(*object_ref),
154            _ => Ok(value),
155        }
156    }
157
158    pub fn resolve_dict<'a>(&'a self, value: &'a PdfValue) -> PdfResult<&'a PdfDictionary> {
159        self.resolve(value)?
160            .as_dictionary()
161            .ok_or_else(|| PdfError::Corrupt("expected dictionary value".to_string()))
162    }
163
164    pub fn allocate_object_ref(&mut self) -> ObjectRef {
165        self.max_object_number += 1;
166        ObjectRef::new(self.max_object_number, 0)
167    }
168
169    pub fn insert_object(&mut self, object_ref: ObjectRef, object: PdfObject) {
170        self.max_object_number = self.max_object_number.max(object_ref.object_number);
171        self.objects.insert(object_ref, object);
172    }
173}