use std::convert::TryFrom;
use crate::{
catalog::assert_len,
error::PdfResult,
objects::{Dictionary, Object},
stream::StreamDict,
trailer::Trailer,
Resolve,
};
pub(super) mod parser;
#[derive(Debug)]
pub struct XrefStream {
pub(crate) dict: XrefStreamDict,
pub(crate) stream: Vec<u8>,
}
#[derive(Debug)]
pub struct XrefStreamDict {
pub(crate) stream_dict: StreamDict,
pub(crate) trailer: Trailer,
pub(crate) index: Vec<(usize, usize)>,
pub(crate) w: XrefStreamFieldWidths,
}
impl XrefStreamDict {
const TYPE: &'static str = "XRef";
pub fn from_dict(
mut dict: Dictionary,
is_previous: bool,
resolver: &mut impl Resolve,
) -> PdfResult<Self> {
dict.expect_type(Self::TYPE, resolver, false)?;
let trailer = Trailer::from_dict_ref(&mut dict, is_previous, resolver)?;
let index = dict
.get_arr("Index", resolver)?
.map(|index| {
index
.chunks_exact(2)
.into_iter()
.map(|obj| {
let obj_number = obj[0].clone();
let num_of_entries = obj[1].clone();
Ok((
usize::try_from(resolver.assert_unsigned_integer(obj_number)?)?,
usize::try_from(resolver.assert_unsigned_integer(num_of_entries)?)?,
))
})
.collect::<PdfResult<Vec<(usize, usize)>>>()
})
.transpose()?
.unwrap_or(vec![(0, trailer.size)]);
let w = XrefStreamFieldWidths::from_arr(dict.expect_arr("W", resolver)?, resolver)?;
let stream_dict = StreamDict::from_dict(dict, resolver)?;
Ok(XrefStreamDict {
stream_dict,
index,
w,
trailer,
})
}
}
#[derive(Debug)]
pub(crate) enum XrefStreamField {
One = 0,
Two = 1,
Three = 2,
}
#[derive(Debug)]
pub(crate) struct XrefStreamFieldWidths {
field0: u32,
field1: u32,
field2: u32,
}
impl XrefStreamFieldWidths {
pub fn from_arr(mut arr: Vec<Object>, resolver: &mut dyn Resolve) -> PdfResult<Self> {
assert_len(&arr, 3)?;
let field2 = resolver.assert_unsigned_integer(arr.pop().unwrap())?;
let field1 = resolver.assert_unsigned_integer(arr.pop().unwrap())?;
let field0 = resolver.assert_unsigned_integer(arr.pop().unwrap())?;
Ok(XrefStreamFieldWidths {
field0,
field1,
field2,
})
}
pub fn field_width(&self, field: XrefStreamField) -> usize {
(match field {
XrefStreamField::One => self.field0,
XrefStreamField::Two => self.field1,
XrefStreamField::Three => self.field2,
}) as usize
}
pub fn total_width(&self) -> u32 {
self.field0 + self.field1 + self.field2
}
}