From 21fc528b6c42e4ce49182b56b334db9a72d2d523 Mon Sep 17 00:00:00 2001 From: Richard Webb Date: Sun, 17 Nov 2024 20:07:57 +0000 Subject: [PATCH] Rework the handling of FMTID0 in OlePropertiesContainer --- .../OlePropertiesExtensionsTests.cs | 6 ++ OpenMcdf.Ole/OlePropertiesContainer.cs | 59 +++++++++++++++---- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/OpenMcdf.Ole.Tests/OlePropertiesExtensionsTests.cs b/OpenMcdf.Ole.Tests/OlePropertiesExtensionsTests.cs index 103b317..cb351e5 100644 --- a/OpenMcdf.Ole.Tests/OlePropertiesExtensionsTests.cs +++ b/OpenMcdf.Ole.Tests/OlePropertiesExtensionsTests.cs @@ -510,11 +510,15 @@ public void TestRetainDictionaryPropertyInAppSpecificStreams() [4] = "Project Name" }; + Guid expectedFmtid0 = Guid.Parse("f0d6d0b1-a0d8-11ce-8aa2-08003601e988"); + using (var cf = RootStorage.Open(modifiedStream, StorageModeFlags.LeaveOpen)) { using CfbStream testStream = cf.OpenStream("Issue134"); OlePropertiesContainer co = new(testStream); + Assert.AreEqual(ContainerType.AppSpecific, co.ContainerType); + Assert.AreEqual(expectedFmtid0, co.FMTID0); CollectionAssert.AreEqual(expectedPropertyNames, co.PropertyNames); // Write test file @@ -527,6 +531,8 @@ public void TestRetainDictionaryPropertyInAppSpecificStreams() using CfbStream testStream = cf.OpenStream("Issue134"); OlePropertiesContainer co = new(testStream); + Assert.AreEqual(ContainerType.AppSpecific, co.ContainerType); + Assert.AreEqual(expectedFmtid0, co.FMTID0); CollectionAssert.AreEqual(expectedPropertyNames, co.PropertyNames); } } diff --git a/OpenMcdf.Ole/OlePropertiesContainer.cs b/OpenMcdf.Ole/OlePropertiesContainer.cs index 4bb1c6c..2a4d17a 100644 --- a/OpenMcdf.Ole/OlePropertiesContainer.cs +++ b/OpenMcdf.Ole/OlePropertiesContainer.cs @@ -19,14 +19,26 @@ public class OlePropertiesContainer public OlePropertiesContainer? UserDefinedProperties { get; private set; } + /// + /// Gets the type of the container. + /// public ContainerType ContainerType { get; } - private Guid? FmtID0 { get; } + + /// + /// Gets the FMTID of the properties container. + /// + public Guid FMTID0 { get; } public PropertyContext Context { get; } private readonly List properties = new(); internal Stream? cfStream; + /// + /// Create a new instance of with the specified code page and container type. + /// + /// The code page to use for the new container. + /// The type of the new container. public OlePropertiesContainer(int codePage, ContainerType containerType) { Context = new PropertyContext @@ -36,6 +48,7 @@ public OlePropertiesContainer(int codePage, ContainerType containerType) }; ContainerType = containerType; + FMTID0 = FmtIdFromContainerType(containerType); } public OlePropertiesContainer(CfbStream cfStream) @@ -47,13 +60,8 @@ public OlePropertiesContainer(CfbStream cfStream) using BinaryReader reader = new(cfStream, Encoding.Unicode, true); pStream.Read(reader); - if (pStream.FMTID0 == FormatIdentifiers.SummaryInformation) - ContainerType = ContainerType.SummaryInfo; - else if (pStream.FMTID0 == FormatIdentifiers.DocSummaryInformation) - ContainerType = ContainerType.DocumentSummaryInfo; - else - ContainerType = ContainerType.AppSpecific; - FmtID0 = pStream.FMTID0; + FMTID0 = pStream.FMTID0; + ContainerType = ContainerTypeFromFmtId(pStream.FMTID0); PropertyNames = (Dictionary?)pStream.PropertySet0!.Properties .FirstOrDefault(p => p.PropertyType == PropertyType.DictionaryProperty)?.Value; @@ -217,8 +225,6 @@ public void Save(Stream cfStream) { using BinaryWriter bw = new(cfStream); - Guid fmtId0 = FmtID0 ?? (ContainerType == ContainerType.SummaryInfo ? FormatIdentifiers.SummaryInformation : FormatIdentifiers.DocSummaryInformation); - PropertySetStream ps = new() { ByteOrder = 0xFFFE, @@ -228,7 +234,7 @@ public void Save(Stream cfStream) NumPropertySets = 1, - FMTID0 = fmtId0, + FMTID0 = this.FMTID0, Offset0 = 0, FMTID1 = Guid.Empty, @@ -284,4 +290,35 @@ public void Save(Stream cfStream) ps.Write(bw); } + + // Determine the type of the container from the FMTID0 property. + private static ContainerType ContainerTypeFromFmtId(Guid fmtId0) + { + if (fmtId0 == FormatIdentifiers.SummaryInformation) + return ContainerType.SummaryInfo; + else if (fmtId0 == FormatIdentifiers.DocSummaryInformation) + return ContainerType.DocumentSummaryInfo; + else if (fmtId0 == FormatIdentifiers.GlobalInfo) + return ContainerType.GlobalInfo; + else if (fmtId0 == FormatIdentifiers.ImageInfo) + return ContainerType.ImageInfo; + else if (fmtId0 == FormatIdentifiers.ImageContents) + return ContainerType.ImageContents; + + return ContainerType.AppSpecific; + } + + // Determine the FMTID property from the container type. + // Note: Uses FMTID_DocSummaryInformation by default to match the previous behavior. + private static Guid FmtIdFromContainerType(ContainerType containerType) + { + return containerType switch + { + ContainerType.SummaryInfo => FormatIdentifiers.SummaryInformation, + ContainerType.GlobalInfo => FormatIdentifiers.GlobalInfo, + ContainerType.ImageContents => FormatIdentifiers.ImageContents, + ContainerType.ImageInfo => FormatIdentifiers.ImageInfo, + _ => FormatIdentifiers.DocSummaryInformation, + }; + } }