use std::fs;
use std::marker::PhantomData;
use std::collections::HashMap;
use std::sync::{Arc};
use std::path::Path;
use std::io::Write;
use crate as pdf;
use crate::error::*;
use crate::object::*;
use crate::primitive::{Primitive, Dictionary, PdfString};
use crate::backend::Backend;
use crate::any::*;
use crate::parser::Lexer;
use crate::parser::{parse_indirect_object, parse, ParseFlags};
use crate::xref::{XRef, XRefTable, XRefInfo};
use crate::crypt::Decoder;
use crate::crypt::CryptDict;
use crate::enc::{StreamFilter, decode};
use std::ops::Range;
use globalcache::sync::SyncCache;
use datasize::DataSize;
#[must_use]
pub struct PromisedRef<T> {
inner: PlainRef,
_marker: PhantomData<T>
}
impl<T> PromisedRef<T> {
pub fn get_inner(&self) -> PlainRef {
self.inner
}
pub fn get_ref(&self) -> Ref<T> {
Ref::new(self.inner)
}
}
pub struct Storage<B: Backend> {
cache: Arc<SyncCache<PlainRef, Result<AnySync, Arc<PdfError>>>>,
stream_cache: Arc<SyncCache<PlainRef, Result<Arc<[u8]>, Arc<PdfError>>>>,
changes: HashMap<ObjNr, Primitive>,
refs: XRefTable,
decoder: Option<Decoder>,
options: ParseOptions,
backend: B,
start_offset: usize,
}
impl<B: Backend> Storage<B> {
fn new(backend: B, options: ParseOptions) -> Result<Storage<B>> {
Ok(Storage {
start_offset: backend.locate_start_offset()?,
backend,
refs: XRefTable::new(0),
cache: SyncCache::new(),
stream_cache: SyncCache::new(),
changes: HashMap::new(),
decoder: None,
options,
})
}
fn decode(&self, id: PlainRef, range: Range<usize>, filters: &[StreamFilter]) -> Result<Arc<[u8]>> {
let data = self.backend.read(range)?;
let mut data = Vec::from(data);
if let Some(ref decoder) = self.decoder {
t!(decoder.decrypt(id, &mut data));
}
for filter in filters {
data = t!(decode(&data, filter), filter);
}
Ok(data.into())
}
}
impl<B: Backend> Resolve for Storage<B> {
fn resolve_flags(&self, r: PlainRef, flags: ParseFlags, depth: usize) -> Result<Primitive> {
match self.changes.get(&r.id) {
Some(p) => Ok((*p).clone()),
None => match t!(self.refs.get(r.id)) {
XRef::Raw {pos, ..} => {
let mut lexer = Lexer::with_offset(t!(self.backend.read(self.start_offset + pos ..)), self.start_offset + pos);
let p = t!(parse_indirect_object(&mut lexer, self, self.decoder.as_ref(), flags)).1;
Ok(p)
}
XRef::Stream {stream_id, index} => {
if !flags.contains(ParseFlags::STREAM) {
return Err(PdfError::PrimitiveNotAllowed { found: ParseFlags::STREAM, allowed: flags });
}
if depth == 0 {
bail!("too deep");
}
let obj_stream = t!(self.resolve_flags(PlainRef {id: stream_id, gen: 0 }, flags, depth-1));
let obj_stream = t!(ObjectStream::from_primitive(obj_stream, self));
let (data, range) = t!(obj_stream.get_object_slice(index, self));
parse(&data[range], self, flags)
}
XRef::Free {..} => err!(PdfError::FreeObject {obj_nr: r.id}),
XRef::Promised => unimplemented!(),
XRef::Invalid => err!(PdfError::NullRef {obj_nr: r.id}),
}
}
}
fn get<T: Object+DataSize>(&self, r: Ref<T>) -> Result<RcRef<T>> {
let key = r.get_inner();
let res = self.cache.get(key, || {
match self.resolve(key).and_then(|p| T::from_primitive(p, self)) {
Ok(obj) => Ok(Shared::new(obj).into()),
Err(e) => Err(Arc::new(e)),
}
});
match res {
Ok(any) => Ok(RcRef::new(key, any.downcast()?)),
Err(e) => Err(PdfError::Shared { source: e.clone()}),
}
}
fn options(&self) -> &ParseOptions {
&self.options
}
fn get_data_or_decode(&self, id: PlainRef, range: Range<usize>, filters: &[StreamFilter]) -> Result<Arc<[u8]>> {
self.stream_cache.get(id, || self.decode(id, range, filters).map_err(Arc::new))
.map_err(|e| e.into())
}
}
impl<B: Backend> Updater for Storage<B> {
fn create<T: ObjectWrite>(&mut self, obj: T) -> Result<RcRef<T>> {
let id = self.refs.len() as u64;
self.refs.push(XRef::Promised);
let primitive = obj.to_primitive(self)?;
self.changes.insert(id, primitive);
let rc = Shared::new(obj);
let r = PlainRef { id, gen: 0 };
Ok(RcRef::new(r, rc))
}
fn update<T: ObjectWrite>(&mut self, old: PlainRef, obj: T) -> Result<RcRef<T>> {
let r = match self.refs.get(old.id)? {
XRef::Free { .. } => panic!(),
XRef::Raw { gen_nr, .. } => PlainRef { id: old.id, gen: gen_nr + 1 },
XRef::Stream { .. } => return self.create(obj),
XRef::Promised => PlainRef { id: old.id, gen: 0 },
XRef::Invalid => panic!()
};
let primitive = obj.to_primitive(self)?;
self.changes.insert(old.id, primitive);
let rc = Shared::new(obj);
Ok(RcRef::new(r, rc))
}
fn promise<T: Object>(&mut self) -> PromisedRef<T> {
let id = self.refs.len() as u64;
self.refs.push(XRef::Promised);
PromisedRef {
inner: PlainRef {
id,
gen: 0
},
_marker: PhantomData
}
}
fn fulfill<T: ObjectWrite>(&mut self, promise: PromisedRef<T>, obj: T) -> Result<RcRef<T>> {
self.update(promise.inner, obj)
}
}
impl Storage<Vec<u8>> {
pub fn save(&mut self, trailer: &mut Trailer) -> Result<&[u8]> {
let xref_promise = self.promise::<Stream<XRefInfo>>();
trailer.highest_id = self.refs.len() as _;
let trailer = trailer.to_dict(self)?;
let mut changes: Vec<_> = self.changes.iter().collect();
changes.sort_unstable_by_key(|&(id, _)| id);
for (&id, primitive) in changes.iter() {
let pos = self.backend.len();
self.refs.set(id, XRef::Raw { pos: pos as _, gen_nr: 0 });
writeln!(self.backend, "{} {} obj", id, 0)?;
primitive.serialize(&mut self.backend, 0)?;
writeln!(self.backend, "endobj")?;
}
let xref_pos = self.backend.len();
let stream = self.refs.write_stream(xref_promise.get_inner().id as _)?;
writeln!(self.backend, "{} {} obj", xref_promise.get_inner().id, 0)?;
let mut xref_and_trailer = stream.to_pdf_stream(&mut NoUpdate)?;
for (k, v) in trailer.into_iter() {
xref_and_trailer.info.insert(k, v);
}
xref_and_trailer.serialize(&mut self.backend)?;
writeln!(self.backend, "endobj")?;
let _ = self.fulfill(xref_promise, stream)?;
write!(self.backend, "\nstartxref\n{}\n%%EOF", xref_pos).unwrap();
Ok(&self.backend)
}
}
pub fn load_storage_and_trailer<B: Backend>(storage: &mut Storage<B>) -> Result<Dictionary>
{
load_storage_and_trailer_password(storage, b"")
}
pub fn load_storage_and_trailer_password<B: Backend>(
storage: &mut Storage<B>,
password: &[u8],
) -> Result<Dictionary> {
let (refs, trailer) = t!(storage.backend.read_xref_table_and_trailer(storage.start_offset, storage));
storage.refs = refs;
if let Some(crypt) = trailer.get("Encrypt") {
let key = trailer
.get("ID")
.ok_or(PdfError::MissingEntry {
typ: "Trailer",
field: "ID".into(),
})?
.as_array()?[0]
.as_string()?
.as_bytes();
let dict = CryptDict::from_primitive(crypt.clone(), storage)?;
storage.decoder = Some(t!(Decoder::from_password(&dict, key, password)));
if let Primitive::Reference(reference) = crypt {
storage.decoder.as_mut().unwrap().encrypt_indirect_object = Some(*reference);
}
if let Some(Primitive::Reference(catalog_ref)) = trailer.get("Root") {
let catalog = t!(t!(storage.resolve(*catalog_ref)).resolve(storage)?.into_dictionary());
if let Some(Primitive::Reference(metadata_ref)) = catalog.get("Metadata") {
storage.decoder.as_mut().unwrap().metadata_indirect_object = Some(*metadata_ref);
}
}
}
Ok(trailer)
}
pub struct File<B: Backend> {
storage: Storage<B>,
pub trailer: Trailer,
}
impl<B: Backend> Resolve for File<B> {
fn resolve_flags(&self, r: PlainRef, flags: ParseFlags, depth: usize) -> Result<Primitive> {
self.storage.resolve_flags(r, flags, depth)
}
fn get<T: Object+DataSize>(&self, r: Ref<T>) -> Result<RcRef<T>> {
self.storage.get(r)
}
fn options(&self) -> &ParseOptions {
self.storage.options()
}
fn get_data_or_decode(&self, id: PlainRef, range: Range<usize>, filters: &[StreamFilter]) -> Result<Arc<[u8]>> {
self.storage.get_data_or_decode(id, range, filters)
}
}
impl<B: Backend> Updater for File<B> {
fn create<T: ObjectWrite>(&mut self, obj: T) -> Result<RcRef<T>> {
self.storage.create(obj)
}
fn update<T: ObjectWrite>(&mut self, old: PlainRef, obj: T) -> Result<RcRef<T>> {
self.storage.update(old, obj)
}
fn promise<T: Object>(&mut self) -> PromisedRef<T> {
self.storage.promise()
}
fn fulfill<T: ObjectWrite>(&mut self, promise: PromisedRef<T>, obj: T) -> Result<RcRef<T>> {
self.storage.fulfill(promise, obj)
}
}
impl File<Vec<u8>> {
pub fn open(path: impl AsRef<Path>) -> Result<Self> {
Self::from_data(fs::read(path)?)
}
pub fn open_password(path: impl AsRef<Path>, password: &[u8]) -> Result<Self> {
Self::from_data_password(fs::read(path)?, password)
}
pub fn save_to(&mut self, path: impl AsRef<Path>) -> Result<()> {
std::fs::write(path, self.storage.save(&mut self.trailer)?)?;
Ok(())
}
}
impl<B: Backend> File<B> {
pub fn from_data_password(backend: B, password: &[u8]) -> Result<Self> {
Self::load_data(backend, password, ParseOptions::strict())
}
pub fn from_data_password_with_options(backend: B, password: &[u8], options: ParseOptions) -> Result<Self> {
Self::load_data(backend, password, options)
}
pub fn from_data(backend: B) -> Result<Self> {
Self::load_data(backend, b"", ParseOptions::strict())
}
pub fn from_data_with_options(backend: B, options: ParseOptions) -> Result<Self> {
Self::load_data(backend, b"", options)
}
fn load_data(backend: B, password: &[u8], options: ParseOptions) -> Result<Self> {
let mut storage = Storage::new(backend, options)?;
let trailer = load_storage_and_trailer_password(&mut storage, password)?;
let trailer = t!(Trailer::from_primitive(
Primitive::Dictionary(trailer),
&storage,
));
Ok(File { storage, trailer })
}
pub fn get_root(&self) -> &Catalog {
&self.trailer.root
}
pub fn pages(&self) -> impl Iterator<Item=Result<PageRc>> + '_ {
(0 .. self.num_pages()).map(move |n| self.get_page(n))
}
pub fn num_pages(&self) -> u32 {
self.trailer.root.pages.count
}
pub fn get_page(&self, n: u32) -> Result<PageRc> {
self.trailer.root.pages.page(self, n)
}
pub fn update_catalog(&mut self, catalog: Catalog) -> Result<()> {
self.trailer.root = self.create(catalog)?;
Ok(())
}
pub fn set_options(&mut self, options: ParseOptions) {
self.storage.options = options;
}
}
#[derive(Object, ObjectWrite, DataSize)]
pub struct Trailer {
#[pdf(key = "Size")]
pub highest_id: i32,
#[pdf(key = "Prev")]
pub prev_trailer_pos: Option<i32>,
#[pdf(key = "Root")]
pub root: RcRef<Catalog>,
#[pdf(key = "Encrypt")]
pub encrypt_dict: Option<RcRef<CryptDict>>,
#[pdf(key = "Info")]
pub info_dict: Option<Dictionary>,
#[pdf(key = "ID")]
pub id: Vec<PdfString>,
}