From 2cc21e19b2a0ea6ac48b0ca4f0fa098ccd5fd727 Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Sat, 17 Oct 2026 04:55:36 +0200 Subject: [PATCH] Ignore non-finite w:sz, w:spacing and w:ind values in DOCX import Found while testing crates/textimport/src/docx.rs:183 (run_attrs, w:sz) and :206-214 (para_attrs, w:spacing/w:ind via the `tw` closure) Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 --- crates/textimport/src/docx.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/crates/textimport/src/docx.rs b/crates/textimport/src/docx.rs index c4375669..783b010c 100644 --- a/crates/textimport/src/docx.rs +++ b/crates/textimport/src/docx.rs @@ -180,7 +180,7 @@ fn run_attrs(rpr: Option<&El>) -> CharAttrs { if let Some(s) = r.on("strike") { a.strikethrough = Some(s); } - if let Some(sz) = r.val("sz").and_then(|v| v.parse::().ok()) { + if let Some(sz) = r.val("sz").and_then(|v| v.parse::().ok()).filter(|v| v.is_finite()) { a.size = Some(sz / 2.0); } if let Some(f) = r.child("rFonts").and_then(|f| f.attr("ascii").or(f.attr("hAnsi"))) { @@ -203,7 +203,7 @@ fn run_attrs(rpr: Option<&El>) -> CharAttrs { fn para_attrs(ppr: Option<&El>) -> ParaAttrs { let mut a = ParaAttrs::default(); let Some(p) = ppr else { return a }; - let tw = |v: Option<&str>| v.and_then(|v| v.parse::().ok()).map(|v| v / 20.0); + let tw = |v: Option<&str>| v.and_then(|v| v.parse::().ok()).filter(|v| v.is_finite()).map(|v| v / 20.0); if let Some(sp) = p.child("spacing") { a.space_before = tw(sp.attr("before")); a.space_after = tw(sp.attr("after")); @@ -680,6 +680,28 @@ mod tests { assert_eq!(st.text, "Date: 1 May 2026.\nLink"); } + /// `str::parse::` accepts "NaN"/"inf"; sizes, spacing and indents must ignore them. + #[test] + fn non_finite_sizes_spacing_and_indents_are_ignored() { + let document = format!( + r#" + + ab + c + "# + ); + let st = import(&docx(&document, "", "")).unwrap().story; + let fin = |v: Option| v.is_none_or(f64::is_finite); + for p in &st.paras { + let p = &p.para; + assert!(fin(p.space_before) && fin(p.space_after), "{p:?}"); + assert!(fin(p.left_indent) && fin(p.right_indent) && fin(p.first_line_indent), "{p:?}"); + } + for at in [0, 1] { + assert!(fin(st.format_after(at).over.size), "{:?}", st.format_after(at).over.size); + } + } + #[test] fn tracked_changes_import_as_accepted_including_moves() { // Regression (#256): text in a tracked move destination (`w:moveTo`) vanished on import.