pdf/
xref.rs

1use std::fmt::{Debug, Formatter};
2use crate::error::*;
3use crate::object::*;
4use crate as pdf;
5use datasize::DataSize;
6
7///////////////////////////
8// Cross-reference table //
9///////////////////////////
10
11#[derive(Copy, Clone, Debug)]
12pub enum XRef {
13    /// Not currently used.
14    Free {
15        next_obj_nr: ObjNr,
16        gen_nr: GenNr
17    },
18
19    /// In use.
20    Raw {
21        pos: usize,
22        gen_nr: GenNr
23    },
24    /// In use and compressed inside an Object Stream
25    Stream {
26        stream_id: ObjNr,
27        index: usize,
28    },
29    
30    Promised,
31    
32    Invalid
33}
34
35impl XRef {
36    pub fn get_gen_nr(&self) -> GenNr {
37        match *self {
38            XRef::Free {gen_nr, ..}
39            | XRef::Raw {gen_nr, ..} => gen_nr,
40            XRef::Stream { .. } => 0, // TODO I think these always have gen nr 0?
41            _ => panic!()
42        }
43    }
44}
45
46
47/// Runtime lookup table of all objects
48#[derive(Clone)]
49pub struct XRefTable {
50    // None means that it's not specified, and should result in an error if used
51    // Thought: None could also mean Free?
52    entries: Vec<XRef>
53}
54
55
56impl XRefTable {
57    pub fn new(num_objects: ObjNr) -> XRefTable {
58        let mut entries = Vec::new();
59        entries.resize(num_objects as usize, XRef::Invalid);
60        entries.push(XRef::Free { next_obj_nr: 0, gen_nr: 0xffff });
61        XRefTable {
62            entries,
63        }
64    }
65
66    pub fn iter(&self) -> impl Iterator<Item=u32> + '_ {
67        self.entries.iter().enumerate()
68            .filter(|(_, xref)| matches!(xref, XRef::Raw { .. } | XRef::Stream { .. } ))
69            .map(|(i, _)| i as u32)
70    }
71
72    pub fn get(&self, id: ObjNr) -> Result<XRef> {
73        match self.entries.get(id as usize) {
74            Some(&entry) => Ok(entry),
75            None => Err(PdfError::UnspecifiedXRefEntry {id}),
76        }
77    }
78    pub fn set(&mut self, id: ObjNr, r: XRef) {
79        self.entries[id as usize] = r;
80    }
81    pub fn len(&self) -> usize {
82        self.entries.len()
83    }
84    pub fn is_empty(&self) -> bool {
85        self.entries.is_empty()
86    }
87    pub fn push(&mut self, new_entry: XRef) {
88        self.entries.push(new_entry);
89    }
90    pub fn num_entries(&self) -> usize {
91        self.entries.len()
92    }
93    pub fn max_field_widths(&self) -> (u64, u64) {
94        let mut max_a = 0;
95        let mut max_b = 0;
96        for &e in &self.entries {
97            let (a, b) = match e {
98                XRef::Raw { pos, gen_nr } => (pos as u64, gen_nr),
99                XRef::Free { next_obj_nr, gen_nr } => (next_obj_nr, gen_nr),
100                XRef::Stream { stream_id, index } => (stream_id, index as u64),
101                _ => continue
102            };
103            max_a = max_a.max(a);
104            max_b = max_b.max(b);
105        }
106        (max_a, max_b)
107    }
108
109    pub fn add_entries_from(&mut self, section: XRefSection) -> Result<()> {
110        for (i, &entry) in section.entries() {
111            if let Some(dst) = self.entries.get_mut(i) {
112                // Early return if the entry we have has larger or equal generation number
113                let should_be_updated = match *dst {
114                    XRef::Raw { gen_nr: gen, .. } | XRef::Free { gen_nr: gen, .. }
115                        => entry.get_gen_nr() > gen,
116                    XRef::Stream { .. } | XRef::Invalid
117                        => true,
118                    x => bail!("found {:?}", x)
119                };
120                if should_be_updated {
121                    *dst = entry;
122                }
123            }
124        }
125        Ok(())
126    }
127
128    pub fn write_stream(&self, size: usize) -> Result<Stream<XRefInfo>> {
129        let (max_a, max_b) = self.max_field_widths();
130        let a_w = byte_len(max_a);
131        let b_w = byte_len(max_b);
132
133        let mut data = Vec::with_capacity((1 + a_w + b_w) * size);
134        for &x in self.entries.iter().take(size) {
135            let (t, a, b) = match x {
136                XRef::Free { next_obj_nr, gen_nr } => (0, next_obj_nr, gen_nr),
137                XRef::Raw { pos, gen_nr } => (1, pos as u64, gen_nr),
138                XRef::Stream { stream_id, index } => (2, stream_id, index as u64),
139                // Treat Invalid and Promised entries as free entries
140                XRef::Invalid | XRef::Promised => (0, 0, 0),
141            };
142            data.push(t);
143            data.extend_from_slice(&a.to_be_bytes()[8 - a_w ..]);
144            data.extend_from_slice(&b.to_be_bytes()[8 - b_w ..]);
145        }
146        let info = XRefInfo {
147            size: size as u32,
148            index: vec![0, size as u32],
149            prev: None,
150            w: vec![1, a_w, b_w],
151        };
152        
153        Ok(Stream::new(info, data))
154    }
155}
156
157fn byte_len(n: u64) -> usize {
158    (64 + 8 - 1 - n.leading_zeros()) as usize / 8 + (n == 0) as usize
159}
160
161impl Debug for XRefTable {
162    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
163        for (i, entry) in self.entries.iter().enumerate() {
164            match *entry {
165                XRef::Free {next_obj_nr, gen_nr} => {
166                    writeln!(f, "{:4}: {:010} {:05} f", i, next_obj_nr, gen_nr)?
167                },
168                XRef::Raw {pos, gen_nr} => {
169                    writeln!(f, "{:4}: {:010} {:05} n", i, pos, gen_nr)?
170                },
171                XRef::Stream {stream_id, index} => {
172                    writeln!(f, "{:4}: in stream {}, index {}", i, stream_id, index)?
173                },
174                XRef::Promised => {
175                    writeln!(f, "{:4}: Promised?", i)?
176                },
177                XRef::Invalid => {
178                    writeln!(f, "{:4}: Invalid!", i)?
179                }
180            }
181        }
182        Ok(())
183    }
184}
185
186/// As found in PDF files
187#[derive(Debug)]
188pub struct XRefSection {
189    pub first_id: u32,
190    pub entries: Vec<XRef>,
191}
192
193
194impl XRefSection {
195    pub fn new(first_id: u32) -> XRefSection {
196        XRefSection {
197            first_id,
198            entries: Vec::new(),
199        }
200    }
201    pub fn add_free_entry(&mut self, next_obj_nr: ObjNr, gen_nr: GenNr) {
202        self.entries.push(XRef::Free{next_obj_nr, gen_nr});
203    }
204    pub fn add_inuse_entry(&mut self, pos: usize, gen_nr: GenNr) {
205        self.entries.push(XRef::Raw{pos, gen_nr});
206    }
207    pub fn entries(&self) -> impl Iterator<Item=(usize, &XRef)> {
208        self.entries.iter().enumerate().map(move |(i, e)| (i + self.first_id as usize, e))
209    }
210}
211
212
213#[derive(Object, ObjectWrite, Debug, DataSize)]
214#[pdf(Type = "XRef")]
215pub struct XRefInfo {
216    // XRefStream fields
217    #[pdf(key = "Size")]
218    pub size: u32,
219
220    //
221    #[pdf(key = "Index", default = "vec![0, size]")]
222    /// Array of pairs of integers for each subsection, (first object number, number of entries).
223    /// Default value (assumed when None): `(0, self.size)`.
224    pub index: Vec<u32>,
225
226    #[pdf(key = "Prev")]
227    prev: Option<i32>,
228
229    #[pdf(key = "W")]
230    pub w: Vec<usize>,
231}
232
233// read_xref_table
234// read_xref_stream
235// read_xref_and_trailer_at