Skip to content
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
794484d
add IsValidChild method for WordprocessingDocument
mikeebowen Apr 10, 2025
9f65d67
add IsValidDocument method for SpreadsheetDocument
mikeebowen Apr 14, 2025
b67a9bf
Add IsMinimumDocument method for Presentation
mikeebowen Apr 23, 2025
6b9d2aa
update tests and xml comments
mikeebowen Apr 23, 2025
61192e4
Merge remote-tracking branch 'upstream/main' into issue-816
mikeebowen Apr 23, 2025
0d6de91
Merge remote-tracking branch 'upstream/main' into issue-816
mikeebowen Apr 28, 2025
e9cca0a
Merge branch 'main' into issue-816
mikeebowen Apr 29, 2025
84edcb0
Merge branch 'issue-816' of github.com:mikeebowen/Open-XML-SDK into i…
mikeebowen Apr 29, 2025
48afb54
only test null argument for < .Net 8+
mikeebowen Apr 29, 2025
f83d1d0
move Wordprocessing minimum document validation to virtual method
mikeebowen Apr 29, 2025
8dc68ef
Change minimum Word doc API to OpenSettings options
mikeebowen May 1, 2025
1a0d73a
add VerifyMinimumPackage option to PresentationDocument
mikeebowen May 5, 2025
8ba0e4d
fix linting issues
mikeebowen May 5, 2025
55e3eef
remove trailing whitespace
mikeebowen May 6, 2025
69a5900
remove unnecessary $ from string
mikeebowen May 6, 2025
9bc42e2
remove unnecessary usings
mikeebowen May 6, 2025
3a0c367
use feature for minimum document
twsouthwick May 12, 2025
fca841a
a bit more
twsouthwick May 12, 2025
b46015b
Merge pull request #3 from twsouthwick/use-feature
mikeebowen May 12, 2025
a4b61a7
move VerfiyMinimumPackage to feature
mikeebowen May 12, 2025
8e1d50d
remove ThrowIfNotMinimumPackage from OpenXmlPackage
mikeebowen May 12, 2025
8d1d6ea
fix merge conflict
mikeebowen May 14, 2025
04ef42b
verify wordprocessing document
mikeebowen May 15, 2025
a236566
add minimum document validation for PowerPoint and Excel
mikeebowen May 15, 2025
af392cc
add tests
mikeebowen May 15, 2025
b6d9b45
Merge branch 'issue-816' of github.com:mikeebowen/Open-XML-SDK into i…
mikeebowen May 15, 2025
7d4c2b4
revert to match main
mikeebowen May 15, 2025
8c4d993
add validation error if part is empty
mikeebowen May 15, 2025
12699db
update how to check for empty parts
mikeebowen May 16, 2025
8772882
fix tests
mikeebowen May 16, 2025
a1847d7
custom file property part test passes
mikeebowen Jun 12, 2025
92dcc74
fix P002_Pptx_DeleteAdd_CoreExtendedProperties test
mikeebowen Jun 12, 2025
1df4b0b
fix X006_Xlsx_DeleteAdd_CoreExtendedProperties and W051_AddNewPart_To…
mikeebowen Jun 13, 2025
1cdf8d2
Merge remote-tracking branch 'upstream/main' into issue-816
mikeebowen Jun 13, 2025
d7ee41b
add blank line
mikeebowen Jun 13, 2025
2097f05
remove file from earlier version of API
mikeebowen Jun 16, 2025
31aec5a
add IsEmptyPart method to ensure stream is disposed
mikeebowen Jun 16, 2025
2d5dd09
Update src/DocumentFormat.OpenXml.Framework/Packaging/OpenXmlPart.cs
mikeebowen Jun 30, 2025
e911447
Merge remote-tracking branch 'upstream/main' into issue-816
mikeebowen Jun 30, 2025
4861f13
move file extension check to IsEmptyPartMethod
mikeebowen Jun 30, 2025
25e5c67
removed unnecessary using
mikeebowen Jun 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/DocumentFormat.OpenXml.Framework/Packaging/OpenSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,17 @@ public MarkupCompatibilityProcessSettings MarkupCompatibilityProcessSettings
/// This property allows you to mitigate denial of service attacks where the attacker submits a package with an extremely large Open XML part. By limiting the size of the part, you can detect the attack and recover reliably.
/// </remarks>
public long MaxCharactersInPart { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to validate that the document meets the minimum requirements for a valid package.
/// </summary>
/// <value>
/// <c>true</c> if the document should be validated for minimum requirements; otherwise, <c>false</c>.
/// </value>
/// <remarks>
/// When set to <c>true</c>, the document will be checked to ensure it contains the necessary parts and structure
/// to be considered a valid Open XML package.
/// </remarks>
public bool VerifyMinimumPackage { get; set; }
}
}
12 changes: 12 additions & 0 deletions src/DocumentFormat.OpenXml.Framework/Packaging/OpenXmlPackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ internal void LoadAllParts()
}
}

