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}