22 Commits
Author SHA1 Message Date
eliets2andeliets2 bb9da1c1c2 Convert replaces a removed forbidden annotation, so it is not reported again (#6306)
Co-authored-by: eliets2 <287273517+eliets2@users.noreply.github.com>
2026-11-05 20:32:39 +01:00
eliets2andeliets2 9a95273c7c Fuzz targets for PDF/A verify and convert (#6308)
Co-authored-by: eliets2 <287273517+eliets2@users.noreply.github.com>
2026-11-05 20:11:27 +01:00
eliets2andeliets2 b1c1dbdad3 One known-answer case per implemented clause (#6301)
Co-authored-by: eliets2 <287273517+eliets2@users.noreply.github.com>
2026-11-05 20:11:00 +01:00
863af864a7 M1: respect generations in PDF object references and full saves (#1143)
* M1: respect generations in COS object references and full saves

Resolve stale references to null instead of replacement objects with the
same number. Validate complete identities in writer readers, indirect
stream lengths and catalog checks, and keep generation-aware length caches.

Cover cache reuse, edit overlays, snapshots, incremental and packed/classic
full saves, and stream lengths with synthetic regressions and independent
hayro checks.

Co-Authored-By: Codex <noreply@openai.com>

* M0: clarify refreshed CI roadmap note

Co-authored-by: OpenAI Codex <noreply@openai.com>

* M1: repair contradictory xref generation references

Address maintainer feedback on the existing PR. Preserve upstream work and document the tested scope and remaining validation limits.

* M1: cover repaired generations and freed-slot round trips

Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.

* M1: document generation repair and bounded diagnostics

Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.

* M1: record generation repair regression evidence

Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.

* M1: document bounded COS generation repair

Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.

* M1: record generation repair parity evidence

Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.

* fix(cos): preserve repaired generations through preflight and saves

Keep accepted xref/header aliases across repair-aware edits and snapshots, canonicalize full-save identities, and retain bounded generation diagnostics from older revisions. Add COS, writer/encryption, and real preflight regression coverage.

* test(preflight): assert repaired aliases share saved identity

Address the review nitpick by comparing reopened HeaderImage and RowImage references after damaged full saves, for classic/packed output and edited/restored snapshots. Focused preflight regression and rustfmt check pass.

* M14: update certificate dependencies for RustSec advisories

Bump rustls-webpki to0.103.16 and webpki-root-certs to1.0.10. Preserve all other locked packages and dependency lists, manifests, Git pins, and advisory policy.

---------

Co-authored-by: MMexicann <MMexicann@users.noreply.github.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
2026-11-05 09:28:43 +01:00
Dylan M. Taylor f76dbb9e8c deps: bump tar, zip, roxmltree, rustls-webpki and symphonia to their latest versions (#5381)
- `zip`: 9.1.0 → 9.1.3

Requirement `roxmltree` 0.20 → 0.21: `ParsingOptions` gained `entity_resolver` (initializers take `..Default::default()`, i.e. none, as before) and is no longer `Copy` (two functions build it with a closure, the pattern merge.rs already used).
2026-10-29 22:21:27 -04:00
Dylan M. Taylor e4966354ee Restore the preflight check flow and the overflow menu title 2026-10-28 00:21:28 +00:00
Dylan M. Taylor c043c82531 Refactor preflight for strict Clippy checks 2026-10-27 23:12:51 +00:00
a047c6ba09 chore: resolve SonarCloud maintainability issues (#4356)
* chore: resolve SonarCloud maintainability issues

* fix(packaging): use verify_sha256 helper function

* style: cargo fmt

* fix: restore wildcard imports and fix method-reference type errors

Revert the glob-import expansions (they missed SomIndices and left unused
imports), revert char::is_ascii_digit where the iterator yields char by
value, and pass the content slice to prune_doomed_xobjects as &[Vec<u8>].

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

* Keep XObject decodability check without binding content in interp

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Dylan Taylor <dylan@craftmaker.dev>
2026-10-23 23:28:18 -04:00
Dylan M. Taylor 93b25f67a6 Merge main into fix/coderabbit-c5-forms-misc
Keep the Ops iterator from this branch and carry main's long-number skip
(MAX_RETRIED_TOKEN) into its operand error path.
2026-10-22 22:07:19 -04:00
aiongg 62b54fce09 fix(preflight): check the actions in an indirect /Next array 2026-10-22 20:56:33 +00:00
aiongg 90982ba9a8 fix(preflight): check the actions an allowed action chains to
Conversion and verification looked only at an action's own /S. An allowed
action (a GoTo, say) whose /Next held a JavaScript or other forbidden
action written directly inside it was kept, and verification never looked
at actions written directly in a catalog /OpenAction or an annotation /A.
Both now follow /Next through the actions written inside an action (an
indirect /Next is an object of its own, checked as one), within a bound,
and conversion removes the whole chain.
2026-10-22 17:57:53 +00:00
aiongg adab150a45 fix(preflight): find annotation pages from one pass over the pages
verify found each annotation's page by copying and searching every page's
/Annots array again for each annotation, so a page with many annotations
cost quadratic time. The annotation-to-page map is built once (the first
page that lists an annotation keeps it, as before).
2026-10-22 17:57:53 +00:00
aiongg 0a30b4e081 fix(preflight): read content colour one operator at a time
content_colour parsed each content stream into a full list of operators
before looking at any of them, so a small compressed stream of millions of
tiny operators became gigabytes of parsed operators in memory. The content
parser's loop is now an iterator (pdfcraft_content::ops), which parse
collects; preflight reads it one operator at a time and stops once gray,
RGB and CMYK are all found.
2026-10-22 17:57:53 +00:00
aiongg 853a9ae1e3 fix(preflight): decode an output-intent profile within 16 MiB
Reading the colour space from an ICC header when /N is missing decoded
the whole profile under the general 1 GiB stream limit to look at four
bytes. The profile now decodes within 16 MiB; a larger one leaves the
component count unknown.
2026-10-22 17:08:54 +00:00
7d9adcb8f1 fix(preflight): identify PDF standards by XML namespace (#3364)
* fix(preflight): identify standards by XML namespace

* fix(preflight): bound XMP attribute parsing work

* fix(preflight): cap XMP during stream decoding

* Preflight: read the PDF/A and PDF/UA identification by its usual prefix when the XMP can't be parsed as XML

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

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 02:48:40 -04:00
Guillem Hermida c56c0160b9 fix(preflight): read device colour from content operators, not whitespace-split bytes (#2260)
uses_device_colour found content streams by their dictionaries and split
their bytes on whitespace. It skipped form XObjects with /Type /XObject and
tiling patterns, missed `cs`/`CS` with a device space, inline images and
operators before a delimiter, and took a `k` in a string, a comment, inline
image data, a font program or an ICC profile for DeviceCMYK. A CMYK logo in a
form therefore got an sRGB output intent and passed pdfa_verify.

Content streams are now found by role (page /Contents, Type 3 glyphs, forms,
appearance streams, tiling patterns) and read with pdfcraft_content::parse.
Reading stops once all three device spaces are seen.
2026-10-15 02:52:28 -04:00
Marco Arnulfo 0108a5b07b fix(preflight): find colour operators after any PDF whitespace (#1334) (#1373)
The PDF/A device-colour scan split content streams only on spaces and
line feeds, so `0 0 0 1 k` written with carriage returns, tabs, form
feeds or NULs between the tokens went unseen: verify reported no
DeviceCMYK, and convert gave the CMYK page an sRGB output intent.

Split on all six whitespace characters of ISO 32000-2 §7.2.3, using the
lexer's own `is_whitespace` (now exported from pdfcraft-cos) instead of
a second list.

Adds tests::device_colour_is_found_after_any_whitespace, which fails
before this change; its gray and RGB controls check that those pages
still get the sRGB output intent.
2026-10-12 06:25:42 -04:00
513a1ecc3a i18n: let the layers below hand their sentences over, so they can be translated (#478)
* i18n: let the layers below hand their sentences over, so they can be translated

The accessibility findings, the PDF/A problems, the signature details, the
page-range mistakes and the edit labels were English in all ten languages,
because matching their wording from the UI with a tl! literal would break
silently whenever the engine changed it.

So each layer now hands the wording over instead, apart from the document's
own words: a WORDINGS list of every sentence it can say, with holes in it, and
said(&words), which looks the wording up through the closure it is given and
fills the holes in a single pass. in_english changes nothing, for the CLI and
the tests; the UI passes &i18n::words, a catalog lookup. A wording with no
entry comes back as it stands, which is the English, so the nine catalogs this
does not touch read exactly as before.

a11y::report_html takes a language tag and a words closure, so a saved report
reads the way the panel read, down to its lang attribute. print::PrintError
gained a variant per thing a person can be wrong about, with the numbers apart
from the words; faults rather than mistakes keep their own text.

Spanish translates all of it (107 entries). spanish_covers_what_the_engine_says
requires an entry per wording in the eight lists and
spanish_keeps_the_holes_in_what_the_engine_says requires the holes to survive
the translation, so the catalog cannot fall behind the engine unnoticed.

No new tl! literal, so the Chinese, French and Russian UI-literal gates are
unaffected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* Sign tests from #1099: compare against the &'static str kinds

* Camera tests: undo returns a Label now

---------

Co-authored-by: Fernando Areán <soporte@codebit.es>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-11 15:45:51 -04:00
e4cd9e2557 PDF/A: no sRGB output intent for CMYK documents, and pdfa_verify checks the intent's colour space (#667) (#732)
* PDF/A: no sRGB output intent for CMYK documents, and verify checks the intent's colour space (#667)

pdfa_convert always added an sRGB output intent when there was none,
even for documents whose only content is DeviceCMYK, and pdfa_verify
then called them compliant: it only checked that some PDF/A output
intent existed. ISO 19005-2 6.2.4.3 allows DeviceCMYK only with a CMYK
output intent, and DeviceRGB only with an RGB one.

- verify reads the PDF/A output intent's destination profile (/N, else
  the ICC header's data colour space) and reports DeviceCMYK under a
  non-CMYK intent and DeviceRGB under a non-RGB one (6.2.4.3, not
  fixable).
- convert adds the generated sRGB intent only when the document has no
  DeviceCMYK; a CMYK document keeps the existing "needs a CMYK output
  intent (not added automatically)" issue instead of a wrong intent.
- Device colour detection tells gray, RGB and CMYK apart (gray works
  under any intent).

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

* PDF/A: DefaultRGB/DefaultCMYK resources satisfy the output-intent colour check

ISO 19005-2 6.2.4.3 accepts device colour drawn through a default colour space under any output
intent.

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

---------

Co-authored-by: DWAA1660 <DWAA1660@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-10 06:22:47 -04:00
Brandon ThomasandClaude Opus 5.5 d3db99818f Rename PrintCraft to PdfCraft (#174)
The app, crates, binaries, bundle id, packaging, icons, screenshots and docs are now
PdfCraft / pdfcraft (repo storytold/pdfcraft). On first launch the desktop app moves the
PrintCraft settings and crash-recovery folders to the new name, and both apps read settings
saved under the old storage key, so upgrades keep recent files, preferences and unsaved work.
The signing test fixtures keep their PrintCraft subject names (they are binary).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 16:03:57 -04:00
Brandon ThomasandClaude Opus 5.5 1434db626a Never crash: deny the panic lints in crates that are already clean
annot, compare, content, cos, export, geom, model, ocr, preflight, print and redact have no
production `unwrap`/`expect`/`panic!`/`unreachable!`/`todo!`/`unimplemented!`. The attribute
keeps it that way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 13:12:21 -04:00
Brandon ThomasandClaude Opus 5.5 4d60af8b1e M11: PDF/A (new preflight crate): verify PDF/A-2b/3b structural rules, Save as PDF/A (XMP identification, generated sRGB output intent, forbidden actions, annotation flags, interpolation, encryption), PDF/A dialog; pdfa_verify, pdfa_convert tools
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 07:19:54 -04:00