use std::{collections::HashMap, convert::TryFrom};
use crate::{Lexer, PdfResult, Reference};
pub(crate) use parser::{TrailerOrOffset, XrefParser};
mod parser;
pub mod stream;
#[derive(Debug, Clone)]
pub struct Xref {
pub(crate) objects: HashMap<usize, XrefEntry>,
}
#[derive(Debug)]
pub enum ByteOffset {
MainFile(usize),
ObjectStream { byte_offset: usize, index: usize },
}
impl Xref {
pub fn get_offset(
&self,
reference: Reference,
lexer: &mut Lexer,
) -> PdfResult<Option<ByteOffset>> {
Ok(
if let Some(entry) = self.objects.get(&reference.object_number) {
match entry {
XrefEntry::Free { .. } | XrefEntry::Null => None,
XrefEntry::InUse { byte_offset, .. } => {
Some(ByteOffset::MainFile(*byte_offset))
}
&XrefEntry::Compressed {
object_number,
index,
} => {
let byte_offset = match self.get_offset(
Reference {
object_number: usize::try_from(object_number)?,
generation: 0,
},
lexer,
)? {
Some(ByteOffset::MainFile(v)) => v,
Some(ByteOffset::ObjectStream { .. }) => todo!(),
None => return Ok(None),
};
Some(ByteOffset::ObjectStream { byte_offset, index })
}
}
} else {
None
},
)
}
pub fn merge_with_previous(&mut self, previous: Xref) {
for (key, value) in previous.objects.into_iter() {
self.objects.entry(key).or_insert(value);
}
}
}
#[derive(Debug, Clone)]
pub(crate) enum XrefEntry {
InUse {
byte_offset: usize,
generation_number: u16,
},
Free {
next_free_object: u64,
generation_number: u16,
},
Compressed {
object_number: u64,
index: usize,
},
Null,
}