Skip to content

Identify object-stream members by header number; accept untyped page-tree nodes - #613

Merged
Velli20 merged 1 commit into
mainfrom
fix-object-stream-members-and-untyped-page-nodes
Oct 27, 2026
Merged

Velli20 merged 1 commit into
mainfrom
fix-object-stream-members-and-untyped-page-nodes

Conversation

@Velli20

@Velli20 Velli20 commented Oct 27, 2026

Copy link
Copy Markdown
Owner

Summary

#573: object-stream members are looked up by object number, not by xref index.
bug1978317 has an object stream with 65,542 members, but its xref stream uses /W [1 3 2]. The 2-byte in-stream index wraps above 65535, so the catalog's index 65541 became 5. The loader matched members by that index and stored whatever object sat there (an annotation) as the catalog, so /Pages was missing.

The object stream's header already names every member's object number, so it is now the only authority:

  • the load plan per object stream is the set of object numbers the xref places in it (BTreeSet<usize>);
  • the header is walked, and each listed member is inserted under its own number, stopping once all requested members are found;
  • objects the xref places in a stream that does not list them stay absent, with a CompressedObject diagnostic, instead of receiving a wrong object (this matches PDFium);
  • the in-stream index is dropped from CrossReferenceEntryType::Compressed, since nothing reads it any more. The xref-stream parser still steps over the field.

#605: page-tree nodes without /Type.
A /Kids entry with no /Type is now a branch when it has /Kids and a page otherwise, as PDFium and pdf.js do, instead of failing the read.

Verification

  • cargo test -p pdf-document -p pdf-parser -p pdf-object-reader, workspace clippy -D warnings and cargo fmt --check all pass. No new tests were added; existing assertions on the removed index were updated.
  • cargo conformance verify conf2-d93ae0eb85b4 exits 0.
  • cargo conformance verify conf2-3de5eaa05167 --allow-different exits 0. issue9105_other now reads but fails differently at render (invalid page bounds), because its page has no MediaBox and PdfPage::page_size() returns None. That is a separate cause and is left for a follow-up.
  • document_open bench, 5 interleaved A/B rounds against main: −0.3% to +2.4%. None of the bench PDFs contains an object stream, so the changed path is not exercised and these numbers are noise.

Fixes #573
Fixes #605

🤖 Generated with Claude Code

…tree nodes

The loader matched compressed objects by the xref's in-stream index and
stored whatever object sat at that index under the requested number. An
xref whose index field is too narrow for a large object stream wraps the
index, so the catalog resolved to an unrelated object. The stream header
already names each member's object number, so members are now inserted
under that number; objects the header does not list stay absent with a
diagnostic. The unused index is dropped from CrossReferenceEntryType.

Page-tree kids without /Type are now a branch when they have /Kids and a
page otherwise, instead of failing the read.

Fixes #573
Fixes #605

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Conformance reads

Documents that Safe-PDF reads differently from the base commit, compared with PDFium. A read
regresses when Safe-PDF fails to open a document it opened before, crashes or times out, or
counts a different number of pages than PDFium.

pdf.js corpus

1009 documents compared with cf0a7d6: 1 read worse, 2 read better.

Regressions

Document Base This pull request
issue17190_1 read, 1 page timeout: time limit exceeded (stage safe-read)

Improvements

Document Base This pull request
bug1978317 read_error: required dictionary key /Pages was not found @ pdf-object-reader::MissingDictionaryKey read, 1 page
issue9105_other read_error: required dictionary key /Type was not found @ pdf-object-reader::MissingDictionaryKey read, 1 page

840 documents of the PDFium corpus read as on cf0a7d6.

Details are in the job summaries of the workflow run. Rerun a case locally with
cargo conformance run --corpus <corpus> --read-only --case <id>.

@Velli20
Velli20 merged commit e43007c into main Oct 27, 2026
10 checks passed
@Velli20
Velli20 deleted the fix-object-stream-members-and-untyped-page-nodes branch October 27, 2026 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant