Skip to content

Commit bd41f4e

Browse files
authored
Add powerpoint support (#71)
1 parent 3aa42ff commit bd41f4e

19 files changed

Lines changed: 592 additions & 11 deletions

src/DeterministicIoPackaging/DeterministicPackage.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ static IReadOnlyList<IPatcher> CreatePatchers()
1111
var documentRelsPatcher = new DocumentRelationshipPatcher();
1212
var sheetRelsPatcher = new SheetRelationshipPatcher();
1313
var wordPartRelsPatcher = new WordPartRelationshipPatcher();
14+
var pptxRelsPatcher = new PptxRelationshipPatcher();
1415
return
1516
[
1617
new ContentTypesPatcher(),
@@ -24,6 +25,8 @@ static IReadOnlyList<IPatcher> CreatePatchers()
2425
new DocumentPatcher(documentRelsPatcher),
2526
wordPartRelsPatcher,
2627
new WordPartPatcher(wordPartRelsPatcher),
28+
pptxRelsPatcher,
29+
new PptxContentPatcher(pptxRelsPatcher),
2730
new NumberingPatcher()
2831
];
2932
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Patches PowerPoint content XML files (presentation.xml, slide*.xml,
2+
// slideLayout*.xml, slideMaster*.xml, notesSlide*.xml, etc.) to remap
3+
// relationship IDs that were renumbered by PptxRelationshipPatcher.
4+
//
5+
// Must be registered after PptxRelationshipPatcher so that ID mappings
6+
// are populated before this patcher runs.
7+
class PptxContentPatcher(PptxRelationshipPatcher relsPatcher) : IPatcher
8+
{
9+
public bool IsMatch(Entry entry) =>
10+
entry.FullName.StartsWith("ppt/") &&
11+
!entry.FullName.Contains("/_rels/") &&
12+
entry.FullName.EndsWith(".xml") &&
13+
relsPatcher.IdMappings.ContainsKey(entry.FullName);
14+
15+
public void PatchXml(XDocument xml, string entryName)
16+
{
17+
if (relsPatcher.IdMappings.TryGetValue(entryName, out var mapping) && mapping.Count > 0)
18+
{
19+
RelationshipRenumber.RemapIds(xml, mapping);
20+
}
21+
}
22+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Patches relationship files for PowerPoint parts (presentation, slides,
2+
// slide layouts, slide masters, notes, themes, etc.). Handles any .rels file
3+
// under ppt/ — e.g. ppt/_rels/presentation.xml.rels,
4+
// ppt/slides/_rels/slide1.xml.rels, ppt/slideMasters/_rels/slideMaster1.xml.rels.
5+
//
6+
// These .rels files contain non-deterministic relationship IDs generated by
7+
// OpenXml SDK methods such as AddPart. This patcher renumbers them to
8+
// deterministic "DeterministicId{n}" values and stores the old→new mapping
9+
// so the corresponding content patcher (PptxContentPatcher) can remap r:id
10+
// references in the matching XML content file.
11+
class PptxRelationshipPatcher : IPatcher
12+
{
13+
// Keyed by content file name (e.g. "ppt/slides/slide1.xml") → old-to-new ID mapping
14+
internal Dictionary<string, Dictionary<string, string>> IdMappings { get; } = new(StringComparer.OrdinalIgnoreCase);
15+
16+
public bool IsMatch(Entry entry) =>
17+
entry.FullName.StartsWith("ppt/") &&
18+
entry.FullName.Contains("/_rels/") &&
19+
entry.FullName.EndsWith(".xml.rels");
20+
21+
public void PatchXml(XDocument xml, string entryName)
22+
{
23+
var mapping = RelationshipRenumber.RenumberAndSort(xml, entryName);
24+
25+
// Derive content file path from .rels path:
26+
// "ppt/slides/_rels/slide1.xml.rels" → "ppt/slides/slide1.xml"
27+
// "ppt/_rels/presentation.xml.rels" → "ppt/presentation.xml"
28+
var contentName = entryName
29+
.Replace("/_rels/", "/")
30+
.Replace(".xml.rels", ".xml");
31+
IdMappings[contentName] = mapping;
32+
}
33+
}

src/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<Project>
33
<PropertyGroup>
44
<NoWarn>CS1591;CS0649;CA1416;NU1608;NU1109;NU1510</NoWarn>
5-
<Version>0.24.3</Version>
5+
<Version>0.25.0</Version>
66
<LangVersion>preview</LangVersion>
77
<AssemblyVersion>1.0.0</AssemblyVersion>
88
<Description>Modify System.IO.Packaging (https://learn.microsoft.com/en-us/dotnet/api/system.io.packaging) files to ensure they are deterministic. Helpful for testing, build reproducibility, security verification, and ensuring package integrity across different build environments.</Description>

src/Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
55
</PropertyGroup>
66
<ItemGroup>
7-
<PackageVersion Include="MarkdownSnippets.MsBuild" Version="28.0.2" />
7+
<PackageVersion Include="MarkdownSnippets.MsBuild" Version="28.1.0" />
88
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.4.0" />
99
<PackageVersion Include="NUnit" Version="4.5.1" />
1010
<PackageVersion Include="NUnit3TestAdapter" Version="6.2.0" />

0 commit comments

Comments
 (0)