diff --git a/OpenMcdf.Ole.Tests/2custom.doc b/OpenMcdf.Ole.Tests/2custom.doc new file mode 100644 index 00000000..0d53d3a1 Binary files /dev/null and b/OpenMcdf.Ole.Tests/2custom.doc differ diff --git a/OpenMcdf.Ole.Tests/CLSIDPropertyTest.file b/OpenMcdf.Ole.Tests/CLSIDPropertyTest.file new file mode 100644 index 00000000..27b609bf Binary files /dev/null and b/OpenMcdf.Ole.Tests/CLSIDPropertyTest.file differ diff --git a/OpenMcdf.Ole.Tests/Issue134.cfs b/OpenMcdf.Ole.Tests/Issue134.cfs new file mode 100644 index 00000000..f53f9b4f Binary files /dev/null and b/OpenMcdf.Ole.Tests/Issue134.cfs differ diff --git a/OpenMcdf.Ole.Tests/OlePropertiesExtensionsTests.cs b/OpenMcdf.Ole.Tests/OlePropertiesExtensionsTests.cs new file mode 100644 index 00000000..6537e36a --- /dev/null +++ b/OpenMcdf.Ole.Tests/OlePropertiesExtensionsTests.cs @@ -0,0 +1,440 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Diagnostics; + +namespace OpenMcdf.Ole.Tests; + +/// +/// Summary description for UnitTest1 +/// +[TestClass] +public class OlePropertiesExtensionsTests +{ + [TestMethod] + public void ReadSummaryInformation() + { + using var cf = RootStorage.OpenRead("_Test.ppt"); + using CfbStream stream = cf.OpenStream("\u0005SummaryInformation"); + OlePropertiesContainer co = new(stream); + + foreach (OleProperty p in co.Properties) + { + Debug.WriteLine(p); + } + } + + [TestMethod] + public void ReadDocumentSummaryInformation() + { + using var cf = RootStorage.OpenRead("_Test.ppt"); + using CfbStream stream = cf.OpenStream("\u0005DocumentSummaryInformation"); + OlePropertiesContainer co = new(stream); + + foreach (OleProperty p in co.Properties) + { + Debug.WriteLine(p); + } + } + + [TestMethod] + public void ReadThenWriteDocumentSummaryInformation() + { + using var cf = RootStorage.OpenRead("_Test.ppt"); + using CfbStream stream = cf.OpenStream("\u0005DocumentSummaryInformation"); + OlePropertiesContainer co = new(stream); + + using var cf2 = RootStorage.CreateInMemory(); + using CfbStream stream2 = cf2.CreateStream("\u0005DocumentSummaryInformation"); + co.Save(stream2); + } + + // Modify some document summary information properties, save to a file, and then validate the expected results + [TestMethod] + public void ModifyDocumentSummaryInformation() + { + using MemoryStream modifiedStream = new(); + using (FileStream stream = File.OpenRead("_Test.ppt")) + stream.CopyTo(modifiedStream); + + // Verify initial properties, and then create a modified document + using (var cf = RootStorage.Open(modifiedStream, StorageModeFlags.LeaveOpen)) + { + using CfbStream dsiStream = cf.OpenStream("\u0005DocumentSummaryInformation"); + OlePropertiesContainer co = new(dsiStream); + + // The company property should exist but be empty + OleProperty companyProperty = co.Properties.First(prop => prop.PropertyName == "PIDDSI_COMPANY"); + Assert.AreEqual("", companyProperty.Value); + + // As a sanity check, check that the value of a property that we don't change remains the same + OleProperty formatProperty = co.Properties.First(prop => prop.PropertyName == "PIDDSI_PRESFORMAT"); + Assert.AreEqual("A4 Paper (210x297 mm)", formatProperty.Value); + + // The manager property shouldn't exist, and we'll add it + Assert.IsFalse(co.Properties.Any(prop => prop.PropertyName == "PIDDSI_MANAGER")); + + OleProperty managerProp = co.CreateProperty(VTPropertyType.VT_LPSTR, 0x0000000E, "PIDDSI_MANAGER"); + co.Add(managerProp); + + companyProperty.Value = "My Company"; + managerProp.Value = "The Boss"; + + co.Save(dsiStream); + } + + using (var cf = RootStorage.Open(modifiedStream)) + { + using CfbStream stream = cf.OpenStream("\u0005DocumentSummaryInformation"); + OlePropertiesContainer co = new(stream); + + OleProperty companyProperty = co.Properties.First(prop => prop.PropertyName == "PIDDSI_COMPANY"); + Assert.AreEqual("My Company", companyProperty.Value); + + OleProperty formatProperty = co.Properties.First(prop => prop.PropertyName == "PIDDSI_PRESFORMAT"); + Assert.AreEqual("A4 Paper (210x297 mm)", formatProperty.Value); + + OleProperty managerProperty = co.Properties.First(prop => prop.PropertyName == "PIDDSI_MANAGER"); + Assert.AreEqual("The Boss", managerProperty.Value); + } + } + + [TestMethod] + public void ReadSummaryInformationUtf8() + { + // Regression test for #33 + using var cf = RootStorage.Open("wstr_presets.doc", FileMode.Open); + using CfbStream stream = cf.OpenStream("\u0005SummaryInformation"); + OlePropertiesContainer co = new(stream); + + foreach (OleProperty p in co.Properties) + { + Debug.WriteLine(p); + } + + using CfbStream stream2 = cf.OpenStream("\u0005DocumentSummaryInformation"); + OlePropertiesContainer co2 = new(stream2); + + foreach (OleProperty p in co2.Properties) + { + Debug.WriteLine(p); + } + } + + [TestMethod] + public void ReadSummaryInformationUtf8Part2() + { + // Regression test for #34 + using var cf = RootStorage.OpenRead("2custom.doc"); + using CfbStream stream = cf.OpenStream("\u0005SummaryInformation"); + OlePropertiesContainer co = new(stream); + + foreach (OleProperty p in co.Properties) + { + Debug.WriteLine(p); + } + + using CfbStream stream2 = cf.OpenStream("\u0005DocumentSummaryInformation"); + OlePropertiesContainer co2 = new(stream2); + + foreach (OleProperty p in co2.Properties) + { + Debug.WriteLine(p); + } + + if (co2.UserDefinedProperties is not null) + { + foreach (OleProperty p in co2.UserDefinedProperties.Properties) + { + Debug.WriteLine(p); + } + } + } + + [TestMethod] + public void SummaryInformationReadLpwstring() + { + using var cf = RootStorage.OpenRead("english.presets.doc"); + using CfbStream stream = cf.OpenStream("\u0005SummaryInformation"); + OlePropertiesContainer co = new(stream); + + foreach (OleProperty p in co.Properties) + { + Debug.WriteLine(p); + } + } + + // Test that we can modify an LPWSTR property, and the value is null terminated as required + [TestMethod] + public void SummaryInformationModifyLpwstring() + { + using MemoryStream modifiedStream = new(); + using (FileStream stream = File.OpenRead("wstr_presets.doc")) + stream.CopyTo(modifiedStream); + + // Modify some LPWSTR properties, and save to a new file + using (var cf = RootStorage.Open(modifiedStream, StorageModeFlags.LeaveOpen)) + { + using CfbStream dsiStream = cf.OpenStream("\u0005SummaryInformation"); + OlePropertiesContainer co = new(dsiStream); + + OleProperty authorProperty = co.Properties.First(prop => prop.PropertyName == "PIDSI_AUTHOR"); + Assert.AreEqual(VTPropertyType.VT_LPWSTR, authorProperty.VTType); + Assert.AreEqual("zkyiqpqoroxnbdwhnjfqroxlgylpbgcwuhjfifpkvycugvuecoputqgknnbs", authorProperty.Value); + + OleProperty keyWordsProperty = co.Properties.First(prop => prop.PropertyName == "PIDSI_KEYWORDS"); + Assert.AreEqual(VTPropertyType.VT_LPWSTR, keyWordsProperty.VTType); + Assert.AreEqual("abcdefghijk", keyWordsProperty.Value); + + authorProperty.Value = "ABC"; + keyWordsProperty.Value = ""; + co.Save(dsiStream); + } + + // Open the new file and check for the expected values + using (var cf = RootStorage.Open(modifiedStream)) + { + using CfbStream stream = cf.OpenStream("\u0005SummaryInformation"); + OlePropertiesContainer co = new(stream); + + OleProperty authorProperty = co.Properties.First(prop => prop.PropertyName == "PIDSI_AUTHOR"); + Assert.AreEqual(VTPropertyType.VT_LPWSTR, authorProperty.VTType); + Assert.AreEqual("ABC", authorProperty.Value); + + OleProperty keyWordsProperty = co.Properties.First(prop => prop.PropertyName == "PIDSI_KEYWORDS"); + Assert.AreEqual(VTPropertyType.VT_LPWSTR, keyWordsProperty.VTType); + Assert.AreEqual("", keyWordsProperty.Value); + } + } + + // winUnicodeDictionary.doc contains a UserProperties section with the CP_WINUNICODE codepage, and LPWSTR string properties + [TestMethod] + public void TestReadUnicodeUserPropertiesDictionary() + { + using var cf = RootStorage.OpenRead("winUnicodeDictionary.doc"); + CfbStream dsiStream = cf.OpenStream("\u0005DocumentSummaryInformation"); + OlePropertiesContainer co = new(dsiStream); + OlePropertiesContainer? userProps = co.UserDefinedProperties; + + // CodePage should be CP_WINUNICODE (1200) + Assert.AreEqual(1200, userProps.Context.CodePage); + + // There should be 5 property names present, and 6 properties (the properties include the code page) + Assert.AreEqual(5, userProps.PropertyNames.Count); + Assert.AreEqual(6, userProps.Properties.Count); + + // Check for expected names and values + OleProperty[] propArray = userProps.Properties.ToArray(); + + // CodePage prop + Assert.AreEqual(1u, propArray[0].PropertyIdentifier); + Assert.AreEqual("0x00000001", propArray[0].PropertyName); + Assert.AreEqual((short)1200, propArray[0].Value); + + // String properties + Assert.AreEqual("A", propArray[1].PropertyName); + Assert.AreEqual("", propArray[1].Value); + Assert.AreEqual("AB", propArray[2].PropertyName); + Assert.AreEqual("X", propArray[2].Value); + Assert.AreEqual("ABC", propArray[3].PropertyName); + Assert.AreEqual("XY", propArray[3].Value); + Assert.AreEqual("ABCD", propArray[4].PropertyName); + Assert.AreEqual("XYZ", propArray[4].Value); + Assert.AreEqual("ABCDE", propArray[5].PropertyName); + Assert.AreEqual("XYZ!", propArray[5].Value); + } + + // Test that we can add user properties of various types and then read them back + [TestMethod] + public void AddDocumentSummaryInformationCustomInfo() + { + using MemoryStream modifiedStream = new(); + using (FileStream stream = File.OpenRead("english.presets.doc")) + stream.CopyTo(modifiedStream); + + // Test value for a VT_FILETIME property + DateTime testNow = DateTime.UtcNow; + + // english.presets.doc has a user defined property section, but no properties other than the codepage + using (var cf = RootStorage.Open(modifiedStream, StorageModeFlags.LeaveOpen)) + { + using CfbStream dsiStream = cf.OpenStream("\u0005DocumentSummaryInformation"); + OlePropertiesContainer co = new(dsiStream); + OlePropertiesContainer? userProperties = co.UserDefinedProperties; + + userProperties.PropertyNames[2] = "StringProperty"; + userProperties.PropertyNames[3] = "BooleanProperty"; + userProperties.PropertyNames[4] = "IntegerProperty"; + userProperties.PropertyNames[5] = "DateProperty"; + userProperties.PropertyNames[6] = "DoubleProperty"; + + OleProperty stringProperty = co.CreateProperty(VTPropertyType.VT_LPSTR, 2); + stringProperty.Value = "Hello"; + userProperties.Add(stringProperty); + + OleProperty booleanProperty = co.CreateProperty(VTPropertyType.VT_BOOL, 3); + booleanProperty.Value = true; + userProperties.Add(booleanProperty); + + OleProperty integerProperty = co.CreateProperty(VTPropertyType.VT_I4, 4); + integerProperty.Value = 3456; + userProperties.Add(integerProperty); + + OleProperty timeProperty = co.CreateProperty(VTPropertyType.VT_FILETIME, 5); + timeProperty.Value = testNow; + userProperties.Add(timeProperty); + + OleProperty doubleProperty = co.CreateProperty(VTPropertyType.VT_R8, 6); + doubleProperty.Value = 1.234567d; + userProperties.Add(doubleProperty); + + co.Save(dsiStream); + } + + using (var cf = RootStorage.Open(modifiedStream)) + { + using CfbStream stream = cf.OpenStream("\u0005DocumentSummaryInformation"); + OlePropertiesContainer co = new(stream); + OleProperty[] propArray = co.UserDefinedProperties.Properties.ToArray(); + Assert.AreEqual(6, propArray.Length); + + // 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("StringProperty", propArray[1].PropertyName); + Assert.AreEqual("Hello", propArray[1].Value); + Assert.AreEqual(VTPropertyType.VT_LPSTR, propArray[1].VTType); + Assert.AreEqual("BooleanProperty", propArray[2].PropertyName); + Assert.AreEqual(true, propArray[2].Value); + Assert.AreEqual(VTPropertyType.VT_BOOL, propArray[2].VTType); + Assert.AreEqual("IntegerProperty", propArray[3].PropertyName); + Assert.AreEqual(3456, propArray[3].Value); + Assert.AreEqual(VTPropertyType.VT_I4, propArray[3].VTType); + Assert.AreEqual("DateProperty", propArray[4].PropertyName); + Assert.AreEqual(testNow, propArray[4].Value); + Assert.AreEqual(VTPropertyType.VT_FILETIME, propArray[4].VTType); + Assert.AreEqual("DoubleProperty", propArray[5].PropertyName); + Assert.AreEqual(1.234567d, propArray[5].Value); + Assert.AreEqual(VTPropertyType.VT_R8, propArray[5].VTType); + } + } + + // Try to read a document which contains Vector/String properties + // refs https://github.com/ironfede/openmcdf/issues/98 + [TestMethod] + public void ReadLpwstringVector() + { + using var cf = RootStorage.OpenRead("SampleWorkBook_bug98.xls"); + using CfbStream stream = cf.OpenStream("\u0005DocumentSummaryInformation"); + OlePropertiesContainer co = new(stream); + + OleProperty docPartsProperty = co.Properties.FirstOrDefault(property => property.PropertyIdentifier == 13); //13 == PIDDSI_DOCPARTS + + var docPartsValues = docPartsProperty.Value as IList; + Assert.AreEqual(3, docPartsValues.Count); + Assert.AreEqual("Sheet1", docPartsValues[0]); + Assert.AreEqual("Sheet2", docPartsValues[1]); + Assert.AreEqual("Sheet3", docPartsValues[2]); + } + + [TestMethod] + public void ReadClsidProperty() + { + Guid guid = new("15891a95-bf6e-4409-b7d0-3a31c391fa31"); + using var cf = RootStorage.OpenRead("CLSIDPropertyTest.file"); + using CfbStream stream = cf.OpenStream("\u0005C3teagxwOttdbfkuIaamtae3Ie"); + OlePropertiesContainer co = new(stream); + OleProperty clsidProp = co.Properties.First(x => x.PropertyName == "DocumentID"); + Assert.AreEqual(guid, clsidProp.Value); + } + + // 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 AddUserDefinedPropertiesSection() + { + using MemoryStream modifiedStream = new(); + using (FileStream stream = File.OpenRead("report.xls")) + stream.CopyTo(modifiedStream); + + using (var cf = RootStorage.Open(modifiedStream, StorageModeFlags.LeaveOpen)) + { + using CfbStream dsiStream = cf.OpenStream("\u0005DocumentSummaryInformation"); + OlePropertiesContainer co = new(dsiStream); + + Assert.IsNull(co.UserDefinedProperties); + + OlePropertiesContainer newUserDefinedProperties = co.CreateUserDefinedProperties(65001); // 65001 - UTF-8 + + newUserDefinedProperties.PropertyNames[2] = "MyCustomProperty"; + + OleProperty CreateProperty = co.CreateProperty(VTPropertyType.VT_LPSTR, 2); + CreateProperty.Value = "Testing"; + newUserDefinedProperties.Add(CreateProperty); + + co.Save(dsiStream); + } + + using (var cf = RootStorage.Open(modifiedStream)) + { + using CfbStream stream = cf.OpenStream("\u0005DocumentSummaryInformation"); + OlePropertiesContainer co = new(stream); + + // User defined properties should be present now + Assert.IsNotNull(co.UserDefinedProperties); + Assert.AreEqual(65001, co.UserDefinedProperties.Context.CodePage); + + // And the expected properties should the there + OleProperty[] 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); + } + } + + // A test for the issue described in https://github.com/ironfede/openmcdf/issues/134 where modifying an AppSpecific stream + // removes any already-existing Dictionary property + [TestMethod] + public void TestRetainDictionaryPropertyInAppSpecificStreams() + { + using MemoryStream modifiedStream = new(); + using (FileStream stream = File.OpenRead("Issue134.cfs")) + stream.CopyTo(modifiedStream); + + Dictionary expectedPropertyNames = new() + { + [2] = "Document Number", + [3] = "Revision", + [4] = "Project Name" + }; + + using (var cf = RootStorage.Open(modifiedStream, StorageModeFlags.LeaveOpen)) + { + using CfbStream testStream = cf.OpenStream("Issue134"); + OlePropertiesContainer co = new(testStream); + + CollectionAssert.AreEqual(expectedPropertyNames, co.PropertyNames); + + // Write test file + co.Save(testStream); + } + + // Open test file, and check that the property names are still as expected. + using (var cf = RootStorage.Open(modifiedStream)) + { + using CfbStream testStream = cf.OpenStream("Issue134"); + OlePropertiesContainer co = new(testStream); + + CollectionAssert.AreEqual(expectedPropertyNames, co.PropertyNames); + } + } +} diff --git a/OpenMcdf.Ole.Tests/OpenMcdf.Ole.Tests.csproj b/OpenMcdf.Ole.Tests/OpenMcdf.Ole.Tests.csproj new file mode 100644 index 00000000..59b58f11 --- /dev/null +++ b/OpenMcdf.Ole.Tests/OpenMcdf.Ole.Tests.csproj @@ -0,0 +1,54 @@ + + + + net48;net8.0 + Exe + 12.0 + enable + enable + + false + true + true + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Always + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Always + + + PreserveNewest + + + + diff --git a/OpenMcdf.Ole.Tests/SampleWorkBook_bug98.xls b/OpenMcdf.Ole.Tests/SampleWorkBook_bug98.xls new file mode 100644 index 00000000..063c04f5 Binary files /dev/null and b/OpenMcdf.Ole.Tests/SampleWorkBook_bug98.xls differ diff --git a/OpenMcdf.Ole.Tests/_Test.ppt b/OpenMcdf.Ole.Tests/_Test.ppt new file mode 100644 index 00000000..4b5a7692 Binary files /dev/null and b/OpenMcdf.Ole.Tests/_Test.ppt differ diff --git a/OpenMcdf.Ole.Tests/english.presets.doc b/OpenMcdf.Ole.Tests/english.presets.doc new file mode 100644 index 00000000..3fdf7297 Binary files /dev/null and b/OpenMcdf.Ole.Tests/english.presets.doc differ diff --git a/OpenMcdf.Ole.Tests/report.xls b/OpenMcdf.Ole.Tests/report.xls new file mode 100644 index 00000000..7b667a50 Binary files /dev/null and b/OpenMcdf.Ole.Tests/report.xls differ diff --git a/OpenMcdf.Ole.Tests/winUnicodeDictionary.doc b/OpenMcdf.Ole.Tests/winUnicodeDictionary.doc new file mode 100644 index 00000000..2ba5153c Binary files /dev/null and b/OpenMcdf.Ole.Tests/winUnicodeDictionary.doc differ diff --git a/OpenMcdf.Ole.Tests/wstr_presets.doc b/OpenMcdf.Ole.Tests/wstr_presets.doc new file mode 100644 index 00000000..884da6af Binary files /dev/null and b/OpenMcdf.Ole.Tests/wstr_presets.doc differ diff --git a/OpenMcdf.Ole/CodePages.cs b/OpenMcdf.Ole/CodePages.cs index 1f5a22c7..fdf34886 100644 --- a/OpenMcdf.Ole/CodePages.cs +++ b/OpenMcdf.Ole/CodePages.cs @@ -1,4 +1,6 @@ -namespace OpenMcdf.Ole; +using System.Text; + +namespace OpenMcdf.Ole; internal static class CodePages { diff --git a/OpenMcdf.Ole/DocumentSummaryInfoPropertyFactory.cs b/OpenMcdf.Ole/DocumentSummaryInfoPropertyFactory.cs index 551e55ed..828dbfa6 100644 --- a/OpenMcdf.Ole/DocumentSummaryInfoPropertyFactory.cs +++ b/OpenMcdf.Ole/DocumentSummaryInfoPropertyFactory.cs @@ -11,6 +11,6 @@ protected override ITypedPropertyValue CreateLpstrProperty(VTPropertyType vType, if (propertyIdentifier is 0x0000000C or 0x0000000D) return new VT_Unaligned_LPSTR_Property(vType, codePage, isVariant); - return CreateLpstrProperty(vType, codePage, propertyIdentifier, isVariant); + return base.CreateLpstrProperty(vType, codePage, propertyIdentifier, isVariant); } } diff --git a/OpenMcdf.Ole/OlePropertiesContainer.cs b/OpenMcdf.Ole/OlePropertiesContainer.cs index 371730d0..f21fea91 100644 --- a/OpenMcdf.Ole/OlePropertiesContainer.cs +++ b/OpenMcdf.Ole/OlePropertiesContainer.cs @@ -1,4 +1,6 @@ -namespace OpenMcdf.Ole; +using System.Text; + +namespace OpenMcdf.Ole; public enum ContainerType { @@ -42,8 +44,7 @@ public OlePropertiesContainer(CfbStream cfStream) this.cfStream = cfStream; - cfStream.Position = 0; - using BinaryReader reader = new(cfStream); + using BinaryReader reader = new(cfStream, Encoding.Unicode, true); pStream.Read(reader); if (pStream.FMTID0 == FormatIdentifiers.SummaryInformation) diff --git a/OpenMcdf.Ole/PropertyFactory.cs b/OpenMcdf.Ole/PropertyFactory.cs index f8a699f1..9a1df14a 100644 --- a/OpenMcdf.Ole/PropertyFactory.cs +++ b/OpenMcdf.Ole/PropertyFactory.cs @@ -6,9 +6,7 @@ internal abstract class PropertyFactory { static PropertyFactory() { -#if NETSTANDARD2_0_OR_GREATER Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); -#endif } public ITypedPropertyValue CreateProperty(VTPropertyType vType, int codePage, uint propertyIdentifier, bool isVariant = false) diff --git a/OpenMcdf.Ole/PropertySetStream.cs b/OpenMcdf.Ole/PropertySetStream.cs index 2f3de824..57caf285 100644 --- a/OpenMcdf.Ole/PropertySetStream.cs +++ b/OpenMcdf.Ole/PropertySetStream.cs @@ -28,6 +28,8 @@ public PropertySetStream() public void Read(BinaryReader br) { + br.BaseStream.Position = 0; + ByteOrder = br.ReadUInt16(); Version = br.ReadUInt16(); SystemIdentifier = br.ReadUInt32(); @@ -113,6 +115,8 @@ public void Read(BinaryReader br) public void Write(BinaryWriter bw) { + bw.BaseStream.Position = 0; + OffsetContainer oc0 = new(); OffsetContainer oc1 = new(); diff --git a/OpenMcdf.Tests/OpenMcdf.Tests.csproj b/OpenMcdf.Tests/OpenMcdf.Tests.csproj index 2736a5b8..dcba798f 100644 --- a/OpenMcdf.Tests/OpenMcdf.Tests.csproj +++ b/OpenMcdf.Tests/OpenMcdf.Tests.csproj @@ -3,7 +3,7 @@ net48;net8.0-windows Exe - 11.0 + 12.0 enable enable diff --git a/OpenMcdf.sln b/OpenMcdf.sln index c241288a..9382d5ec 100644 --- a/OpenMcdf.sln +++ b/OpenMcdf.sln @@ -24,6 +24,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenMcdf.Ole", "OpenMcdf.Ol EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StructuredStorageExplorer", "StructuredStorageExplorer\StructuredStorageExplorer.csproj", "{D5DDCC19-80C4-40D2-AEBF-2DA1CCB1D543}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMcdf.Ole.Tests", "OpenMcdf.Ole.Tests\OpenMcdf.Ole.Tests.csproj", "{34F153C4-3EFA-4D6E-B860-AEE300CCCF98}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -58,6 +60,10 @@ Global {D5DDCC19-80C4-40D2-AEBF-2DA1CCB1D543}.Debug|Any CPU.Build.0 = Debug|Any CPU {D5DDCC19-80C4-40D2-AEBF-2DA1CCB1D543}.Release|Any CPU.ActiveCfg = Release|Any CPU {D5DDCC19-80C4-40D2-AEBF-2DA1CCB1D543}.Release|Any CPU.Build.0 = Release|Any CPU + {34F153C4-3EFA-4D6E-B860-AEE300CCCF98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {34F153C4-3EFA-4D6E-B860-AEE300CCCF98}.Debug|Any CPU.Build.0 = Debug|Any CPU + {34F153C4-3EFA-4D6E-B860-AEE300CCCF98}.Release|Any CPU.ActiveCfg = Release|Any CPU + {34F153C4-3EFA-4D6E-B860-AEE300CCCF98}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/OpenMcdf/RootStorage.cs b/OpenMcdf/RootStorage.cs index 86e2c3fd..e6a45cd4 100644 --- a/OpenMcdf/RootStorage.cs +++ b/OpenMcdf/RootStorage.cs @@ -58,6 +58,8 @@ public static RootStorage Create(Stream stream, Version version = Version.V3, St return new RootStorage(rootContextSite, flags); } + public static RootStorage CreateInMemory(Version version = Version.V3) => Create(new MemoryStream(), version); + public static RootStorage Open(string fileName, FileMode mode, StorageModeFlags flags = StorageModeFlags.None) { ThrowIfLeaveOpen(flags); @@ -91,7 +93,7 @@ public static RootStorage Open(Stream stream, StorageModeFlags flags = StorageMo this.storageModeFlags = storageModeFlags; } - public void Dispose() => Context?.Dispose(); + public void Dispose() => Context.Dispose(); public void Flush(bool consolidate = false) { diff --git a/StructuredStorageExplorer/StreamDataProvider.cs b/StructuredStorageExplorer/StreamDataProvider.cs index e99c23b7..d2973128 100644 --- a/StructuredStorageExplorer/StreamDataProvider.cs +++ b/StructuredStorageExplorer/StreamDataProvider.cs @@ -3,7 +3,7 @@ namespace StructuredStorageExplorer; -public class StreamDataProvider : IByteProvider +internal sealed class StreamDataProvider : IByteProvider { /// /// Modifying stream