From e54cbe4129d88ad62775c650070002b23cf554c7 Mon Sep 17 00:00:00 2001 From: Sebastian K Date: Fri, 1 Dec 2023 16:40:57 +0100 Subject: [PATCH] fix bugs --- pdf/Cargo.toml | 2 +- pdf/src/file.rs | 21 +++++++++++++-------- pdf/src/font.rs | 2 +- pdf/src/object/types.rs | 3 +++ pdf_derive/src/lib.rs | 13 ++++++++++++- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/pdf/Cargo.toml b/pdf/Cargo.toml index 66ff7462..c33db926 100644 --- a/pdf/Cargo.toml +++ b/pdf/Cargo.toml @@ -40,7 +40,7 @@ euclid = { version = "0.22.7", optional = true } bitflags = "1.3" istring = { version = "0.3.3", features = ["std", "size"] } datasize = "0.2.13" -globalcache = { version = "0.2", features = ["sync"], optional = true } +globalcache = { version = "0.2.2", features = ["sync"], optional = true } indexmap = "2.1.0" [dev-dependencies] diff --git a/pdf/src/file.rs b/pdf/src/file.rs index 1f4bda25..22b391cd 100644 --- a/pdf/src/file.rs +++ b/pdf/src/file.rs @@ -39,12 +39,14 @@ impl PromisedRef { pub trait Cache { fn get_or_compute(&self, key: PlainRef, compute: impl FnOnce() -> T) -> T; + fn clear(&self); } pub struct NoCache; impl Cache for NoCache { fn get_or_compute(&self, _key: PlainRef, compute: impl FnOnce() -> T) -> T { compute() } + fn clear(&self) {} } #[cfg(feature="cache")] @@ -52,6 +54,9 @@ impl Cache for Arc T) -> T { self.get(key, compute) } + fn clear(&self) { + (**self).clear() + } } pub trait Log { @@ -67,7 +72,7 @@ pub struct Storage { stream_cache: SC, // objects that differ from the backend - changes: HashMap, + changes: HashMap, refs: XRefTable, @@ -226,7 +231,7 @@ where } fn resolve_ref(&self, r: PlainRef, flags: ParseFlags, resolve: &impl Resolve) -> Result { match self.changes.get(&r.id) { - Some(p) => Ok((*p).clone()), + 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); @@ -347,7 +352,7 @@ where let id = self.refs.len() as u64; self.refs.push(XRef::Promised); let primitive = obj.to_primitive(self)?; - self.changes.insert(id, primitive); + self.changes.insert(id, (primitive, 0)); let rc = Shared::new(obj); let r = PlainRef { id, gen: 0 }; @@ -362,7 +367,7 @@ where XRef::Invalid => panic!() }; let primitive = obj.to_primitive(self)?; - self.changes.insert(old.id, primitive); + self.changes.insert(old.id, (primitive, r.gen)); let rc = Shared::new(obj); Ok(RcRef::new(r, rc)) @@ -400,14 +405,13 @@ where let xref_promise = self.promise::>(); - let mut changes: Vec<_> = self.changes.iter().collect(); changes.sort_unstable_by_key(|&(id, _)| id); - for (&id, primitive) in changes.iter() { + for &(&id, &(ref primitive, gen)) 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)?; + self.refs.set(id, XRef::Raw { pos: pos as _, gen_nr: gen }); + writeln!(self.backend, "{} {} obj", id, gen)?; primitive.serialize(&mut self.backend)?; writeln!(self.backend, "endobj")?; } @@ -431,6 +435,7 @@ where write!(self.backend, "\nstartxref\n{}\n%%EOF", xref_pos).unwrap(); // update trailer which may have change now. + self.cache.clear(); *trailer = Trailer::from_dict(trailer_dict, &self.resolver())?; Ok(&self.backend) diff --git a/pdf/src/font.rs b/pdf/src/font.rs index f1f1881a..f97ded2b 100644 --- a/pdf/src/font.rs +++ b/pdf/src/font.rs @@ -517,7 +517,7 @@ impl ToUnicodeMap { pub fn utf16be_to_char( data: &[u8], ) -> impl Iterator> + '_ { - char::decode_utf16(data.chunks(2).map(|w| u16::from_be_bytes([w[0], w[1]]))) + char::decode_utf16(data.chunks_exact(2).map(|w| u16::from_be_bytes([w[0], w[1]]))) } /// converts UTF16-BE to a string replacing illegal/unknown characters pub fn utf16be_to_string_lossy(data: &[u8]) -> String { diff --git a/pdf/src/object/types.rs b/pdf/src/object/types.rs index 44bd41a8..4ee43b1c 100644 --- a/pdf/src/object/types.rs +++ b/pdf/src/object/types.rs @@ -958,6 +958,9 @@ pub struct FieldDictionary { #[pdf(key="AA")] pub actions: Option, + + #[pdf(other)] + pub other: Dictionary } #[derive(Debug, DataSize)] diff --git a/pdf_derive/src/lib.rs b/pdf_derive/src/lib.rs index 82159758..5cb5417e 100644 --- a/pdf_derive/src/lib.rs +++ b/pdf_derive/src/lib.rs @@ -725,6 +725,17 @@ fn impl_objectwrite_for_struct(ast: &DeriveInput, fields: &Fields) -> SynStream None => quote! {} }; + let other = parts.iter().filter(|(field, attrs, _)| attrs.other).flat_map(|(field, _, _)| field).next(); + let init_dict = if let Some(other) = other { + quote! { + let mut dict = self.#other.clone(); + } + } else { + quote! { + let mut dict = pdf::primitive::Dictionary::new(); + } + }; + quote! { impl #impl_generics pdf::object::ObjectWrite for #id #ty_generics #where_clause { fn to_primitive(&self, update: &mut impl pdf::object::Updater) -> Result { @@ -733,7 +744,7 @@ fn impl_objectwrite_for_struct(ast: &DeriveInput, fields: &Fields) -> SynStream } impl #impl_generics pdf::object::ToDict for #id #ty_generics #where_clause { fn to_dict(&self, updater: &mut impl pdf::object::Updater) -> Result { - let mut dict = pdf::primitive::Dictionary::new(); + #init_dict #pdf_type #( #checks_code )* #(#fields_ser)*