diff --git a/CHANGELOG.md b/CHANGELOG.md index fb6b3c3..4c43887 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to this project will be documented in this file. - CSS-based label filtering enables responsive toggle without any re-rendering ### Fixed +- **NullReferenceException in FindIndexOfNextParaMark when comparing documents with body-level bookmarks** - `FindIndexOfNextParaMark` assumed all elements in the comparison unit array were `ComparisonUnitWord`, but documents with `bookmarkStart`/`bookmarkEnd` as direct children of `w:body` produce other `ComparisonUnit` types. Now handles any `ComparisonUnit` with `Contents` (including `ComparisonUnitGroup`) and adds a null guard for the `LastOrDefault()` call. - **Paginated rendering: text clipped at page bottom + inconsistent paragraph spacing (Issue #114)** - Fixed `lineRule` default handling: when `w:lineRule` is absent but `w:line` is present, treat as "auto" per OOXML spec (ISO/IEC 29500). Previously the line value was ignored, causing accumulated line-height mismatches that clipped the last line on pages. - Fixed `contextualSpacing` handling: now suppresses both `spacingAfter` (margin-bottom) AND `spacingBefore` (margin-top) for consecutive same-style paragraphs. Previously only `spacingAfter` was suppressed, leaving inconsistent inter-paragraph gaps. diff --git a/Docxodus.Tests/WmlComparerBodyLevelBookmarkTests.cs b/Docxodus.Tests/WmlComparerBodyLevelBookmarkTests.cs new file mode 100644 index 0000000..25074f9 --- /dev/null +++ b/Docxodus.Tests/WmlComparerBodyLevelBookmarkTests.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable + +using System; +using System.IO; +using Docxodus; +using Xunit; + +namespace OxPt +{ + public class WmlComparerBodyLevelBookmarkTests + { + [Fact] + public void Compare_WithBodyLevelBookmarks_DoesNotThrowNullReference() + { + DirectoryInfo sourceDir = new DirectoryInfo("../../../../TestFiles/"); + var original = new WmlDocument(Path.Combine(sourceDir.FullName, "WC/WC-BodyBookmarks-Before.docx")); + var modified = new WmlDocument(Path.Combine(sourceDir.FullName, "WC/WC-BodyBookmarks-After.docx")); + + var settings = new WmlComparerSettings(); + + // The modified document has bookmarkStart/bookmarkEnd as direct children + // of w:body (siblings of w:p). This caused a NullReferenceException in + // FindIndexOfNextParaMark because it assumed all ComparisonUnits were + // ComparisonUnitWord, but body-level bookmarks produce other types. + // + // This document pair also triggers a separate "Internal error" in + // ProcessFootnoteEndnote (the modified document converted endnotes to + // footnotes). That is a different bug — this test verifies only that the + // NullReferenceException in FindIndexOfNextParaMark is fixed. + var ex = Record.Exception(() => WmlComparer.Compare(original, modified, settings)); + + Assert.True( + ex is not NullReferenceException, + $"Expected no NullReferenceException but got: {ex}"); + } + } +} diff --git a/Docxodus/WmlComparer.cs b/Docxodus/WmlComparer.cs index 7915d46..17a227f 100644 --- a/Docxodus/WmlComparer.cs +++ b/Docxodus/WmlComparer.cs @@ -7676,9 +7676,12 @@ private static int FindIndexOfNextParaMark(ComparisonUnit[] cul) { for (int i = 0; i < cul.Length; i++) { - var cuw = cul[i] as ComparisonUnitWord; - var lastAtom = cuw.DescendantContentAtoms().LastOrDefault(); - if (lastAtom.ContentElement.Name == W.pPr) + var comparisonUnit = cul[i]; + if (comparisonUnit == null || comparisonUnit.Contents == null) + continue; + + var lastAtom = comparisonUnit.DescendantContentAtoms().LastOrDefault(); + if (lastAtom != null && lastAtom.ContentElement.Name == W.pPr) return i; } return cul.Length; diff --git a/TestFiles/WC/WC-BodyBookmarks-After.docx b/TestFiles/WC/WC-BodyBookmarks-After.docx new file mode 100644 index 0000000..4285c38 Binary files /dev/null and b/TestFiles/WC/WC-BodyBookmarks-After.docx differ diff --git a/TestFiles/WC/WC-BodyBookmarks-Before.docx b/TestFiles/WC/WC-BodyBookmarks-Before.docx new file mode 100644 index 0000000..8df94a4 Binary files /dev/null and b/TestFiles/WC/WC-BodyBookmarks-Before.docx differ