1use alloc::boxed::Box;
13use alloc::collections::BTreeMap;
14use alloc::string::String;
15use alloc::vec::Vec;
16use core::cell::RefCell;
17
18use pith_digest::{Error as KErr, Result as KResult};
19
20use crate::content::{Resources, extract_page_text};
21use crate::font::Resolve;
22use crate::object::{Obj, Ref, decode_stream, dict_get, parse_obj};
23use crate::xref::{Loc, Xref, read_xref, scan_xref};
24
25#[derive(Debug)]
28pub enum Error {
29 Kit(KErr),
31 Object {
33 object: u32,
35 generation: u16,
37 cause: Box<Error>,
39 },
40 Page {
42 page: usize,
44 cause: Box<Error>,
46 },
47}
48
49pub type Result<T, E = Error> = core::result::Result<T, E>;
51
52impl From<KErr> for Error {
53 fn from(e: KErr) -> Error {
54 Error::Kit(e)
55 }
56}
57
58impl core::fmt::Display for Error {
59 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
60 match self {
61 Error::Kit(e) => e.fmt(f),
62 Error::Object {
63 object,
64 generation,
65 cause,
66 } => {
67 f.write_str("object ")?;
68 write_u32(f, *object)?;
69 f.write_str(" ")?;
70 write_u32(f, u32::from(*generation))?;
71 f.write_str(": ")?;
72 cause.fmt(f)
73 }
74 Error::Page { page, cause } => {
75 f.write_str("page ")?;
76 write_usize(f, *page)?;
77 f.write_str(": ")?;
78 cause.fmt(f)
79 }
80 }
81 }
82}
83
84fn write_u32(f: &mut core::fmt::Formatter<'_>, v: u32) -> core::fmt::Result {
85 let mut buf = [0u8; 10];
87 let mut i = buf.len();
88 let mut v = v;
89 if v == 0 {
90 return f.write_str("0");
91 }
92 while v > 0 {
93 i -= 1;
94 buf[i] = b'0' + (v % 10) as u8;
95 v /= 10;
96 }
97 let s = core::str::from_utf8(&buf[i..]).unwrap_or("?");
98 f.write_str(s)
99}
100
101fn write_usize(f: &mut core::fmt::Formatter<'_>, v: usize) -> core::fmt::Result {
102 write_u32(f, v as u32)
103}
104
105struct Page {
108 r: Ref,
110 resources: Vec<(Vec<u8>, Obj)>,
112}
113
114pub struct Document<'a> {
116 data: &'a [u8],
117 xref: Xref,
118 limits: pith_inflate::Limits,
119 pages: Vec<Page>,
120 encrypt: Option<Ref>,
121 cache: RefCell<BTreeMap<u32, Obj>>,
122 objstms: RefCell<BTreeMap<u32, Vec<(u32, Obj)>>>,
124}
125
126impl Resolve for Document<'_> {
127 fn deref(&self, r: Ref) -> KResult<Obj> {
128 self.resolve_obj(r).map_err(|e| match e {
129 Error::Kit(k) => k,
130 _ => KErr::BadValue("indirect object"),
131 })
132 }
133}
134
135type PageStackItem = (Ref, Vec<(Vec<u8>, Obj)>);
137
138impl<'a> Document<'a> {
139 pub fn open(data: &'a [u8]) -> Result<Document<'a>> {
141 Self::open_with_limits(data, pith_inflate::Limits::default())
142 }
143
144 pub fn open_with_limits(data: &'a [u8], limits: pith_inflate::Limits) -> Result<Document<'a>> {
146 if data.len() < 8 {
147 return Err(Error::Kit(KErr::Truncated {
148 what: "PDF header",
149 needed: 8,
150 found: data.len(),
151 }));
152 }
153 let sig = data[..1024.min(data.len())]
156 .windows(5)
157 .position(|w| w == b"%PDF-")
158 .ok_or(KErr::InvalidMagic {
159 what: "PDF signature",
160 })?;
161 let _ = sig;
162
163 let xref = match read_xref(data, &limits) {
164 Ok(x) => x,
165 Err(_) => scan_xref(data, &limits)?,
166 };
167 let trailer = &xref.trailer;
168
169 let encrypt = dict_get(trailer, b"Encrypt").and_then(Obj::as_ref);
170
171 let root = dict_get(trailer, b"Root")
172 .and_then(Obj::as_ref)
173 .ok_or(KErr::BadValue("trailer /Root"))?;
174
175 let mut doc = Document {
176 data,
177 xref,
178 limits,
179 pages: Vec::new(),
180 encrypt,
181 cache: RefCell::new(BTreeMap::new()),
182 objstms: RefCell::new(BTreeMap::new()),
183 };
184 let catalog = doc.resolve_obj(root)?;
185 let catalog_dict = catalog.dict().ok_or(KErr::BadValue("/Root"))?;
186 match dict_get(catalog_dict, b"Type") {
187 Some(Obj::Name(n)) if n.as_slice() == b"Catalog" => {}
188 _ => return Err(KErr::BadValue("/Root is not a Catalog").into()),
189 }
190 let pages_ref = dict_get(catalog_dict, b"Pages")
191 .and_then(Obj::as_ref)
192 .ok_or(KErr::BadValue("catalog /Pages"))?;
193 doc.collect_pages(pages_ref, &[])?;
194 if doc.pages.is_empty() {
195 return Err(KErr::BadValue("empty page tree").into());
196 }
197 Ok(doc)
198 }
199
200 pub fn xref_was_rebuilt(&self) -> bool {
203 self.xref.rebuilt
204 }
205
206 pub fn is_encrypted(&self) -> bool {
209 self.encrypt.is_some()
210 }
211
212 pub fn encryption(&self) -> Option<Ref> {
214 self.encrypt
215 }
216
217 pub fn pages(&self) -> usize {
219 self.pages.len()
220 }
221
222 pub fn object(&self, r: Ref) -> Result<Obj> {
225 self.resolve_obj(r).map_err(|e| Error::Object {
226 object: r.num,
227 generation: r.generation,
228 cause: Box::new(match e {
229 Error::Kit(k) => Error::Kit(k),
230 other => other,
231 }),
232 })
233 }
234
235 pub fn page_text(&self, page: usize) -> Result<String> {
237 let p = self
238 .pages
239 .get(page)
240 .ok_or(KErr::BadValue("page index"))
241 .map_err(Error::from)?;
242 if let Some(er) = self.encrypt {
243 return Err(Error::Page {
244 page,
245 cause: Box::new(Error::Object {
246 object: er.num,
247 generation: er.generation,
248 cause: Box::new(Error::Kit(KErr::Unsupported(
249 "encrypted document (/Encrypt in trailer)",
250 ))),
251 }),
252 });
253 }
254 self.page_text_inner(p).map_err(|e| Error::Page {
255 page,
256 cause: Box::new(e),
257 })
258 }
259
260 pub fn text(&self) -> Result<String> {
263 let mut out = String::new();
264 for i in 0..self.pages.len() {
265 if i > 0 {
266 out.push('\x0c');
267 }
268 out.push_str(&self.page_text(i)?);
269 }
270 Ok(out)
271 }
272
273 fn resolve_obj(&self, r: Ref) -> Result<Obj> {
276 if let Some(o) = self.cache.borrow().get(&r.num) {
277 return Ok(o.clone());
278 }
279 let loc = self
280 .xref
281 .map
282 .get(&r.num)
283 .copied()
284 .ok_or(KErr::BadValue("reference to missing object"))?;
285 let obj = match loc {
286 Loc::Plain { offset, generation } => {
287 if generation != r.generation {
288 }
292 let p = parse_obj(self.data, offset)?;
293 let mut obj = p.obj;
294 if let Some((len_ref, start)) = p.pending {
295 let len = self
297 .resolve_obj(len_ref)?
298 .as_i64()
299 .ok_or(KErr::BadValue("indirect /Length value"))?;
300 if len < 0 {
301 return Err(KErr::BadValue("negative /Length").into());
302 }
303 if let Obj::Stream { data: d, .. } = &mut obj {
304 let end = start
305 .checked_add(len as usize)
306 .and_then(|e| self.data.get(..e).map(|_| e))
307 .ok_or(KErr::Truncated {
308 what: "stream data",
309 needed: len as usize,
310 found: self.data.len().saturating_sub(start),
311 })?;
312 *d = self.data[start..end].to_vec();
313 }
314 }
315 obj
316 }
317 Loc::InStm { stm, idx } => {
318 self.expand_objstm(stm)?;
319 let members = self.objstms.borrow();
320 let list = members
321 .get(&stm)
322 .ok_or(KErr::BadValue("object stream missing"))?;
323 let (n, o) = list
324 .get(idx as usize)
325 .ok_or(KErr::BadValue("object stream index"))?;
326 if *n != r.num {
327 return Err(KErr::BadValue("object stream member number").into());
328 }
329 o.clone()
330 }
331 };
332 self.cache.borrow_mut().insert(r.num, obj.clone());
333 Ok(obj)
334 }
335
336 fn expand_objstm(&self, stm: u32) -> Result<()> {
338 if self.objstms.borrow().contains_key(&stm) {
339 return Ok(());
340 }
341 let sobj = self.resolve_obj(Ref {
342 num: stm,
343 generation: 0,
344 })?;
345 let dict = sobj.dict().ok_or(KErr::BadValue("ObjStm dict"))?;
346 let n = dict_get(dict, b"N")
347 .and_then(Obj::as_usize)
348 .ok_or(KErr::BadValue("ObjStm /N"))?;
349 let first = dict_get(dict, b"First")
350 .and_then(Obj::as_usize)
351 .ok_or(KErr::BadValue("ObjStm /First"))?;
352 let raw = decode_stream(&sobj, &self.limits)?;
353 if first > raw.len() {
354 return Err(KErr::BadValue("ObjStm /First").into());
355 }
356 let mut lx = crate::lex::Lexer::new(&raw);
358 let mut hdr: Vec<(u32, usize)> = Vec::with_capacity(n);
359 for _ in 0..n {
360 let num = lx.expect_int("ObjStm member number")?;
361 let off = lx.expect_int("ObjStm member offset")?;
362 if num < 0 || num > i64::from(u32::MAX) || off < 0 {
363 return Err(KErr::BadValue("ObjStm member header").into());
364 }
365 let off = off as usize;
366 if off >= raw.len() - first && off != 0 {
367 return Err(KErr::BadValue("ObjStm member offset").into());
368 }
369 hdr.push((num as u32, off));
370 }
371 let mut members: Vec<(u32, Obj)> = Vec::with_capacity(n);
372 for (i, &(num, off)) in hdr.iter().enumerate() {
373 let start = first + off;
374 let end = hdr.get(i + 1).map(|&(_, o)| first + o).unwrap_or(raw.len());
375 if start > raw.len() || end > raw.len() || end < start {
376 return Err(KErr::BadValue("ObjStm member span").into());
377 }
378 let slice = &raw[start..end];
379 let p = crate::object::parse_standalone(slice, 0)?;
380 members.push((num, p.obj));
381 }
382 self.objstms.borrow_mut().insert(stm, members);
383 Ok(())
384 }
385
386 fn collect_pages(&mut self, node: Ref, inherited: &[(Vec<u8>, Obj)]) -> Result<()> {
389 let mut stack: Vec<PageStackItem> = alloc::vec![(node, inherited.to_vec())];
390 let mut visited = 0usize;
391 while let Some((r, inh)) = stack.pop() {
392 visited += 1;
393 if visited > 1 << 16 {
394 return Err(KErr::TooLarge {
395 what: "page tree nodes",
396 limit: 1 << 16,
397 }
398 .into());
399 }
400 let obj = self.resolve_obj(r)?;
401 let dict = obj.dict().ok_or(KErr::BadValue("page tree node"))?;
402 let mut res = inh.clone();
404 if let Some(rd) = dict_get(dict, b"Resources").and_then(Obj::dict) {
405 for (k, v) in rd {
406 res.retain(|(ek, _)| ek != k);
407 res.push((k.clone(), v.clone()));
408 }
409 }
410 match dict_get(dict, b"Type") {
411 Some(Obj::Name(t)) if t.as_slice() == b"Page" => {
412 self.pages.push(Page { r, resources: res });
413 }
414 Some(Obj::Name(t)) if t.as_slice() == b"Pages" => {
415 match dict_get(dict, b"Kids").and_then(Obj::as_array) {
416 Some(kids) => {
417 for k in kids.iter().rev() {
419 let kr =
420 k.as_ref().ok_or(KErr::BadValue("page tree /Kids entry"))?;
421 stack.push((kr, res.clone()));
422 }
423 }
424 None => return Err(KErr::BadValue("page tree /Kids").into()),
425 }
426 }
427 _ => {
430 if let Some(kids) = dict_get(dict, b"Kids").and_then(Obj::as_array) {
431 for k in kids.iter().rev() {
432 let kr = k.as_ref().ok_or(KErr::BadValue("page tree /Kids entry"))?;
433 stack.push((kr, res.clone()));
434 }
435 } else {
436 self.pages.push(Page { r, resources: res });
437 }
438 }
439 }
440 }
441 Ok(())
442 }
443
444 fn page_text_inner(&self, p: &Page) -> Result<String> {
445 let page_obj = self.resolve_obj(p.r)?;
446 let dict = page_obj.dict().ok_or(KErr::BadValue("page dictionary"))?;
447 let contents = match dict_get(dict, b"Contents") {
450 None | Some(Obj::Null) => return Ok(String::new()),
451 Some(o) => o.clone(),
452 };
453 let mut streams: Vec<Vec<u8>> = Vec::new();
454 let collect = |o: &Obj, streams: &mut Vec<Vec<u8>>| -> Result<()> {
455 let o = match o {
456 Obj::Ref(r) => self.resolve_obj(*r)?,
457 other => other.clone(),
458 };
459 if let Obj::Stream { .. } = o {
460 let raw = decode_stream(&o, &self.limits)?;
461 streams.push(raw);
462 Ok(())
463 } else {
464 Err(KErr::BadValue("page /Contents entry").into())
465 }
466 };
467 match &contents {
468 Obj::Arr(a) => {
469 for o in a {
470 collect(o, &mut streams)?;
471 }
472 }
473 other => collect(other, &mut streams)?,
474 }
475 let res = Resources::from_dict(Some(&p.resources));
476 extract_page_text(&streams, &res, self, &self.limits).map_err(Error::Kit)
477 }
478}