Repository navigation
Skip a dictionary value that has no key rather than refusing the document - #64
Conversation
…ment A dictionary entry is a name followed by a value, and the parser threw "name expected" the moment it found anything else where a key belonged. pdfTeX has broken that rule for decades: it writes its PTEX.FullBanner into the document information dictionary as two bare strings with no key in front of them, so every document TeX Live produces was unreadable in every open mode. Adobe Acrobat, Chrome and Edge all step over the stray values and read the rest of the file. The pairing loop now walks the items one at a time instead of two at a time. A name takes the item after it as its value; anything else is a value with nothing to key it under, and is stepped over on its own. That matters beyond the pdfTeX case: a single stray value leaves an odd number of items, and a loop that always advances by two would read the following key as its value and the value after that as a key, quietly mispairing every entry to the end of the dictionary. Dropping the dangling key of a truncated dictionary still falls out of the same loop, so the assertion that guarded that case goes away with it.
|
Warning Review limit reached
Next review available in: 8 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PR Summary by QodoTolerate keyless values in PDF dictionaries during parsing
AI Description
Diagram
High-Level Assessment
Files changed (3)
|
There was a problem hiding this comment.
Pull request overview
This PR improves PdfSharpCore’s resilience when reading malformed PDF dictionaries by tolerating stray dictionary values without keys (notably the PTEX.FullBanner strings produced by pdfTeX), aligning behavior with common PDF readers and fixing the failure described in empira/PDFsharp#376.
Changes:
- Updated
Parser.ReadDictionaryto advance one item at a time, pairing onlyPdfNamekeys with the following value and skipping unkeyed values. - Extended the
RawPdf.Buildtest helper to optionally inject extra trailer entries (used to model pdfTeX’s/Infotrailer reference). - Added a focused regression test suite covering pdfTeX-style
/Infodictionaries, odd-item mispairing prevention, and save/reopen behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| PdfSharpCore/Pdf.IO/Parser.cs | Makes dictionary parsing tolerant of unkeyed values to avoid rejecting otherwise readable PDFs. |
| PdfSharpCore.Test/IO/RawPdf.cs | Adds optional trailer augmentation to support constructing pdfTeX-like PDFs in tests. |
| PdfSharpCore.Test/IO/DictionaryEntryWithoutKeyTests.cs | Adds regression coverage for unkeyed dictionary values and ensures correct pairing and round-tripping. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| /// Anything in <paramref name="extraTrailerEntries" /> is written into the trailer beside | ||
| /// the size and the root. |
Code Review by Qodo
1.
|
A parser change can spin rather than throw, and these tests feed the parser dictionaries no writer should produce. They now open the document on a worker thread under a timeout, the way the content lexer tests already do, so a pairing loop that stops advancing fails the run instead of stalling the test host on it. The trailer entries the builder takes are copied in verbatim, so say so: a caller that leaves the leading solidus off gets a malformed document rather than an argument error.
Reproduces and fixes empira/PDFsharp#376 in this fork.
What was wrong
Parser.ReadDictionarywalked the parsed items two at a time and threwname expectedthe moment the item in the key position was not aPdfName.pdfTeX has broken that rule for decades. It writes its
PTEX.FullBannerinto the document information dictionary as two bare strings with no key in front of them:Every document TeX Live produces was therefore unreadable in every open mode, with no option to suppress it. Acrobat, Chrome and Edge all step over the stray values and read the rest of the file.
The fix
The pairing loop now advances one item at a time. A name takes the item after it as its value; anything else is a value with nothing to key it under, and is stepped over on its own.
That matters beyond the pdfTeX case, which happens to leave an even number of items. A single stray value leaves an odd number, and a loop that always advances by two reads the following key as its value and the value after that as a key — quietly mispairing every entry to the end of the dictionary.
AValueWithNoKeyDoesNotPairTheEntriesAfterItUpWronglypins that down.Dropping the dangling key of a truncated dictionary falls out of the same loop, so the
Debug.Assertthat guarded that case goes away with it. The existingUnterminatedObjectTestsstill cover it.Tests
PdfSharpCore.Test/IO/DictionaryEntryWithoutKeyTests.cs— 8 tests, all failing before the change:RawPdf.Buildgained an optionalextraTrailerEntriesparameter so a test can hang an/Infodictionary off the trailer the way pdfTeX does.Full suite: 1048 passed, 1 skipped, on both
net8.0andnet10.0.