diff --git a/sources/OpenMcdf.Extensions/OLEProperties/OLEPropertiesContainer.cs b/sources/OpenMcdf.Extensions/OLEProperties/OLEPropertiesContainer.cs
index 0dc62fbc..4c240890 100644
--- a/sources/OpenMcdf.Extensions/OLEProperties/OLEPropertiesContainer.cs
+++ b/sources/OpenMcdf.Extensions/OLEProperties/OLEPropertiesContainer.cs
@@ -194,6 +194,41 @@ public void RemoveProperty(uint propertyIdentifier)
properties.Remove(toRemove);
}
+ ///
+ /// Create a new UserDefinedProperties container within this container.
+ ///
+ ///
+ /// Only containers of type DocumentSummaryInfo can contain user defined properties.
+ ///
+ /// The code page to use for the user defined properties.
+ /// The UserDefinedProperties container.
+ /// If this container is a type that doesn't suppose user defined properties.
+ public OLEPropertiesContainer CreateUserDefinedProperties(int codePage)
+ {
+ // Only the DocumentSummaryInfo stream can contain a UserDefinedProperties
+ if (this.ContainerType != ContainerType.DocumentSummaryInfo)
+ {
+ throw new CFInvalidOperation($"Only a DocumentSummaryInfo can contain user defined properties. Current container type is {this.ContainerType}");
+ }
+
+ // Create the container, and add the codepage to the initial set of properties
+ UserDefinedProperties = new OLEPropertiesContainer(codePage, ContainerType.UserDefinedProperties)
+ {
+ PropertyNames = new Dictionary()
+ };
+
+ var op = new OLEProperty(UserDefinedProperties)
+ {
+ VTType = VTPropertyType.VT_I2,
+ PropertyIdentifier = 1,
+ Value = (short)codePage
+ };
+
+ UserDefinedProperties.properties.Add(op);
+ this.HasUserDefinedProperties = true;
+
+ return UserDefinedProperties;
+ }
public void Save(CFStream cfStream)
{
diff --git a/sources/OpenMcdf/CompoundFile.cs b/sources/OpenMcdf/CompoundFile.cs
index df2d429d..0266c690 100644
--- a/sources/OpenMcdf/CompoundFile.cs
+++ b/sources/OpenMcdf/CompoundFile.cs
@@ -27,7 +27,7 @@ public int Compare(CFItem x, CFItem y)
}
///
- /// Configuration parameters for the compund files.
+ /// Configuration parameters for the compound files.
/// They can be OR-combined to configure
/// Compound file behaviour.
/// All flags are NOT set by Default.
@@ -112,7 +112,7 @@ public enum CFSUpdateMode
/// Standard Microsoft© Compound File implementation.
/// It is also known as OLE/COM structured storage
/// and contains a hierarchy of storage and stream objects providing
- /// efficent storage of multiple kinds of documents in a single file.
+ /// efficient storage of multiple kinds of documents in a single file.
/// Version 3 and 4 of specifications are supported.
///
public class CompoundFile : IDisposable
@@ -1146,7 +1146,7 @@ private void AllocateDIFATSectorChain(List FATsectorChain)
nCurrentSectors++;
//... so, adding a FAT sector may induce DIFAT sectors to increase by one
- // and consequently this may induce ANOTHER FAT sector (TO-THINK: May this condition occure ?)
+ // and consequently this may induce ANOTHER FAT sector (TO-THINK: May this condition occur ?)
if (nDIFATSectors * DIFAT_SECTOR_FAT_ENTRIES_COUNT <
(header.FATSectorsNumber > HEADER_DIFAT_ENTRIES_COUNT ?
header.FATSectorsNumber - HEADER_DIFAT_ENTRIES_COUNT :
@@ -1569,7 +1569,7 @@ internal List GetSectorChain(int secID, SectorType chainType)
return GetMiniSectorChain(secID);
default:
- throw new CFException("Unsupproted chain type");
+ throw new CFException("Unsupported chain type");
}
}
@@ -2668,7 +2668,7 @@ void IDisposable.Dispose()
///
/// When called from user code, release all resources, otherwise, in the case runtime called it,
- /// only unmanagd resources are released.
+ /// only unmanaged resources are released.
///
/// If true, method has been called from User code, if false it's been called from .net runtime
protected virtual void Dispose(bool disposing)
@@ -2760,7 +2760,7 @@ private IList FindDirectoryEntries(String entryName)
///
/// Get a list of all entries with a given name contained in the document.
///
- /// Name of entries to retrive
+ /// Name of entries to retrieve
/// A list of name-matching entries
/// This function is aimed to speed up entity lookup in
/// flat-structure files (only one or little more known entries)
diff --git a/sources/Test/OpenMcdf.Extensions.Test/OLEPropertiesExtensionsTest.cs b/sources/Test/OpenMcdf.Extensions.Test/OLEPropertiesExtensionsTest.cs
index 30858259..953535d7 100644
--- a/sources/Test/OpenMcdf.Extensions.Test/OLEPropertiesExtensionsTest.cs
+++ b/sources/Test/OpenMcdf.Extensions.Test/OLEPropertiesExtensionsTest.cs
@@ -486,5 +486,58 @@ public void Test_CLSID_PROPERTY()
}
}
+
+ // The test file 'report.xls' contains a DocumentSummaryInfo section, but no user defined properties.
+ // This tests adding a new user defined properties section to the existing DocumentSummaryInfo.
+ [TestMethod]
+ public void Test_ADD_USER_DEFINED_PROPERTIES_SECTION()
+ {
+ if (File.Exists("test_add_user_defined_properties.xls"))
+ File.Delete("test_add_user_defined_properties.xls");
+
+ using (CompoundFile cf = new CompoundFile("report.xls"))
+ {
+ var dsiStream = cf.RootStorage.GetStream("\u0005DocumentSummaryInformation");
+ var co = dsiStream.AsOLEPropertiesContainer();
+
+ Assert.IsFalse(co.HasUserDefinedProperties);
+ Assert.IsNull(co.UserDefinedProperties);
+
+ var newUserDefinedProperties = co.CreateUserDefinedProperties(65001); // 65001 - UTF-8
+
+ newUserDefinedProperties.PropertyNames[2] = "MyCustomProperty";
+
+ var newProperty = co.NewProperty(VTPropertyType.VT_LPSTR, 2);
+ newProperty.Value = "Testing";
+ newUserDefinedProperties.AddProperty(newProperty);
+
+ co.Save(dsiStream);
+ cf.SaveAs("test_add_user_defined_properties.xls");
+ }
+
+ using (CompoundFile cf = new CompoundFile("test_add_user_defined_properties.xls"))
+ {
+ var co = cf.RootStorage.GetStream("\u0005DocumentSummaryInformation").AsOLEPropertiesContainer();
+
+ // User defined properties should be present now
+ Assert.IsTrue(co.HasUserDefinedProperties);
+ Assert.IsNotNull(co.UserDefinedProperties);
+ Assert.AreEqual(65001, co.UserDefinedProperties.Context.CodePage);
+
+ // And the expected properties should the there
+ var propArray = co.UserDefinedProperties.Properties.ToArray();
+ Assert.AreEqual(propArray.Length, 2);
+
+ // CodePage prop
+ Assert.AreEqual(1u, propArray[0].PropertyIdentifier);
+ Assert.AreEqual("0x00000001", propArray[0].PropertyName);
+ Assert.AreEqual((short)-535, propArray[0].Value);
+
+ // User properties
+ Assert.AreEqual("MyCustomProperty", propArray[1].PropertyName);
+ Assert.AreEqual("Testing", propArray[1].Value);
+ Assert.AreEqual(VTPropertyType.VT_LPSTR, propArray[1].VTType);
+ }
+ }
}
}