spectre_parse 1.0.0

Lazy PDF parser — xref-only at open(), objects materialize on demand. Read-only. Powers the spectre_pdf extraction crate.
Documentation
//! Walk the first few outline entries of the supplied PDF, printing
//! their /A /D values so we can verify the named-dest path triggers.
use spectre_parse::{Document, Object};

fn main() {
    let path = std::env::args().nth(1).expect("usage: trace_one_outline <pdf>");
    let bytes = std::fs::read(&path).expect("read");
    let doc = Document::open(&bytes).expect("open");
    let cat = doc.catalog().expect("catalog");
    let outlines_ref = cat
        .get(b"Outlines")
        .expect("Outlines")
        .as_reference()
        .expect("Outlines ref");
    let outlines = doc.get_dictionary(outlines_ref).expect("Outlines dict");
    let first_ref = outlines
        .get(b"First")
        .expect("First")
        .as_reference()
        .expect("First ref");

    let mut cur = Some(first_ref);
    let mut count = 0;
    while let Some(id) = cur {
        if count >= 5 {
            break;
        }
        count += 1;
        let dict = match doc.get_dictionary(id) {
            Ok(d) => d,
            Err(e) => {
                println!("err: {e}");
                break;
            }
        };
        let title = dict.get_optional(b"Title");
        println!("--- entry #{count} (id={id:?}) ---");
        println!("  Title: {title:?}");
        if let Some(a_obj) = dict.get_optional(b"A") {
            println!("  A: {a_obj:?}");
            let action = match a_obj {
                Object::Reference(aid) => doc.get_dictionary(*aid).ok(),
                Object::Dictionary(d) => Some(d.clone()),
                _ => None,
            };
            if let Some(action) = action {
                let d = action.get_optional(b"D");
                println!("  A.D: {d:?}");
                let s = action.get_optional(b"S");
                println!("  A.S: {s:?}");
            }
        }
        if let Some(dest_obj) = dict.get_optional(b"Dest") {
            println!("  Dest: {dest_obj:?}");
        }
        cur = dict
            .get_optional(b"Next")
            .and_then(|o| o.as_reference().ok());
    }
}