/// <summary>
/// Throws a <see cref="FileFormatException"/> if the current <see cref="OpenXmlPackage"/> does not meet the minimum requirements for a valid package.
/// </summary>
/// <exception cref="FileFormatException">
/// Thrown when the package does not conform to the minimum requirements for Office to open.
/// </exception>
/// <remarks>
/// This method is intended to be overridden by derived classes to implement specific validation logic
/// for different types of Open XML packages (e.g., Wordprocessing, Spreadsheet, or Presentation documents).
/// </remarks>
protected virtual void ThrowIfNotMinimumPackage() => throw new FileFormatException("The provided package does not conform to the minimum requirements for Office to open.");

#region public methods

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1009,3 +1009,5 @@ DocumentFormat.OpenXml.OpenXmlPartWriterSettings.Encoding.set -> void
DocumentFormat.OpenXml.OpenXmlPartWriterSettings.OpenXmlPartWriterSettings() -> void
DocumentFormat.OpenXml.OpenXmlPartWriter.OpenXmlPartWriter(DocumentFormat.OpenXml.Packaging.OpenXmlPart! openXmlPart, DocumentFormat.OpenXml.OpenXmlPartWriterSettings! settings) -> void
DocumentFormat.OpenXml.OpenXmlPartWriter.OpenXmlPartWriter(System.IO.Stream! partStream, DocumentFormat.OpenXml.OpenXmlPartWriterSettings! settings) -> void
DocumentFormat.OpenXml.Packaging.OpenSettings.VerifyMinimumPackage.get -> bool
DocumentFormat.OpenXml.Packaging.OpenSettings.VerifyMinimumPackage.set -> void
64 changes: 64 additions & 0 deletions src/DocumentFormat.OpenXml/Packaging/PresentationDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using DocumentFormat.OpenXml.Builder;
using DocumentFormat.OpenXml.Features;
using DocumentFormat.OpenXml.Presentation;
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
Expand Down Expand Up @@ -231,6 +232,13 @@ public static PresentationDocument Open(Package package)
public static PresentationDocument Open(string path, bool isEditable, OpenSettings openSettings)
=> CreateDefaultBuilder()
.UseSettings(openSettings)
.Use(package =>
{
if (openSettings.VerifyMinimumPackage)
{
package.ThrowIfNotMinimumPackage();
}
})
.Build()
.Open(path, isEditable);

