Skip to content

Close out #83/#84 hardening residue (MCID, field encoding, wordwrap, list markers, justify, sig page) - #93

Merged
Tim81 merged 1 commit into
mainfrom
v1.5.5-hardening-closeout
Jun 16, 2026
Merged

Close out #83/#84 hardening residue (MCID, field encoding, wordwrap, list markers, justify, sig page)#93
Tim81 merged 1 commit into
mainfrom
v1.5.5-hardening-closeout

Conversation

@Tim81

@Tim81 Tim81 commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Closes #83 and #84 — the residual sub-items from the 2026-06-12 full-library review (most were already fixed across v1.5.1–v1.5.4; this finishes the rest).

#83 — Document/Forms

  • MCID ParentTree sizing (conformance-critical): the per-page structure ParentTree is sized by max(MCID)+1 instead of leaf-element count, so non-contiguous/sparse MCIDs produce a valid sparse array (null holes) instead of aborting Save. Only negative MCIDs are rejected; the duplicate-MCID guard (the bijection veraPDF checks) is kept; each element is still placed at index == MCID.
  • Field text encoding: AcroForm field names, values, and choice options are written as proper PDF text strings (Latin-1 when representable, else UTF-16BE+BOM) instead of silently mangling non-Latin-1 to ?. Appearance text the Standard-14 font cannot render now throws a clear error instead of writing ?.
  • Signature widget page: new PdfSignatureSettings.SignaturePage (0-based, default 0) selects the widget page; out-of-range rejected. Also fixed a latent bug where the signing path's effectiveSettings rebuild dropped new settings when SigningTime was unset.

#84 — Layout

  • WordWrap: normalises \r\n and lone \r to line breaks and splits on Unicode whitespace — Windows text no longer leaves a stray CR glyph; tabs and runs of spaces wrap correctly.
  • Nested list markers: nested ordered lists use the configured scheme (alpha/roman/decimal) via ListElement.FormatMarker instead of hardcoded decimal.
  • Justified text: word-gap counting shares one tokenization for measure and draw, consistent between embedded and Standard-14 fonts.

Tests

  • New HardeningV155CloseoutTests in both test projects; the pre-existing out-of-range-MCID-throws test updated to assert the new sparse-array (no-throw) behaviour.
  • 632 Kernel + 187 Layout tests pass; dotnet format --verify-no-changes clean; AOT smoke passes.

The MCID change is the sharp edge — the existing PdfUA1_* / PdfA2a_* veraPDF oracles (CI) are the conformance safety net. Bumps version to 1.5.5.

Implements the remaining sub-items from the 2026-06-12 review.

#83 (Document/Forms):
- ParentTree sized by max(MCID)+1 per page (sparse arrays valid; only
  negative MCIDs rejected; duplicate-MCID guard kept) so non-contiguous
  MCIDs no longer abort Save. Marked-content<->structure mapping unchanged.
- AcroForm field names/values/choice options use proper PDF text-string
  encoding (Latin-1 when representable, else UTF-16BE+BOM) instead of
  lossy '?'. Appearance text the Standard-14 font cannot render now throws.
- PdfSignatureSettings.SignaturePage selects the signature widget page
  (default 0, out-of-range rejected); wired through the signing path.

#84 (Layout):
- WordWrap normalises \r\n and lone \r to line breaks and splits on
  Unicode whitespace (no stray CR glyph; tabs/multi-space handled).
- Nested ordered list markers honour the configured scheme via
  ListElement.FormatMarker instead of hardcoded decimal.
- Justified word-gap counting shares one tokenization for measure and
  draw, consistent across embedded and Standard-14 fonts.

Tests: new HardeningV155CloseoutTests in both test projects; the obsolete
out-of-range-MCID-throws test updated to assert the new sparse behaviour.
632 Kernel + 187 Layout pass, format clean, AOT smoke passes. Bump 1.5.5.
@Tim81
Tim81 merged commit 3c8b981 into main Jun 16, 2026
@Tim81
Tim81 deleted the v1.5.5-hardening-closeout branch June 16, 2026 16:15
Tim81 added a commit that referenced this pull request Jun 16, 2026
…94)

A self-review of #93 (v1.5.5) found a regression: the per-page ParentTree
array is sized by (max MCID + 1), and PdfStructElem.Mcid is a public
setter, so a hand-built structure tree with a huge MCID (or int.MaxValue)
would attempt a multi-gigabyte allocation or overflow the length to a
negative value — crashing mid-Save instead of failing cleanly.

Cap the per-page MCID at 1,000,000 (far above any real page's
marked-content count, which is bounded by content-stream size) and throw
a clear InvalidOperationException above it, before the array is sized.
Documents tagged through the canvas are unaffected: their per-page MCIDs
are dense and sequential.

Bump to 1.5.6.
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.

Document/Forms: hardening (MCID bijection fragility, lossy Latin-1, outline Count, radio Off, dup field names)

1 participant