Skip to content

Drop XML-illegal control characters from PDF/A XMP packet - #2827

Open
Silvertree2010 wants to merge 1 commit into
storytold:mainfrom
Silvertree2010:fix/h1987-pdf-a-conversion-writes-xml-ille
Open

Silvertree2010 wants to merge 1 commit into
storytold:mainfrom
Silvertree2010:fix/h1987-pdf-a-conversion-writes-xml-ille

Conversation

@Silvertree2010

Copy link
Copy Markdown
Contributor

Found while testing crates/preflight/src/xmp.rs:37 (no existing issue): PDF/A conversion writes XML-illegal control characters from /Info into the XMP packet.

Cause

xmp::esc only replaced & < > ", so C0 control characters in /Info values (Title, Author, Subject, Keywords, Producer, Creator) were copied into the XMP packet. XML 1.0 forbids those characters, so the packet was malformed and the PDF/A output invalid.

Fix

xmp::esc now drops the characters XML 1.0 forbids before escaping. These are the C0 controls other than tab, LF and CR, plus U+FFFE and U+FFFF. This matches export::esc and organize::pdfx::esc. The regression test builds a document with control characters in each /Info field and checks the packet.

Verified

  • Regression test xmp_packet_drops_xml_illegal_characters_from_info: fails on main without the fix and passes with it (cargo test -p pdfcraft-preflight --lib xmp_packet_drops_xml_illegal_characters_from_info).
  • cargo xtask ci passes.

Not changed

DEL (U+007F) is legal in XML 1.0 and is still passed through. Reading XMP back (unescape) and the other XMP fields are unchanged.

🤖 Generated with Claude Code

Found while testing crates/preflight/src/xmp.rs:37

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

@ahmadmuj ahmadmuj left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked XML 1.0 boundaries and exact values for all six Info fields with Expat after conversion, save, and reopen. Both PDF/A-2b and PDF/A-3b pass; the unchanged checks fail on the base. This checks the metadata XML, not full PDF/A conformance.

One local gate fails on the declared Rust 1.95 toolchain: cargo clippy -p pdfcraft-preflight -j 2 --lib --tests -- -D warnings reports nonminimal_bool at xmp.rs:41. The base passes; CI uses Rust 1.99.1. Could we replace the first clause with (*c >= '\u{20}' || matches!(c, '\t' | '\n' | '\r'))? This keeps the same character boundaries.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants