Commit Graph
171 Commits
Author SHA1 Message Date
Martin BallandClaude Opus 5.5 17d19b42c5 #3642: review — the DIFAT sample is test-only, valid .doc/.xls files pass the guard, and budget drops are logged
- repeating_difat_sample is built only for tests: this crate's, and the
  readers' through a `test-support` feature they turn on as a
  dev-dependency; it is no longer in the production API.
- Tests write valid compound files with the cfb crate in Word's and Excel's
  shapes (WordDocument + table stream with Data, summary and ObjectPool
  streams; Workbook with summary streams), in 512- and 4096-byte sectors,
  plus an 8 MB one whose FAT sectors spill into a DIFAT chain; each passes
  cfb_guard::check and opens (no Word- or Excel-made files are added).
- The .doc work budget notes what it leaves out (floating objects, link
  targets, alt text, Prm formatting) and logs one warning per kind once the
  document is read (#3692).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CX1hMKX28764Lrx5moxs1o
2026-10-25 23:47:39 +00:00
Martin BallandClaude Opus 5.5 bbeb7e2253 #3642: compound-file precheck shared in wordcraft-doc; .docx encryption sniff and .xls reader call it too
Finding 63 follow-up. #3642 names three cfb call sites: the .doc reader, the encrypted-package sniff and decrypt in docx/crypt.rs (reached for any .docx name), and the .xls reader. The DIFAT precheck moves from docbin to wordcraft_doc::cfb_guard::check (bytes only, no cfb dependency) and runs before every CompoundFile::open in the three crates. The crypt.rs change is only the two precheck calls (open PR #2125 also edits that file).

Regression tests use the shared hostile sample (cfb_guard::repeating_difat_sample): docbin a_difat_repeating_one_fat_sector_is_refused_before_cfb_builds_the_fat, docx tests/malformed.rs and formats sheet::xls a_repeating_difat_is_refused_before_cfb_opens_it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 23:47:30 +00:00
Dylan M. Taylor e5cffe7641 Merge pull request #4233 from VoiceLessQ/fix/small-cleanups
Small fixes: MERGEFIELD in any case, 18 SonarCloud closures, one unused constructor
2026-10-25 16:45:39 -04:00
divyanshu2074 b37a732455 fix(formats): support negative timezone offsets and author fallback in ODT metadata (#2189) 2026-10-25 10:39:59 -04:00
SimoneandLucenx9 b0b7e6b5ea Fix Markdown code span line endings (#3804)
Co-authored-by: Lucenx9 <185146821+Lucenx9@users.noreply.github.com>
2026-10-25 10:32:31 -04:00
divyanshu2074 1b0faddfa8 fix(formats): ignore block and inline HTML comments in markdown import (#2225) 2026-10-25 10:31:01 -04:00
divyanshu2074 0d2d1776dd fix(formats): support backslash space, soft breaks and zero-width spaces in RTF (#2250) 2026-10-25 10:29:09 -04:00
VoiceLessQ 65a0dc8dc6 Method paths for 18 closures that only call a method (SonarCloud S1612)
SonarCloud's analysis of main at b4da59f0c lists 23 closures such as `|v| v.as_slice()` that hand their argument straight to one method. This passes the method itself: `Vec::as_slice`, `str::to_ascii_lowercase`, `f64::total_cmp` and the like, all forms the repo already uses elsewhere. Behaviour is unchanged.

Five stay. The four in crates/proof/src/es/mod.rs sit in code that #4191 replaces, and its replacement already uses `PoisonError::into_inner`. In crates/engine/src/io/safe_save.rs the path would be `<dyn std::error::Error + Send + Sync>::is::<Guided>`, which reads worse than `|inner| inner.is::<Guided>()`.
2026-10-25 01:19:28 -02:00
aiongg db8efbe593 LaTeX: \'{} and \"{} import as the spacing acute and diaeresis, not an apostrophe and a quotation mark (#4170) 2026-10-24 21:05:19 +00:00
aiongg 26c4d4b869 Merge PR #4170: Import LaTeX \^{} and \~{} as plain ^ and ~ 2026-10-24 20:38:55 +00:00
VoiceLessQ d7429d217a Pictures: one decoder checks the header against the budget, progressive JPEG coefficients included (#3644)
Document pictures now decode through wordcraft_geom::picture (behind a
new `image` feature of the geom crate). It reads the header, refuses the
picture before anything is allocated when the decode's peak would pass
the budget, then decodes with the header's size and the budget as
limits.

The peak is the larger of three moments: the decoder's output beside
what it holds while decoding, the output beside its RGBA8 conversion,
and that beside a premultiplied copy. A progressive JPEG's decoder
(zune-jpeg) holds an i16 for every coefficient of every component, in
whole MCUs, for the whole picture; the SOF header gives that size. A
7900 x 7900 progressive JPEG without subsampling needs 9 bytes a pixel
(561 MB), past the 512 MB budget, although two RGBA buffers (499 MB)
fit. With the fix reverted, the test's header-only file of that size
was decoded and the test process peaked at 542 MiB resident.

- Render and PDF export ask the probe in their wrappers (decode_pixmap,
  load_image), so a picture past the budget gets the grey box or is
  left out, as before.
- The crop dialog and every picture edit decoded with load_from_memory
  and looked at the size afterwards. They decode through the probe now,
  and so do wrap outlines and the RTF re-encode.
- A picture edit has the drawing budget instead of an 80 M pixel cap
  checked after decoding. A picture past that budget (about 67 M RGBA
  pixels) can't be drawn either, so no edit that could be seen is lost.
2026-10-24 18:01:45 -01:00
NetterSilverandClaude Haiku 5.5 ee558313b0 Import LaTeX \^{} and \~{} as plain ^ and ~
Found while testing crates/formats/src/latex.rs:2212-2216 (accent command handling, fallback for an empty argument)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 18:45:44 +00:00
NetterSilverandClaude Haiku 5.5 97a6a26ca9 Format negative zero as 0 in spreadsheet import (#4040)
Found while testing crates/formats/src/sheet.rs:726-727 (fn number)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-24 10:02:47 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 01d0c63451 Sonar S1612: use fn paths for simple method closures (#4103)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 04:33:08 -04:00
47edcd2ff2 chore: resolve SonarCloud maintainability issues (#4083)
* chore: resolve SonarCloud maintainability issues

* fix: restore compiling refactors, revert behaviour changes, run cargo fmt

- fontdb::norm: keep the closure for filter (char::is_alphanumeric takes
  self, not &self, so it does not fit Iterator::filter).
- story.rs: write_mark_rpr needs &mut self (rev_attrs, rpr_change).
- Revert the viewport meta change and the return 0 added to
  workspace_version/sha256, which changed behaviour or masked failures.
- cargo fmt.

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

* Import Document in odt page_parts after dropping glob re-export

* fix: apply_kind_properties binds ContentControl; cell_ref keeps char closures

* fix(engine): pass case helpers by value (clippy needless borrows)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Dylan Taylor <dylan@craftmaker.dev>
2026-10-24 03:54:19 -04:00
NetterSilverandClaude Haiku 5.5 957b1c3e6e Drop U+FFFE and U+FFFF from ODT export text (#3817)
Found while testing crates/formats/src/odt.rs:49-63 (fn x, the ODT text escaper; filter at line 58)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-23 10:31:21 -04:00
aiongg eb12fc6ee4 Integration: cargo fmt 2026-10-22 01:59:03 +00:00
aiongg 64f98d824a Merge PR #2280: fix(formats): support xs:time, string-value, and case-insensitive cell types in spreadsheets 2026-10-22 01:54:24 +00:00
aiongg 04b3881e3e Integration: track t06
docs/gaps.md row 4: one row (t06 had kept a second, older copy of it); t05's #1840 and t06's #2964 clauses both in, main's #2963 clause kept. docs/recovery.md: t06's retry sentence with t01's base64 size text. Test files: both tracks' tests kept whole.
2026-10-22 01:47:34 +00:00
aiongg 16d1c8a933 Integration: track t05
crates/pdf/src/lib.rs: t01's vector_text kept before t05's watermark (box area signature). Test files and canvas.rs tests: both tracks' tests kept whole. Docs: status lines combined, rows unioned or word-merged.
2026-10-22 01:46:47 +00:00
aiongg 0d3b8eb0cb Integration: track t04
crates/formats/src/odt.rs: t01's Body::new/take_blocks kept; take_blocks finishes tables with t04's TableB::finish (column widths). Test files: both tracks' tests kept whole. Docs: status lines combined, rows unioned or word-merged.
2026-10-22 01:46:17 +00:00
aiongg 86df1e70ce Integration: track t03
# Conflicts:
#	ROADMAP.md
#	crates/formats/src/html.rs
#	docs/gaps.md
#	docs/ui-parity.md
2026-10-22 01:44:54 +00:00
aiongg 245b5bd8d0 Integration: track t02
Docs: status lines combined (t02's entries first); log rows unioned; file-format-parity .rtf row from t02 (#1653, duplicate .rtf row dropped as t02 did), .odt row word-merged.
2026-10-22 01:44:01 +00:00
aiongg 520f54cb81 Integration: cargo fmt 2026-10-22 01:34:26 +00:00
aiongg 5c260a16fd Integration: cargo fmt 2026-10-22 01:31:48 +00:00
aiongg d015988e93 Integration: #2334 test a formula string result continued in a CONTINUE record 2026-10-22 01:25:01 +00:00
aiongg 92b36ceae0 Merge PR #2557: #1681: HTML export and import keep furigana (ruby)
docs/file-format-parity.md: main's status line with this change added; both progress-log rows, this one first.
docs/localization-parity.md: main's status line with this change added.
2026-10-22 01:23:40 +00:00
aiongg 9cd24539bd Merge PR #2549: #1653: RTF import decodes the East Asian multibyte code pages (932/936/949/950)
docs/file-format-parity.md: main's status line with this change added.
2026-10-22 01:23:23 +00:00
aiongg a05c650a16 Merge PR #3391: ODT: table column widths are read, so a resized column survives a save
crates/formats/src/odt.rs: StyleInfo keeps both cell_valign (#2416) and column_width.
ROADMAP.md, docs/file-format-parity.md, docs/gaps.md: main's status lines kept; the PR's log rows added.
2026-10-22 01:23:19 +00:00
aiongg 5b19acb4ec Merge PR #3193: ODT: read an embedded equation's own MathML instead of its undecodable metafile preview
ROADMAP.md: progress log carries both sides.
docs/file-format-parity.md: ODT row keeps #873's headers and footers and adds #3193's formula objects.
2026-10-22 01:23:17 +00:00
aiongg a7b8e32fde Merge PR #2331: fix(mathml): support linethickness=none and menclose notations
crates/formats/src/mathml.rs: menclose keeps main's box-with-strikes reading (the writer emits "box horizontalstrike") and adds the PR's radical, actuarial, cross and case-insensitive notations.
2026-10-22 01:22:19 +00:00
aiongg 601af83f2c Integration: #2416 collapse the nested vertical-align if (clippy::collapsible_if) 2026-10-22 01:22:13 +00:00
aiongg 544647318d Merge PR #873: ODT: read headers and footers from the master page (#863)
crates/formats/src/odt.rs: Body::new from #873 with main's xml_space_end; parse_tracked returns main's document font as 4th element and #873's page parts as 5th (the reviewed integration fix for #873).
docs/file-format-parity.md: status line, ODT row and change log carry both sides.
2026-10-22 01:22:10 +00:00
aiongg c8b657ff9b Merge PR #2416: fix(formats): support table cell vertical alignment in rtf, html, and odt
crates/formats/src/html.rs: both sides' appended tests kept.
2026-10-22 01:22:05 +00:00
aiongg 96dd01bb30 Integration: #2273 Latin weight/style and line styles take precedence over Asian, complex and line-type attributes 2026-10-22 01:21:51 +00:00
aiongg 82b9795c62 Merge PR #2273: fix(formats): support asian/complex scripts and underline/strike types in ODT
crates/formats/src/odt.rs: kept main's tests and added the PR's test after them.
2026-10-22 01:21:33 +00:00
aiongg 415320056b Integration: #2269 LaTeX lengths keep macro names case-sensitive 2026-10-22 01:21:17 +00:00
aiongg eae3d8496e Merge PR #2269: fix(formats): parse leading plus and case-insensitive units in LaTeX lengths 2026-10-22 01:21:08 +00:00
aiongg f14a0ce13f Integration: #2268 ODT lengths accept only the standard pc unit for picas 2026-10-22 01:20:59 +00:00
aiongg 7d8f31547e Merge PR #3320: Require hex digits in percent_decode escapes 2026-10-22 01:20:54 +00:00
aiongg 61fbb080a9 Merge PR #2232: fix(formats): support borderless and bordered tables in LaTeX import and export
crates/formats/src/latex.rs: kept both sides' new tests
2026-10-22 01:20:23 +00:00
aiongg d15c57a713 Integration: #2153 drop trailing blank line and use assert! for bool checks in tab_separated_list_markers 2026-10-22 01:20:12 +00:00
aiongg 0c583fe58c Merge PR #2153: fix(formats): support tab-separated list markers in markdown
crates/formats/src/markdown.rs: kept both sides' new tests
2026-10-22 01:20:08 +00:00
aiongg 5b9b1f552b Merge PR #2144: fix(formats): support distributed paragraph alignment in RTF 2026-10-22 01:20:00 +00:00
aiongg d8e5b1823d Merge PR #2140: fix(formats): support left alignment in markdown tables
crates/formats/src/markdown.rs: kept both sides' new tests
2026-10-22 01:19:56 +00:00
aiongg 0c039708db Integration: #3267 leave footnote definitions out of link definitions 2026-10-22 01:19:54 +00:00
aiongg c88b2740d8 Merge PR #2268: fix(formats): parse case-insensitive and pica units in ODT lengths 2026-10-22 01:19:50 +00:00
aiongg f2e441862d Merge PR #2249: fix(formats): support 4/8-digit hex, space-separated rgb and hsl in parse_color 2026-10-22 01:19:47 +00:00
aiongg 05c34486f5 Merge PR #2086: fix(export): pictures marked decorative are skipped by screen readers 2026-10-22 01:19:47 +00:00
aiongg 81fbf9fb77 Merge PR #3322: wasm: use the browser clock only on wasm32-unknown-unknown, not on WASI 2026-10-22 01:19:46 +00:00