Expand All @@ -248,6 +256,13 @@ public static PresentationDocument Open(string path, bool isEditable, OpenSettin
public static PresentationDocument Open(Stream stream, bool isEditable, OpenSettings openSettings)
=> CreateDefaultBuilder()
.UseSettings(openSettings)
.Use(package =>
{
if (openSettings.VerifyMinimumPackage)
{
package.ThrowIfNotMinimumPackage();
}
})
.Build()
.Open(stream, isEditable);

Expand All @@ -264,9 +279,58 @@ public static PresentationDocument Open(Stream stream, bool isEditable, OpenSett
public static PresentationDocument Open(Package package, OpenSettings openSettings)
=> CreateDefaultBuilder()
.UseSettings(openSettings)
.Use(package =>
{
if (openSettings.VerifyMinimumPackage)
{
package.ThrowIfNotMinimumPackage();
}
})
.Build()
.Open(package);

/// <summary>
/// Validates that the current <see cref="PresentationDocument"/> meets the minimum requirements for a valid package.
/// </summary>
/// <exception cref="NotSupportedException">
/// Thrown if the <see cref="PresentationDocumentType"/> is <see cref="PresentationDocumentType.Slideshow"/>,
/// <see cref="PresentationDocumentType.MacroEnabledSlideshow"/>, or <see cref="PresentationDocumentType.AddIn"/>,
/// as validation for these types is not supported.
/// </exception>
/// <exception cref="FileFormatException">
/// Thrown if the <see cref="PresentationPart"/> does not contain valid <c>NotesSize</c> dimensions
/// or if the dimensions are outside the acceptable range for PowerPoint to open.
/// </exception>
/// <remarks>
/// This method ensures that the document conforms to the minimum requirements for PowerPoint to open it.
/// </remarks>
protected override void ThrowIfNotMinimumPackage()
{
if (this.DocumentType == PresentationDocumentType.Slideshow)
{
throw new NotSupportedException("Minimum package verification for PresentationDocumentType.Slideshow (.ppsx) is not supported.");
}

if (this.DocumentType == PresentationDocumentType.MacroEnabledSlideshow)
{
throw new NotSupportedException("Minimum package verification for PresentationDocumentType.MacroEnabledSlideshow (.ppsm) is not supported.");
}

if (this.DocumentType == PresentationDocumentType.AddIn)
{
throw new NotSupportedException("Minimum package verification for PresentationDocumentType.AddIn (.ppam) is not supported.");
}

NotesSize? notesSize = this.PresentationPart?.Presentation?.NotesSize;

if (!(notesSize is not null && notesSize.Cx is not null && notesSize.Cx.HasValue &&
notesSize.Cx >= 0 && notesSize.Cx <= 27273042316900 && notesSize.Cy is not null &&
notesSize.Cy.HasValue && notesSize.Cy >= 0 && notesSize.Cy <= 27273042316900))
{
throw new FileFormatException("The provided package does not conform to the minimum requirements for PowerPoint to open.");
}
}

/// <summary>
/// Changes the document type.
/// </summary>
Expand Down
55 changes: 55 additions & 0 deletions src/DocumentFormat.OpenXml/Packaging/SpreadsheetDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using DocumentFormat.OpenXml.Builder;
using DocumentFormat.OpenXml.Features;
using DocumentFormat.OpenXml.Spreadsheet;
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
Expand Down Expand Up @@ -197,6 +198,13 @@ public static SpreadsheetDocument CreateFromTemplate(string path)
public static SpreadsheetDocument Open(string path, bool isEditable, OpenSettings openSettings)
=> CreateDefaultBuilder()
.UseSettings(openSettings)
.Use(package =>
{
if (openSettings.VerifyMinimumPackage)
{
package.ThrowIfNotMinimumPackage();
}
})
.Build()
.Open(path, isEditable);

Expand All @@ -214,6 +222,13 @@ public static SpreadsheetDocument Open(string path, bool isEditable, OpenSetting
public static SpreadsheetDocument Open(Stream stream, bool isEditable, OpenSettings openSettings)
=> CreateDefaultBuilder()
.UseSettings(openSettings)
.Use(package =>
{
if (openSettings.VerifyMinimumPackage)
{
package.ThrowIfNotMinimumPackage();
}
})
.Build()
.Open(stream, isEditable);

Expand All @@ -230,6 +245,13 @@ public static SpreadsheetDocument Open(Stream stream, bool isEditable, OpenSetti
public static SpreadsheetDocument Open(Package package, OpenSettings openSettings)
=> CreateDefaultBuilder()
.UseSettings(openSettings)
.Use(package =>
{
if (openSettings.VerifyMinimumPackage)
{
package.ThrowIfNotMinimumPackage();
}
})
.Build()
.Open(package);

Expand Down Expand Up @@ -267,6 +289,39 @@ public static SpreadsheetDocument Open(System.IO.Stream stream, bool isEditable)
public static SpreadsheetDocument Open(System.IO.Packaging.Package package)
=> Open(package, new OpenSettings());

/// <summary>
/// Throws a <see cref="FileFormatException"/> if the current <see cref="SpreadsheetDocument"/>
/// does not meet the minimum requirements for a valid package.
/// </summary>
/// <exception cref="FileFormatException">
/// Thrown when the <see cref="SpreadsheetDocument"/> does not conform to the minimum requirements
/// for Excel to open. This includes:
/// <list type="bullet">
/// <item><description>The document type is <see cref="SpreadsheetDocumentType.AddIn"/>.</description></item>
/// <item><description>The <see cref="WorkbookPart"/> is missing or does not contain a valid <see cref="Sheet"/>.</description></item>
/// <item><description>The <see cref="SheetData"/> in the first <see cref="WorksheetPart"/> is missing.</description></item>
/// </list>
/// </exception>
/// <remarks>
/// This method ensures that the <see cref="SpreadsheetDocument"/> contains the necessary parts and structure
/// to be opened with Excel.
/// </remarks>
protected override void ThrowIfNotMinimumPackage()
{
if (this.DocumentType == SpreadsheetDocumentType.AddIn)
{
throw new NotSupportedException("Validation for SpreadsheetDocument.AddIn (.xlam) is not supported.");
}

Sheet? sheet = this.WorkbookPart?.Workbook?.Sheets?.GetFirstChild<Sheet>();
SheetData? sheetData = this.WorkbookPart?.WorksheetParts?.FirstOrDefaultAndMaxOne()?.Worksheet?.GetFirstChild<SheetData>();

if (sheet is null || sheetData is null)
{
throw new FileFormatException("The provided package does not conform to the minimum requirements for Excel to open.");
}
}

/// <summary>
/// Changes the document type.
/// </summary>
Expand Down
39 changes: 39 additions & 0 deletions src/DocumentFormat.OpenXml/Packaging/WordprocessingDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,13 @@ public static WordprocessingDocument Open(Stream stream, bool isEditable)
public static WordprocessingDocument Open(string path, bool isEditable, OpenSettings openSettings)
=> CreateDefaultBuilder()
.UseSettings(openSettings)
.Use(package =>
{
if (openSettings.VerifyMinimumPackage)
{
package.ThrowIfNotMinimumPackage();
}
})
.Build()
.Open(path, isEditable);

Expand All @@ -281,6 +288,13 @@ public static WordprocessingDocument Open(string path, bool isEditable, OpenSett
public static WordprocessingDocument Open(Stream stream, bool isEditable, OpenSettings openSettings)
=> CreateDefaultBuilder()
.UseSettings(openSettings)
.Use(package =>
{
if (openSettings.VerifyMinimumPackage)
{
package.ThrowIfNotMinimumPackage();
}
})
.Build()
.Open(stream, isEditable);

Expand All @@ -297,6 +311,13 @@ public static WordprocessingDocument Open(Stream stream, bool isEditable, OpenSe
public static WordprocessingDocument Open(Package package, OpenSettings openSettings)
=> CreateDefaultBuilder()
.UseSettings(openSettings)
.Use(package =>
{
if (openSettings.VerifyMinimumPackage)
{
package.ThrowIfNotMinimumPackage();
}
})
.Build()
.Open(package);

Expand All @@ -311,6 +332,24 @@ public static WordprocessingDocument Open(Package package, OpenSettings openSett
public static WordprocessingDocument Open(Package package)
=> Open(package, new OpenSettings());

/// <summary>
/// Throws a <see cref="FileFormatException"/> if the current <see cref="WordprocessingDocument"/> does not meet the minimum requirements for a valid package.
/// </summary>
/// <exception cref="FileFormatException">
/// Thrown when the <see cref="MainDocumentPart"/> is missing or its <see cref="Document.Body"/> is null.
/// </exception>
/// <remarks>
/// This method ensures that the <see cref="WordprocessingDocument"/> contains the necessary parts and structure
/// to be opened with Word.
/// </remarks>
protected override void ThrowIfNotMinimumPackage()
{
if (this.MainDocumentPart?.Document?.Body is null)
{
throw new FileFormatException("The provided package does not conform to the minimum requirements for Word to open.");
}
}

/// <summary>
/// Changes the document type.
/// </summary>
Expand Down
Loading
Loading