From b1311838361886a7005c82c0868e2029620896fc Mon Sep 17 00:00:00 2001 From: ironfede Date: Wed, 17 Apr 2013 20:48:35 +0000 Subject: [PATCH 01/18] Name change highlights development branch --- Clean.cmd | 59 +- LocalTestRun.testrunconfig | 4 +- Memory Test/OpenMcdfMemTest.csproj | 99 ++ {OleCfsMemoryTest => Memory Test}/Program.cs | 56 +- .../Properties/AssemblyInfo.cs | 0 Memory Test/app.config | 3 + .../testfile/report.xls | Bin .../testfile/reportOverwriteMultiple.xls | Bin .../BinaryTree/BinarySearchTree.cs | 547 ----------- .../BinaryTree/BinaryTree.cs | 46 - .../BinaryTree/BinaryTreeNode.cs | 71 -- OLECompoundFileStorage/BinaryTree/Node.cs | 61 -- OLECompoundFileStorage/BinaryTree/NodeList.cs | 47 - .../BinaryTree/TraversalMethods.cs | 20 - OLECompoundFileStorage/CFStream.cs | 177 ---- OLECompoundFileStorage/RBTree/RedBlack.cs | 648 ------------- .../RBTree/RedBlackEnumerator.cs | 195 ---- .../RBTree/RedBlackException.cs | 20 - OLECompoundFileStorage/RBTree/RedBlackNode.cs | 121 --- OpenMcdf.Extensions/CFStreamExtensions.cs | 120 +++ .../OpenMcdf.Extensions.csproj | 25 +- .../Properties/AssemblyInfo.cs | 36 + OpenMcdf.sln | 49 +- OpenMcdf.vsmdi | 4 +- .../CFSStreamExtensionsTest.cs | 94 ++ .../Helpers.cs | 3 +- .../OpenMcdfExtensionsTest.csproj | 41 +- .../Properties/AssemblyInfo.cs | 35 + .../Helpers.cs | 0 .../OpenMcdfPerfTest.csproj | 48 +- .../Program.cs | 2 +- .../Properties/AssemblyInfo.cs | 0 Performance Test/app.config | 3 + .../InputBox.cs | 0 .../MainForm.Designer.cs | 0 .../MainForm.cs | 8 +- .../MainForm.resx | 0 .../Program.cs | 0 .../Properties/AssemblyInfo.cs | 2 +- .../Properties/Resources.Designer.cs | 4 +- .../Properties/Resources.resx | 0 .../Properties/Settings.Designer.cs | 4 +- .../Properties/Settings.settings | 0 .../StreamDataProvider.cs | 0 .../StructuredStorageExplorer.csproj | 55 +- .../Utils.cs | 0 Structured Storage Explorer/app.config | 15 + .../img/disk.png | Bin .../img/door_out.png | Bin .../img/folder.png | Bin .../img/page_white.png | Bin .../img/storage.png | Bin .../img/stream.png | Bin .../lib/Be.Windows.Forms.HexBox.dll | Bin 81920 -> 81920 bytes TESTOpenMCDF/app.config | 15 - {OLECFSTest => Unit Test}/AuthoringTests.txt | 0 {OLECFSTest => Unit Test}/CFSStreamTest.cs | 179 +++- {OLECFSTest => Unit Test}/CFSTorageTest.cs | 40 +- {OLECFSTest => Unit Test}/CompoundFileTest.cs | 136 ++- Unit Test/Helpers.cs | 56 ++ Unit Test/OpenMcdfTest.csproj | 112 +++ .../Properties/AssemblyInfo.cs | 0 Unit Test/RBTreeTest.cs | 236 +++++ .../SectorCollectionTest.cs | 0 .../CFException.cs | 0 {OLECompoundFileStorage => src}/CFItem.cs | 22 +- {OLECompoundFileStorage => src}/CFMock.cs | 5 + {OLECompoundFileStorage => src}/CFStorage.cs | 94 +- src/CFStream.cs | 264 ++++++ .../CompoundFile.cs | 877 ++++++++++++------ {OLECompoundFileStorage => src}/Directory.cs | 0 .../DirectoryEntry.cs | 9 +- {OLECompoundFileStorage => src}/Header.cs | 0 .../IDirectoryEntry.cs | 2 +- .../OpenMcdf.csproj | 55 +- .../OpenMcdfClassDiagram.cd | 18 +- .../Properties/AssemblyInfo.cs | 7 +- src/RBTree/RBTree.cs | 709 ++++++++++++++ {OLECompoundFileStorage => src}/Sector.cs | 0 .../SectorCollection.cs | 0 {OLECompoundFileStorage => src}/StreamRW.cs | 0 {OLECompoundFileStorage => src}/StreamView.cs | 51 +- 82 files changed, 3036 insertions(+), 2573 deletions(-) create mode 100644 Memory Test/OpenMcdfMemTest.csproj rename {OleCfsMemoryTest => Memory Test}/Program.cs (79%) rename {OleCfsMemoryTest => Memory Test}/Properties/AssemblyInfo.cs (100%) create mode 100644 Memory Test/app.config rename {OleCfsMemoryTest => Memory Test}/testfile/report.xls (100%) rename {OleCfsMemoryTest => Memory Test}/testfile/reportOverwriteMultiple.xls (100%) delete mode 100644 OLECompoundFileStorage/BinaryTree/BinarySearchTree.cs delete mode 100644 OLECompoundFileStorage/BinaryTree/BinaryTree.cs delete mode 100644 OLECompoundFileStorage/BinaryTree/BinaryTreeNode.cs delete mode 100644 OLECompoundFileStorage/BinaryTree/Node.cs delete mode 100644 OLECompoundFileStorage/BinaryTree/NodeList.cs delete mode 100644 OLECompoundFileStorage/BinaryTree/TraversalMethods.cs delete mode 100644 OLECompoundFileStorage/CFStream.cs delete mode 100644 OLECompoundFileStorage/RBTree/RedBlack.cs delete mode 100644 OLECompoundFileStorage/RBTree/RedBlackEnumerator.cs delete mode 100644 OLECompoundFileStorage/RBTree/RedBlackException.cs delete mode 100644 OLECompoundFileStorage/RBTree/RedBlackNode.cs create mode 100644 OpenMcdf.Extensions/CFStreamExtensions.cs rename OleCfsMemoryTest/OpenMcdfMemTest.csproj => OpenMcdf.Extensions/OpenMcdf.Extensions.csproj (71%) create mode 100644 OpenMcdf.Extensions/Properties/AssemblyInfo.cs create mode 100644 OpenMcdfExtensionsTest/CFSStreamExtensionsTest.cs rename {OLECFSTest => OpenMcdfExtensionsTest}/Helpers.cs (92%) rename OLECFSTest/OpenMcdfTest.csproj => OpenMcdfExtensionsTest/OpenMcdfExtensionsTest.csproj (61%) create mode 100644 OpenMcdfExtensionsTest/Properties/AssemblyInfo.cs rename {OpenMcdfPerfTest => Performance Test}/Helpers.cs (100%) rename {OpenMcdfPerfTest => Performance Test}/OpenMcdfPerfTest.csproj (51%) rename {OpenMcdfPerfTest => Performance Test}/Program.cs (92%) rename {OpenMcdfPerfTest => Performance Test}/Properties/AssemblyInfo.cs (100%) create mode 100644 Performance Test/app.config rename {TESTOpenMCDF => Structured Storage Explorer}/InputBox.cs (100%) rename {TESTOpenMCDF => Structured Storage Explorer}/MainForm.Designer.cs (100%) rename {TESTOpenMCDF => Structured Storage Explorer}/MainForm.cs (94%) rename {TESTOpenMCDF => Structured Storage Explorer}/MainForm.resx (100%) rename {TESTOpenMCDF => Structured Storage Explorer}/Program.cs (100%) rename {TESTOpenMCDF => Structured Storage Explorer}/Properties/AssemblyInfo.cs (95%) rename {TESTOpenMCDF => Structured Storage Explorer}/Properties/Resources.Designer.cs (95%) rename {TESTOpenMCDF => Structured Storage Explorer}/Properties/Resources.resx (100%) rename {TESTOpenMCDF => Structured Storage Explorer}/Properties/Settings.Designer.cs (93%) rename {TESTOpenMCDF => Structured Storage Explorer}/Properties/Settings.settings (100%) rename {TESTOpenMCDF => Structured Storage Explorer}/StreamDataProvider.cs (100%) rename {TESTOpenMCDF => Structured Storage Explorer}/StructuredStorageExplorer.csproj (62%) rename {TESTOpenMCDF => Structured Storage Explorer}/Utils.cs (100%) create mode 100644 Structured Storage Explorer/app.config rename {TESTOpenMCDF => Structured Storage Explorer}/img/disk.png (100%) rename {TESTOpenMCDF => Structured Storage Explorer}/img/door_out.png (100%) rename {TESTOpenMCDF => Structured Storage Explorer}/img/folder.png (100%) rename {TESTOpenMCDF => Structured Storage Explorer}/img/page_white.png (100%) rename {TESTOpenMCDF => Structured Storage Explorer}/img/storage.png (100%) rename {TESTOpenMCDF => Structured Storage Explorer}/img/stream.png (100%) rename {TESTOpenMCDF => Structured Storage Explorer}/lib/Be.Windows.Forms.HexBox.dll (58%) delete mode 100644 TESTOpenMCDF/app.config rename {OLECFSTest => Unit Test}/AuthoringTests.txt (100%) rename {OLECFSTest => Unit Test}/CFSStreamTest.cs (77%) rename {OLECFSTest => Unit Test}/CFSTorageTest.cs (87%) rename {OLECFSTest => Unit Test}/CompoundFileTest.cs (77%) create mode 100644 Unit Test/Helpers.cs create mode 100644 Unit Test/OpenMcdfTest.csproj rename {OLECFSTest => Unit Test}/Properties/AssemblyInfo.cs (100%) create mode 100644 Unit Test/RBTreeTest.cs rename {OLECFSTest => Unit Test}/SectorCollectionTest.cs (100%) rename {OLECompoundFileStorage => src}/CFException.cs (100%) rename {OLECompoundFileStorage => src}/CFItem.cs (90%) rename {OLECompoundFileStorage => src}/CFMock.cs (88%) rename {OLECompoundFileStorage => src}/CFStorage.cs (83%) create mode 100644 src/CFStream.cs rename {OLECompoundFileStorage => src}/CompoundFile.cs (75%) rename {OLECompoundFileStorage => src}/Directory.cs (100%) rename {OLECompoundFileStorage => src}/DirectoryEntry.cs (94%) rename {OLECompoundFileStorage => src}/Header.cs (100%) rename {OLECompoundFileStorage => src}/IDirectoryEntry.cs (95%) rename {OLECompoundFileStorage => src}/OpenMcdf.csproj (58%) rename {OLECompoundFileStorage => src}/OpenMcdfClassDiagram.cd (94%) rename {OLECompoundFileStorage => src}/Properties/AssemblyInfo.cs (85%) create mode 100644 src/RBTree/RBTree.cs rename {OLECompoundFileStorage => src}/Sector.cs (100%) rename {OLECompoundFileStorage => src}/SectorCollection.cs (100%) rename {OLECompoundFileStorage => src}/StreamRW.cs (100%) rename {OLECompoundFileStorage => src}/StreamView.cs (87%) diff --git a/Clean.cmd b/Clean.cmd index 013bec60..4e30d0ef 100644 --- a/Clean.cmd +++ b/Clean.cmd @@ -1,26 +1,37 @@ -rd /s /Q "OleCfsMemoryTest\bin\Debug" -rd /s /Q OleCfsMemoryTest\bin\Release -rd /s /Q OleCfsMemoryTest\obj\Debug -rd /s /Q OleCfsMemoryTest\obj\Release - -rd /s /Q OLECFSTest\bin\Debug -rd /s /Q OLECFSTest\bin\Release -rd /s /Q OLECFSTest\obj\Debug -rd /s /Q OLECFSTest\obj\Release - -rd /s /Q OLECompoundFileStorage\bin\Debug -rd /s /Q OLECompoundFileStorage\bin\Release -rd /s /Q OLECompoundFileStorage\obj\Debug -rd /s /Q OLECompoundFileStorage\obj\Release - -rd /s /Q OleCfsMemoryTest\bin\Debug -rd /s /Q OleCfsMemoryTest\bin\Release -rd /s /Q OleCfsMemoryTest\obj\Debug -rd /s /Q OleCfsMemoryTest\obj\Release - -rd /s /Q TESTOpenMCDF\bin\Debug -rd /s /Q TESTOpenMCDF\bin\Release -rd /s /Q TESTOpenMCDF\obj\Debug -rd /s /Q TESTOpenMCDF\obj\Release +rd /s /Q "Memory Test\bin\Debug" +rd /s /Q "Memory Test\bin\Release" +rd /s /Q "Memory Test\obj\Debug" +rd /s /Q "Memory Test\obj\Release" + +rd /s /Q "Unit Test\bin\Debug" +rd /s /Q "Unit Test\bin\Release" +rd /s /Q "Unit Test\obj\Debug" +rd /s /Q "Unit Test\obj\Release" + +rd /s /Q Src\bin\Debug +rd /s /Q Src\bin\Release +rd /s /Q Src\obj\Debug +rd /s /Q Src\obj\Release + +rd /s /Q "OpenMcdf.Extensions\bin\Debug" +rd /s /Q "OpenMcdf.Extensions\bin\Release +rd /s /Q "OpenMcdf.Extensions\obj\Debug" +rd /s /Q "OpenMcdf.Extensions\obj\Release" + +rd /s /Q "OpenMcdfExtensionsTest\bin\Debug" +rd /s /Q "OpenMcdfExtensionsTest\bin\Release +rd /s /Q "OpenMcdfExtensionsTest\obj\Debug" +rd /s /Q "OpenMcdfExtensionsTest\obj\Release" + +rd /s /Q "Structured Storage Explorer\bin\Debug" +rd /s /Q "Structured Storage Explorer\bin\Release +rd /s /Q "Structured Storage Explorer\obj\Debug" +rd /s /Q "Structured Storage Explorer\obj\Release" + + +rd /s /Q "Performance Test\bin\Debug" +rd /s /Q "Performance Test\bin\Release" +rd /s /Q "Performance Test\obj\Debug" +rd /s /Q "Performance Test\obj\Release" rd /s /Q TestResults \ No newline at end of file diff --git a/LocalTestRun.testrunconfig b/LocalTestRun.testrunconfig index 9a387bfd..f34ab719 100644 --- a/LocalTestRun.testrunconfig +++ b/LocalTestRun.testrunconfig @@ -1,5 +1,5 @@ - - + + This is a default test run configuration for a local test run. diff --git a/Memory Test/OpenMcdfMemTest.csproj b/Memory Test/OpenMcdfMemTest.csproj new file mode 100644 index 00000000..2fcaedb6 --- /dev/null +++ b/Memory Test/OpenMcdfMemTest.csproj @@ -0,0 +1,99 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {E2BAD82D-3040-462B-BAA2-6E608A9054F4} + Exe + Properties + OpenMcdfMemTest + OpenMcdfMemTest + v4.0 + 512 + + + 3.5 + + http://localhost/OpenMcdfMemTest/ + true + Web + true + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + true + false + true + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + + + + + + + + + + + {56E15D4A-8A37-4C7C-BB44-FD59AFF220C1} + OpenMcdf + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/OleCfsMemoryTest/Program.cs b/Memory Test/Program.cs similarity index 79% rename from OleCfsMemoryTest/Program.cs rename to Memory Test/Program.cs index bbdab535..79a76280 100644 --- a/OleCfsMemoryTest/Program.cs +++ b/Memory Test/Program.cs @@ -1,11 +1,8 @@ using System; -using System.Collections.Generic; -using System.Text; -using OpenMcdf; using System.IO; using System.Diagnostics; -using System.Threading; +using OpenMcdf; //This project is used for profiling memory and performances of OpenMCDF . namespace OpenMcdfMemTest @@ -41,13 +38,13 @@ private static void TestCode() Stopwatch sw = new Stopwatch(); sw.Start(); - var cf = new CompoundFile(CFSVersion.Ver_3, true, false); + var cf = new CompoundFile(CFSVersion.Ver_3, CFSConfiguration.SectorRecycle); cf.RootStorage.AddStream("A").SetData(bA); cf.Save("OneStream.cfs"); cf.Close(); - cf = new CompoundFile("OneStream.cfs", UpdateMode.ReadOnly, true, false); + cf = new CompoundFile("OneStream.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.SectorRecycle); cf.RootStorage.AddStream("B").SetData(bB); cf.RootStorage.AddStream("C").SetData(bC); @@ -60,10 +57,10 @@ private static void TestCode() cf.Save("8_Streams.cfs"); cf.Close(); - + File.Copy("8_Streams.cfs", "6_Streams.cfs", true); - cf = new CompoundFile("6_Streams.cfs", UpdateMode.Update, true, true); + cf = new CompoundFile("6_Streams.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle|CFSConfiguration.EraseFreeSectors); cf.RootStorage.Delete("D"); cf.RootStorage.Delete("G"); cf.Commit(); @@ -72,45 +69,45 @@ private static void TestCode() File.Copy("6_Streams.cfs", "6_Streams_Shrinked.cfs", true); - cf = new CompoundFile("6_Streams_Shrinked.cfs", UpdateMode.Update, true, false); + cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); cf.RootStorage.AddStream("ZZZ").SetData(bF); - cf.RootStorage.GetStream("E").AppendData(bE2); + cf.RootStorage.GetStream("E").Append(bE2); cf.Commit(); cf.Close(); - cf = new CompoundFile("6_Streams_Shrinked.cfs", UpdateMode.Update, true, false); + cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); cf.RootStorage.CLSID = new Guid("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"); cf.Commit(); cf.Close(); - cf = new CompoundFile("6_Streams_Shrinked.cfs", UpdateMode.Update, true, false); - cf.RootStorage.AddStorage("MyStorage").AddStream("ANS").AppendData(bE); + cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); + cf.RootStorage.AddStorage("MyStorage").AddStream("ANS").Append(bE); cf.Commit(); cf.Close(); - cf = new CompoundFile("6_Streams_Shrinked.cfs", UpdateMode.Update, true, false); - cf.RootStorage.AddStorage("AnotherStorage").AddStream("ANS").AppendData(bE); + cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); + cf.RootStorage.AddStorage("AnotherStorage").AddStream("ANS").Append(bE); cf.RootStorage.Delete("MyStorage"); cf.Commit(); cf.Close(); CompoundFile.ShrinkCompoundFile("6_Streams_Shrinked.cfs"); - cf = new CompoundFile("6_Streams_Shrinked.cfs", UpdateMode.Update, true, false); - cf.RootStorage.AddStorage("MiniStorage").AddStream("miniSt").AppendData(bMini); - cf.RootStorage.GetStorage("MiniStorage").AddStream("miniSt2").AppendData(bMini); + cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); + cf.RootStorage.AddStorage("MiniStorage").AddStream("miniSt").Append(bMini); + cf.RootStorage.GetStorage("MiniStorage").AddStream("miniSt2").Append(bMini); cf.Commit(); cf.Close(); - cf = new CompoundFile("6_Streams_Shrinked.cfs", UpdateMode.Update, true, false); + cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); cf.RootStorage.GetStorage("MiniStorage").Delete("miniSt"); - cf.RootStorage.GetStorage("MiniStorage").GetStream("miniSt2").AppendData(bE); + cf.RootStorage.GetStorage("MiniStorage").GetStream("miniSt2").Append(bE); cf.Commit(); cf.Close(); - cf = new CompoundFile("6_Streams_Shrinked.cfs", UpdateMode.ReadOnly, true, false); + cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.SectorRecycle); var myStream = cf.RootStorage.GetStream("C"); var data = myStream.GetData(); @@ -136,7 +133,7 @@ private static void StressMemory() byte[] b = GetBuffer(1024 * 1024 * MB_SIZE); //2GB buffer byte[] cmp = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }; - CompoundFile cf = new CompoundFile(CFSVersion.Ver_4, false, false); + CompoundFile cf = new CompoundFile(CFSVersion.Ver_4, CFSConfiguration.Default); CFStream st = cf.RootStorage.AddStream("MySuperLargeStream"); cf.Save("LARGE.cfs"); cf.Close(); @@ -144,7 +141,7 @@ private static void StressMemory() //Console.WriteLine("Closed save"); //Console.ReadKey(); - cf = new CompoundFile("LARGE.cfs", UpdateMode.Update, false, false); + cf = new CompoundFile("LARGE.cfs", CFSUpdateMode.Update, CFSConfiguration.Default); CFStream cfst = cf.RootStorage.GetStream("MySuperLargeStream"); Stopwatch sw = new Stopwatch(); @@ -152,14 +149,14 @@ private static void StressMemory() for (int i = 0; i < N_LOOP; i++) { - cfst.AppendData(b); + cfst.Append(b); cf.Commit(true); Console.WriteLine(" Updated " + i.ToString()); //Console.ReadKey(); } - cfst.AppendData(cmp); + cfst.Append(cmp); cf.Commit(true); sw.Stop(); @@ -178,9 +175,10 @@ private static void StressMemory() int count = 8; sw.Reset(); sw.Start(); - byte[] data = cf.RootStorage.GetStream("MySuperLargeStream").GetData(b.Length * (long)N_LOOP, ref count); + byte[] data = new byte[count]; + count = cf.RootStorage.GetStream("MySuperLargeStream").Read(data, b.Length * (long)N_LOOP, count); sw.Stop(); - Console.Write(data.Length); + Console.Write(count); cf.Close(); Console.WriteLine("Closed Final " + sw.ElapsedMilliseconds); @@ -219,7 +217,7 @@ private static void DummyFile() private static void AddNodes(String depth, CFStorage cfs) { - VisitedEntryAction va = delegate(CFItem target) + Action va = delegate(CFItem target) { String temp = target.Name + (target is CFStorage ? "" : " (" + target.Size + " bytes )"); @@ -251,7 +249,7 @@ public static void TestMultipleStreamCommit() //Console.ReadKey(); File.Copy(srcFilename, dstFilename, true); - CompoundFile cf = new CompoundFile(dstFilename, UpdateMode.Update, true, false); + CompoundFile cf = new CompoundFile(dstFilename, CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); Random r = new Random(); diff --git a/OleCfsMemoryTest/Properties/AssemblyInfo.cs b/Memory Test/Properties/AssemblyInfo.cs similarity index 100% rename from OleCfsMemoryTest/Properties/AssemblyInfo.cs rename to Memory Test/Properties/AssemblyInfo.cs diff --git a/Memory Test/app.config b/Memory Test/app.config new file mode 100644 index 00000000..cb2586be --- /dev/null +++ b/Memory Test/app.config @@ -0,0 +1,3 @@ + + + diff --git a/OleCfsMemoryTest/testfile/report.xls b/Memory Test/testfile/report.xls similarity index 100% rename from OleCfsMemoryTest/testfile/report.xls rename to Memory Test/testfile/report.xls diff --git a/OleCfsMemoryTest/testfile/reportOverwriteMultiple.xls b/Memory Test/testfile/reportOverwriteMultiple.xls similarity index 100% rename from OleCfsMemoryTest/testfile/reportOverwriteMultiple.xls rename to Memory Test/testfile/reportOverwriteMultiple.xls diff --git a/OLECompoundFileStorage/BinaryTree/BinarySearchTree.cs b/OLECompoundFileStorage/BinaryTree/BinarySearchTree.cs deleted file mode 100644 index b1037b69..00000000 --- a/OLECompoundFileStorage/BinaryTree/BinarySearchTree.cs +++ /dev/null @@ -1,547 +0,0 @@ -#region Using directives - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Text; - -#endregion - -namespace BinaryTrees -{ - public delegate void NodeAction(BinaryTreeNode node); - - /// - /// Represents a binary search tree. A binary search tree is a binary tree whose nodes are arranged - /// such that for any given node k, all nodes in k's left subtree have a value less than k, and all - /// nodes in k's right subtree have a value greater than k. - /// - /// The type of data stored in the binary tree nodes. - public class BinarySearchTree : ICollection, IEnumerable - { - - #region Private Member Variables - private BinaryTreeNode root = null; - private int count = 0; - private IComparer comparer = Comparer.Default; // used to compare node values when percolating down the tree - #endregion - - #region Constructors - public BinarySearchTree() { } - public BinarySearchTree(IComparer comparer) - { - this.comparer = comparer; - } - - #endregion - - #region Public Methods - #region Clear - /// - /// Removes the contents of the BST - /// - public void Clear() - { - root = null; - count = 0; - } - #endregion - - #region CopyTo - /// - /// Copies the contents of the BST to an appropriately-sized array of type T, using the Inorder - /// traversal method. - /// - public void CopyTo(T[] array, int index) - { - CopyTo(array, index, TraversalMethod.Inorder); - } - - /// - /// Copies the contents of the BST to an appropriately-sized array of type T, using a specified - /// traversal method. - /// - public void CopyTo(T[] array, int index, TraversalMethod TraversalMethod) - { - IEnumerable enumProp = null; - - // Determine which Enumerator-returning property to use, based on the TraversalMethod input parameter - switch (TraversalMethod) - { - case TraversalMethod.Preorder: - enumProp = Preorder; - break; - - case TraversalMethod.Inorder: - enumProp = Inorder; - break; - - case TraversalMethod.Postorder: - default: - enumProp = Postorder; - break; - } - - // dump the contents of the tree into the passed-in array - int i = 0; - foreach (T value in enumProp) - { - array[i + index] = value; - i++; - } - } - #endregion - - #region Add - /// - /// Adds a new value to the BST. - /// - /// The data to insert into the BST. - /// Adding a value already in the BST has no effect; that is, the SkipList is not - /// altered, the Add() method simply exits. - public virtual void Add(T data) - { - // create a new Node instance - BinaryTreeNode n = new BinaryTreeNode(data); - int result; - - // now, insert n into the tree - // trace down the tree until we hit a NULL - BinaryTreeNode current = root, parent = null; - while (current != null) - { - result = comparer.Compare(current.Value, data); - if (result == 0) - // they are equal - attempting to enter a duplicate - do nothing - //return; - throw new BSTDuplicatedException(); - else if (result < 0) - { - // current.Value < data, must add n to current's right subtree - parent = current; - current = current.Right; - } - else if (result > 0) - { - // current.Value > data, must add n to current's left subtree - parent = current; - current = current.Left; - } - } - - // We're ready to add the node! - count++; - if (parent == null) - // the tree was empty, make n the root - root = n; - else - { - result = comparer.Compare(parent.Value, data); - if (result > 0) - // parent.Value > data , therefore n must be added to the left subtree - parent.Left = n; - else - // parent.Value < data , therefore n must be added to the right subtree - parent.Right = n; - } - } - #endregion - - #region Contains - - /// - /// Returns a Boolean, indicating if a specified value is contained within the BST. - /// - /// The data to search for. - /// True if data is found in the BST; false otherwise. - public bool Contains(T data) - { - // search the tree for a node that contains data - BinaryTreeNode current = root; - int result; - while (current != null) - { - result = comparer.Compare(current.Value, data); - if (result == 0) - // we found data - return true; - else if (result > 0) - // current.Value > data, search current's left subtree - current = current.Left; - else if (result < 0) - // current.Value < data, search current's right subtree - current = current.Right; - } - - return false; // didn't find data - } - - #endregion - - - /// - /// Returns a Boolean, indicating if a specified value is contained within the BST. - /// - /// The data to search for. - /// True if data is found in the BST; false otherwise. - public bool TryFind(T data, out T foundObject) - { - foundObject = default(T); - - // search the tree for a node that contains data - BinaryTreeNode current = root; - int result; - while (current != null) - { - result = comparer.Compare(current.Value, data); - if (result == 0) - { - // we found data - foundObject = current.Value; - return true; - } - else if (result > 0) - // current.Value > data, search current's right subtree - current = current.Left; - else if (result < 0) - // current.Value < data, search current's left subtree - current = current.Right; - } - - return false; // didn't find data - } - - - - #region Remove - /// - /// Attempts to remove the specified data element from the BST. - /// - /// The data to remove from the BST. - /// True if the element is found in the tree, and removed; false if the element is not - /// found in the tree. - public bool Remove(T data) - { - // first make sure there exist some items in this tree - if (root == null) - return false; // no items to remove - - // Now, try to find data in the tree - BinaryTreeNode current = root, parent = null; - int result = comparer.Compare(current.Value, data); - while (result != 0) - { - if (result > 0) - { - // current.Value > data, if data exists it's in the left subtree - parent = current; - current = current.Left; - } - else if (result < 0) - { - // current.Value < data, if data exists it's in the right subtree - parent = current; - current = current.Right; - } - - // If current == null, then we didn't find the item to remove - if (current == null) - return false; - else - result = comparer.Compare(current.Value, data); - } - - // At this point, we've found the node to remove - count--; - - // We now need to "rethread" the tree - // CASE 1: If current has no right child, then current's left child becomes - // the node pointed to by the parent - if (current.Right == null) - { - if (parent == null) - root = current.Left; - else - { - result = comparer.Compare(parent.Value, current.Value); - if (result > 0) - // parent.Value > current.Value, so make current's left child a left child of parent - parent.Left = current.Left; - else if (result < 0) - // parent.Value < current.Value, so make current's left child a right child of parent - parent.Right = current.Left; - } - } - // CASE 2: If current's right child has no left child, then current's right child - // replaces current in the tree - else if (current.Right.Left == null) - { - current.Right.Left = current.Left; - - if (parent == null) - root = current.Right; - else - { - result = comparer.Compare(parent.Value, current.Value); - if (result > 0) - // parent.Value > current.Value, so make current's right child a left child of parent - parent.Left = current.Right; - else if (result < 0) - // parent.Value < current.Value, so make current's right child a right child of parent - parent.Right = current.Right; - } - } - // CASE 3: If current's right child has a left child, replace current with current's - // right child's left-most descendent - else - { - // We first need to find the right node's left-most child - BinaryTreeNode leftmost = current.Right.Left, lmParent = current.Right; - while (leftmost.Left != null) - { - lmParent = leftmost; - leftmost = leftmost.Left; - } - - // the parent's left subtree becomes the leftmost's right subtree - lmParent.Left = leftmost.Right; - - // assign leftmost's left and right to current's left and right children - leftmost.Left = current.Left; - leftmost.Right = current.Right; - - if (parent == null) - root = leftmost; - else - { - result = comparer.Compare(parent.Value, current.Value); - if (result > 0) - // parent.Value > current.Value, so make leftmost a left child of parent - parent.Left = leftmost; - else if (result < 0) - // parent.Value < current.Value, so make leftmost a right child of parent - parent.Right = leftmost; - } - } - - // Clear out the values from current - current.Left = current.Right = null; - current = null; - - return true; - } - #endregion - - #region GetEnumerator - - - /// - /// Enumerates the BST's contents using inorder traversal. - /// - /// An enumerator that provides inorder access to the BST's elements. - public virtual IEnumerator GetEnumerator() - { - return GetEnumerator(TraversalMethod.Inorder); - } - - /// - /// Enumerates the BST's contents using a specified traversal method. - /// - /// The type of traversal to perform. - /// An enumerator that provides access to the BST's elements using a specified traversal technique. - public virtual IEnumerator GetEnumerator(TraversalMethod TraversalMethod) - { - // The traversal approaches are defined as public properties in the BST class... - // This method simply returns the appropriate property. - switch (TraversalMethod) - { - case TraversalMethod.Preorder: - return Preorder.GetEnumerator(); - - case TraversalMethod.Inorder: - return Inorder.GetEnumerator(); - - case TraversalMethod.Postorder: - default: - return Postorder.GetEnumerator(); - } - } - #endregion - - public void VisitTreeInOrder(NodeAction nodeCallback) - { - if (root != null) - DoVisitInOrder(root, nodeCallback); - } - - public void VisitTreeInOrder(NodeAction nodeCallback, bool recursive) - { - if (root != null) - DoVisitInOrder(root, nodeCallback); - } - - private void DoVisitInOrder(BinaryTreeNode node, NodeAction nodeCallback) - { - if (node.Left != null) DoVisitInOrder(node.Left, nodeCallback); - - if (nodeCallback != null) - { - nodeCallback(node); - } - - if (node.Right != null) DoVisitInOrder(node.Right, nodeCallback); - } - - #endregion - - #region Public Properties - - public BinaryTreeNode Root - { - get - { - return root; - } - } - - - #region Enumerable Properties - /// - /// Provides enumeration through the BST using preorder traversal. - /// - public IEnumerable Preorder - { - get - { - // A single stack is sufficient here - it simply maintains the correct - // order with which to process the children. - Stack> toVisit = new Stack>(Count); - BinaryTreeNode current = root; - if (current != null) toVisit.Push(current); - - while (toVisit.Count != 0) - { - // take the top item from the stack - current = toVisit.Pop(); - - // add the right and left children, if not null - if (current.Right != null) toVisit.Push(current.Right); - if (current.Left != null) toVisit.Push(current.Left); - - // return the current node - yield return current.Value; - } - } - } - - /// - /// Provides enumeration through the BST using inorder traversal. - /// - public IEnumerable Inorder - { - get - { - // A single stack is sufficient - this code was made available by Grant Richins: - // http://blogs.msdn.com/grantri/archive/2004/04/08/110165.aspx - Stack> toVisit = new Stack>(Count); - for (BinaryTreeNode current = root; current != null || toVisit.Count != 0; current = current.Right) - { - // Get the left-most item in the subtree, remembering the path taken - while (current != null) - { - toVisit.Push(current); - current = current.Left; - } - - current = toVisit.Pop(); - yield return current.Value; - } - } - } - - /// - /// Provides enumeration through the BST using postorder traversal. - /// - public IEnumerable Postorder - { - get - { - // maintain two stacks, one of a list of nodes to visit, - // and one of booleans, indicating if the note has been processed - // or not. - Stack> toVisit = new Stack>(Count); - Stack hasBeenProcessed = new Stack(Count); - BinaryTreeNode current = root; - if (current != null) - { - toVisit.Push(current); - hasBeenProcessed.Push(false); - current = current.Left; - } - - while (toVisit.Count != 0) - { - if (current != null) - { - // add this node to the stack with a false processed value - toVisit.Push(current); - hasBeenProcessed.Push(false); - current = current.Left; - } - else - { - // see if the node on the stack has been processed - bool processed = hasBeenProcessed.Pop(); - BinaryTreeNode node = toVisit.Pop(); - if (!processed) - { - // if it's not been processed, "recurse" down the right subtree - toVisit.Push(node); - hasBeenProcessed.Push(true); // it's now been processed - current = node.Right; - } - else - yield return node.Value; - } - } - } - } - #endregion - - /// - /// Returns the number of elements in the BST. - /// - public int Count - { - get - { - return count; - } - } - - public bool IsReadOnly - { - get - { - return false; - } - } - #endregion - - - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - - } - - public class BSTDuplicatedException : ApplicationException - { - public BSTDuplicatedException() - : base("Duplicated item already present in BSTree") - { - } - } -} diff --git a/OLECompoundFileStorage/BinaryTree/BinaryTree.cs b/OLECompoundFileStorage/BinaryTree/BinaryTree.cs deleted file mode 100644 index c4a488b7..00000000 --- a/OLECompoundFileStorage/BinaryTree/BinaryTree.cs +++ /dev/null @@ -1,46 +0,0 @@ -#region Using directives - -using System; -using System.Collections.Generic; -using System.Text; - -#endregion - -namespace BinaryTrees -{ - /// - /// Represents a binary tree. This class provides access to the Root of the tree. The developer - /// must manually create the binary tree by adding descendents to the root. - /// - /// The type of data stored in the binary tree's nodes. - public class BinaryTree - { - #region Private Member Variables - private BinaryTreeNode root = null; - #endregion - - #region Public Methods - /// - /// Clears out the contents of the binary tree. - /// - public void Clear() - { - root = null; - } - #endregion - - #region Public Properties - public BinaryTreeNode Root - { - get - { - return root; - } - set - { - root = value; - } - } - #endregion - } -} diff --git a/OLECompoundFileStorage/BinaryTree/BinaryTreeNode.cs b/OLECompoundFileStorage/BinaryTree/BinaryTreeNode.cs deleted file mode 100644 index 342feea6..00000000 --- a/OLECompoundFileStorage/BinaryTree/BinaryTreeNode.cs +++ /dev/null @@ -1,71 +0,0 @@ -#region Using directives - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Text; - -#endregion - -namespace BinaryTrees -{ - /// - /// The BinaryTreeNode class represents a node in a binary tree, or a binary search tree. - /// It has precisely two neighbors, which can be accessed via the Left and Right properties. - /// - /// The type of data stored in the binary tree node. - public class BinaryTreeNode : Node - { - #region Constructors - public BinaryTreeNode() : base() {} - public BinaryTreeNode(T data) : base(data, null) {} - public BinaryTreeNode(T data, BinaryTreeNode left, BinaryTreeNode right) - { - base.Value = data; - NodeList children = new NodeList(2); - children[0] = left; - children[1] = right; - - base.Neighbors = children; - } - #endregion - - #region Public Properties - public BinaryTreeNode Left - { - get - { - if (base.Neighbors == null) - return null; - else - return (BinaryTreeNode) base.Neighbors[0]; - } - set - { - if (base.Neighbors == null) - base.Neighbors = new NodeList(2); - - base.Neighbors[0] = value; - } - } - - public BinaryTreeNode Right - { - get - { - if (base.Neighbors == null) - return null; - else - return (BinaryTreeNode) base.Neighbors[1]; - } - set - { - if (base.Neighbors == null) - base.Neighbors = new NodeList(2); - - base.Neighbors[1] = value; - } - } - #endregion - } -} diff --git a/OLECompoundFileStorage/BinaryTree/Node.cs b/OLECompoundFileStorage/BinaryTree/Node.cs deleted file mode 100644 index 6f526bb6..00000000 --- a/OLECompoundFileStorage/BinaryTree/Node.cs +++ /dev/null @@ -1,61 +0,0 @@ -#region Using directives - -using System; -using System.Collections.Generic; -using System.Text; - -#endregion - -namespace BinaryTrees -{ - /// - /// The Node<T> class represents the base concept of a Node for a tree or graph. It contains - /// a data item of type T, and a list of neighbors. - /// - /// The type of data contained in the Node. - /// None of the classes in the SkmDataStructures2 namespace use the Node class directly; - /// they all derive from this class, adding necessary functionality specific to each data structure. - public class Node - { - #region Private Member Variables - private T data; - private NodeList neighbors = null; - #endregion - - #region Constructors - public Node() {} - public Node(T data) : this(data, null) {} - public Node(T data, NodeList neighbors) - { - this.data = data; - this.neighbors = neighbors; - } - #endregion - - #region Properties - public T Value - { - get - { - return data; - } - set - { - data = value; - } - } - - protected NodeList Neighbors - { - get - { - return neighbors; - } - set - { - neighbors = value; - } - } - #endregion - } -} diff --git a/OLECompoundFileStorage/BinaryTree/NodeList.cs b/OLECompoundFileStorage/BinaryTree/NodeList.cs deleted file mode 100644 index a979d0e1..00000000 --- a/OLECompoundFileStorage/BinaryTree/NodeList.cs +++ /dev/null @@ -1,47 +0,0 @@ -#region Using directives - -using System; -using System.Collections.Generic; -using System.Text; -using System.Collections.ObjectModel; - -#endregion - -namespace BinaryTrees -{ - /// - /// Represents a collection of Node<T> instances. - /// - /// The type of data held in the Node instances referenced by this class. - public class NodeList : Collection> - { - #region Constructors - public NodeList() : base() { } - - public NodeList(int initialSize) - { - // Add the specified number of items - for (int i = 0; i < initialSize; i++) - base.Items.Add(default(Node)); - } - #endregion - - #region Methods - /// - /// Searches the NodeList for a Node containing a particular value. - /// - /// The value to search for. - /// The Node in the NodeList, if it exists; null otherwise. - public Node FindByValue(T value) - { - // search the list for the value - foreach (Node node in Items) - if (node.Value.Equals(value)) - return node; - - // if we reached here, we didn't find a matching node - return null; - } - #endregion - } -} diff --git a/OLECompoundFileStorage/BinaryTree/TraversalMethods.cs b/OLECompoundFileStorage/BinaryTree/TraversalMethods.cs deleted file mode 100644 index 48069857..00000000 --- a/OLECompoundFileStorage/BinaryTree/TraversalMethods.cs +++ /dev/null @@ -1,20 +0,0 @@ -#region Using directives - -using System; -using System.Collections.Generic; -using System.Text; - -#endregion - -namespace BinaryTrees -{ - /// - /// Provides the set of values by which a binary search tree can be enumerated. - /// - public enum TraversalMethod - { - Preorder, - Inorder, - Postorder - } -} diff --git a/OLECompoundFileStorage/CFStream.cs b/OLECompoundFileStorage/CFStream.cs deleted file mode 100644 index 9f9c8017..00000000 --- a/OLECompoundFileStorage/CFStream.cs +++ /dev/null @@ -1,177 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; -using BinaryTrees; - -/* - The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - - The Original Code is OpenMCDF - Compound Document Format library. - - The Initial Developer of the Original Code is Federico Blaseotto. -*/ - -namespace OpenMcdf -{ - - /// - /// OLE structured storage stream Object - /// It is contained inside a Storage object in a file-directory - /// relationship and indexed by its name. - /// - public class CFStream : CFItem - { - - internal CFStream(CompoundFile sectorManager) - : base(sectorManager) - { - this.DirEntry = new DirectoryEntry(StgType.StgStream); - this.DirEntry.StgColor = StgColor.Black; - - sectorManager.InsertNewDirectoryEntry(this.DirEntry); - - } - - internal CFStream(CompoundFile sectorManager, IDirectoryEntry dirEntry) - : base(sectorManager) - { - if (dirEntry == null || dirEntry.SID < 0) - throw new CFException("Attempting to add a CFStream using an unitialized directory"); - - this.DirEntry = dirEntry; - } - - /// - /// Set the data associated with the stream object. - /// - /// - /// - /// byte[] b = new byte[]{0x0,0x1,0x2,0x3}; - /// CompoundFile cf = new CompoundFile(); - /// CFStream myStream = cf.RootStorage.AddStream("MyStream"); - /// myStream.SetData(b); - /// - /// - /// Data bytes to write to this stream - public void SetData(Byte[] data) - { - CheckDisposed(); - - this.CompoundFile.SetData(this, data); - } - - /// - /// Append the provided data to stream data. - /// - /// - /// - /// byte[] b = new byte[]{0x0,0x1,0x2,0x3}; - /// byte[] b2 = new byte[]{0x4,0x5,0x6,0x7}; - /// CompoundFile cf = new CompoundFile(); - /// CFStream myStream = cf.RootStorage.AddStream("MyStream"); - /// myStream.SetData(b); // here we could also have invoked .AppendData - /// myStream.AppendData(b2); - /// cf.Save("MyLargeStreamsFile.cfs); - /// cf.Close(); - /// - /// - /// Data bytes to append to this stream - /// - /// This method allows user to create stream with more than 2GB of data, - /// appending data to the end of existing ones. - /// Large streams (>2GB) are only supported by CFS version 4. - /// Append data can also be invoked on streams with no data in order - /// to simplify its use inside loops. - /// - public void AppendData(Byte[] data) - { - CheckDisposed(); - if (this.Size > 0) - { - this.CompoundFile.AppendData(this, data); - } - else - { - this.CompoundFile.SetData(this, data); - } - } - - /// - /// Get the data associated with the stream object. - /// - /// - /// - /// CompoundFile cf2 = new CompoundFile("AFileName.cfs"); - /// CFStream st = cf2.RootStorage.GetStream("MyStream"); - /// byte[] buffer = st.GetData(); - /// - /// - /// Array of byte containing stream data - /// - /// Raised when the owner compound file has been closed. - /// - public Byte[] GetData() - { - CheckDisposed(); - - return this.CompoundFile.GetData(this); - } - - /// - /// Get bytes associated with the stream object, starting from - /// a provided . When method returns, count will contain the - /// effective count of bytes read. - /// - /// - /// - /// CompoundFile cf = new CompoundFile("AFileName.cfs"); - /// CFStream st = cf.RootStorage.GetStream("MyStream"); - /// int count = 8; - /// // The stream is supposed to have a length greater than offset + count - /// byte[] data = st.GetData(20, ref count); - /// cf.Close(); - /// - /// - /// Array of byte containing stream data - /// - /// Raised when the owner compound file has been closed. - /// - public Byte[] GetData(long offset, ref int count) - { - CheckDisposed(); - - return this.CompoundFile.GetData(this, offset, ref count); - } - - /// - /// Copy data from an existing stream. - /// - /// A stream to read from - /// - /// Input stream is NOT closed after method invocation. - /// - public void CopyFrom(Stream input) - { - CheckDisposed(); - - byte[] buffer = new byte[input.Length]; - - if (input.CanSeek) - { - input.Seek(0, SeekOrigin.Begin); - } - - input.Read(buffer, 0, (int)input.Length); - this.SetData(buffer); - } - } -} diff --git a/OLECompoundFileStorage/RBTree/RedBlack.cs b/OLECompoundFileStorage/RBTree/RedBlack.cs deleted file mode 100644 index 42d1f452..00000000 --- a/OLECompoundFileStorage/RBTree/RedBlack.cs +++ /dev/null @@ -1,648 +0,0 @@ - -using System.Collections; -using System.Text; -using System; -using System.Reflection; - -namespace RBTree -{ - /// - ///A red-black tree must satisfy these properties: - /// - ///1. The root is black. - ///2. All leaves are black. - ///3. Red nodes can only have black children. - ///4. All paths from a node to its leaves contain the same number of black nodes. - /// - public class RedBlack : object - { - // the number of nodes contained in the tree - private int intCount; - // a simple randomized hash code. The hash code could be used as a key - // if it is "unique" enough. Note: The IComparable interface would need to - // be replaced with int. - private int intHashCode; - // identifies the owner of the tree - private string strIdentifier; - // the tree - private RedBlackNode rbTree; - // sentinelNode is convenient way of indicating a leaf node. - public static RedBlackNode sentinelNode; - // the node that was last found; used to optimize searches - private RedBlackNode lastNodeFound; - private Random rand = new Random(); - - public RedBlack() - { - strIdentifier = base.ToString() + rand.Next(); - intHashCode = rand.Next(); - - // set up the sentinel node. the sentinel node is the key to a successfull - // implementation and for understanding the red-black tree properties. - sentinelNode = new RedBlackNode(); - sentinelNode.Left = null; - sentinelNode.Right = null; - sentinelNode.Parent = null; - sentinelNode.Color = RedBlackNode.BLACK; - rbTree = sentinelNode; - lastNodeFound = sentinelNode; - } - - public RedBlack(string strIdentifier) - { - intHashCode = rand.Next(); - this.strIdentifier = strIdentifier; - } - - /// - /// Add - /// args: ByVal key As IComparable, ByVal data As Object - /// key is object that implements IComparable interface - /// performance tip: change to use use int type (such as the hashcode) - /// - public void Add(IComparable key, object data) - { - if(key == null || data == null) - throw(new RedBlackException("RedBlackNode key and data must not be null")); - - // traverse tree - find where node belongs - int result = 0; - // create new node - RedBlackNode node = new RedBlackNode(); - RedBlackNode temp = rbTree; // grab the rbTree node of the tree - - while(temp != sentinelNode) - { // find Parent - node.Parent = temp; - result = key.CompareTo(temp.Key); - if(result == 0) - throw(new RedBlackException("A Node with the same key already exists")); - if(result > 0) - temp = temp.Right; - else - temp = temp.Left; - } - - // setup node - node.Key = key; - node.Data = data; - node.Left = sentinelNode; - node.Right = sentinelNode; - - // insert node into tree starting at parent's location - if(node.Parent != null) - { - result = node.Key.CompareTo(node.Parent.Key); - if(result > 0) - node.Parent.Right = node; - else - node.Parent.Left = node; - } - else - rbTree = node; // first node added - - RestoreAfterInsert(node); // restore red-black properities - - lastNodeFound = node; - - intCount = intCount + 1; - } - /// - /// RestoreAfterInsert - /// Additions to red-black trees usually destroy the red-black - /// properties. Examine the tree and restore. Rotations are normally - /// required to restore it - /// - private void RestoreAfterInsert(RedBlackNode x) - { - // x and y are used as variable names for brevity, in a more formal - // implementation, you should probably change the names - - RedBlackNode y; - - // maintain red-black tree properties after adding x - while(x != rbTree && x.Parent.Color == RedBlackNode.RED) - { - // Parent node is .Colored red; - if(x.Parent == x.Parent.Parent.Left) // determine traversal path - { // is it on the Left or Right subtree? - y = x.Parent.Parent.Right; // get uncle - if(y!= null && y.Color == RedBlackNode.RED) - { // uncle is red; change x's Parent and uncle to black - x.Parent.Color = RedBlackNode.BLACK; - y.Color = RedBlackNode.BLACK; - // grandparent must be red. Why? Every red node that is not - // a leaf has only black children - x.Parent.Parent.Color = RedBlackNode.RED; - x = x.Parent.Parent; // continue loop with grandparent - } - else - { - // uncle is black; determine if x is greater than Parent - if(x == x.Parent.Right) - { // yes, x is greater than Parent; rotate Left - // make x a Left child - x = x.Parent; - RotateLeft(x); - } - // no, x is less than Parent - x.Parent.Color = RedBlackNode.BLACK; // make Parent black - x.Parent.Parent.Color = RedBlackNode.RED; // make grandparent black - RotateRight(x.Parent.Parent); // rotate right - } - } - else - { // x's Parent is on the Right subtree - // this code is the same as above with "Left" and "Right" swapped - y = x.Parent.Parent.Left; - if(y!= null && y.Color == RedBlackNode.RED) - { - x.Parent.Color = RedBlackNode.BLACK; - y.Color = RedBlackNode.BLACK; - x.Parent.Parent.Color = RedBlackNode.RED; - x = x.Parent.Parent; - } - else - { - if(x == x.Parent.Left) - { - x = x.Parent; - RotateRight(x); - } - x.Parent.Color = RedBlackNode.BLACK; - x.Parent.Parent.Color = RedBlackNode.RED; - RotateLeft(x.Parent.Parent); - } - } - } - rbTree.Color = RedBlackNode.BLACK; // rbTree should always be black - } - - /// - /// RotateLeft - /// Rebalance the tree by rotating the nodes to the left - /// - public void RotateLeft(RedBlackNode x) - { - // pushing node x down and to the Left to balance the tree. x's Right child (y) - // replaces x (since y > x), and y's Left child becomes x's Right child - // (since it's < y but > x). - - RedBlackNode y = x.Right; // get x's Right node, this becomes y - - // set x's Right link - x.Right = y.Left; // y's Left child's becomes x's Right child - - // modify parents - if(y.Left != sentinelNode) - y.Left.Parent = x; // sets y's Left Parent to x - - if(y != sentinelNode) - y.Parent = x.Parent; // set y's Parent to x's Parent - - if(x.Parent != null) - { // determine which side of it's Parent x was on - if(x == x.Parent.Left) - x.Parent.Left = y; // set Left Parent to y - else - x.Parent.Right = y; // set Right Parent to y - } - else - rbTree = y; // at rbTree, set it to y - - // link x and y - y.Left = x; // put x on y's Left - if(x != sentinelNode) // set y as x's Parent - x.Parent = y; - } - /// - /// RotateRight - /// Rebalance the tree by rotating the nodes to the right - /// - public void RotateRight(RedBlackNode x) - { - // pushing node x down and to the Right to balance the tree. x's Left child (y) - // replaces x (since x < y), and y's Right child becomes x's Left child - // (since it's < x but > y). - - RedBlackNode y = x.Left; // get x's Left node, this becomes y - - // set x's Right link - x.Left = y.Right; // y's Right child becomes x's Left child - - // modify parents - if(y.Right != sentinelNode) - y.Right.Parent = x; // sets y's Right Parent to x - - if(y != sentinelNode) - y.Parent = x.Parent; // set y's Parent to x's Parent - - if(x.Parent != null) // null=rbTree, could also have used rbTree - { // determine which side of it's Parent x was on - if(x == x.Parent.Right) - x.Parent.Right = y; // set Right Parent to y - else - x.Parent.Left = y; // set Left Parent to y - } - else - rbTree = y; // at rbTree, set it to y - - // link x and y - y.Right = x; // put x on y's Right - if(x != sentinelNode) // set y as x's Parent - x.Parent = y; - } - /// - /// GetData - /// Gets the data object associated with the specified key - /// - public object GetData(IComparable key) - { - int result; - - RedBlackNode treeNode = rbTree; // begin at root - - // traverse tree until node is found - while(treeNode != sentinelNode) - { - result = key.CompareTo(treeNode.Key); - if(result == 0) - { - lastNodeFound = treeNode; - return treeNode.Data; - } - if(result < 0) - treeNode = treeNode.Left; - else - treeNode = treeNode.Right; - } - - throw(new RedBlackException("RedBlackNode key was not found")); - } - /// - /// GetMinKey - /// Returns the minimum key value - /// - public IComparable GetMinKey() - { - RedBlackNode treeNode = rbTree; - - if(treeNode == null || treeNode == sentinelNode) - throw(new RedBlackException("RedBlack tree is empty")); - - // traverse to the extreme left to find the smallest key - while(treeNode.Left != sentinelNode) - treeNode = treeNode.Left; - - lastNodeFound = treeNode; - - return treeNode.Key; - - } - /// - /// GetMaxKey - /// Returns the maximum key value - /// - public IComparable GetMaxKey() - { - RedBlackNode treeNode = rbTree; - - if(treeNode == null || treeNode == sentinelNode) - throw(new RedBlackException("RedBlack tree is empty")); - - // traverse to the extreme right to find the largest key - while(treeNode.Right != sentinelNode) - treeNode = treeNode.Right; - - lastNodeFound = treeNode; - - return treeNode.Key; - - } - /// - /// GetMinValue - /// Returns the object having the minimum key value - /// - public object GetMinValue() - { - return GetData(GetMinKey()); - } - /// - /// GetMaxValue - /// Returns the object having the maximum key - /// - public object GetMaxValue() - { - return GetData(GetMaxKey()); - } - /// - /// GetEnumerator - /// return an enumerator that returns the tree nodes in order - /// - public RedBlackEnumerator GetEnumerator() - { - // elements is simply a generic name to refer to the - // data objects the nodes contain - return Elements(true); - } - /// - /// Keys - /// if(ascending is true, the keys will be returned in ascending order, else - /// the keys will be returned in descending order. - /// - public RedBlackEnumerator Keys() - { - return Keys(true); - } - public RedBlackEnumerator Keys(bool ascending) - { - return new RedBlackEnumerator(rbTree, true, ascending); - } - /// - /// Values - /// Provided for .NET compatibility. - /// - public RedBlackEnumerator Values() - { - return Elements(true); - } - /// - /// Elements - /// Returns an enumeration of the data objects. - /// if(ascending is true, the objects will be returned in ascending order, - /// else the objects will be returned in descending order. - /// - public RedBlackEnumerator Elements() - { - return Elements(true); - } - public RedBlackEnumerator Elements(bool ascending) - { - return new RedBlackEnumerator(rbTree, false, ascending); - } - /// - /// IsEmpty - /// Is the tree empty? - /// - public bool IsEmpty() - { - return (rbTree == null); - } - /// - /// Remove - /// removes the key and data object (delete) - /// - public void Remove(IComparable key) - { - if(key == null) - throw(new RedBlackException("RedBlackNode key is null")); - - // find node - int result; - RedBlackNode node; - - // see if node to be deleted was the last one found - result = key.CompareTo(lastNodeFound.Key); - if(result == 0) - node = lastNodeFound; - else - { // not found, must search - node = rbTree; - while(node != sentinelNode) - { - result = key.CompareTo(node.Key); - if(result == 0) - break; - if(result < 0) - node = node.Left; - else - node = node.Right; - } - - if(node == sentinelNode) - return; // key not found - } - - Delete(node); - - intCount = intCount - 1; - } - /// - /// Delete - /// Delete a node from the tree and restore red black properties - /// - private void Delete(RedBlackNode z) - { - // A node to be deleted will be: - // 1. a leaf with no children - // 2. have one child - // 3. have two children - // If the deleted node is red, the red black properties still hold. - // If the deleted node is black, the tree needs rebalancing - - RedBlackNode x = new RedBlackNode(); // work node to contain the replacement node - RedBlackNode y; // work node - - // find the replacement node (the successor to x) - the node one with - // at *most* one child. - if(z.Left == sentinelNode || z.Right == sentinelNode) - y = z; // node has sentinel as a child - else - { - // z has two children, find replacement node which will - // be the leftmost node greater than z - y = z.Right; // traverse right subtree - while(y.Left != sentinelNode) // to find next node in sequence - y = y.Left; - } - - // at this point, y contains the replacement node. it's content will be copied - // to the valules in the node to be deleted - - // x (y's only child) is the node that will be linked to y's old parent. - if(y.Left != sentinelNode) - x = y.Left; - else - x = y.Right; - - // replace x's parent with y's parent and - // link x to proper subtree in parent - // this removes y from the chain - x.Parent = y.Parent; - if(y.Parent != null) - if(y == y.Parent.Left) - y.Parent.Left = x; - else - y.Parent.Right = x; - else - rbTree = x; // make x the root node - - // copy the values from y (the replacement node) to the node being deleted. - // note: this effectively deletes the node. - if(y != z) - { - z.Key = y.Key; - z.Data = y.Data; - } - - if(y.Color == RedBlackNode.BLACK) - RestoreAfterDelete(x); - - lastNodeFound = sentinelNode; - } - - /// - /// RestoreAfterDelete - /// Deletions from red-black trees may destroy the red-black - /// properties. Examine the tree and restore. Rotations are normally - /// required to restore it - /// - private void RestoreAfterDelete(RedBlackNode x) - { - // maintain Red-Black tree balance after deleting node - - RedBlackNode y; - - while(x != rbTree && x.Color == RedBlackNode.BLACK) - { - if(x == x.Parent.Left) // determine sub tree from parent - { - y = x.Parent.Right; // y is x's sibling - if(y.Color == RedBlackNode.RED) - { // x is black, y is red - make both black and rotate - y.Color = RedBlackNode.BLACK; - x.Parent.Color = RedBlackNode.RED; - RotateLeft(x.Parent); - y = x.Parent.Right; - } - if(y.Left.Color == RedBlackNode.BLACK && - y.Right.Color == RedBlackNode.BLACK) - { // children are both black - y.Color = RedBlackNode.RED; // change parent to red - x = x.Parent; // move up the tree - } - else - { - if(y.Right.Color == RedBlackNode.BLACK) - { - y.Left.Color = RedBlackNode.BLACK; - y.Color = RedBlackNode.RED; - RotateRight(y); - y = x.Parent.Right; - } - y.Color = x.Parent.Color; - x.Parent.Color = RedBlackNode.BLACK; - y.Right.Color = RedBlackNode.BLACK; - RotateLeft(x.Parent); - x = rbTree; - } - } - else - { // right subtree - same as code above with right and left swapped - y = x.Parent.Left; - if(y.Color == RedBlackNode.RED) - { - y.Color = RedBlackNode.BLACK; - x.Parent.Color = RedBlackNode.RED; - RotateRight (x.Parent); - y = x.Parent.Left; - } - if(y.Right.Color == RedBlackNode.BLACK && - y.Left.Color == RedBlackNode.BLACK) - { - y.Color = RedBlackNode.RED; - x = x.Parent; - } - else - { - if(y.Left.Color == RedBlackNode.BLACK) - { - y.Right.Color = RedBlackNode.BLACK; - y.Color = RedBlackNode.RED; - RotateLeft(y); - y = x.Parent.Left; - } - y.Color = x.Parent.Color; - x.Parent.Color = RedBlackNode.BLACK; - y.Left.Color = RedBlackNode.BLACK; - RotateRight(x.Parent); - x = rbTree; - } - } - } - x.Color = RedBlackNode.BLACK; - } - - /// - /// RemoveMin - /// removes the node with the minimum key - /// - public void RemoveMin() - { - if(rbTree == null) - throw(new RedBlackException("RedBlackNode is null")); - - Remove(GetMinKey()); - } - /// - /// RemoveMax - /// removes the node with the maximum key - /// - public void RemoveMax() - { - if(rbTree == null) - throw(new RedBlackException("RedBlackNode is null")); - - Remove(GetMaxKey()); - } - /// - /// Clear - /// Empties or clears the tree - /// - public void Clear () - { - rbTree = sentinelNode; - intCount = 0; - } - /// - /// Size - /// returns the size (number of nodes) in the tree - /// - public int Size() - { - // number of keys - return intCount; - } - /// - /// Equals - /// - public override bool Equals(object obj) - { - if(obj == null) - return false; - - if(!(obj is RedBlackNode )) - return false; - - if(this == obj) - return true; - - return (ToString().Equals(((RedBlackNode)(obj)).ToString())); - - } - /// - /// HashCode - /// - public override int GetHashCode() - { - return intHashCode; - } - /// - /// ToString - /// - public override string ToString() - { - return strIdentifier.ToString(); - } - } -} diff --git a/OLECompoundFileStorage/RBTree/RedBlackEnumerator.cs b/OLECompoundFileStorage/RBTree/RedBlackEnumerator.cs deleted file mode 100644 index d3b142b2..00000000 --- a/OLECompoundFileStorage/RBTree/RedBlackEnumerator.cs +++ /dev/null @@ -1,195 +0,0 @@ - -using System; -using System.Collections; - -namespace RBTree -{ - /// - /// The RedBlackEnumerator class returns the keys or data objects of the treap in - /// sorted order. - /// - public class RedBlackEnumerator - { - // the treap uses the stack to order the nodes - private Stack stack; - // return the keys - private bool keys; - // return in ascending order (true) or descending (false) - private bool ascending; - - // key - private IComparable ordKey; - // the data or value associated with the key - private object objValue; - - public string Color; // testing only, don't use in live system - public IComparable parentKey; // testing only, don't use in live system - - /// - ///Key - /// - public IComparable Key - { - get - { - return ordKey; - } - - set - { - ordKey = value; - } - } - /// - ///Data - /// - public object Value - { - get - { - return objValue; - } - - set - { - objValue = value; - } - } - - public RedBlackEnumerator() - { - } - /// - /// Determine order, walk the tree and push the nodes onto the stack - /// - public RedBlackEnumerator(RedBlackNode tnode, bool keys, bool ascending) - { - - stack = new Stack(); - this.keys = keys; - this.ascending = ascending; - - // use depth-first traversal to push nodes into stack - // the lowest node will be at the top of the stack - if(ascending) - { // find the lowest node - while(tnode != RedBlack.sentinelNode) - { - stack.Push(tnode); - tnode = tnode.Left; - } - } - else - { - // the highest node will be at top of stack - while(tnode != RedBlack.sentinelNode) - { - stack.Push(tnode); - tnode = tnode.Right; - } - } - - } - /// - /// HasMoreElements - /// - public bool HasMoreElements() - { - return (stack.Count > 0); - } - /// - /// NextElement - /// - public object NextElement() - { - if(stack.Count == 0) - throw(new RedBlackException("Element not found")); - - // the top of stack will always have the next item - // get top of stack but don't remove it as the next nodes in sequence - // may be pushed onto the top - // the stack will be popped after all the nodes have been returned - RedBlackNode node = (RedBlackNode) stack.Peek(); //next node in sequence - - if(ascending) - { - if(node.Right == RedBlack.sentinelNode) - { - // yes, top node is lowest node in subtree - pop node off stack - RedBlackNode tn = (RedBlackNode) stack.Pop(); - // peek at right node's parent - // get rid of it if it has already been used - while(HasMoreElements()&& ((RedBlackNode) stack.Peek()).Right == tn) - tn = (RedBlackNode) stack.Pop(); - } - else - { - // find the next items in the sequence - // traverse to left; find lowest and push onto stack - RedBlackNode tn = node.Right; - while(tn != RedBlack.sentinelNode) - { - stack.Push(tn); - tn = tn.Left; - } - } - } - else // descending, same comments as above apply - { - if(node.Left == RedBlack.sentinelNode) - { - // walk the tree - RedBlackNode tn = (RedBlackNode) stack.Pop(); - while(HasMoreElements() && ((RedBlackNode)stack.Peek()).Left == tn) - tn = (RedBlackNode) stack.Pop(); - } - else - { - // determine next node in sequence - // traverse to left subtree and find greatest node - push onto stack - RedBlackNode tn = node.Left; - while(tn != RedBlack.sentinelNode) - { - stack.Push(tn); - tn = tn.Right; - } - } - } - - // the following is for .NET compatibility (see MoveNext()) - Key = node.Key; - Value = node.Data; - // ******** testing only ******** - try - { - parentKey = node.Parent.Key; // testing only - - } - catch(Exception e) - { - object o = e; // stop compiler from complaining - parentKey = 0; - } - if(node.Color == 0) // testing only - Color = "Red"; - else - Color = "Black"; - // ******** testing only ******** - - return keys == true ? node.Key : node.Data; - } - /// - /// MoveNext - /// For .NET compatibility - /// - public bool MoveNext() - { - if(HasMoreElements()) - { - NextElement(); - return true; - } - return false; - } - } -} diff --git a/OLECompoundFileStorage/RBTree/RedBlackException.cs b/OLECompoundFileStorage/RBTree/RedBlackException.cs deleted file mode 100644 index 6fc36fdf..00000000 --- a/OLECompoundFileStorage/RBTree/RedBlackException.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace RBTree -{ - /// - /// The RedBlackException class distinguishes read black tree exceptions from .NET - /// exceptions. - /// - public class RedBlackException : Exception - { - public RedBlackException() - { - } - - public RedBlackException(string msg) - : base(msg) - { - } - } -} diff --git a/OLECompoundFileStorage/RBTree/RedBlackNode.cs b/OLECompoundFileStorage/RBTree/RedBlackNode.cs deleted file mode 100644 index e09afd19..00000000 --- a/OLECompoundFileStorage/RBTree/RedBlackNode.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System; -using System.Text; - -namespace RBTree -{ - /// - /// The RedBlackNode class encapsulates a node in the tree - /// - public class RedBlackNode - { - // tree node colors - public static int RED = 0; - public static int BLACK = 1; - - // key provided by the calling class - private IComparable ordKey; - // the data or value associated with the key - private object objData; - // color - used to balance the tree - private int intColor; - // left node - private RedBlackNode rbnLeft; - // right node - private RedBlackNode rbnRight; - // parent node - private RedBlackNode rbnParent; - - /// - ///Key - /// - public IComparable Key - { - get - { - return ordKey; - } - - set - { - ordKey = value; - } - } - /// - ///Data - /// - public object Data - { - get - { - return objData; - } - - set - { - objData = value; - } - } - /// - ///Color - /// - public int Color - { - get - { - return intColor; - } - - set - { - intColor = value; - } - } - /// - ///Left - /// - public RedBlackNode Left - { - get - { - return rbnLeft; - } - - set - { - rbnLeft = value; - } - } - /// - /// Right - /// - public RedBlackNode Right - { - get - { - return rbnRight; - } - - set - { - rbnRight = value; - } - } - public RedBlackNode Parent - { - get - { - return rbnParent; - } - - set - { - rbnParent = value; - } - } - - public RedBlackNode() - { - Color = RED; - } - } -} diff --git a/OpenMcdf.Extensions/CFStreamExtensions.cs b/OpenMcdf.Extensions/CFStreamExtensions.cs new file mode 100644 index 00000000..6237cbff --- /dev/null +++ b/OpenMcdf.Extensions/CFStreamExtensions.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace OpenMcdf.Extensions +{ + public static class CFStreamExtension + { + private class StreamDecorator : Stream + { + private CFStream cfStream; + private long position = 0; + + public StreamDecorator(CFStream cfstream) + { + this.cfStream = cfstream; + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return true; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override void Flush() + { + // nothing to do; + } + + public override long Length + { + get { return cfStream.Size; } + } + + public override long Position + { + get + { + return position; + } + set + { + position = value; + } + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (count > buffer.Length) + throw new ArgumentException("Count parameter exceeds buffer size"); + + if (buffer == null) + throw new ArgumentNullException("Buffer cannot be null"); + + if (offset < 0 || count < 0) + throw new ArgumentOutOfRangeException("Offset and Count parameters must be non-negative numbers"); + + if (position >= cfStream.Size) + return 0; + + count = this.cfStream.Read(buffer, position, offset, count); + position += count; + return count; + } + + public override long Seek(long offset, SeekOrigin origin) + { + switch (origin) + { + case SeekOrigin.Begin: + position = offset; + break; + case SeekOrigin.Current: + position += offset; + break; + case SeekOrigin.End: + position -= offset; + break; + default: + throw new Exception("Invalid origin selected"); + } + + return position; + } + + public override void SetLength(long value) + { + this.cfStream.Resize(value); + } + + public override void Write(byte[] buffer, int offset, int count) + { + this.cfStream.Write(buffer, position, offset, count); + position += count; + } + } + + /// + /// Return the current CFStream object + /// as a Stream object. + /// + /// Current CFStream object + /// A Stream object representing structured stream data + public static Stream AsIOStream(this CFStream cfStream) + { + return new StreamDecorator(cfStream); + } + } +} diff --git a/OleCfsMemoryTest/OpenMcdfMemTest.csproj b/OpenMcdf.Extensions/OpenMcdf.Extensions.csproj similarity index 71% rename from OleCfsMemoryTest/OpenMcdfMemTest.csproj rename to OpenMcdf.Extensions/OpenMcdf.Extensions.csproj index 716a18d2..25e3accd 100644 --- a/OleCfsMemoryTest/OpenMcdfMemTest.csproj +++ b/OpenMcdf.Extensions/OpenMcdf.Extensions.csproj @@ -1,16 +1,16 @@  - + Debug AnyCPU - 9.0.30729 + 8.0.30703 2.0 - {E2BAD82D-3040-462B-BAA2-6E608A9054F4} - Exe + {DB748C1D-D71C-442B-832D-2E33BE816CBB} + Library Properties - OpenMcdfMemTest - OpenMcdfMemTest - v2.0 + OpenMcdf.Extensions + OpenMcdf.Extensions + v4.0 512 @@ -32,22 +32,23 @@ + + + + - + - + {56E15D4A-8A37-4C7C-BB44-FD59AFF220C1} OpenMcdf - - - + \ No newline at end of file diff --git a/OLECFSTest/Properties/AssemblyInfo.cs b/Unit Test/Properties/AssemblyInfo.cs similarity index 100% rename from OLECFSTest/Properties/AssemblyInfo.cs rename to Unit Test/Properties/AssemblyInfo.cs diff --git a/Unit Test/RBTreeTest.cs b/Unit Test/RBTreeTest.cs new file mode 100644 index 00000000..8d81b9a4 --- /dev/null +++ b/Unit Test/RBTreeTest.cs @@ -0,0 +1,236 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenMcdf; +using RedBlackTree; + +namespace OpenMcdfTest +{ + /// + /// Summary description for RBTreeTest + /// + [TestClass] + public class RBTreeTest + { + public RBTreeTest() + { + + } + + private TestContext testContextInstance; + + /// + ///Gets or sets the test context which provides + ///information about and functionality for the current test run. + /// + public TestContext TestContext + { + get + { + return testContextInstance; + } + set + { + testContextInstance = value; + } + } + + #region Additional test attributes + // + // You can use the following additional attributes as you write your tests: + // + // Use ClassInitialize to run code before running the first test in the class + // [ClassInitialize()] + // public static void MyClassInitialize(TestContext testContext) { } + // + // Use ClassCleanup to run code after all tests in a class have run + // [ClassCleanup()] + // public static void MyClassCleanup() { } + // + // Use TestInitialize to run code before running each test + // [TestInitialize()] + // public void MyTestInitialize() { } + // + // Use TestCleanup to run code after each test has run + // [TestCleanup()] + // public void MyTestCleanup() { } + // + #endregion + + [TestMethod] + public void Test_RBTREE_INSERT() + { + RBTree rbTree = new RBTree(); + + List itemsToInsert = new List(); + + for (int i = 0; i < 25; i++) + { + itemsToInsert.Add(new CFMock(i.ToString(), StgType.StgStream)); + } + + foreach (var item in itemsToInsert) + { + rbTree.Insert(item); + } + + for (int i = 0; i < itemsToInsert.Count; i++) + { + CFItem c; + rbTree.TryLookup(new CFMock(i.ToString(), StgType.StgStream), out c); + Assert.IsTrue(c is CFItem); + Assert.IsTrue(c.Name == i.ToString()); + Assert.IsTrue(c.IsStream); + } + } + + + [TestMethod] + public void Test_RBTREE_DELETE() + { + RBTree rbTree = new RBTree(); + + List itemsToInsert = new List(); + + for (int i = 0; i < 25; i++) + { + itemsToInsert.Add(new CFMock(i.ToString(), StgType.StgStream)); + } + + foreach (var item in itemsToInsert) + { + rbTree.Insert(item); + } + + try + { + rbTree.Delete(new CFMock("17", StgType.StgStream)); + rbTree.Delete(new CFMock("24", StgType.StgStream)); + rbTree.Delete(new CFMock("7", StgType.StgStream)); + } + catch (Exception ex) + { + Assert.Fail("Item removal failed: " + ex.Message); + } + + + + CFItem c; + bool s = rbTree.TryLookup(new CFMock("7", StgType.StgStream), out c); + + + Assert.IsFalse(s); + + c = null; + + Assert.IsTrue(rbTree.TryLookup(new CFMock("6", StgType.StgStream), out c)); + Assert.IsTrue(c.IsStream); + Assert.IsTrue(rbTree.TryLookup(new CFMock("12", StgType.StgStream), out c)); + Assert.IsTrue(c.Name == "12"); + + + } + + private static void VerifyProperties(RBTree t) + { + + VerifyProperty1(t.Root); + VerifyProperty2(t.Root); + // Property 3 is implicit + VerifyProperty4(t.Root); + VerifyProperty5(t.Root); + } + + private static Color NodeColor(RBNode n) where K : IComparable + { + return n == null ? Color.BLACK : n.Color; + } + + private static void VerifyProperty1(RBNode n) where K : IComparable + { + + Assert.IsTrue(NodeColor(n) == Color.RED || NodeColor(n) == Color.BLACK); + + if (n == null) return; + VerifyProperty1(n.Left); + VerifyProperty1(n.Right); + } + + private static void VerifyProperty2(RBNode root) where K : IComparable + { + Assert.IsTrue(NodeColor(root) == Color.BLACK); + } + + private static void VerifyProperty4(RBNode n) where K : IComparable + { + + if (NodeColor(n) == Color.RED) + { + Assert.IsTrue((NodeColor(n.Left) == Color.BLACK)); + Assert.IsTrue((NodeColor(n.Right) == Color.BLACK)); + Assert.IsTrue((NodeColor(n.Parent) == Color.BLACK)); + } + + if (n == null) return; + VerifyProperty4(n.Left); + VerifyProperty4(n.Right); + } + + private static void VerifyProperty5(RBNode root) where K : IComparable + { + VerifyProperty5Helper(root, 0, -1); + } + + private static int VerifyProperty5Helper(RBNode n, int blackCount, int pathBlackCount) where K : IComparable + { + if (NodeColor(n) == Color.BLACK) + { + blackCount++; + } + if (n == null) + { + if (pathBlackCount == -1) + { + pathBlackCount = blackCount; + } + else + { + + Assert.IsTrue(blackCount == pathBlackCount); + + } + return pathBlackCount; + } + + pathBlackCount = VerifyProperty5Helper(n.Left, blackCount, pathBlackCount); + pathBlackCount = VerifyProperty5Helper(n.Right, blackCount, pathBlackCount); + + return pathBlackCount; + } + + + + [TestMethod] + public void Test_RBTREE_ENUMERATE() + { + RBTree rbTree = new RBTree(); + + List itemsToInsert = new List(); + + for (int i = 0; i < 25; i++) + { + itemsToInsert.Add(new CFMock(i.ToString(), StgType.StgStream)); + } + + foreach (var item in itemsToInsert) + { + rbTree.Insert(item); + } + + VerifyProperties(rbTree); + //rbTree.Print(); + } + } +} diff --git a/OLECFSTest/SectorCollectionTest.cs b/Unit Test/SectorCollectionTest.cs similarity index 100% rename from OLECFSTest/SectorCollectionTest.cs rename to Unit Test/SectorCollectionTest.cs diff --git a/OLECompoundFileStorage/CFException.cs b/src/CFException.cs similarity index 100% rename from OLECompoundFileStorage/CFException.cs rename to src/CFException.cs diff --git a/OLECompoundFileStorage/CFItem.cs b/src/CFItem.cs similarity index 90% rename from OLECompoundFileStorage/CFItem.cs rename to src/CFItem.cs index 63cf7c9b..0aaacc4c 100644 --- a/OLECompoundFileStorage/CFItem.cs +++ b/src/CFItem.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Text; -using BinaryTrees; /* The contents of this file are subject to the Mozilla Public License @@ -46,7 +45,7 @@ namespace OpenMcdf /// /// /// - public abstract class CFItem : IComparable + public abstract class CFItem : IComparable { private CompoundFile compoundFile; @@ -84,15 +83,11 @@ internal IDirectoryEntry DirEntry internal int CompareTo(CFItem other) { + return this.dirEntry.CompareTo(other.DirEntry); } - - - - - #endregion #region IComparable Members @@ -269,5 +264,18 @@ public Guid CLSID throw new CFException("Object class GUID can only be set on Root and Storage entries"); } } + + int IComparable.CompareTo(CFItem other) + { + return this.dirEntry.CompareTo(other.DirEntry); + } + + public override string ToString() + { + if (this.dirEntry != null) + return "[" + this.dirEntry.LeftSibling + "," + this.dirEntry.SID + "," + this.dirEntry.RightSibling + "]" + " " + this.dirEntry.GetEntryName(); + else + return String.Empty; + } } } diff --git a/OLECompoundFileStorage/CFMock.cs b/src/CFMock.cs similarity index 88% rename from OLECompoundFileStorage/CFMock.cs rename to src/CFMock.cs index 0c7d965e..34fcd74c 100644 --- a/OLECompoundFileStorage/CFMock.cs +++ b/src/CFMock.cs @@ -31,5 +31,10 @@ internal CFMock(String dirName, StgType dirType): base() this.DirEntry = new DirectoryEntry(dirType); this.DirEntry.SetEntryName(dirName); } + + public override string ToString() + { + return this.DirEntry.Name; + } } } diff --git a/OLECompoundFileStorage/CFStorage.cs b/src/CFStorage.cs similarity index 83% rename from OLECompoundFileStorage/CFStorage.cs rename to src/CFStorage.cs index afaf9dd4..8af09b0c 100644 --- a/OLECompoundFileStorage/CFStorage.cs +++ b/src/CFStorage.cs @@ -1,7 +1,8 @@ using System; using System.Collections.Generic; using System.Text; -using BinaryTrees; +using RedBlackTree; +using System.Diagnostics; /* The contents of this file are subject to the Mozilla Public License @@ -54,9 +55,9 @@ namespace OpenMcdf /// public class CFStorage : CFItem { - private BinarySearchTree children; + private RBTree children; - internal BinarySearchTree Children + internal RBTree Children { get { @@ -69,7 +70,7 @@ internal BinarySearchTree Children } else { - children = new BinarySearchTree(); + children = this.CompoundFile.CreateNewTree(); } } @@ -103,9 +104,16 @@ internal CFStorage(CompoundFile compFile, IDirectoryEntry dirEntry) this.DirEntry = dirEntry; } - private BinarySearchTree LoadChildren(int SID) + private RBTree LoadChildren(int SID) { - return this.CompoundFile.GetChildrenTree(SID); + RBTree childrenTree = this.CompoundFile.GetChildrenTree(SID); + + if (childrenTree.Root != null) + this.DirEntry.Child = childrenTree.Root.Value.DirEntry.SID; + else + this.DirEntry.Child = DirectoryEntry.NOSTREAM; + + return childrenTree; } /// @@ -150,15 +158,16 @@ public CFStream AddStream(String streamName) try { // Add object to Siblings tree - this.Children.Add(cfo); - + this.Children.Insert(cfo); + //Trace.WriteLine("**** INSERT STREAM " + cfo.Name + "******"); + //this.Children.Print(); //Rethread children tree... - CompoundFile.RefreshIterative(Children.Root); + // CompoundFile.RefreshIterative(Children.Root); //... and set the root of the tree as new child of the current item directory entry this.DirEntry.Child = Children.Root.Value.DirEntry.SID; } - catch (BSTDuplicatedException) + catch (RBTreeException) { CompoundFile.ResetDirectoryEntry(cfo.DirEntry.SID); cfo = null; @@ -203,7 +212,7 @@ public CFStream GetStream(String streamName) CFItem outDe = null; - if (Children.TryFind(tmp, out outDe) && outDe.DirEntry.StgType == StgType.StgStream) + if (Children.TryLookup(tmp, out outDe) && outDe.DirEntry.StgType == StgType.StgStream) { return outDe as CFStream; } @@ -239,7 +248,7 @@ public CFStorage GetStorage(String storageName) CFMock tmp = new CFMock(storageName, StgType.StgStorage); CFItem outDe = null; - if (Children.TryFind(tmp, out outDe) && outDe.DirEntry.StgType == StgType.StgStorage) + if (Children.TryLookup(tmp, out outDe) && outDe.DirEntry.StgType == StgType.StgStorage) { return outDe as CFStorage; } @@ -290,9 +299,11 @@ public CFStorage AddStorage(String storageName) try { // Add object to Siblings tree - Children.Add(cfo); + //Trace.WriteLine("**** INSERT STORAGE " + cfo.Name + "******"); + Children.Insert(cfo); + //Children.Print(); } - catch (BSTDuplicatedException) + catch (RBTreeDuplicatedItemException) { CompoundFile.ResetDirectoryEntry(cfo.DirEntry.SID); @@ -301,7 +312,7 @@ public CFStorage AddStorage(String storageName) } - CompoundFile.RefreshIterative(Children.Root); + //CompoundFile.RefreshIterative(Children.Root); this.DirEntry.Child = Children.Root.Value.DirEntry.SID; return cfo; } @@ -319,9 +330,6 @@ public CFStorage AddStorage(String storageName) // return result; //} - - private NodeAction internalAction; - /// /// Visit all entities contained in the storage applying a user provided action /// @@ -346,19 +354,19 @@ public CFStorage AddStorage(String storageName) /// tw.Close(); /// /// - public void VisitEntries(VisitedEntryAction action, bool recursive) + public void VisitEntries(Action action, bool recursive) { CheckDisposed(); if (action != null) { - List> subStorages - = new List>(); + List> subStorages + = new List>(); - internalAction = - delegate(BinaryTreeNode targetNode) + Action> internalAction = + delegate(RBNode targetNode) { - action(targetNode.Value as CFItem); + action(targetNode.Value); if (targetNode.Value.DirEntry.Child != DirectoryEntry.NOSTREAM) subStorages.Add(targetNode); @@ -366,10 +374,10 @@ List> subStorages return; }; - this.Children.VisitTreeInOrder(internalAction); + this.Children.VisitTreeNodes(internalAction); if (recursive && subStorages.Count > 0) - foreach (BinaryTreeNode n in subStorages) + foreach (RBNode n in subStorages) { ((CFStorage)n.Value).VisitEntries(action, recursive); } @@ -413,7 +421,7 @@ public void Delete(String entryName) CFItem foundObj = null; - this.Children.TryFind(tmp, out foundObj); + this.Children.TryLookup(tmp, out foundObj); if (foundObj == null) throw new CFItemNotFound("Entry named [" + entryName + "] was not found"); @@ -430,35 +438,39 @@ public void Delete(String entryName) CFStorage temp = (CFStorage)foundObj; - foreach (CFItem de in temp.Children) + // This is a storage. we have to remove children items first + foreach (RBNode de in temp.Children) { - temp.Delete(de.Name); + temp.Delete(de.Value.Name); } - // Remove item from children tree - this.Children.Remove(foundObj); - - // Synchronize tree with directory entries - this.CompoundFile.RefreshIterative(this.Children.Root); - - // Rethread the root of siblings tree... + // ...then we need to rethread the root of siblings tree... if (this.Children.Root != null) this.DirEntry.Child = this.Children.Root.Value.DirEntry.SID; else this.DirEntry.Child = DirectoryEntry.NOSTREAM; - // ...and now remove directory (storage) entry + // ...and finally Remove storage item from children tree... + this.Children.Delete(foundObj); + + // ...and remove directory (storage) entry this.CompoundFile.RemoveDirectoryEntry(foundObj.DirEntry.SID); + //Trace.WriteLine("**** DELETED STORAGE " + entryName + "******"); + + // Synchronize tree with directory entries + //this.CompoundFile.RefreshIterative(this.Children.Root); + break; case StgType.StgStream: // Remove item from children tree - this.Children.Remove(foundObj); - - // Synchronize tree with directory entries - this.CompoundFile.RefreshIterative(this.Children.Root); + this.Children.Delete(foundObj); + //Trace.WriteLine("**** DELETED STREAM " + entryName + "******"); + + // Synchronize tree with directory entries + //this.CompoundFile.RefreshIterative(this.Children.Root); // Rethread the root of siblings tree... if (this.Children.Root != null) diff --git a/src/CFStream.cs b/src/CFStream.cs new file mode 100644 index 00000000..d5abcb01 --- /dev/null +++ b/src/CFStream.cs @@ -0,0 +1,264 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +/* + The contents of this file are subject to the Mozilla Public License + Version 1.1 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + License for the specific language governing rights and limitations + under the License. + + The Original Code is OpenMCDF - Compound Document Format library. + + The Initial Developer of the Original Code is Federico Blaseotto. +*/ + +namespace OpenMcdf +{ + + /// + /// OLE structured storage stream Object + /// It is contained inside a Storage object in a file-directory + /// relationship and indexed by its name. + /// + public class CFStream : CFItem + { + private long position = 0; + + internal CFStream(CompoundFile sectorManager) + : base(sectorManager) + { + this.DirEntry = new DirectoryEntry(StgType.StgStream); + this.DirEntry.StgColor = StgColor.Black; + + sectorManager.InsertNewDirectoryEntry(this.DirEntry); + } + + internal CFStream(CompoundFile sectorManager, IDirectoryEntry dirEntry) + : base(sectorManager) + { + if (dirEntry == null || dirEntry.SID < 0) + throw new CFException("Attempting to add a CFStream using an unitialized directory"); + + this.DirEntry = dirEntry; + } + + /// + /// Set the data associated with the stream object. + /// + /// + /// + /// byte[] b = new byte[]{0x0,0x1,0x2,0x3}; + /// CompoundFile cf = new CompoundFile(); + /// CFStream myStream = cf.RootStorage.AddStream("MyStream"); + /// myStream.SetData(b); + /// + /// + /// Data bytes to write to this stream + /// Existing associated data will be lost after method invocation + public void SetData(Byte[] data) + { + CheckDisposed(); + + this.CompoundFile.FreeData(this); + this.CompoundFile.WriteData(this, data); + } + + + /// + /// Write a data buffer to a specific position into current CFStream object + /// + /// Data buffer to Write + /// Position into the stream object to start writing from + /// Current stream will be extended to receive data buffer over + /// its current size + public void Write(byte[] data, long position) + { + this.Write(data, position, 0, data.Length); + } + + /// + /// Write Count bytes of a data buffer to a specific position into + /// the current CFStream object starting from the specified position. + /// + /// Data buffer to copy bytes from + /// Position into the stream object to start writing from + /// The zero-based byte offset in buffer at which to + /// begin copying bytes to the current CFStream. + /// The number of bytes to be written to the current CFStream + /// Current stream will be extended to receive data buffer over + /// its current size. + internal void Write(byte[] data, long position, int offset, int count) + { + CheckDisposed(); + this.CompoundFile.WriteData(this, data, position, offset, count); + } + + /// + /// Append the provided data to stream data. + /// + /// + /// + /// byte[] b = new byte[]{0x0,0x1,0x2,0x3}; + /// byte[] b2 = new byte[]{0x4,0x5,0x6,0x7}; + /// CompoundFile cf = new CompoundFile(); + /// CFStream myStream = cf.RootStorage.AddStream("MyStream"); + /// myStream.SetData(b); // here we could also have invoked .AppendData + /// myStream.AppendData(b2); + /// cf.Save("MyLargeStreamsFile.cfs); + /// cf.Close(); + /// + /// + /// Data bytes to append to this stream + /// + /// This method allows user to create stream with more than 2GB of data, + /// appending data to the end of existing ones. + /// Large streams (>2GB) are only supported by CFS version 4. + /// Append data can also be invoked on streams with no data in order + /// to simplify its use inside loops. + /// + public void Append(Byte[] data) + { + CheckDisposed(); + if (this.Size > 0) + { + this.CompoundFile.AppendData(this, data); + } + else + { + this.CompoundFile.WriteData(this, data); + } + } + + /// + /// Get all the data associated with the stream object. + /// + /// + /// + /// CompoundFile cf2 = new CompoundFile("AFileName.cfs"); + /// CFStream st = cf2.RootStorage.GetStream("MyStream"); + /// byte[] buffer = st.ReadAll(); + /// + /// + /// Array of byte containing stream data + /// + /// Raised when the owner compound file has been closed. + /// + public Byte[] GetData() + { + CheckDisposed(); + + return this.CompoundFile.GetData(this); + } + + + /// + /// Read bytes associated with the stream object, starting from + /// a provided . Method returns the effective count of bytes + /// read. + /// + /// Array of bytes that will contain stream data + /// The zero-based byte position in the stream at which to begin reading + /// the data from. + /// The maximum number of bytes to be read from the current stream. + /// The count of bytes effectively read + /// Method may read a number of bytes lesser then the requested one. + /// + /// CompoundFile cf = null; + /// byte[] b = Helpers.GetBuffer(1024 * 2, 0xAA); //2MB buffer + /// CFStream item = cf.RootStorage.GetStream("AStream"); + /// + /// cf = new CompoundFile("$AFILENAME.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.Default); + /// item = cf.RootStorage.GetStream("AStream"); + /// + /// byte[] buffer = new byte[2048]; + /// item.Read(buffer, 0, 2048); + /// Assert.IsTrue(Helpers.CompareBuffer(b, buffer)); + /// + /// + /// + /// Raised when the owner compound file has been closed. + /// + public int Read(byte[] buffer, long position, int count) + { + CheckDisposed(); + return this.CompoundFile.ReadData(this, position, buffer, 0, count); + } + + + + /// + /// Read bytes associated with the stream object, starting from + /// a provided . Method returns the effective count of bytes + /// read. + /// + /// Array of bytes that will contain stream data + /// The zero-based byte position in the stream at which to begin reading + /// the data from. + /// The zero-based byte offset in buffer at which to begin storing the data read from the current stream. + /// The maximum number of bytes to be read from the current stream. + /// The count of bytes effectively read + /// Method may read a number of bytes lesser then the requested one. + /// + /// CompoundFile cf = null; + /// byte[] b = Helpers.GetBuffer(1024 * 2, 0xAA); //2MB buffer + /// CFStream item = cf.RootStorage.GetStream("AStream"); + /// + /// cf = new CompoundFile("$AFILENAME.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.Default); + /// item = cf.RootStorage.GetStream("AStream"); + /// + /// byte[] buffer = new byte[2048]; + /// item.Read(buffer, 0, 2048); + /// Assert.IsTrue(Helpers.CompareBuffer(b, buffer)); + /// + /// + /// + /// Raised when the owner compound file has been closed. + /// + internal int Read(byte[] buffer, long position, int offset, int count) + { + CheckDisposed(); + return this.CompoundFile.ReadData(this, position, buffer, offset, count); + } + + + /// + /// Copy data from an existing stream. + /// + /// A stream to read from + /// + /// Input stream will NOT be closed after method invocation. + /// Existing associated data will be deleted. + /// + public void CopyFrom(Stream input) + { + CheckDisposed(); + + byte[] buffer = new byte[input.Length]; + + if (input.CanSeek) + { + input.Seek(0, SeekOrigin.Begin); + } + + input.Read(buffer, 0, (int)input.Length); + this.SetData(buffer); + } + + + /// + /// Resize stream padding with zero if enlarging, trimming data if reducing size. + /// + /// New length to assign to this stream + public void Resize(long length) + { + this.CompoundFile.SetStreamLength(this, length); + } + } +} diff --git a/OLECompoundFileStorage/CompoundFile.cs b/src/CompoundFile.cs similarity index 75% rename from OLECompoundFileStorage/CompoundFile.cs rename to src/CompoundFile.cs index 73cb891e..e23c5bc2 100644 --- a/OLECompoundFileStorage/CompoundFile.cs +++ b/src/CompoundFile.cs @@ -20,10 +20,11 @@ The Initial Developer of the Original Code is Federico Blaseotto. using System.Collections.Generic; using System.Text; using System.IO; -using BinaryTrees; using System.Collections; using System.Security.AccessControl; using System.Threading; +using RedBlackTree; +using System.Diagnostics; namespace OpenMcdf { @@ -38,6 +39,42 @@ public int Compare(CFItem x, CFItem y) } } + /// + /// Configuration parameters for the compund files. + /// They can be OR-combined to configure + /// Compound file behaviour. + /// All flags are NOT set by Default. + /// + [Flags] + public enum CFSConfiguration + { + /// + /// Sector Recycling turn off, + /// free sectors erasing off, + /// format validation exception raised + /// + Default = 1, + + /// + /// Sector recycling reduces data writing performances + /// but avoids space wasting in scenarios with frequently + /// data manipulation of the same streams. + /// + SectorRecycle = 2, + + /// + /// Free sectors are erased to avoid information leakage + /// + EraseFreeSectors = 4, + + /// + /// No exception is raised when a validation error occurs. + /// This can possibly lead to a security issue but gives + /// a chance to corrupted files to load. + /// + NoValidationException = 8 + } + /// /// Binary File Format Version. Sector size is 512 byte for version 3, /// 4096 for version 4 @@ -58,15 +95,17 @@ public enum CFSVersion : int /// Update mode of the compound file. /// Default is ReadOnly. /// - public enum UpdateMode + public enum CFSUpdateMode { /// /// ReadOnly update mode prevents overwriting /// of the opened file. /// Data changes are allowed but they have to be - /// persisted on a different file when required. + /// persisted on a different file when required + /// using method /// ReadOnly, + /// /// Update mode allows subsequent data changing operations /// to be persisted directly on the opened file or stream @@ -85,6 +124,20 @@ public enum UpdateMode /// public class CompoundFile : IDisposable { + private CFSConfiguration configuration + = CFSConfiguration.Default; + + /// + /// Get the configuration parameters of the CompoundFile object. + /// + public CFSConfiguration Configuration + { + get + { + return configuration; + } + } + /// /// Returns the size of standard sectors switching on CFS version (3 or 4) /// @@ -136,8 +189,9 @@ internal int GetSectorSize() /// private const int FLUSHING_BUFFER_MAX_SIZE = 1024 * 1024 * 16; + private SectorCollection sectors = new SectorCollection(); - //private ArrayList sectors = new ArrayList(); + /// /// CompoundFile header @@ -207,12 +261,12 @@ void OnSizeLimitReached() _lockSectorId = rangeLockSector.Id; } + /// /// Create a new, blank, compound file. /// /// Use a specific Compound File Version to set 512 or 4096 bytes sectors - /// If true, recycle unused sectors - /// If true, unallocated sectors will be overwritten with zeros + /// Set configuration parameters for the new compound file /// /// /// @@ -222,7 +276,7 @@ void OnSizeLimitReached() /// b[i % 120] = (byte)i; /// } /// - /// CompoundFile cf = new CompoundFile(CFSVersion.Ver_4, true, true); + /// CompoundFile cf = new CompoundFile(CFSVersion.Ver_4, CFSConfiguration.Default); /// CFStream myStream = cf.RootStorage.AddStream("MyStream"); /// /// Assert.IsNotNull(myStream); @@ -232,16 +286,17 @@ void OnSizeLimitReached() /// /// /// - /// - /// Sector recycling reduces data writing performances but avoids space wasting in scenarios with frequently - /// data manipulation of the same streams. The new compound file is open in Update mode. - /// - public CompoundFile(CFSVersion cfsVersion, bool sectorRecycle, bool eraseFreeSectors) + public CompoundFile(CFSVersion cfsVersion, CFSConfiguration configFlags) { + this.configuration = configFlags; + + bool sectorRecycle = configFlags.HasFlag(CFSConfiguration.SectorRecycle); + bool eraseFreeSectors = configFlags.HasFlag(CFSConfiguration.EraseFreeSectors); + this.header = new Header((ushort)cfsVersion); this.sectorRecycle = sectorRecycle; - + DIFAT_SECTOR_FAT_ENTRIES_COUNT = (GetSectorSize() / 4) - 1; FAT_SECTOR_ENTRIES_COUNT = (GetSectorSize() / 4); @@ -285,7 +340,7 @@ public CompoundFile(CFSVersion cfsVersion, bool sectorRecycle, bool eraseFreeSec public CompoundFile(String fileName) { this.sectorRecycle = false; - this.updateMode = UpdateMode.ReadOnly; + this.updateMode = CFSUpdateMode.ReadOnly; this.eraseFreeSectors = false; LoadFile(fileName); @@ -319,53 +374,12 @@ public CompoundFile(String fileName) /// /// /// - public CompoundFile(String fileName, UpdateMode updateMode, bool sectorRecycle, bool eraseFreeSectors) - { - this.sectorRecycle = sectorRecycle; - this.updateMode = updateMode; - this.eraseFreeSectors = eraseFreeSectors; - - LoadFile(fileName); - - DIFAT_SECTOR_FAT_ENTRIES_COUNT = (GetSectorSize() / 4) - 1; - FAT_SECTOR_ENTRIES_COUNT = (GetSectorSize() / 4); - } - - /// - /// Load an existing compound file. - /// - /// Compound file to read from - /// If true, recycle unused sectors - /// Select the update mode of the underlying data file - /// If true, overwrite with zeros unallocated sectors - /// If true, no CFCorruptedFileException - /// will be thrown even if corrupted file is loaded. Please note that this option is could pose a potential security threat - /// - /// - /// String srcFilename = "data_YOU_CAN_CHANGE.xls"; - /// - /// CompoundFile cf = new CompoundFile(srcFilename, UpdateMode.Update, true, true, true); - /// - /// - /// Random r = new Random(); - /// - /// byte[] buffer = GetBuffer(r.Next(3, 4095), 0x0A); - /// - /// cf.RootStorage.AddStream("MyStream").SetData(buffer); - /// - /// //This will persist data to the underlying media. - /// cf.Commit(); - /// cf.Close(); - /// - /// - /// - public CompoundFile(String fileName, UpdateMode updateMode, bool sectorRecycle, bool eraseFreeSectors, bool noValidationException) + public CompoundFile(String fileName, CFSUpdateMode updateMode, CFSConfiguration configParameters) { - this.validationExceptionEnabled = !noValidationException; - - this.sectorRecycle = sectorRecycle; + this.validationExceptionEnabled = !configParameters.HasFlag(CFSConfiguration.NoValidationException); + this.sectorRecycle = configParameters.HasFlag(CFSConfiguration.SectorRecycle); this.updateMode = updateMode; - this.eraseFreeSectors = eraseFreeSectors; + this.eraseFreeSectors = configParameters.HasFlag(CFSConfiguration.EraseFreeSectors); LoadFile(fileName); @@ -407,60 +421,20 @@ public bool ValidationExceptionEnabled /// /// Raised when trying to open a non-seekable stream /// Raised stream is null - public CompoundFile(Stream stream, UpdateMode updateMode, bool sectorRecycle, bool eraseFreeSectors) + public CompoundFile(Stream stream, CFSUpdateMode updateMode, CFSConfiguration configParameters) { - this.sectorRecycle = sectorRecycle; - this.updateMode = updateMode; - this.eraseFreeSectors = eraseFreeSectors; + this.validationExceptionEnabled = !configParameters.HasFlag(CFSConfiguration.NoValidationException); + this.sectorRecycle = configParameters.HasFlag(CFSConfiguration.SectorRecycle); + this.eraseFreeSectors = configParameters.HasFlag(CFSConfiguration.EraseFreeSectors); + this.updateMode = updateMode; LoadStream(stream); DIFAT_SECTOR_FAT_ENTRIES_COUNT = (GetSectorSize() / 4) - 1; FAT_SECTOR_ENTRIES_COUNT = (GetSectorSize() / 4); } - /// - /// Load an existing compound file. - /// - /// A stream containing a compound file to read - /// If true, recycle unused sectors - /// Select the update mode of the underlying data file - /// If true, overwrite with zeros unallocated sectors - /// If true, openMcdf will try to ignore invalid references or format in order to load a possibly corrupted file anyway - /// The 'noValidationEcxception' parameter could possibly lead to security issues so it's recommanded to use it only on trusted sources - /// - /// - /// - /// String filename = "reportREAD.xls"; - /// - /// FileStream fs = new FileStream(filename, FileMode.Open); - /// CompoundFile cf = new CompoundFile(fs, UpdateMode.ReadOnly, false, false, false, true); - /// CFStream foundStream = cf.RootStorage.GetStream("Workbook"); - /// - /// byte[] temp = foundStream.GetData(); //if 'reportRead.xls' is corrupted, openMcdf will try to lad it anyway [noValidationException set true] - /// - /// Assert.IsNotNull(temp); - /// - /// cf.Close(); - /// - /// - /// - /// Raised when trying to open a non-seekable stream - /// Raised stream is null - public CompoundFile(Stream stream, UpdateMode updateMode, bool sectorRecycle, bool eraseFreeSectors, bool noValidationException) - { - this.validationExceptionEnabled = !noValidationException; - - this.sectorRecycle = sectorRecycle; - this.updateMode = updateMode; - this.eraseFreeSectors = eraseFreeSectors; - - LoadStream(stream); - DIFAT_SECTOR_FAT_ENTRIES_COUNT = (GetSectorSize() / 4) - 1; - FAT_SECTOR_ENTRIES_COUNT = (GetSectorSize() / 4); - - } /// /// Load an existing compound file from a stream. /// @@ -492,7 +466,7 @@ public CompoundFile(Stream stream) FAT_SECTOR_ENTRIES_COUNT = (GetSectorSize() / 4); } - private UpdateMode updateMode = UpdateMode.ReadOnly; + private CFSUpdateMode updateMode = CFSUpdateMode.ReadOnly; private String fileName = String.Empty; @@ -532,7 +506,7 @@ public void Commit(bool releaseMemory) if (_disposed) throw new CFDisposedException("Compound File closed: cannot commit data"); - if (updateMode != UpdateMode.Update) + if (updateMode != CFSUpdateMode.Update) throw new CFInvalidOperation("Cannot commit data in Read-Only update mode"); //try @@ -584,6 +558,7 @@ public void Commit(bool releaseMemory) } if (releaseMemory) { + s.ReleaseData(); s = null; sectors[i] = null; @@ -680,6 +655,7 @@ public void Commit(bool releaseMemory) sourceStream.Seek(0, SeekOrigin.Begin); header.Write(sourceStream); + sourceStream.SetLength((sectors.Count + 1) * sSize); sourceStream.Flush(); @@ -741,29 +717,26 @@ private void LoadFile(String fileName) try { - if (this.updateMode == UpdateMode.ReadOnly) + if (this.updateMode == CFSUpdateMode.ReadOnly) { - fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); + fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); } else { - fs = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); + fs = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); } Load(fs); } - catch (Exception ex) + catch { if (fs != null) fs.Close(); - throw; } - - } private void LoadStream(Stream stream) @@ -818,7 +791,9 @@ StreamView miniStreamView this.rootStorage.Size, sourceStream); + // Set updated/new sectors within the ministream + // We are writing data in a NORMAL Sector chain. for (int i = 0; i < sectorChain.Count; i++) { Sector s = sectorChain[i]; @@ -826,9 +801,9 @@ StreamView miniStreamView if (s.Id != -1) { // Overwrite - miniStreamView.Seek(Sector.MINISECTOR_SIZE * s.Id, SeekOrigin.Begin); miniStreamView.Write(s.GetData(), 0, Sector.MINISECTOR_SIZE); + } else { @@ -849,14 +824,10 @@ StreamView miniStreamView Int32 currentId = sectorChain[i].Id; Int32 nextId = sectorChain[i + 1].Id; - //AssureLength(miniFATView, Math.Max(currentId * SIZE_OF_SID, nextId * SIZE_OF_SID)); - miniFATView.Seek(currentId * 4, SeekOrigin.Begin); miniFATView.Write(BitConverter.GetBytes(nextId), 0, 4); } - //AssureLength(miniFATView, sectorChain[sectorChain.Count - 1].Id * SIZE_OF_SID); - // Write End of Chain in MiniFAT miniFATView.Seek(sectorChain[sectorChain.Count - 1].Id * SIZE_OF_SID, SeekOrigin.Begin); miniFATView.Write(BitConverter.GetBytes(Sector.ENDOFCHAIN), 0, 4); @@ -874,8 +845,36 @@ StreamView miniStreamView } } + internal void FreeData(CFStream stream) + { + if (stream.Size == 0) + return; + + List sectorChain = null; + + if (stream.Size < header.MinSizeStandardStream) + { + sectorChain = GetSectorChain(stream.DirEntry.StartSetc, SectorType.Mini); + FreeMiniChain(sectorChain, this.eraseFreeSectors); + } + else + { + sectorChain = GetSectorChain(stream.DirEntry.StartSetc, SectorType.Normal); + FreeChain(sectorChain, this.eraseFreeSectors); + } + + stream.DirEntry.StartSetc = Sector.ENDOFCHAIN; + stream.DirEntry.Size = 0; + } + private void FreeChain(List sectorChain, bool zeroSector) { + FreeChain(sectorChain, 0, zeroSector); + } + + private void FreeChain(List sectorChain, int nth_sector_to_remove, bool zeroSector) + { + // Dummy zero buffer byte[] ZEROED_SECTOR = new byte[GetSectorSize()]; List FAT @@ -884,31 +883,39 @@ List FAT StreamView FATView = new StreamView(FAT, GetSectorSize(), FAT.Count * GetSectorSize(), sourceStream); - // Zeroes out sector data (if requested) - + // Zeroes out sector data (if required)------------- if (zeroSector) { - for (int i = 0; i < sectorChain.Count; i++) + for (int i = nth_sector_to_remove; i < sectorChain.Count; i++) { Sector s = sectorChain[i]; s.ZeroData(); } } - // Update FAT marking unallocated sectors - for (int i = 0; i < sectorChain.Count - 1; i++) + // Update FAT marking unallocated sectors ---------- + for (int i = nth_sector_to_remove; i < sectorChain.Count - 1; i++) { Int32 currentId = sectorChain[i].Id; - Int32 nextId = sectorChain[i + 1].Id; - - //AssureLength(FATView, Math.Max(currentId * SIZE_OF_SID, nextId * SIZE_OF_SID)); FATView.Seek(currentId * 4, SeekOrigin.Begin); FATView.Write(BitConverter.GetBytes(Sector.FREESECT), 0, 4); } + + // Write new end of chain if partial free ---------- + if (nth_sector_to_remove > 0 && sectorChain.Count > 0) + { + FATView.Seek(sectorChain[nth_sector_to_remove - 1].Id * 4, SeekOrigin.Begin); + FATView.Write(BitConverter.GetBytes(Sector.ENDOFCHAIN), 0, 4); + } } private void FreeMiniChain(List sectorChain, bool zeroSector) + { + FreeMiniChain(sectorChain, 0, zeroSector); + } + + private void FreeMiniChain(List sectorChain, int nth_sector_to_remove, bool zeroSector) { byte[] ZEROED_MINI_SECTOR = new byte[Sector.MINISECTOR_SIZE]; @@ -924,10 +931,10 @@ StreamView miniFATView StreamView miniStreamView = new StreamView(miniStream, GetSectorSize(), this.rootStorage.Size, sourceStream); - // Set updated/new sectors within the ministream + // Set updated/new sectors within the ministream ---------- if (zeroSector) { - for (int i = 0; i < sectorChain.Count; i++) + for (int i = nth_sector_to_remove; i < sectorChain.Count; i++) { Sector s = sectorChain[i]; @@ -940,25 +947,20 @@ StreamView miniStreamView } } - // Update miniFAT - for (int i = 0; i < sectorChain.Count - 1; i++) + // Update miniFAT --------------------------------------- + for (int i = nth_sector_to_remove; i < sectorChain.Count - 1; i++) { Int32 currentId = sectorChain[i].Id; - Int32 nextId = sectorChain[i + 1].Id; - - // AssureLength(miniFATView, Math.Max(currentId * SIZE_OF_SID, nextId * SIZE_OF_SID)); miniFATView.Seek(currentId * 4, SeekOrigin.Begin); miniFATView.Write(BitConverter.GetBytes(Sector.FREESECT), 0, 4); } - //AssureLength(miniFATView, sectorChain[sectorChain.Count - 1].Id * SIZE_OF_SID); - - // Write End of Chain in MiniFAT - miniFATView.Seek(sectorChain[sectorChain.Count - 1].Id * SIZE_OF_SID, SeekOrigin.Begin); - miniFATView.Write(BitConverter.GetBytes(Sector.FREESECT), 0, 4); + // Write End of Chain in MiniFAT --------------------------------------- + miniFATView.Seek(sectorChain[(sectorChain.Count - 1) - nth_sector_to_remove].Id * SIZE_OF_SID, SeekOrigin.Begin); + miniFATView.Write(BitConverter.GetBytes(Sector.ENDOFCHAIN), 0, 4); - // Update sector chains + // Update sector chains --------------------------------------- SetNormalSectorChain(miniStreamView.BaseSectorChain); SetNormalSectorChain(miniFATView.BaseSectorChain); @@ -971,6 +973,28 @@ StreamView miniStreamView } } + /// + /// Allocate space, setup sectors id in the FAT and refresh header + /// for the new or updated sector chain (Normal or Mini sectors) + /// + /// The new or updated normal or mini sector chain + private void SetSectorChain(List sectorChain) + { + if (sectorChain == null || sectorChain.Count == 0) + return; + + SectorType _st = sectorChain[0].Type; + + if (_st == SectorType.Normal) + { + SetNormalSectorChain(sectorChain); + } + else if (_st == SectorType.Mini) + { + SetMiniSectorChain(sectorChain); + } + } + /// /// Allocate space, setup sectors id and refresh header /// for the new or updated sector chain. @@ -984,6 +1008,7 @@ private void SetNormalSectorChain(List sectorChain) { sectors.Add(s); s.Id = sectors.Count - 1; + } } @@ -1019,6 +1044,7 @@ private void CheckForLockSector() private void SetFATSectorChain(List sectorChain) { List fatSectors = GetSectorChain(-1, SectorType.FAT); + StreamView fatStream = new StreamView( fatSectors, @@ -1183,7 +1209,6 @@ StreamView difatStream StreamView fatSv = new StreamView(FATsectorChain, GetSectorSize(), header.FATSectorsNumber * GetSectorSize(), sourceStream); - for (int i = 0; i < header.DIFATSectorsNumber; i++) { fatSv.Seek(difatStream.BaseSectorChain[i].Id * 4, SeekOrigin.Begin); @@ -1377,10 +1402,10 @@ StreamView fatStream while (true) { if (nextSecID == Sector.ENDOFCHAIN) break; - + if (nextSecID >= sectors.Count) throw new CFCorruptedFileException(String.Format("Next Sector ID reference an out of range sector. NextID : {0} while sector count {1}", nextSecID, sectors.Count)); - + Sector s = sectors[nextSecID] as Sector; if (s == null) { @@ -1561,38 +1586,179 @@ internal void ResetDirectoryEntry(int sid) } - internal BinarySearchTree GetChildrenTree(int sid) + internal void OnNodeInsert(RBNode node) + { + + } + + internal void OnNodeDeleted(RBNode obj) + { + + } + + private bool _deserializing; + private bool Deserializing + { + get { return _deserializing; } + set + { + _deserializing = value; + + if (value) + { + _deserializing = value; + Trace.WriteLine("Deserializing..."); + Trace.Indent(); + } + else + { + Trace.WriteLine("Deserializing DONE"); + Trace.Unindent(); + } + } + } + + void OnNodeOperation(RBNode node, NodeOperation operation) + { + if (!Deserializing) + { + switch (operation) + { + case NodeOperation.LeftAssigned: + if (node.Left != null && (node.Left.Value.DirEntry.StgType != StgType.StgInvalid)) + { + node.Value.DirEntry.LeftSibling = node.Left.Value.DirEntry.SID; + } + else + { + node.Value.DirEntry.LeftSibling = DirectoryEntry.NOSTREAM; + } + break; + + case NodeOperation.RightAssigned: + + if (node.Right != null && (node.Right.Value.DirEntry.StgType != StgType.StgInvalid)) + { + node.Value.DirEntry.RightSibling = node.Right.Value.DirEntry.SID; + } + else + { + node.Value.DirEntry.RightSibling = DirectoryEntry.NOSTREAM; + } + break; + + case NodeOperation.ColorAssigned: + node.Value.DirEntry.StgColor = (StgColor)node.Color; + break; + + case NodeOperation.ValueAssigned: + + if (node.Value != null) + { + if (node.Left != null) + node.Value.DirEntry.LeftSibling = node.Left.Value.DirEntry.SID; + else + node.Value.DirEntry.LeftSibling = DirectoryEntry.NOSTREAM; + + if (node.Right != null) + node.Value.DirEntry.RightSibling = node.Right.Value.DirEntry.SID; + else + node.Value.DirEntry.RightSibling = DirectoryEntry.NOSTREAM; + + node.Value.DirEntry.StgColor = (StgColor)node.Color; + + //Rethread parent + if (node.Parent != null) + { + if (node.Parent.Left == node) + node.Parent.Value.DirEntry.LeftSibling = node.Value.DirEntry.SID; + else + node.Parent.Value.DirEntry.RightSibling = node.Value.DirEntry.SID; + } + + } + + break; + + default: + throw new CFException("Unsupported Red Black Node operation"); + } + } + } + + //internal class NodeFactory : IRBTreeDeserializer + //{ + + // public RBNode DeserizlizeFromValues() + // { + // RBNode node = new RBNode(value,(Color)value.DirEntry.StgColor, + // } + //} + + internal RBTree CreateNewTree() + { + RBTree bst = new RBTree(); + bst.NodeInserted += OnNodeInsert; + bst.NodeOperation += OnNodeOperation; + //bst.NodeDeleted += new Action>(OnNodeDeleted); + // bst.ValueAssignedAction += new Action, CFItem>(OnValueAssigned); + return bst; + } + + //void OnValueAssigned(RBNode node, CFItem from) + //{ + // if (from.DirEntry != null && from.DirEntry.LeftSibling != DirectoryEntry.NOSTREAM) + + // if (from.DirEntry != null && from.DirEntry.LeftSibling != DirectoryEntry.NOSTREAM) + // node.Value.DirEntry.LeftSibling = from.DirEntry.LeftSibling; + + // if (from.DirEntry != null && from.DirEntry.RightSibling != DirectoryEntry.NOSTREAM) + // node.Value.DirEntry.RightSibling = from.DirEntry.RightSibling; + //} + + + internal RBTree GetChildrenTree(int sid) { - BinarySearchTree bst - = new BinarySearchTree(new CFItemComparer()); + RBTree bst = new RBTree(); + bst.NodeInserted += OnNodeInsert; + bst.NodeOperation += OnNodeOperation; + //bst.NodeDeleted += OnNodeDeleted; // Load children from their original tree. DoLoadChildren(bst, directoryEntries[sid]); - // Rebuild of (Red)-Black tree of entry children. - bst.VisitTreeInOrder(RefreshSIDs); + // Rethreading of Red-Black tree of entry children after first loading + bst.VisitTreeNodes(RefreshSIDs); + + //bst.Print(); + //Trace.WriteLine("#### After rethreading"); return bst; } - private void DoLoadChildren(BinarySearchTree bst, IDirectoryEntry de) + + private void DoLoadChildren(RBTree bst, IDirectoryEntry de) { - if (de.Child != DirectoryEntry.NOSTREAM ) + Deserializing = true; //Loading existing entries, not just-in-time rethreading + + if (de.Child != DirectoryEntry.NOSTREAM) { if (directoryEntries[de.Child].StgType == StgType.StgInvalid) return; if (directoryEntries[de.Child].StgType == StgType.StgStream) - bst.Add(new CFStream(this, directoryEntries[de.Child])); + bst.Insert(new CFStream(this, directoryEntries[de.Child])); else - bst.Add(new CFStorage(this, directoryEntries[de.Child])); + bst.Insert(new CFStorage(this, directoryEntries[de.Child])); LoadSiblings(bst, directoryEntries[de.Child]); } + + Deserializing = false; } // Doubling methods allows iterative behavior while avoiding // to insert duplicate items - private void LoadSiblings(BinarySearchTree bst, IDirectoryEntry de) + private void LoadSiblings(RBTree bst, IDirectoryEntry de) { if (de.LeftSibling != DirectoryEntry.NOSTREAM) { @@ -1607,7 +1773,7 @@ private void LoadSiblings(BinarySearchTree bst, IDirectoryEntry de) } } - private void DoLoadSiblings(BinarySearchTree bst, IDirectoryEntry de) + private void DoLoadSiblings(RBTree bst, IDirectoryEntry de) { if (ValidateSibling(de.LeftSibling)) { @@ -1616,9 +1782,9 @@ private void DoLoadSiblings(BinarySearchTree bst, IDirectoryEntry de) } if (directoryEntries[de.SID].StgType == StgType.StgStream) - bst.Add(new CFStream(this, directoryEntries[de.SID])); + bst.Insert(new CFStream(this, directoryEntries[de.SID])); else if (directoryEntries[de.SID].StgType == StgType.StgStorage) - bst.Add(new CFStorage(this, directoryEntries[de.SID])); + bst.Insert(new CFStorage(this, directoryEntries[de.SID])); if (ValidateSibling(de.RightSibling)) @@ -1702,10 +1868,14 @@ DirectoryEntry de } } - internal void RefreshSIDs(BinaryTreeNode Node) + internal void RefreshSIDs(RedBlackTree.RBNode Node) { if (Node.Value != null) { + //Set directory color from the node color + Node.Value.DirEntry.StgColor = (StgColor)Node.Color; + + //Synchronize relations with SIDs of directory items if (Node.Left != null && (Node.Left.Value.DirEntry.StgType != StgType.StgInvalid)) { Node.Value.DirEntry.LeftSibling = Node.Left.Value.DirEntry.SID; @@ -1724,15 +1894,17 @@ internal void RefreshSIDs(BinaryTreeNode Node) Node.Value.DirEntry.RightSibling = DirectoryEntry.NOSTREAM; } } + else + throw new CFException("Internal error: null data node"); } - internal void RefreshIterative(BinaryTreeNode node) - { - if (node == null) return; - RefreshSIDs(node); - RefreshIterative(node.Left); - RefreshIterative(node.Right); - } + //internal void RefreshIterative(RedBlackTree.RBNode node) + //{ + // //if (node == null) return; + // //RefreshSIDs(node); + // //RefreshIterative(node.Left); + // //RefreshIterative(node.Right); + //} /// /// Commit directory entries change on the Current Source stream @@ -1818,7 +1990,7 @@ public void Save(String fileName) /// Saves the in-memory image of Compound File to a stream. /// /// - /// Destination Stream must be seekable. + /// Destination Stream must be seekable. Uncommitted data will be persisted to the destination stream. /// /// The stream to save compound File to /// Raised if destination stream is not seekable @@ -1859,7 +2031,6 @@ public void Save(Stream stream) { Sector s = sectors[i] as Sector; - if (s == null) { // Load source (unmodified) sectors @@ -1894,7 +2065,7 @@ public void Save(Stream stream) /// Scan FAT o miniFAT for free sectors to reuse. /// /// Type of sector to look for - /// A stack of available sectors or minisectors already allocated + /// A Queue of available sectors or minisectors already allocated internal Queue FindFreeSectors(SectorType sType) { Queue freeList = new Queue(); @@ -1941,23 +2112,22 @@ List miniStream StreamView miniStreamView = new StreamView(miniStream, GetSectorSize(), rootStorage.Size, sourceStream); - long ptr = 0; + int idx = 0; int nMinisectors = (int)(miniStreamView.Length / Sector.MINISECTOR_SIZE); - while (ptr < nMinisectors) + while (idx < nMinisectors) { //AssureLength(miniStreamView, (int)miniFATView.Length); - int id = miniFATView.ReadInt32(); - ptr += 4; + int nextId = miniFATView.ReadInt32(); - if (id == Sector.FREESECT) + if (nextId == Sector.FREESECT) { Sector ms = new Sector(Sector.MINISECTOR_SIZE, sourceStream); byte[] temp = new byte[Sector.MINISECTOR_SIZE]; - ms.Id = (int)((ptr - 4) / 4); + ms.Id = idx; ms.Type = SectorType.Mini; miniStreamView.Seek(ms.Id * Sector.MINISECTOR_SIZE, SeekOrigin.Begin); @@ -1965,216 +2135,318 @@ StreamView miniStreamView freeList.Enqueue(ms); } + + idx++; } } return freeList; } - internal void SetData(CFItem cfItem, Byte[] buffer) - { - SetStreamData(cfItem, buffer); - } - /// /// INTERNAL DEVELOPMENT. DO NOT CALL. /// /// internal void AppendData(CFItem cfItem, Byte[] buffer) { - //CheckFileLength(); + WriteData(cfItem, cfItem.Size, buffer); + } - if (buffer == null) - throw new CFException("Parameter [buffer] cannot be null"); + /// + /// Resize stream length + /// + /// + /// + internal void SetStreamLength(CFItem cfItem, long length) + { + if (cfItem.Size == length) + return; - //Quick and dirty :-) - if (buffer.Length == 0) return; + SectorType newSectorType = SectorType.Normal; + int newSectorSize = GetSectorSize(); - IDirectoryEntry directoryEntry = cfItem.DirEntry; + if (length < header.MinSizeStandardStream) + { + newSectorType = SectorType.Mini; + newSectorSize = Sector.MINISECTOR_SIZE; + } - SectorType _st = SectorType.Normal; - int _sectorSize = GetSectorSize(); + SectorType oldSectorType = SectorType.Normal; + int oldSectorSize = GetSectorSize(); - if (buffer.Length + directoryEntry.Size < header.MinSizeStandardStream) + if (cfItem.Size < header.MinSizeStandardStream) { - _st = SectorType.Mini; - _sectorSize = Sector.MINISECTOR_SIZE; + oldSectorType = SectorType.Mini; + oldSectorSize = Sector.MINISECTOR_SIZE; } + long oldSize = cfItem.Size; + + + // Get Sector chain and delta size induced by client + List sectorChain = GetSectorChain(cfItem.DirEntry.StartSetc, oldSectorType); + long delta = length - cfItem.Size; + // Check for transition ministream -> stream: // Only in this case we need to free old sectors, // otherwise they will be overwritten. + bool transitionToMini = false; + bool transitionToNormal = false; + List oldChain = null; - byte[] tempMini = null; - - if (directoryEntry.StartSetc != Sector.ENDOFCHAIN) + if (cfItem.DirEntry.StartSetc != Sector.ENDOFCHAIN) { - if ((directoryEntry.Size + buffer.Length) > header.MinSizeStandardStream && directoryEntry.Size < header.MinSizeStandardStream) + if ( + (length < header.MinSizeStandardStream && cfItem.DirEntry.Size > header.MinSizeStandardStream) + || (length > header.MinSizeStandardStream && cfItem.DirEntry.Size < header.MinSizeStandardStream) + ) { - tempMini = new byte[directoryEntry.Size]; - - StreamView miniData - = new StreamView(GetMiniSectorChain(directoryEntry.StartSetc), Sector.MINISECTOR_SIZE, sourceStream); + if (cfItem.DirEntry.Size < header.MinSizeStandardStream) + { + transitionToNormal = true; + oldChain = sectorChain; + } + else + { + transitionToMini = true; + oldChain = sectorChain; + } - miniData.Read(tempMini, 0, (int)directoryEntry.Size); - FreeMiniChain(GetMiniSectorChain(directoryEntry.StartSetc), this.eraseFreeSectors); + // No transition caused by size change - directoryEntry.StartSetc = Sector.ENDOFCHAIN; - directoryEntry.Size = 0; } } - List sectorChain - = GetSectorChain(directoryEntry.StartSetc, _st); - - Queue freeList = FindFreeSectors(_st); // Collect available free sectors - StreamView sv = new StreamView(sectorChain, _sectorSize, tempMini != null ? buffer.Length + tempMini.Length : buffer.Length, freeList, sourceStream); + Queue freeList = null; + StreamView sv = null; - // If stream was a ministream, copy ministream data - // in the new stream - if (tempMini != null) + if (!transitionToMini && !transitionToNormal) //############ NO TRANSITION { - sv.Seek(0, SeekOrigin.Begin); - sv.Write(tempMini, 0, tempMini.Length); + if (delta > 0) // Enlarging stream... + { + if (this.sectorRecycle) + freeList = FindFreeSectors(newSectorType); // Collect available free sectors + + sv = new StreamView(sectorChain, newSectorSize, length, freeList, sourceStream); + + //Set up destination chain + SetSectorChain(sectorChain); + } + else if (delta < 0) // Reducing size... + { + + int nSec = (int)Math.Floor(((double)(Math.Abs(delta)) / newSectorSize)); //number of sectors to mark as free + + if (newSectorSize == Sector.MINISECTOR_SIZE) + FreeMiniChain(sectorChain, nSec, this.eraseFreeSectors); + else + FreeChain(sectorChain, nSec, this.eraseFreeSectors); + } + + if (sectorChain.Count > 0) + { + cfItem.DirEntry.StartSetc = sectorChain[0].Id; + cfItem.DirEntry.Size = length; + } + else + { + cfItem.DirEntry.StartSetc = Sector.ENDOFCHAIN; + cfItem.DirEntry.Size = 0; + } + } - else + else if (transitionToMini) //############## TRANSITION TO MINISTREAM { - sv.Seek(directoryEntry.Size, SeekOrigin.Begin); - } + // Transition Normal chain -> Mini chain - // Write appended data - sv.Write(buffer, 0, buffer.Length); + // Collect available MINI free sectors - switch (_st) - { - case SectorType.Normal: - SetNormalSectorChain(sv.BaseSectorChain); - break; + if (this.sectorRecycle) + freeList = FindFreeSectors(SectorType.Mini); - case SectorType.Mini: - SetMiniSectorChain(sv.BaseSectorChain); - break; - } + sv = new StreamView(oldChain, oldSectorSize, oldSize, sourceStream); + // Reset start sector and size of dir entry + cfItem.DirEntry.StartSetc = Sector.ENDOFCHAIN; + cfItem.DirEntry.Size = 0; - if (sv.BaseSectorChain.Count > 0) - { - directoryEntry.StartSetc = sv.BaseSectorChain[0].Id; - directoryEntry.Size = (long)(buffer.Length) + directoryEntry.Size; + List newChain = GetMiniSectorChain(Sector.ENDOFCHAIN); + StreamView destSv = new StreamView(newChain, Sector.MINISECTOR_SIZE, length, freeList, sourceStream); + + // Buffered trimmed copy from old (larger) to new (smaller) + int cnt = 4096 < length ? 4096 : (int)length; - if (tempMini != null) - directoryEntry.Size += tempMini.Length; + byte[] buf = new byte[4096]; + long toRead = length; + + //Copy old to new chain + while (toRead > cnt) + { + cnt = sv.Read(buf, 0, cnt); + toRead -= cnt; + destSv.Write(buf, 0, cnt); + } + + sv.Read(buf, 0, (int)toRead); + destSv.Write(buf, 0, (int)toRead); + + //Free old chain + FreeChain(oldChain, this.eraseFreeSectors); + + //Set up destination chain + SetMiniSectorChain(destSv.BaseSectorChain); + + //Update dir item + if (destSv.BaseSectorChain.Count > 0) + { + cfItem.DirEntry.StartSetc = destSv.BaseSectorChain[0].Id; + cfItem.DirEntry.Size = length; + } + else + { + cfItem.DirEntry.StartSetc = Sector.ENDOFCHAIN; + cfItem.DirEntry.Size = 0; + } } - else + else if (transitionToNormal) //############## TRANSITION TO NORMAL STREAM { - directoryEntry.StartSetc = Sector.ENDOFCHAIN; - directoryEntry.Size = 0; + // Transition Mini chain -> Normal chain + + if (this.sectorRecycle) + freeList = FindFreeSectors(SectorType.Normal); // Collect available Normal free sectors + + sv = new StreamView(oldChain, oldSectorSize, oldSize, sourceStream); + + List newChain = GetNormalSectorChain(Sector.ENDOFCHAIN); + StreamView destSv = new StreamView(newChain, GetSectorSize(), length, freeList, sourceStream); + + int cnt = 256 < length ? 256 : (int)length; + + byte[] buf = new byte[256]; + long toRead = Math.Min(length, cfItem.Size); + + //Copy old to new chain + while (toRead > cnt) + { + cnt = sv.Read(buf, 0, cnt); + toRead -= cnt; + destSv.Write(buf, 0, cnt); + } + + sv.Read(buf, 0, (int)toRead); + destSv.Write(buf, 0, (int)toRead); + + //Free old mini chain + int oldChainCount = oldChain.Count; + FreeMiniChain(oldChain, this.eraseFreeSectors); + + //Set up normal destination chain + SetNormalSectorChain(destSv.BaseSectorChain); + + //Update dir item + if (destSv.BaseSectorChain.Count > 0) + { + cfItem.DirEntry.StartSetc = destSv.BaseSectorChain[0].Id; + cfItem.DirEntry.Size = length; + } + else + { + cfItem.DirEntry.StartSetc = Sector.ENDOFCHAIN; + cfItem.DirEntry.Size = 0; + } } } - private void SetStreamData(CFItem cfItem, Byte[] buffer) + internal void WriteData(CFItem cfItem, long position, byte[] buffer) { - //CheckFileLength(); - - if (buffer == null) - throw new CFException("Parameter [buffer] cannot be null"); + WriteData(cfItem, buffer, position, 0, buffer.Length); + } - //CheckFileLength(); + internal void WriteData(CFItem cfItem, byte[] buffer, long position, int offset, int count) + { if (buffer == null) - throw new CFException("Parameter [buffer] cannot be null"); + throw new CFInvalidOperation("Parameter [buffer] cannot be null"); + + if (cfItem.DirEntry == null) + throw new CFException("Internal error [cfItem.DirEntry] cannot be null"); - //Quick and dirty :-) if (buffer.Length == 0) return; - IDirectoryEntry directoryEntry = cfItem.DirEntry; + // Get delta size induced by client + long delta = (position + count) - cfItem.Size < 0 ? 0 : (position + count) - cfItem.Size; + long newLength = cfItem.Size + delta; + + SetStreamLength(cfItem, newLength); + // Calculate NEW sectors SIZE SectorType _st = SectorType.Normal; int _sectorSize = GetSectorSize(); - if (buffer.Length < header.MinSizeStandardStream) + if (cfItem.Size < header.MinSizeStandardStream) { _st = SectorType.Mini; _sectorSize = Sector.MINISECTOR_SIZE; } - // Check for transition ministream -> stream: - // Only in this case we need to free old sectors, - // otherwise they will be overwritten. - - if (directoryEntry.StartSetc != Sector.ENDOFCHAIN) - { - if ( - (buffer.Length < header.MinSizeStandardStream && directoryEntry.Size > header.MinSizeStandardStream) - || (buffer.Length > header.MinSizeStandardStream && directoryEntry.Size < header.MinSizeStandardStream) - ) - { + List sectorChain = GetSectorChain(cfItem.DirEntry.StartSetc, _st); + StreamView sv = new StreamView(sectorChain, _sectorSize, newLength, null, sourceStream); - if (directoryEntry.Size < header.MinSizeStandardStream) - { - FreeMiniChain(GetMiniSectorChain(directoryEntry.StartSetc), this.eraseFreeSectors); - } - else - { - FreeChain(GetNormalSectorChain(directoryEntry.StartSetc), this.eraseFreeSectors); - } + sv.Seek(position, SeekOrigin.Begin); + sv.Write(buffer, offset, count); - directoryEntry.Size = 0; - directoryEntry.StartSetc = Sector.ENDOFCHAIN; - } - } + SetSectorChain(sv.BaseSectorChain); + } - List sectorChain - = GetSectorChain(directoryEntry.StartSetc, _st); + internal void WriteData(CFItem cfItem, Byte[] buffer) + { + WriteData(cfItem, 0, buffer); + } - Queue freeList = null; + /// + /// Check file size limit ( 2GB for version 3 ) + /// + private void CheckFileLength() + { + throw new NotImplementedException(); + } - if (this.sectorRecycle) - freeList = FindFreeSectors(_st); // Collect available free sectors - StreamView sv = new StreamView(sectorChain, _sectorSize, buffer.Length, freeList, sourceStream); + internal int ReadData(CFStream cFStream, long position, byte[] buffer, int count) + { + if (count > buffer.Length) + throw new ArgumentException("count parameter exceeds buffer size"); - sv.Write(buffer, 0, buffer.Length); + IDirectoryEntry de = cFStream.DirEntry; - switch (_st) - { - case SectorType.Normal: - SetNormalSectorChain(sv.BaseSectorChain); - break; + count = (int)Math.Min((long)(de.Size - position), (long)count); - case SectorType.Mini: - SetMiniSectorChain(sv.BaseSectorChain); - break; - } + StreamView sView = null; - if (sv.BaseSectorChain.Count > 0) + if (de.Size < header.MinSizeStandardStream) { - directoryEntry.StartSetc = sv.BaseSectorChain[0].Id; - directoryEntry.Size = buffer.Length; + sView + = new StreamView(GetSectorChain(de.StartSetc, SectorType.Mini), Sector.MINISECTOR_SIZE, de.Size, sourceStream); } else { - directoryEntry.StartSetc = Sector.ENDOFCHAIN; - directoryEntry.Size = 0; + + sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Normal), GetSectorSize(), de.Size, sourceStream); } - } - /// - /// Check file size limit ( 2GB for version 3 ) - /// - private void CheckFileLength() - { - throw new NotImplementedException(); - } + sView.Seek(position, SeekOrigin.Begin); + int result = sView.Read(buffer, 0, count); - internal byte[] GetData(CFStream cFStream, long offset, ref int count) + return result; + } + + internal int ReadData(CFStream cFStream, long position, byte[] buffer, int offset, int count) { - byte[] result = null; IDirectoryEntry de = cFStream.DirEntry; count = (int)Math.Min((long)(de.Size - offset), (long)count); @@ -2193,12 +2465,9 @@ internal byte[] GetData(CFStream cFStream, long offset, ref int count) sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Normal), GetSectorSize(), de.Size, sourceStream); } - result = new byte[(int)(count)]; - - - sView.Seek(offset, SeekOrigin.Begin); - sView.Read(result, 0, result.Length); + sView.Seek(position, SeekOrigin.Begin); + int result = sView.Read(buffer, offset, count); return result; } @@ -2496,7 +2765,7 @@ public static void ShrinkCompoundFile(Stream s) if (cf.header.MajorVersion != (ushort)CFSVersion.Ver_3) throw new CFException("Current implementation of free space compression does not support version 4 of Compound File Format"); - using (CompoundFile tempCF = new CompoundFile((CFSVersion)cf.header.MajorVersion, cf.sectorRecycle, cf.eraseFreeSectors)) + using (CompoundFile tempCF = new CompoundFile((CFSVersion)cf.header.MajorVersion, cf.Configuration)) { //Copy Root CLSID tempCF.RootStorage.CLSID = new Guid(cf.RootStorage.CLSID.ToByteArray()); @@ -2571,7 +2840,7 @@ public static void ShrinkCompoundFile(String fileName) /// Current cloned destination storage private static void DoCompression(CFStorage currSrcStorage, CFStorage currDstStorage) { - VisitedEntryAction va = + Action va = delegate(CFItem item) { if (item.IsStream) diff --git a/OLECompoundFileStorage/Directory.cs b/src/Directory.cs similarity index 100% rename from OLECompoundFileStorage/Directory.cs rename to src/Directory.cs diff --git a/OLECompoundFileStorage/DirectoryEntry.cs b/src/DirectoryEntry.cs similarity index 94% rename from OLECompoundFileStorage/DirectoryEntry.cs rename to src/DirectoryEntry.cs index c3738c7c..cf084d7e 100644 --- a/OLECompoundFileStorage/DirectoryEntry.cs +++ b/src/DirectoryEntry.cs @@ -3,7 +3,6 @@ using System.Text; using System.IO; using System.Globalization; -using BinaryTrees; /* The contents of this file are subject to the Mozilla Public License @@ -39,7 +38,7 @@ public enum StgColor : int Black = 1 } - internal class DirectoryEntry : IComparable, IDirectoryEntry + internal class DirectoryEntry : IDirectoryEntry { private int sid = -1; @@ -385,13 +384,13 @@ public void Read(Stream stream) entryName = rw.ReadBytes(64); nameLength = rw.ReadUInt16(); stgType = (StgType)rw.ReadByte(); - rw.ReadByte();//Ignore color, only black tree - //stgColor = (StgColor)br.ReadByte(); + //rw.ReadByte();//Ignore color, only black tree + stgColor = (StgColor)rw.ReadByte(); leftSibling = rw.ReadInt32(); rightSibling = rw.ReadInt32(); child = rw.ReadInt32(); - // Thank you to bugaccount (BugTrack id 3519554) + // Thanks to bugaccount (BugTrack id 3519554) if (stgType == StgType.StgInvalid) { leftSibling = NOSTREAM; diff --git a/OLECompoundFileStorage/Header.cs b/src/Header.cs similarity index 100% rename from OLECompoundFileStorage/Header.cs rename to src/Header.cs diff --git a/OLECompoundFileStorage/IDirectoryEntry.cs b/src/IDirectoryEntry.cs similarity index 95% rename from OLECompoundFileStorage/IDirectoryEntry.cs rename to src/IDirectoryEntry.cs index 8b416eac..58b08642 100644 --- a/OLECompoundFileStorage/IDirectoryEntry.cs +++ b/src/IDirectoryEntry.cs @@ -1,5 +1,5 @@ using System; -using BinaryTrees; + /* The contents of this file are subject to the Mozilla Public License diff --git a/OLECompoundFileStorage/OpenMcdf.csproj b/src/OpenMcdf.csproj similarity index 58% rename from OLECompoundFileStorage/OpenMcdf.csproj rename to src/OpenMcdf.csproj index dd7619d5..982e7c04 100644 --- a/OLECompoundFileStorage/OpenMcdf.csproj +++ b/src/OpenMcdf.csproj @@ -1,5 +1,5 @@  - + Debug AnyCPU @@ -10,8 +10,28 @@ Properties OpenMcdf OpenMcdf - v2.0 + v4.0 512 + + + 3.5 + + http://localhost/OpenMcdf/ + true + Web + true + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + true + false + true + true @@ -23,6 +43,7 @@ 4 bin\Debug\OpenMcdf.xml 1591,1592,1573,1571,1570,1572 + AllRules.ruleset pdbonly @@ -33,6 +54,7 @@ 4 bin\Release\OpenMcdf.xml 1591,1592,1573,1571,1570,1572 + AllRules.ruleset @@ -40,12 +62,6 @@ - - - - - - @@ -53,14 +69,11 @@ + - - - - @@ -68,6 +81,24 @@ + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + *ZK6W`8P@&&OQ;;g$9EV~ao&v-lR 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�Qz{Xd<7vbT?#O_&vns^Rr+p}c*piB}K9bTl5 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 public class CFStorage : CFItem { - private RBTree children; + private RBTree children; - internal RBTree Children + internal RBTree Children { get { @@ -82,13 +82,13 @@ internal RBTree Children /// Create a new CFStorage /// /// The Storage Owner - CompoundFile - internal CFStorage(CompoundFile compFile) - : base(compFile) - { - this.DirEntry = new DirectoryEntry(StgType.StgStorage); - this.DirEntry.StgColor = StgColor.Black; - compFile.InsertNewDirectoryEntry(this.DirEntry); - } + //internal CFStorage(CompoundFile compFile, String name) + // : base(compFile) + //{ + // this.DirEntry = new DirectoryEntry(name, StgType.StgStorage, compFile.GetDirectories()); + // this.DirEntry.StgColor = StgColor.Black; + // compFile.InsertNewDirectoryEntry(this.DirEntry); + //} /// /// Create a CFStorage using an existing directory (previously loaded). @@ -104,12 +104,12 @@ internal CFStorage(CompoundFile compFile, IDirectoryEntry dirEntry) this.DirEntry = dirEntry; } - private RBTree LoadChildren(int SID) + private RBTree LoadChildren(int SID) { - RBTree childrenTree = this.CompoundFile.GetChildrenTree(SID); + RBTree childrenTree = this.CompoundFile.GetChildrenTree(SID); if (childrenTree.Root != null) - this.DirEntry.Child = childrenTree.Root.Value.DirEntry.SID; + this.DirEntry.Child = (childrenTree.Root as IDirectoryEntry).SID; else this.DirEntry.Child = DirectoryEntry.NOSTREAM; @@ -149,23 +149,22 @@ public CFStream AddStream(String streamName) CFStream cfo = null; + DirectoryEntry dirEntry = new DirectoryEntry(streamName, StgType.StgStream, this.CompoundFile.GetDirectories()); // Add new Stream directory entry - cfo = new CFStream(this.CompoundFile); - cfo.DirEntry.SetEntryName(streamName); - + //cfo = new CFStream(this.CompoundFile, streamName); try { // Add object to Siblings tree - this.Children.Insert(cfo); + this.Children.Insert(dirEntry); //Trace.WriteLine("**** INSERT STREAM " + cfo.Name + "******"); //this.Children.Print(); //Rethread children tree... // CompoundFile.RefreshIterative(Children.Root); //... and set the root of the tree as new child of the current item directory entry - this.DirEntry.Child = Children.Root.Value.DirEntry.SID; + this.DirEntry.Child = (Children.Root as IDirectoryEntry).SID; } catch (RBTreeException) { @@ -174,7 +173,7 @@ public CFStream AddStream(String streamName) throw new CFDuplicatedItemException("An entry with name '" + streamName + "' is already present in storage '" + this.Name + "' "); } - return cfo as CFStream; + return new CFStream(this.CompoundFile, dirEntry); } @@ -203,18 +202,18 @@ public CFStream GetStream(String streamName) { CheckDisposed(); - CFMock tmp = new CFMock(streamName, StgType.StgStream); + DirectoryEntry tmp = new DirectoryEntry(streamName, StgType.StgStream, null); //if (children == null) //{ // children = compoundFile.GetChildrenTree(SID); //} - CFItem outDe = null; + IRBNode outDe = null; - if (Children.TryLookup(tmp, out outDe) && outDe.DirEntry.StgType == StgType.StgStream) + if (Children.TryLookup(tmp, out outDe) && (((IDirectoryEntry)outDe).StgType == StgType.StgStream)) { - return outDe as CFStream; + return new CFStream(this.CompoundFile, (IDirectoryEntry)outDe); } else { @@ -245,10 +244,10 @@ public CFStorage GetStorage(String storageName) { CheckDisposed(); - CFMock tmp = new CFMock(storageName, StgType.StgStorage); + IDirectoryEntry template = new DirectoryEntry(storageName, StgType.StgInvalid, null); + IRBNode outDe = null; - CFItem outDe = null; - if (Children.TryLookup(tmp, out outDe) && outDe.DirEntry.StgType == StgType.StgStorage) + if (Children.TryLookup(template, out outDe) && ((IDirectoryEntry)outDe).StgType == StgType.StgStorage) { return outDe as CFStorage; } @@ -291,10 +290,10 @@ public CFStorage AddStorage(String storageName) throw new CFException("Stream name cannot be null or empty"); // Add new Storage directory entry - CFStorage cfo = null; + IDirectoryEntry cfo + = new DirectoryEntry(storageName, StgType.StgStorage, this.CompoundFile.GetDirectories()); - cfo = new CFStorage(this.CompoundFile); - cfo.DirEntry.SetEntryName(storageName); + //this.CompoundFile.InsertNewDirectoryEntry(cfo); try { @@ -305,31 +304,17 @@ public CFStorage AddStorage(String storageName) } catch (RBTreeDuplicatedItemException) { - - CompoundFile.ResetDirectoryEntry(cfo.DirEntry.SID); + CompoundFile.ResetDirectoryEntry(cfo.SID); cfo = null; throw new CFDuplicatedItemException("An entry with name '" + storageName + "' is already present in storage '" + this.Name + "' "); } + IDirectoryEntry childrenRoot = Children.Root as IDirectoryEntry; + this.DirEntry.Child = childrenRoot.SID; - //CompoundFile.RefreshIterative(Children.Root); - this.DirEntry.Child = Children.Root.Value.DirEntry.SID; - return cfo; + return new CFStorage(this.CompoundFile, cfo); } - //public List GetSubTreeObjects() - //{ - // List result = new List(); - - // children.VisitTree(TraversalMethod.Inorder, - // delegate(BinaryTreeNode node) - // { - // result.Add(node.Value); - // }); - - // return result; - //} - /// /// Visit all entities contained in the storage applying a user provided action /// @@ -360,15 +345,19 @@ public void VisitEntries(Action action, bool recursive) if (action != null) { - List> subStorages - = new List>(); + List subStorages + = new List(); - Action> internalAction = - delegate(RBNode targetNode) + Action internalAction = + delegate(IRBNode targetNode) { - action(targetNode.Value); + IDirectoryEntry d = targetNode as IDirectoryEntry; + if (d.StgType == StgType.StgStream) + action(new CFStream(this.CompoundFile, d)); + else + action(new CFStorage(this.CompoundFile, d)); - if (targetNode.Value.DirEntry.Child != DirectoryEntry.NOSTREAM) + if (d.Child != DirectoryEntry.NOSTREAM) subStorages.Add(targetNode); return; @@ -377,26 +366,14 @@ List> subStorages this.Children.VisitTreeNodes(internalAction); if (recursive && subStorages.Count > 0) - foreach (RBNode n in subStorages) + foreach (IRBNode n in subStorages) { - ((CFStorage)n.Value).VisitEntries(action, recursive); + IDirectoryEntry d = n as IDirectoryEntry; + (new CFStorage(this.CompoundFile, d)).VisitEntries(action, recursive); } } } - - //public void DeleteStream(String name) - //{ - // Delete(name, typeof(CFStream)); - //} - - //public void DeleteStorage(String name) - //{ - // Delete(name, typeof(CFStorage)); - //} - - - /// /// Remove an entry from the current storage and compound file. /// @@ -417,11 +394,11 @@ public void Delete(String entryName) CheckDisposed(); // Find entry to delete - CFMock tmp = new CFMock(entryName, StgType.StgInvalid); + IDirectoryEntry tmp = new DirectoryEntry(entryName,StgType.StgInvalid, null); - CFItem foundObj = null; + IRBNode foundObj = null; - this.Children.TryLookup(tmp, out foundObj); + this.Children.TryLookup(tmp, out foundObj ); if (foundObj == null) throw new CFItemNotFound("Entry named [" + entryName + "] was not found"); @@ -429,24 +406,25 @@ public void Delete(String entryName) //if (foundObj.GetType() != typeCheck) // throw new CFException("Entry named [" + entryName + "] has not the correct type"); - if (foundObj.DirEntry.StgType == StgType.StgRoot) + if (((IDirectoryEntry)foundObj).StgType == StgType.StgRoot) throw new CFException("Root storage cannot be removed"); - switch (foundObj.DirEntry.StgType) + switch (((IDirectoryEntry)foundObj).StgType) { case StgType.StgStorage: - CFStorage temp = (CFStorage)foundObj; + CFStorage temp = new CFStorage(this.CompoundFile, ((IDirectoryEntry)foundObj)); // This is a storage. we have to remove children items first - foreach (RBNode de in temp.Children) + foreach (IRBNode de in temp.Children) { - temp.Delete(de.Value.Name); + IDirectoryEntry ded = de as IDirectoryEntry; + temp.Delete(ded.Name); } // ...then we need to rethread the root of siblings tree... if (this.Children.Root != null) - this.DirEntry.Child = this.Children.Root.Value.DirEntry.SID; + this.DirEntry.Child = (this.Children.Root as IDirectoryEntry).SID; else this.DirEntry.Child = DirectoryEntry.NOSTREAM; @@ -454,7 +432,7 @@ public void Delete(String entryName) this.Children.Delete(foundObj); // ...and remove directory (storage) entry - this.CompoundFile.RemoveDirectoryEntry(foundObj.DirEntry.SID); + this.CompoundFile.RemoveDirectoryEntry(((IDirectoryEntry)foundObj).SID); //Trace.WriteLine("**** DELETED STORAGE " + entryName + "******"); @@ -468,18 +446,20 @@ public void Delete(String entryName) // Remove item from children tree this.Children.Delete(foundObj); //Trace.WriteLine("**** DELETED STREAM " + entryName + "******"); - - // Synchronize tree with directory entries + + // Synchronize tree with directory entries //this.CompoundFile.RefreshIterative(this.Children.Root); // Rethread the root of siblings tree... if (this.Children.Root != null) - this.DirEntry.Child = this.Children.Root.Value.DirEntry.SID; + this.DirEntry.Child = (this.Children.Root as IDirectoryEntry).SID; else this.DirEntry.Child = DirectoryEntry.NOSTREAM; + // Remove directory entry - this.CompoundFile.RemoveDirectoryEntry(foundObj.DirEntry.SID); + this.CompoundFile.RemoveDirectoryEntry(((IDirectoryEntry)foundObj).SID); + break; } diff --git a/src/CFStream.cs b/src/CFStream.cs index d5abcb01..ff875b3a 100644 --- a/src/CFStream.cs +++ b/src/CFStream.cs @@ -29,19 +29,8 @@ namespace OpenMcdf /// public class CFStream : CFItem { - private long position = 0; - - internal CFStream(CompoundFile sectorManager) - : base(sectorManager) - { - this.DirEntry = new DirectoryEntry(StgType.StgStream); - this.DirEntry.StgColor = StgColor.Black; - - sectorManager.InsertNewDirectoryEntry(this.DirEntry); - } - - internal CFStream(CompoundFile sectorManager, IDirectoryEntry dirEntry) - : base(sectorManager) + internal CFStream(CompoundFile compoundFile, IDirectoryEntry dirEntry) + : base(compoundFile) { if (dirEntry == null || dirEntry.SID < 0) throw new CFException("Attempting to add a CFStream using an unitialized directory"); diff --git a/src/CompoundFile.cs b/src/CompoundFile.cs index 480e0712..17253dac 100644 --- a/src/CompoundFile.cs +++ b/src/CompoundFile.cs @@ -240,9 +240,8 @@ public CompoundFile() FAT_SECTOR_ENTRIES_COUNT = (GetSectorSize() / 4); //Root -- - rootStorage = new CFStorage(this); - - rootStorage.DirEntry.SetEntryName("Root Entry"); + DirectoryEntry de = new DirectoryEntry("Root Entry", StgType.StgRoot, directoryEntries); + rootStorage = new CFStorage(this, de); rootStorage.DirEntry.StgType = StgType.StgRoot; rootStorage.DirEntry.StgColor = StgColor.Black; @@ -301,13 +300,14 @@ public CompoundFile(CFSVersion cfsVersion, CFSConfiguration configFlags) FAT_SECTOR_ENTRIES_COUNT = (GetSectorSize() / 4); //Root -- - rootStorage = new CFStorage(this); + IDirectoryEntry rootDir = new DirectoryEntry("Root Entry", StgType.StgRoot, directoryEntries); + rootDir.StgColor = StgColor.Black; + //this.InsertNewDirectoryEntry(rootDir); - rootStorage.DirEntry.SetEntryName("Root Entry"); - rootStorage.DirEntry.StgType = StgType.StgRoot; - rootStorage.DirEntry.StgColor = StgColor.Black; + rootStorage = new CFStorage(this, rootDir); - //this.InsertNewDirectoryEntry(rootStorage.DirEntry); + + // } @@ -782,7 +782,7 @@ StreamView miniStreamView if (s.Id == -1) throw new CFException("Invalid minisector index"); - // Overwrite + // Ministream sectors already allocated miniStreamView.Seek(Sector.MINISECTOR_SIZE * s.Id, SeekOrigin.Begin); miniStreamView.Write(s.GetData(), 0, Sector.MINISECTOR_SIZE); } @@ -823,14 +823,7 @@ StreamView miniStreamView { Sector s = sectorChain[i]; - if (s.Id != -1) - { - // Overwrite - //miniStreamView.Seek(Sector.MINISECTOR_SIZE * s.Id, SeekOrigin.Begin); - //miniStreamView.Write(s.GetData(), 0, Sector.MINISECTOR_SIZE); - - } - else + if(s.Id == -1) { // Allocate, position ministream at the end of already allocated // ministream's sectors @@ -858,8 +851,8 @@ StreamView miniStreamView miniFATView.Write(BitConverter.GetBytes(Sector.ENDOFCHAIN), 0, 4); // Update sector chains - SetNormalSectorChain(miniStreamView.BaseSectorChain); - SetNormalSectorChain(miniFATView.BaseSectorChain); + AllocateSectorChain(miniStreamView.BaseSectorChain); + AllocateSectorChain(miniFATView.BaseSectorChain); //Update HEADER and root storage when ministream changes if (miniFAT.Count > 0) @@ -985,9 +978,10 @@ StreamView miniStreamView miniFATView.Seek(sectorChain[(sectorChain.Count - 1) - nth_sector_to_remove].Id * SIZE_OF_SID, SeekOrigin.Begin); miniFATView.Write(BitConverter.GetBytes(Sector.ENDOFCHAIN), 0, 4); + // Update sector chains --------------------------------------- - SetNormalSectorChain(miniStreamView.BaseSectorChain); - SetNormalSectorChain(miniFATView.BaseSectorChain); + AllocateSectorChain(miniStreamView.BaseSectorChain); + AllocateSectorChain(miniFATView.BaseSectorChain); //Update HEADER and root storage when ministream changes if (miniFAT.Count > 0) @@ -1012,7 +1006,7 @@ private void SetSectorChain(List sectorChain) if (_st == SectorType.Normal) { - SetNormalSectorChain(sectorChain); + AllocateSectorChain(sectorChain); } else if (_st == SectorType.Mini) { @@ -1025,7 +1019,7 @@ private void SetSectorChain(List sectorChain) /// for the new or updated sector chain. /// /// The new or updated generic sector chain - private void SetNormalSectorChain(List sectorChain) + private void AllocateSectorChain(List sectorChain) { foreach (Sector s in sectorChain) { @@ -1037,7 +1031,7 @@ private void SetNormalSectorChain(List sectorChain) } } - SetFATSectorChain(sectorChain); + AllocateFATSectorChain(sectorChain); } internal bool _transactionLockAdded = false; @@ -1066,7 +1060,7 @@ private void CheckForLockSector() /// for the new or updated FAT sector chain. /// /// The new or updated generic sector chain - private void SetFATSectorChain(List sectorChain) + private void AllocateFATSectorChain(List sectorChain) { List fatSectors = GetSectorChain(-1, SectorType.FAT); @@ -1093,14 +1087,14 @@ private void SetFATSectorChain(List sectorChain) fatStream.Write(BitConverter.GetBytes(Sector.ENDOFCHAIN), 0, 4); // Merge chain to CFS - SetDIFATSectorChain(fatStream.BaseSectorChain); + AllocateDIFATSectorChain(fatStream.BaseSectorChain); } /// /// Setup the DIFAT sector chain /// /// A FAT sector chain - private void SetDIFATSectorChain(List FATsectorChain) + private void AllocateDIFATSectorChain(List FATsectorChain) { // Get initial sector's count header.FATSectorsNumber = FATsectorChain.Count; @@ -1607,109 +1601,10 @@ internal void InsertNewDirectoryEntry(IDirectoryEntry de) /// Sid of the directory to invalidate internal void ResetDirectoryEntry(int sid) { - directoryEntries[sid] = new DirectoryEntry(StgType.StgInvalid); - } - - - internal void OnNodeInsert(RBNode node) - { - - } - - internal void OnNodeDeleted(RBNode obj) - { - - } - - private bool _deserializing; - private bool Deserializing - { - get { return _deserializing; } - set - { - _deserializing = value; - - if (value) - { - _deserializing = value; - Trace.WriteLine("Deserializing..."); - Trace.Indent(); - } - else - { - Trace.WriteLine("Deserializing DONE"); - Trace.Unindent(); - } - } + directoryEntries[sid] = new DirectoryEntry(String.Empty, StgType.StgInvalid, directoryEntries.AsReadOnly()); } - void OnNodeOperation(RBNode node, NodeOperation operation) - { - if (!Deserializing) - { - switch (operation) - { - case NodeOperation.LeftAssigned: - if (node.Left != null && (node.Left.Value.DirEntry.StgType != StgType.StgInvalid)) - { - node.Value.DirEntry.LeftSibling = node.Left.Value.DirEntry.SID; - } - else - { - node.Value.DirEntry.LeftSibling = DirectoryEntry.NOSTREAM; - } - break; - - case NodeOperation.RightAssigned: - - if (node.Right != null && (node.Right.Value.DirEntry.StgType != StgType.StgInvalid)) - { - node.Value.DirEntry.RightSibling = node.Right.Value.DirEntry.SID; - } - else - { - node.Value.DirEntry.RightSibling = DirectoryEntry.NOSTREAM; - } - break; - - case NodeOperation.ColorAssigned: - node.Value.DirEntry.StgColor = (StgColor)node.Color; - break; - - case NodeOperation.ValueAssigned: - - if (node.Value != null) - { - if (node.Left != null) - node.Value.DirEntry.LeftSibling = node.Left.Value.DirEntry.SID; - else - node.Value.DirEntry.LeftSibling = DirectoryEntry.NOSTREAM; - - if (node.Right != null) - node.Value.DirEntry.RightSibling = node.Right.Value.DirEntry.SID; - else - node.Value.DirEntry.RightSibling = DirectoryEntry.NOSTREAM; - - node.Value.DirEntry.StgColor = (StgColor)node.Color; - - //Rethread parent - if (node.Parent != null) - { - if (node.Parent.Left == node) - node.Parent.Value.DirEntry.LeftSibling = node.Value.DirEntry.SID; - else - node.Parent.Value.DirEntry.RightSibling = node.Value.DirEntry.SID; - } - - } - - break; - default: - throw new CFException("Unsupported Red Black Node operation"); - } - } - } //internal class NodeFactory : IRBTreeDeserializer //{ @@ -1720,11 +1615,11 @@ void OnNodeOperation(RBNode node, NodeOperation operation) // } //} - internal RBTree CreateNewTree() + internal RBTree CreateNewTree() { - RBTree bst = new RBTree(); - bst.NodeInserted += OnNodeInsert; - bst.NodeOperation += OnNodeOperation; + RBTree bst = new RBTree(); + //bst.NodeInserted += OnNodeInsert; + //bst.NodeOperation += OnNodeOperation; //bst.NodeDeleted += new Action>(OnNodeDeleted); // bst.ValueAssignedAction += new Action, CFItem>(OnValueAssigned); return bst; @@ -1742,18 +1637,13 @@ internal RBTree CreateNewTree() //} - internal RBTree GetChildrenTree(int sid) + internal RBTree GetChildrenTree(int sid) { - RBTree bst = new RBTree(); - bst.NodeInserted += OnNodeInsert; - bst.NodeOperation += OnNodeOperation; - //bst.NodeDeleted += OnNodeDeleted; + RBTree bst = new RBTree(); // Load children from their original tree. - DoLoadChildren(bst, directoryEntries[sid]); - - // Rethreading of Red-Black tree of entry children after first loading - bst.VisitTreeNodes(RefreshSIDs); + //DoLoadChildren(bst, directoryEntries[sid]); + bst = DoLoadChildrenTrusted(directoryEntries[sid]); //bst.Print(); //Trace.WriteLine("#### After rethreading"); @@ -1761,29 +1651,38 @@ internal RBTree GetChildrenTree(int sid) return bst; } + private RBTree DoLoadChildrenTrusted(IDirectoryEntry de) + { + RBTree bst = null; + + if (de.Child != DirectoryEntry.NOSTREAM) + { + bst = new RBTree(directoryEntries[de.SID]); + } + + return bst; + } + - private void DoLoadChildren(RBTree bst, IDirectoryEntry de) + private void DoLoadChildren(RBTree bst, IDirectoryEntry de) { - Deserializing = true; //Loading existing entries, not just-in-time rethreading if (de.Child != DirectoryEntry.NOSTREAM) { if (directoryEntries[de.Child].StgType == StgType.StgInvalid) return; if (directoryEntries[de.Child].StgType == StgType.StgStream) - bst.Insert(new CFStream(this, directoryEntries[de.Child])); + bst.Insert(directoryEntries[de.Child]); else - bst.Insert(new CFStorage(this, directoryEntries[de.Child])); + bst.Insert(directoryEntries[de.Child]); LoadSiblings(bst, directoryEntries[de.Child]); } - - Deserializing = false; } // Doubling methods allows iterative behavior while avoiding // to insert duplicate items - private void LoadSiblings(RBTree bst, IDirectoryEntry de) + private void LoadSiblings(RBTree bst, IDirectoryEntry de) { if (de.LeftSibling != DirectoryEntry.NOSTREAM) { @@ -1798,7 +1697,7 @@ private void LoadSiblings(RBTree bst, IDirectoryEntry de) } } - private void DoLoadSiblings(RBTree bst, IDirectoryEntry de) + private void DoLoadSiblings(RBTree bst, IDirectoryEntry de) { if (ValidateSibling(de.LeftSibling)) { @@ -1807,9 +1706,9 @@ private void DoLoadSiblings(RBTree bst, IDirectoryEntry de) } if (directoryEntries[de.SID].StgType == StgType.StgStream) - bst.Insert(new CFStream(this, directoryEntries[de.SID])); + bst.Insert(directoryEntries[de.SID]); else if (directoryEntries[de.SID].StgType == StgType.StgStorage) - bst.Insert(new CFStorage(this, directoryEntries[de.SID])); + bst.Insert(directoryEntries[de.SID]); if (ValidateSibling(de.RightSibling)) @@ -1884,52 +1783,15 @@ StreamView dirReader while (dirReader.Position < directoryChain.Count * GetSectorSize()) { DirectoryEntry de - = new DirectoryEntry(StgType.StgInvalid); + = new DirectoryEntry(String.Empty, StgType.StgInvalid, directoryEntries); //We are not inserting dirs. Do not use 'InsertNewDirectoryEntry' de.Read(dirReader); - directoryEntries.Add(de); - de.SID = directoryEntries.Count - 1; + } } - internal void RefreshSIDs(RedBlackTree.RBNode Node) - { - if (Node.Value != null) - { - //Set directory color from the node color - Node.Value.DirEntry.StgColor = (StgColor)Node.Color; - - //Synchronize relations with SIDs of directory items - if (Node.Left != null && (Node.Left.Value.DirEntry.StgType != StgType.StgInvalid)) - { - Node.Value.DirEntry.LeftSibling = Node.Left.Value.DirEntry.SID; - } - else - { - Node.Value.DirEntry.LeftSibling = DirectoryEntry.NOSTREAM; - } - - if (Node.Right != null && (Node.Right.Value.DirEntry.StgType != StgType.StgInvalid)) - { - Node.Value.DirEntry.RightSibling = Node.Right.Value.DirEntry.SID; - } - else - { - Node.Value.DirEntry.RightSibling = DirectoryEntry.NOSTREAM; - } - } - else - throw new CFException("Internal error: null data node"); - } - //internal void RefreshIterative(RedBlackTree.RBNode node) - //{ - // //if (node == null) return; - // //RefreshSIDs(node); - // //RefreshIterative(node.Left); - // //RefreshIterative(node.Right); - //} /// /// Commit directory entries change on the Current Source stream @@ -1952,7 +1814,7 @@ List directorySectors while (delta % (GetSectorSize() / DIRECTORY_SIZE) != 0) { - DirectoryEntry dummy = new DirectoryEntry(StgType.StgInvalid); + DirectoryEntry dummy = new DirectoryEntry(String.Empty, StgType.StgInvalid, directoryEntries.AsReadOnly()); dummy.Write(sv); delta++; } @@ -1962,7 +1824,7 @@ List directorySectors s.Type = SectorType.Directory; } - SetNormalSectorChain(directorySectors); + AllocateSectorChain(directorySectors); header.FirstDirectorySectorID = directorySectors[0].Id; @@ -2371,7 +2233,7 @@ internal void SetStreamLength(CFItem cfItem, long length) FreeMiniChain(oldChain, this.eraseFreeSectors); //Set up normal destination chain - SetNormalSectorChain(destSv.BaseSectorChain); + AllocateSectorChain(destSv.BaseSectorChain); //Update dir item if (destSv.BaseSectorChain.Count > 0) @@ -2698,6 +2560,11 @@ internal bool IsClosed private List directoryEntries = new List(); + internal IList GetDirectories() + { + return directoryEntries; + } + //internal List DirectoryEntries //{ // get { return directoryEntries; } diff --git a/src/DirectoryEntry.cs b/src/DirectoryEntry.cs index cf084d7e..04badd6b 100644 --- a/src/DirectoryEntry.cs +++ b/src/DirectoryEntry.cs @@ -38,8 +38,9 @@ public enum StgColor : int Black = 1 } - internal class DirectoryEntry : IDirectoryEntry + internal class DirectoryEntry : IDirectoryEntry { + private IList dirRepository; private int sid = -1; public int SID @@ -51,8 +52,12 @@ public int SID internal static Int32 NOSTREAM = unchecked((int)0xFFFFFFFF); - public DirectoryEntry(StgType stgType) + public DirectoryEntry(String name, StgType stgType, IList dirRepository) { + this.dirRepository = dirRepository; + this.dirRepository.Add(this); + this.sid = this.dirRepository.Count - 1; + this.stgType = stgType; switch (stgType) @@ -74,6 +79,8 @@ public DirectoryEntry(StgType stgType) break; } + this.SetEntryName(name); + } private byte[] entryName = new byte[64]; @@ -154,6 +161,7 @@ public StgType StgType } } private StgColor stgColor = StgColor.Black; + public StgColor StgColor { get @@ -411,5 +419,115 @@ public string Name get { return GetEntryName(); } } + + public RedBlackTree.IRBNode Left + { + get + { + if (leftSibling == DirectoryEntry.NOSTREAM) + return null; + + return dirRepository[leftSibling]; + } + set + { + leftSibling = value != null ? ((IDirectoryEntry)value).SID : DirectoryEntry.NOSTREAM; + + if (leftSibling != DirectoryEntry.NOSTREAM) + dirRepository[leftSibling].Parent = this; + } + } + + public RedBlackTree.IRBNode Right + { + get + { + if (rightSibling == DirectoryEntry.NOSTREAM) + return null; + + return dirRepository[rightSibling]; + } + set + { + + rightSibling = value != null ? ((IDirectoryEntry)value).SID : DirectoryEntry.NOSTREAM; + + if (rightSibling != DirectoryEntry.NOSTREAM) + dirRepository[rightSibling].Parent = this; + + } + } + + public RedBlackTree.Color Color + { + get + { + return (RedBlackTree.Color)StgColor; + } + set + { + StgColor = (StgColor)value; + } + } + + private IDirectoryEntry parent = null; + + public RedBlackTree.IRBNode Parent + { + get + { + return parent; + } + set + { + parent = value as IDirectoryEntry; + } + } + + public RedBlackTree.IRBNode Grandparent() + { + return parent != null ? parent.Parent : null; + } + + public RedBlackTree.IRBNode Sibling() + { + if (this == Parent.Left) + return Parent.Right; + else + return Parent.Left; + } + + public RedBlackTree.IRBNode Uncle() + { + return parent != null ? Parent.Sibling() : null; + } + + public object Clone() + { + DirectoryEntry d = new DirectoryEntry(this.Name, this.stgType, this.dirRepository); + d.child = this.child; + d.Color = this.Color; + + d.creationDate = new byte[this.creationDate.Length]; + this.creationDate.CopyTo(d.creationDate, 0); + + d.leftSibling = this.leftSibling; + + d.modifyDate = new byte[this.modifyDate.Length]; + this.modifyDate.CopyTo(d.modifyDate, 0); + + d.nameLength = this.nameLength; + d.parent = this.parent; + d.rightSibling = this.rightSibling; + + d.size = this.size; + d.startSetc = this.startSetc; + d.stateBits = this.stateBits; + d.stgColor = this.stgColor; + d.stgType = this.stgType; + d.storageCLSID = new Guid(this.storageCLSID.ToByteArray()); + + return d; + } } } diff --git a/src/DirectoryFactory.cs b/src/DirectoryFactory.cs new file mode 100644 index 00000000..ccd2bc85 --- /dev/null +++ b/src/DirectoryFactory.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenMcdf +{ + internal class DirectoryCollection + { + public void Add(IDirectoryEntry d) + { + + } + } +} diff --git a/src/IDirectoryEntry.cs b/src/IDirectoryEntry.cs index 58b08642..be5a624e 100644 --- a/src/IDirectoryEntry.cs +++ b/src/IDirectoryEntry.cs @@ -1,4 +1,5 @@ -using System; +using RedBlackTree; +using System; /* @@ -19,7 +20,7 @@ The Initial Developer of the Original Code is Federico Blaseotto. namespace OpenMcdf { - internal interface IDirectoryEntry : IComparable + internal interface IDirectoryEntry : IComparable, IRBNode { int Child { get; set; } byte[] CreationDate { get; set; } diff --git a/src/OpenMcdf.csproj b/src/OpenMcdf.csproj index 982e7c04..5038b706 100644 --- a/src/OpenMcdf.csproj +++ b/src/OpenMcdf.csproj @@ -67,6 +67,7 @@ + diff --git a/src/Properties/AssemblyInfo.cs b/src/Properties/AssemblyInfo.cs index a16e3c41..06d3266e 100644 --- a/src/Properties/AssemblyInfo.cs +++ b/src/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ [assembly: AssemblyDescription("MS Compound File Storage .NET Implementation")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Federico Blaseotto")] -[assembly: AssemblyProduct("OpenMcdf")] +[assembly: AssemblyProduct("OpenMcdf 2.0 (prerelease)")] [assembly: AssemblyCopyright("Copyright © 2010-2014, Federico Blaseotto")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/src/RBTree/RBTree.cs b/src/RBTree/RBTree.cs index 07f2c153..6a2cca24 100644 --- a/src/RBTree/RBTree.cs +++ b/src/RBTree/RBTree.cs @@ -33,144 +33,67 @@ public RBTreeDuplicatedItemException(String msg) } } - - public interface IRBTreeDeserializer where V : IComparable - { - RBNode Deseriazlize(); - } - public enum Color { RED = 0, BLACK = 1 } /// /// Red Black Node class /// /// - public class RBNode - where V : IComparable + public interface IRBNode : IComparable, ICloneable { - private RBTree owner; - public RBTree Owner - { - get { return owner; } - set { owner = value; } - } - - private V value; - public V Value - { - get - { - return value; - } - set - { - this.value = value; - owner.FireNodeOperation(this, NodeOperation.ValueAssigned); - } - } - - private RBNode left; - public RBNode Left + IRBNode Left { - get { return left; } - set - { - left = value; - - owner.FireNodeOperation(this, NodeOperation.LeftAssigned); - } + get; + set; } - private RBNode right; - public RBNode Right + IRBNode Right { - get { return right; } - set - { - right = value; - owner.FireNodeOperation(this, NodeOperation.RightAssigned); - } + get; + set; } - private Color color; - public Color Color - { - get - { - return color; - } - set - { - color = value; - owner.FireNodeOperation(this, NodeOperation.ColorAssigned); - - } - } + Color Color - public RBNode Parent { get; set; } - - public override string ToString() - { - if (value != null) - return value.ToString(); - else - return String.Empty; + { get; set; } - } - public RBNode(V value, Color nodeColor, RBNode left, RBNode right, RBTree owner) - { - this.owner = owner; - this.Value = value; - this.Left = left; - this.Right = right; - this.Color = nodeColor; - if (left != null) left.Parent = this; - if (right != null) right.Parent = this; - this.Parent = null; + IRBNode Parent { get; set; } - } - public RBNode Grandparent() - { + IRBNode Grandparent(); -#if ASSERT - Debug.Assert(Parent != null); // Not the root node - Debug.Assert(Parent.Parent != null); // Not child of root -#endif - return Parent.Parent; - } - public RBNode Sibling() - { -#if ASSERT - Debug.Assert(Parent != null); // Root node has no sibling -#endif - if (this == Parent.Left) - return Parent.Right; - else - return Parent.Left; - } + IRBNode Sibling(); + // { + //#if ASSERT + // Debug.Assert(Parent != null); // Root node has no sibling + //#endif + // if (this == Parent.Left) + // return Parent.Right; + // else + // return Parent.Left; + // } - public RBNode Uncle() - { -#if ASSERT - Debug.Assert(Parent != null); // Root node has no uncle - Debug.Assert(Parent.Parent != null); // Children of root have no uncle -#endif - return Parent.Sibling(); - } + IRBNode Uncle(); + // { + //#if ASSERT + // Debug.Assert(Parent != null); // Root node has no uncle + // Debug.Assert(Parent.Parent != null); // Children of root have no uncle + //#endif + // return Parent.Sibling(); + // } + // } } - public class RBTree - where V : IComparable + public class RBTree { - public RBNode Root { get; set; } + public IRBNode Root { get; set; } - private static Color NodeColor(RBNode n) + private static Color NodeColor(IRBNode n) { return n == null ? Color.BLACK : n.Color; } @@ -180,18 +103,20 @@ public RBTree() } - public RBTree(IRBTreeDeserializer deserializer) + public RBTree(IRBNode root) { - Root = deserializer.Deseriazlize(); + this.Root = root; } - private RBNode LookupNode(V val) + + private IRBNode LookupNode(IRBNode template) { - RBNode n = Root; + IRBNode n = Root; while (n != null) { - int compResult = val.CompareTo(n.Value); + int compResult = template.CompareTo(n); + if (compResult == 0) { return n; @@ -210,23 +135,23 @@ private RBNode LookupNode(V val) return n; } - public bool TryLookup(V template, out V val) + public bool TryLookup(IRBNode template, out IRBNode val) { - RBNode n = LookupNode(template); + IRBNode n = LookupNode(template); if (n == null) { - val = default(V); + val = null; return false; } else { - val = n.Value; + val = n; return true; } } - private void ReplaceNode(RBNode oldn, RBNode newn) + private void ReplaceNode(IRBNode oldn, IRBNode newn) { if (oldn.Parent == null) { @@ -245,9 +170,9 @@ private void ReplaceNode(RBNode oldn, RBNode newn) } } - private void RotateLeft(RBNode n) + private void RotateLeft(IRBNode n) { - RBNode r = n.Right; + IRBNode r = n.Right; ReplaceNode(n, r); n.Right = r.Left; if (r.Left != null) @@ -258,9 +183,9 @@ private void RotateLeft(RBNode n) n.Parent = r; } - private void RotateRight(RBNode n) + private void RotateRight(IRBNode n) { - RBNode l = n.Left; + IRBNode l = n.Left; ReplaceNode(n, l); n.Left = l.Right; @@ -273,14 +198,12 @@ private void RotateRight(RBNode n) n.Parent = l; } - private void DeserializeFromValues(IList values) - { - - } + - public void Insert(V value) + public void Insert(IRBNode newNode) { - RBNode insertedNode = new RBNode(value, Color.RED, null, null, this); + newNode.Color = Color.RED; + IRBNode insertedNode = newNode; if (Root == null) { @@ -288,10 +211,10 @@ public void Insert(V value) } else { - RBNode n = Root; + IRBNode n = Root; while (true) { - int compResult = value.CompareTo(n.Value); + int compResult = newNode.CompareTo(n); if (compResult == 0) { throw new RBTreeDuplicatedItemException("OhiOhi Duplicated Item"); @@ -339,7 +262,7 @@ public void Insert(V value) } //------------------------------------ - private void InsertCase1(RBNode n) + private void InsertCase1(IRBNode n) { if (n.Parent == null) n.Color = Color.BLACK; @@ -348,7 +271,7 @@ private void InsertCase1(RBNode n) } //----------------------------------- - private void InsertCase2(RBNode n) + private void InsertCase2(IRBNode n) { if (NodeColor(n.Parent) == Color.BLACK) return; // Tree is still valid @@ -357,7 +280,7 @@ private void InsertCase2(RBNode n) } //---------------------------- - private void InsertCase3(RBNode n) + private void InsertCase3(IRBNode n) { if (NodeColor(n.Uncle()) == Color.RED) { @@ -373,7 +296,7 @@ private void InsertCase3(RBNode n) } //---------------------------- - private void InsertCase4(RBNode n) + private void InsertCase4(IRBNode n) { if (n == n.Parent.Right && n.Parent == n.Grandparent().Left) { @@ -390,7 +313,7 @@ private void InsertCase4(RBNode n) } //---------------------------- - private void InsertCase5(RBNode n) + private void InsertCase5(IRBNode n) { n.Parent.Color = Color.BLACK; n.Grandparent().Color = Color.RED; @@ -405,7 +328,7 @@ private void InsertCase5(RBNode n) } } - private static RBNode MaximumNode(RBNode n) + private static IRBNode MaximumNode(IRBNode n) { //assert n != null; while (n.Right != null) @@ -417,21 +340,21 @@ private static RBNode MaximumNode(RBNode n) } - public void Delete(V value) + public void Delete(IRBNode template) { - RBNode n = LookupNode(value); + IRBNode n = LookupNode(template); if (n == null) return; // Key not found, do nothing if (n.Left != null && n.Right != null) { // Copy key/value from predecessor and then delete it instead - RBNode pred = MaximumNode(n.Left); - n.Value = pred.Value; + IRBNode pred = MaximumNode(n.Left); + n = pred.Clone() as IRBNode; n = pred; } //assert n.left == null || n.right == null; - RBNode child = (n.Right == null) ? n.Left : n.Right; + IRBNode child = (n.Right == null) ? n.Left : n.Right; if (NodeColor(n) == Color.BLACK) { n.Color = NodeColor(child); @@ -449,11 +372,9 @@ public void Delete(V value) //Print(); - - } - private void DeleteCase1(RBNode n) + private void DeleteCase1(IRBNode n) { if (n.Parent == null) return; @@ -462,7 +383,7 @@ private void DeleteCase1(RBNode n) } - private void DeleteCase2(RBNode n) + private void DeleteCase2(IRBNode n) { if (NodeColor(n.Sibling()) == Color.RED) { @@ -477,7 +398,7 @@ private void DeleteCase2(RBNode n) DeleteCase3(n); } - private void DeleteCase3(RBNode n) + private void DeleteCase3(IRBNode n) { if (NodeColor(n.Parent) == Color.BLACK && NodeColor(n.Sibling()) == Color.BLACK && @@ -491,7 +412,7 @@ private void DeleteCase3(RBNode n) DeleteCase4(n); } - private void DeleteCase4(RBNode n) + private void DeleteCase4(IRBNode n) { if (NodeColor(n.Parent) == Color.RED && NodeColor(n.Sibling()) == Color.BLACK && @@ -505,7 +426,7 @@ private void DeleteCase4(RBNode n) DeleteCase5(n); } - private void DeleteCase5(RBNode n) + private void DeleteCase5(IRBNode n) { if (n == n.Parent.Left && NodeColor(n.Sibling()) == Color.BLACK && @@ -529,7 +450,7 @@ private void DeleteCase5(RBNode n) DeleteCase6(n); } - private void DeleteCase6(RBNode n) + private void DeleteCase6(IRBNode n) { n.Sibling().Color = NodeColor(n.Parent); n.Parent.Color = Color.BLACK; @@ -547,16 +468,16 @@ private void DeleteCase6(RBNode n) } } - public void VisitTree(Action action) + public void VisitTree(Action action) { //IN Order visit - RBNode walker = Root; + IRBNode walker = Root; if (walker != null) DoVisitTree(action, walker); } - private void DoVisitTree(Action action, RBNode walker) + private void DoVisitTree(Action action, IRBNode walker) { if (walker.Left != null) { @@ -564,7 +485,7 @@ private void DoVisitTree(Action action, RBNode walker) } if (action != null) - action(walker.Value); + action(walker); if (walker.Right != null) { @@ -573,16 +494,16 @@ private void DoVisitTree(Action action, RBNode walker) } - internal void VisitTreeNodes(Action> action) + internal void VisitTreeNodes(Action action) { //IN Order visit - RBNode walker = Root; + IRBNode walker = Root; if (walker != null) DoVisitTreeNodes(action, walker); } - private void DoVisitTreeNodes(Action> action, RBNode walker) + private void DoVisitTreeNodes(Action action, IRBNode walker) { if (walker.Left != null) { @@ -600,17 +521,17 @@ private void DoVisitTreeNodes(Action> action, RBNode walker) } - public class RBTreeEnumerator : IEnumerator> + public class RBTreeEnumerator : IEnumerator { int position = -1; - private Queue> heap = new Queue>(); + private Queue heap = new Queue(); - internal RBTreeEnumerator(RBTree tree) + internal RBTreeEnumerator(RBTree tree) { tree.VisitTreeNodes(item => heap.Enqueue(item)); } - public RBNode Current + public IRBNode Current { get { @@ -654,7 +575,7 @@ public void Print() PrintHelper(Root, 0); } - private static void PrintHelper(RBNode n, int indent) + private static void PrintHelper(IRBNode n, int indent) { if (n == null) { @@ -670,9 +591,9 @@ private static void PrintHelper(RBNode n, int indent) for (int i = 0; i < indent; i++) Trace.Write(" "); if (n.Color == Color.BLACK) - Trace.WriteLine(" " + n.Value + " "); + Trace.WriteLine(" " + n.ToString() + " "); else - Trace.WriteLine("<" + n.Value + ">"); + Trace.WriteLine("<" + n.ToString() + ">"); if (n.Right != null) { @@ -680,7 +601,7 @@ private static void PrintHelper(RBNode n, int indent) } } - internal void FireNodeOperation(RBNode node, NodeOperation operation) + internal void FireNodeOperation(IRBNode node, NodeOperation operation) { if (NodeOperation != null) NodeOperation(node, operation); @@ -692,9 +613,9 @@ internal void FireNodeOperation(RBNode node, NodeOperation operation) // ValueAssignedAction(node, value); //} - internal event Action> NodeInserted; + internal event Action NodeInserted; //internal event Action> NodeDeleted; - internal event Action, NodeOperation> NodeOperation; + internal event Action NodeOperation; } From 390e0a2d253ef4035a82ecaa3890be4088d4748f Mon Sep 17 00:00:00 2001 From: ironfede Date: Sun, 7 Dec 2014 12:14:50 +0000 Subject: [PATCH 06/18] Fixed cloning issue in RBTree item removal: decoupled data release from directory invalidation. --- Unit Test/CFSStreamTest.cs | 4 +- Unit Test/CompoundFileTest.cs | 3 +- Unit Test/RBTreeTest.cs | 23 +++---- src/CFMock.cs | 30 ++++----- src/CFStorage.cs | 46 +++++++------ src/CompoundFile.cs | 123 +++++++++++++++------------------- src/DirectoryEntry.cs | 121 ++++++++++++++++++++++++++++++--- src/RBTree/RBTree.cs | 35 +++++----- src/StreamRW.cs | 6 +- 9 files changed, 248 insertions(+), 143 deletions(-) diff --git a/Unit Test/CFSStreamTest.cs b/Unit Test/CFSStreamTest.cs index edd493f0..0c9f8f8a 100644 --- a/Unit Test/CFSStreamTest.cs +++ b/Unit Test/CFSStreamTest.cs @@ -986,8 +986,10 @@ public void Test_DELETE_STREAM_SECTOR_REUSE() st.Append(Helpers.GetBuffer(1024 * 1024 * 1)); cf.Save("SectorRecycleSmaller.cfs"); cf.Close(); + long larger = (new FileInfo("SectorRecycle.cfs").Length); + long smaller = (new FileInfo("SectorRecycleSmaller.cfs").Length); - Assert.IsTrue((new FileInfo("SectorRecycle.cfs").Length) >= (new FileInfo("SectorRecycleSmaller.cfs").Length)); + Assert.IsTrue(larger >= smaller, "Larger size:" + larger.ToString() + " - Smaller size:" + smaller.ToString()); } diff --git a/Unit Test/CompoundFileTest.cs b/Unit Test/CompoundFileTest.cs index a51b27a6..05ba71fa 100644 --- a/Unit Test/CompoundFileTest.cs +++ b/Unit Test/CompoundFileTest.cs @@ -389,6 +389,7 @@ public void Test_FUNCTIONAL_BEHAVIOUR() //########### + Trace.Listeners.Add(new ConsoleTraceListener()); // Phase 3 cf = new CompoundFile("6_Streams.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle | CFSConfiguration.EraseFreeSectors); cf.RootStorage.Delete("D"); @@ -672,7 +673,7 @@ public void Test_ADD_LARGE_NUMBER_OF_ITEMS() f.Save("$ItemsLargeNumber.cfs"); f.Close(); - + Trace.Listeners.Add(new ConsoleTraceListener()); f = new CompoundFile("$ItemsLargeNumber.cfs"); CFStream cfs = f.RootStorage.GetStream("Stream" + (ITEM_NUMBER / 2).ToString()); diff --git a/Unit Test/RBTreeTest.cs b/Unit Test/RBTreeTest.cs index 4ad3a9df..acc0043c 100644 --- a/Unit Test/RBTreeTest.cs +++ b/Unit Test/RBTreeTest.cs @@ -59,14 +59,12 @@ public TestContext TestContext // #endregion - internal IList GetDirectoryRepository() + internal IList GetDirectoryRepository(int count) { List repo = new List(); - for (int i = 0; i < 25; i++) + for (int i = 0; i < count; i++) { - DirectoryEntry de = new DirectoryEntry(i.ToString(), StgType.StgInvalid, repo.AsReadOnly()); - repo.Add(de); - de.SID = i; + IDirectoryEntry de = DirectoryEntry.New(i.ToString(), StgType.StgInvalid, repo); } return repo; @@ -76,7 +74,7 @@ internal IList GetDirectoryRepository() public void Test_RBTREE_INSERT() { RBTree rbTree = new RBTree(); - System.Collections.Generic.IList repo = GetDirectoryRepository(); + System.Collections.Generic.IList repo = GetDirectoryRepository(25); foreach (var item in repo) { @@ -86,7 +84,7 @@ public void Test_RBTREE_INSERT() for (int i = 0; i < repo.Count; i++) { IRBNode c; - rbTree.TryLookup(new DirectoryEntry(i.ToString(), StgType.StgInvalid,null), out c); + rbTree.TryLookup(DirectoryEntry.Mock(i.ToString(), StgType.StgInvalid), out c); Assert.IsTrue(c is IDirectoryEntry); Assert.IsTrue(((IDirectoryEntry)c).Name == i.ToString()); //Assert.IsTrue(c.IsStream); @@ -98,7 +96,7 @@ public void Test_RBTREE_INSERT() public void Test_RBTREE_DELETE() { RBTree rbTree = new RBTree(); - System.Collections.Generic.IList repo = GetDirectoryRepository(); + System.Collections.Generic.IList repo = GetDirectoryRepository(25); foreach (var item in repo) @@ -108,9 +106,10 @@ public void Test_RBTREE_DELETE() try { - rbTree.Delete(new DirectoryEntry("5", StgType.StgInvalid, repo)); - rbTree.Delete(new DirectoryEntry("24", StgType.StgInvalid, repo)); - rbTree.Delete(new DirectoryEntry("7", StgType.StgInvalid, repo)); + IRBNode n; + rbTree.Delete(DirectoryEntry.Mock("5", StgType.StgInvalid),out n); + rbTree.Delete(DirectoryEntry.Mock("24", StgType.StgInvalid), out n); + rbTree.Delete(DirectoryEntry.Mock("7", StgType.StgInvalid), out n); } catch (Exception ex) { @@ -220,7 +219,7 @@ private static int VerifyProperty5Helper(IRBNode n, int blackCount, int pathBlac public void Test_RBTREE_ENUMERATE() { RBTree rbTree = new RBTree(); - System.Collections.Generic.IList repo = GetDirectoryRepository(); + System.Collections.Generic.IList repo = GetDirectoryRepository(10000); foreach (var item in repo) { diff --git a/src/CFMock.cs b/src/CFMock.cs index e15ca356..7994906a 100644 --- a/src/CFMock.cs +++ b/src/CFMock.cs @@ -21,20 +21,20 @@ The Initial Developer of the Original Code is Federico Blaseotto. namespace OpenMcdf { - /// - /// Used as internal template object for binary tree searches. - /// - internal class CFMock : CFItem - { - internal CFMock(String dirName, StgType dirType, IList dirs) - : base() - { - this.DirEntry = new DirectoryEntry(dirName, dirType, dirs); - } + ///// + ///// Used as internal template object for binary tree searches. + ///// + //internal class CFMock : CFItem + //{ + // internal CFMock(String dirName, StgType dirType, IList dirs) + // : base() + // { + // this.DirEntry = new DirectoryEntry(dirName, dirType, dirs); + // } - public override string ToString() - { - return this.DirEntry.Name; - } - } + // public override string ToString() + // { + // return this.DirEntry.Name; + // } + //} } diff --git a/src/CFStorage.cs b/src/CFStorage.cs index 4348800b..c0290c94 100644 --- a/src/CFStorage.cs +++ b/src/CFStorage.cs @@ -149,7 +149,7 @@ public CFStream AddStream(String streamName) CFStream cfo = null; - DirectoryEntry dirEntry = new DirectoryEntry(streamName, StgType.StgStream, this.CompoundFile.GetDirectories()); + IDirectoryEntry dirEntry = DirectoryEntry.TryNew(streamName, StgType.StgStream, this.CompoundFile.GetDirectories()); // Add new Stream directory entry //cfo = new CFStream(this.CompoundFile, streamName); @@ -202,7 +202,7 @@ public CFStream GetStream(String streamName) { CheckDisposed(); - DirectoryEntry tmp = new DirectoryEntry(streamName, StgType.StgStream, null); + IDirectoryEntry tmp = DirectoryEntry.Mock(streamName, StgType.StgStream); //if (children == null) //{ @@ -244,12 +244,12 @@ public CFStorage GetStorage(String storageName) { CheckDisposed(); - IDirectoryEntry template = new DirectoryEntry(storageName, StgType.StgInvalid, null); + IDirectoryEntry template = DirectoryEntry.Mock(storageName, StgType.StgInvalid); IRBNode outDe = null; if (Children.TryLookup(template, out outDe) && ((IDirectoryEntry)outDe).StgType == StgType.StgStorage) { - return outDe as CFStorage; + return new CFStorage(this.CompoundFile, outDe as IDirectoryEntry); } else { @@ -291,7 +291,7 @@ public CFStorage AddStorage(String storageName) // Add new Storage directory entry IDirectoryEntry cfo - = new DirectoryEntry(storageName, StgType.StgStorage, this.CompoundFile.GetDirectories()); + = DirectoryEntry.New(storageName, StgType.StgStorage, this.CompoundFile.GetDirectories()); //this.CompoundFile.InsertNewDirectoryEntry(cfo); @@ -394,11 +394,11 @@ public void Delete(String entryName) CheckDisposed(); // Find entry to delete - IDirectoryEntry tmp = new DirectoryEntry(entryName,StgType.StgInvalid, null); + IDirectoryEntry tmp = DirectoryEntry.Mock(entryName, StgType.StgInvalid); IRBNode foundObj = null; - this.Children.TryLookup(tmp, out foundObj ); + this.Children.TryLookup(tmp, out foundObj); if (foundObj == null) throw new CFItemNotFound("Entry named [" + entryName + "] was not found"); @@ -409,6 +409,8 @@ public void Delete(String entryName) if (((IDirectoryEntry)foundObj).StgType == StgType.StgRoot) throw new CFException("Root storage cannot be removed"); + + IRBNode altDel = null; switch (((IDirectoryEntry)foundObj).StgType) { case StgType.StgStorage: @@ -429,26 +431,26 @@ public void Delete(String entryName) this.DirEntry.Child = DirectoryEntry.NOSTREAM; // ...and finally Remove storage item from children tree... - this.Children.Delete(foundObj); + this.Children.Delete(foundObj, out altDel); // ...and remove directory (storage) entry - this.CompoundFile.RemoveDirectoryEntry(((IDirectoryEntry)foundObj).SID); - //Trace.WriteLine("**** DELETED STORAGE " + entryName + "******"); + if (altDel != null) + { + foundObj = altDel; + } - // Synchronize tree with directory entries - //this.CompoundFile.RefreshIterative(this.Children.Root); + this.CompoundFile.InvalidateDirectoryEntry(((IDirectoryEntry)foundObj).SID); break; case StgType.StgStream: - // Remove item from children tree - this.Children.Delete(foundObj); - //Trace.WriteLine("**** DELETED STREAM " + entryName + "******"); + // Free directory associated data stream. + CompoundFile.FreeAssociatedData((foundObj as IDirectoryEntry).SID); - // Synchronize tree with directory entries - //this.CompoundFile.RefreshIterative(this.Children.Root); + // Remove item from children tree + this.Children.Delete(foundObj,out altDel); // Rethread the root of siblings tree... if (this.Children.Root != null) @@ -456,10 +458,16 @@ public void Delete(String entryName) else this.DirEntry.Child = DirectoryEntry.NOSTREAM; + // Delete operation could possibly have cloned a directory, changing its SID. + // Invalidate the ACTUALLY deleted directory. + if (altDel != null) + { + foundObj = altDel; + } - // Remove directory entry - this.CompoundFile.RemoveDirectoryEntry(((IDirectoryEntry)foundObj).SID); + this.CompoundFile.InvalidateDirectoryEntry(((IDirectoryEntry)foundObj).SID); + this.Children.Print(); break; } diff --git a/src/CompoundFile.cs b/src/CompoundFile.cs index 17253dac..d2378606 100644 --- a/src/CompoundFile.cs +++ b/src/CompoundFile.cs @@ -240,7 +240,7 @@ public CompoundFile() FAT_SECTOR_ENTRIES_COUNT = (GetSectorSize() / 4); //Root -- - DirectoryEntry de = new DirectoryEntry("Root Entry", StgType.StgRoot, directoryEntries); + IDirectoryEntry de = DirectoryEntry.New("Root Entry", StgType.StgRoot, directoryEntries); rootStorage = new CFStorage(this, de); rootStorage.DirEntry.StgType = StgType.StgRoot; rootStorage.DirEntry.StgColor = StgColor.Black; @@ -300,7 +300,7 @@ public CompoundFile(CFSVersion cfsVersion, CFSConfiguration configFlags) FAT_SECTOR_ENTRIES_COUNT = (GetSectorSize() / 4); //Root -- - IDirectoryEntry rootDir = new DirectoryEntry("Root Entry", StgType.StgRoot, directoryEntries); + IDirectoryEntry rootDir = DirectoryEntry.New("Root Entry", StgType.StgRoot, directoryEntries); rootDir.StgColor = StgColor.Black; //this.InsertNewDirectoryEntry(rootDir); @@ -823,7 +823,7 @@ StreamView miniStreamView { Sector s = sectorChain[i]; - if(s.Id == -1) + if (s.Id == -1) { // Allocate, position ministream at the end of already allocated // ministream's sectors @@ -1572,28 +1572,7 @@ public CFSVersion Version } } - internal void InsertNewDirectoryEntry(IDirectoryEntry de) - { - // If we are not adding an invalid dirEntry as - // in a normal loading from file (invalid dirs MAY pad a sector) - if (de != null) - { - // Find first available invalid slot (if any) to reuse it - for (int i = 0; i < directoryEntries.Count; i++) - { - if (directoryEntries[i].StgType == StgType.StgInvalid) - { - directoryEntries[i] = de; - de.SID = i; - return; - } - } - } - // No invalid directory entry found - directoryEntries.Add(de); - de.SID = directoryEntries.Count - 1; - } /// /// Reset a directory entry setting it to StgInvalid in the Directory. @@ -1601,7 +1580,11 @@ internal void InsertNewDirectoryEntry(IDirectoryEntry de) /// Sid of the directory to invalidate internal void ResetDirectoryEntry(int sid) { - directoryEntries[sid] = new DirectoryEntry(String.Empty, StgType.StgInvalid, directoryEntries.AsReadOnly()); + directoryEntries[sid].SetEntryName(String.Empty); + directoryEntries[sid].Left = null; + directoryEntries[sid].Right = null; + directoryEntries[sid].Parent = null; + directoryEntries[sid].StgType = StgType.StgInvalid; } @@ -1641,10 +1624,12 @@ internal RBTree GetChildrenTree(int sid) { RBTree bst = new RBTree(); + // Load children from their original tree. - //DoLoadChildren(bst, directoryEntries[sid]); - bst = DoLoadChildrenTrusted(directoryEntries[sid]); + DoLoadChildren(bst, directoryEntries[sid]); + //bst = DoLoadChildrenTrusted(directoryEntries[sid]); + //bst.Print(); //bst.Print(); //Trace.WriteLine("#### After rethreading"); @@ -1657,7 +1642,7 @@ private RBTree DoLoadChildrenTrusted(IDirectoryEntry de) if (de.Child != DirectoryEntry.NOSTREAM) { - bst = new RBTree(directoryEntries[de.SID]); + bst = new RBTree(directoryEntries[de.Child]); } return bst; @@ -1671,15 +1656,19 @@ private void DoLoadChildren(RBTree bst, IDirectoryEntry de) { if (directoryEntries[de.Child].StgType == StgType.StgInvalid) return; - if (directoryEntries[de.Child].StgType == StgType.StgStream) - bst.Insert(directoryEntries[de.Child]); - else - bst.Insert(directoryEntries[de.Child]); - LoadSiblings(bst, directoryEntries[de.Child]); + NullifyChildNodes(directoryEntries[de.Child]); + bst.Insert(directoryEntries[de.Child]); } } + private void NullifyChildNodes(IDirectoryEntry de) + { + de.Parent = null; + de.Left = null; + de.Right = null; + } + // Doubling methods allows iterative behavior while avoiding // to insert duplicate items private void LoadSiblings(RBTree bst, IDirectoryEntry de) @@ -1688,12 +1677,14 @@ private void LoadSiblings(RBTree bst, IDirectoryEntry de) { // If there're more left siblings load them... DoLoadSiblings(bst, directoryEntries[de.LeftSibling]); + //NullifyChildNodes(directoryEntries[de.LeftSibling]); } if (de.RightSibling != DirectoryEntry.NOSTREAM) { // If there're more right siblings load them... DoLoadSiblings(bst, directoryEntries[de.RightSibling]); + //NullifyChildNodes(directoryEntries[de.RightSibling]); } } @@ -1705,17 +1696,14 @@ private void DoLoadSiblings(RBTree bst, IDirectoryEntry de) DoLoadSiblings(bst, directoryEntries[de.LeftSibling]); } - if (directoryEntries[de.SID].StgType == StgType.StgStream) - bst.Insert(directoryEntries[de.SID]); - else if (directoryEntries[de.SID].StgType == StgType.StgStorage) - bst.Insert(directoryEntries[de.SID]); - - if (ValidateSibling(de.RightSibling)) { // If there're more right siblings load them... DoLoadSiblings(bst, directoryEntries[de.RightSibling]); } + + NullifyChildNodes(de); + bst.Insert(de); } private bool ValidateSibling(int sid) @@ -1727,7 +1715,7 @@ private bool ValidateSibling(int sid) { if (this.validationExceptionEnabled) { - this.Close(); + //this.Close(); throw new CFCorruptedFileException("A Directory Entry references the non-existent sid number " + sid.ToString()); } else @@ -1739,8 +1727,8 @@ private bool ValidateSibling(int sid) { if (this.validationExceptionEnabled) { - this.Close(); - throw new CFCorruptedFileException("A Directory Entry has a valid reference to an Invalid Storage Type directory"); + //this.Close(); + throw new CFCorruptedFileException("A Directory Entry has a valid reference to an Invalid Storage Type directory [" + sid + "]"); } else return false; @@ -1751,7 +1739,7 @@ private bool ValidateSibling(int sid) if (this.validationExceptionEnabled) { - this.Close(); + //this.Close(); throw new CFCorruptedFileException("A Directory Entry has an invalid Storage Type"); } else @@ -1782,12 +1770,12 @@ StreamView dirReader while (dirReader.Position < directoryChain.Count * GetSectorSize()) { - DirectoryEntry de - = new DirectoryEntry(String.Empty, StgType.StgInvalid, directoryEntries); + IDirectoryEntry de + = DirectoryEntry.New(String.Empty, StgType.StgInvalid, directoryEntries); //We are not inserting dirs. Do not use 'InsertNewDirectoryEntry' de.Read(dirReader); - + } } @@ -1814,7 +1802,7 @@ List directorySectors while (delta % (GetSectorSize() / DIRECTORY_SIZE) != 0) { - DirectoryEntry dummy = new DirectoryEntry(String.Empty, StgType.StgInvalid, directoryEntries.AsReadOnly()); + IDirectoryEntry dummy = DirectoryEntry.New(String.Empty, StgType.StgInvalid, directoryEntries); dummy.Write(sv); delta++; } @@ -2416,35 +2404,34 @@ private static int LowSaturation(int i) } - internal void RemoveDirectoryEntry(int sid) + internal void InvalidateDirectoryEntry(int sid) { if (sid >= directoryEntries.Count) throw new CFException("Invalid SID of the directory entry to remove"); - if (directoryEntries[sid].StgType == StgType.StgStream) + //Random r = new Random(); + directoryEntries[sid].SetEntryName("_DELETED_NAME_" + sid.ToString()); + directoryEntries[sid].StgType = StgType.StgInvalid; + } + + internal void FreeAssociatedData(int sid) + { + // Clear the associated stream (or ministream) if required + if (directoryEntries[sid].Size > 0) //thanks to Mark Bosold for this ! { - // Clear the associated stream (or ministream) if required - if (directoryEntries[sid].Size > 0) //thanks to Mark Bosold for this ! + if (directoryEntries[sid].Size < header.MinSizeStandardStream) { - if (directoryEntries[sid].Size < header.MinSizeStandardStream) - { - List miniChain - = GetSectorChain(directoryEntries[sid].StartSetc, SectorType.Mini); - FreeMiniChain(miniChain, this.eraseFreeSectors); - } - else - { - List chain - = GetSectorChain(directoryEntries[sid].StartSetc, SectorType.Normal); - FreeChain(chain, this.eraseFreeSectors); - } + List miniChain + = GetSectorChain(directoryEntries[sid].StartSetc, SectorType.Mini); + FreeMiniChain(miniChain, this.eraseFreeSectors); + } + else + { + List chain + = GetSectorChain(directoryEntries[sid].StartSetc, SectorType.Normal); + FreeChain(chain, this.eraseFreeSectors); } } - - - Random r = new Random(); - directoryEntries[sid].SetEntryName("_DELETED_NAME_" + r.Next(short.MaxValue).ToString()); - directoryEntries[sid].StgType = StgType.StgInvalid; } /// diff --git a/src/DirectoryEntry.cs b/src/DirectoryEntry.cs index 04badd6b..ebed604e 100644 --- a/src/DirectoryEntry.cs +++ b/src/DirectoryEntry.cs @@ -38,8 +38,10 @@ public enum StgColor : int Black = 1 } - internal class DirectoryEntry : IDirectoryEntry + public class DirectoryEntry : IDirectoryEntry { + internal const int THIS_IS_GREATER = 1; + internal const int OTHER_IS_GREATER = -1; private IList dirRepository; private int sid = -1; @@ -52,11 +54,9 @@ public int SID internal static Int32 NOSTREAM = unchecked((int)0xFFFFFFFF); - public DirectoryEntry(String name, StgType stgType, IList dirRepository) + private DirectoryEntry(String name, StgType stgType, IList dirRepository) { this.dirRepository = dirRepository; - this.dirRepository.Add(this); - this.sid = this.dirRepository.Count - 1; this.stgType = stgType; @@ -275,8 +275,7 @@ public long Size public int CompareTo(object obj) { - const int THIS_IS_GREATER = 1; - const int OTHER_IS_GREATER = -1; + IDirectoryEntry otherDir = obj as IDirectoryEntry; if (otherDir == null) @@ -292,14 +291,17 @@ public int CompareTo(object obj) } else { - String thisName = Encoding.Unicode.GetString(this.EntryName, 0, this.NameLength).ToUpper(CultureInfo.InvariantCulture); - String otherName = Encoding.Unicode.GetString(otherDir.EntryName, 0, otherDir.NameLength).ToUpper(CultureInfo.InvariantCulture); + String thisName = Encoding.Unicode.GetString(this.EntryName, 0, this.NameLength); + String otherName = Encoding.Unicode.GetString(otherDir.EntryName, 0, otherDir.NameLength); for (int z = 0; z < thisName.Length; z++) { - if (BitConverter.ToInt16(BitConverter.GetBytes(thisName[z]), 0) > BitConverter.ToInt16(BitConverter.GetBytes(otherName[z]), 0)) + char thisChar = char.ToUpperInvariant(thisName[z]); + char otherChar = char.ToUpperInvariant(otherName[z]); + + if (thisChar > otherChar) return THIS_IS_GREATER; - else if (BitConverter.ToInt16(BitConverter.GetBytes(thisName[z]), 0) < BitConverter.ToInt16(BitConverter.GetBytes(otherName[z]), 0)) + else if (thisChar < otherChar) return OTHER_IS_GREATER; } @@ -529,5 +531,104 @@ public object Clone() return d; } + + internal static IDirectoryEntry New(String name, StgType stgType, IList dirRepository) + { + DirectoryEntry de = null; + if (dirRepository != null) + { + de = new DirectoryEntry(name, stgType, dirRepository); + // No invalid directory entry found + dirRepository.Add(de); + de.SID = dirRepository.Count - 1; + } + else + throw new ArgumentNullException("dirRepository", "Directory repository cannot be null in New() method"); + + return de; + } + + internal static IDirectoryEntry Mock(String name, StgType stgType) + { + DirectoryEntry de = new DirectoryEntry(name, stgType, null); + + return de; + } + + internal static IDirectoryEntry TryNew(String name, StgType stgType, IList dirRepository) + { + DirectoryEntry de = new DirectoryEntry(name, stgType, dirRepository); + + // If we are not adding an invalid dirEntry as + // in a normal loading from file (invalid dirs MAY pad a sector) + if (de != null) + { + // Find first available invalid slot (if any) to reuse it + for (int i = 0; i < dirRepository.Count; i++) + { + if (dirRepository[i].StgType == StgType.StgInvalid) + { + dirRepository[i] = de; + de.SID = i; + return de; + } + } + } + + // No invalid directory entry found + dirRepository.Add(de); + de.SID = dirRepository.Count - 1; + + return de; + } + + //private static void InsertNewDirectoryEntry(DirectoryEntry de, IList directoryEntries) + //{ + // // If we are not adding an invalid dirEntry as + // // in a normal loading from file (invalid dirs MAY pad a sector) + // if (de != null) + // { + // // Find first available invalid slot (if any) to reuse it + // for (int i = 0; i < directoryEntries.Count; i++) + // { + // if (directoryEntries[i].StgType == StgType.StgInvalid) + // { + // directoryEntries[i] = de; + // de.SID = i; + // return; + // } + // } + // } + + // // No invalid directory entry found + // directoryEntries.Add(de); + // de.SID = directoryEntries.Count - 1; + //} + + + public override string ToString() + { + return this.Name + " [" + this.sid + "]"; + } + + + public void AssignValueTo(RedBlackTree.IRBNode other) + { + DirectoryEntry d = other as DirectoryEntry; + + d.SetEntryName(this.GetEntryName()); + + d.creationDate = new byte[this.creationDate.Length]; + this.creationDate.CopyTo(d.creationDate, 0); + + d.modifyDate = new byte[this.modifyDate.Length]; + this.modifyDate.CopyTo(d.modifyDate, 0); + + d.size = this.size; + d.startSetc = this.startSetc; + d.stateBits = this.stateBits; + d.stgType = this.stgType; + d.storageCLSID = new Guid(this.storageCLSID.ToByteArray()); + } } } diff --git a/src/RBTree/RBTree.cs b/src/RBTree/RBTree.cs index 6a2cca24..1d764d91 100644 --- a/src/RBTree/RBTree.cs +++ b/src/RBTree/RBTree.cs @@ -39,35 +39,35 @@ public enum Color { RED = 0, BLACK = 1 } /// Red Black Node class /// /// - public interface IRBNode : IComparable, ICloneable + public interface IRBNode : IComparable { - IRBNode Left + IRBNode Left { get; set; } - IRBNode Right + IRBNode Right { get; set; } - Color Color + Color Color { get; set; } - IRBNode Parent { get; set; } + IRBNode Parent { get; set; } - IRBNode Grandparent(); + IRBNode Grandparent(); - IRBNode Sibling(); + IRBNode Sibling(); // { //#if ASSERT // Debug.Assert(Parent != null); // Root node has no sibling @@ -78,7 +78,7 @@ Color Color // return Parent.Left; // } - IRBNode Uncle(); + IRBNode Uncle(); // { //#if ASSERT // Debug.Assert(Parent != null); // Root node has no uncle @@ -87,6 +87,8 @@ Color Color // return Parent.Sibling(); // } // } + + void AssignValueTo(IRBNode other); } public class RBTree @@ -198,7 +200,7 @@ private void RotateRight(IRBNode n) n.Parent = l; } - + public void Insert(IRBNode newNode) { @@ -217,7 +219,7 @@ public void Insert(IRBNode newNode) int compResult = newNode.CompareTo(n); if (compResult == 0) { - throw new RBTreeDuplicatedItemException("OhiOhi Duplicated Item"); + throw new RBTreeDuplicatedItemException("RBNode " + newNode.ToString() + " already present in tree"); //n.Value = value; //return; } @@ -226,6 +228,7 @@ public void Insert(IRBNode newNode) if (n.Left == null) { n.Left = insertedNode; + break; } else @@ -239,6 +242,7 @@ public void Insert(IRBNode newNode) if (n.Right == null) { n.Right = insertedNode; + break; } else @@ -340,17 +344,20 @@ private static IRBNode MaximumNode(IRBNode n) } - public void Delete(IRBNode template) + public void Delete(IRBNode template, out IRBNode deletedAlt) { + deletedAlt = null; IRBNode n = LookupNode(template); + template = n; if (n == null) return; // Key not found, do nothing if (n.Left != null && n.Right != null) { // Copy key/value from predecessor and then delete it instead IRBNode pred = MaximumNode(n.Left); - n = pred.Clone() as IRBNode; + pred.AssignValueTo(n); n = pred; + deletedAlt = pred; } //assert n.left == null || n.right == null; @@ -368,10 +375,8 @@ public void Delete(IRBNode template) Root.Color = Color.BLACK; } - //Trace.WriteLine(" "); - - //Print(); + return; } private void DeleteCase1(IRBNode n) diff --git a/src/StreamRW.cs b/src/StreamRW.cs index 3712a7a9..eb82d664 100644 --- a/src/StreamRW.cs +++ b/src/StreamRW.cs @@ -23,7 +23,8 @@ public long Seek(long offset) public byte ReadByte() { - return (byte)this.stream.ReadByte(); + this.stream.Read(buffer, 0, 1); + return buffer[0]; } public ushort ReadUInt16() @@ -74,7 +75,8 @@ public byte[] ReadBytes(int count, out int r_count) public void Write(byte b) { - this.stream.WriteByte(b); + buffer[0] = b; + this.stream.Write(buffer, 0, 1); } public void Write(ushort value) From b282b4c98ed0ea657fbfbaebe14eb388230898b4 Mon Sep 17 00:00:00 2001 From: ironfede Date: Sun, 7 Dec 2014 14:51:03 +0000 Subject: [PATCH 07/18] Fixed issue (#18) on ReadInt64 method of StreamRW class. --- Unit Test/CompoundFileTest.cs | 2 +- Unit Test/OpenMcdfTest.csproj | 1 + Unit Test/StreamRWTest.cs | 52 ++++++++++++++++++++++++++++++++++ src/CFStorage.cs | 8 +----- src/DirectoryEntry.cs | 51 +-------------------------------- src/DirectoryFactory.cs | 15 ---------- src/OpenMcdf.csproj | 1 - src/Properties/AssemblyInfo.cs | 2 +- src/StreamRW.cs | 2 +- 9 files changed, 58 insertions(+), 76 deletions(-) create mode 100644 Unit Test/StreamRWTest.cs delete mode 100644 src/DirectoryFactory.cs diff --git a/Unit Test/CompoundFileTest.cs b/Unit Test/CompoundFileTest.cs index 05ba71fa..2eb8238d 100644 --- a/Unit Test/CompoundFileTest.cs +++ b/Unit Test/CompoundFileTest.cs @@ -673,7 +673,7 @@ public void Test_ADD_LARGE_NUMBER_OF_ITEMS() f.Save("$ItemsLargeNumber.cfs"); f.Close(); - Trace.Listeners.Add(new ConsoleTraceListener()); + f = new CompoundFile("$ItemsLargeNumber.cfs"); CFStream cfs = f.RootStorage.GetStream("Stream" + (ITEM_NUMBER / 2).ToString()); diff --git a/Unit Test/OpenMcdfTest.csproj b/Unit Test/OpenMcdfTest.csproj index a2d2d800..ce38f1d1 100644 --- a/Unit Test/OpenMcdfTest.csproj +++ b/Unit Test/OpenMcdfTest.csproj @@ -69,6 +69,7 @@ + diff --git a/Unit Test/StreamRWTest.cs b/Unit Test/StreamRWTest.cs new file mode 100644 index 00000000..e26fdde3 --- /dev/null +++ b/Unit Test/StreamRWTest.cs @@ -0,0 +1,52 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.IO; + +namespace OpenMcdfTest +{ + [TestClass] + public class StreamRWTest + { + [TestMethod] + public void ReadInt64_MaxSizeRead() + { + Int64 input = Int64.MaxValue; + byte[] bytes = BitConverter.GetBytes(input); + long actual = 0; + using (MemoryStream memStream = new MemoryStream(bytes)) + { + OpenMcdf.StreamRW reader = new OpenMcdf.StreamRW(memStream); + actual = reader.ReadInt64(); + } + Assert.AreEqual((long)input, actual); + } + + [TestMethod] + public void ReadInt64_SmallNumber() + { + Int64 input = 1234; + byte[] bytes = BitConverter.GetBytes(input); + long actual = 0; + using (MemoryStream memStream = new MemoryStream(bytes)) + { + OpenMcdf.StreamRW reader = new OpenMcdf.StreamRW(memStream); + actual = reader.ReadInt64(); + } + Assert.AreEqual((long)input, actual); + } + + [TestMethod] + public void ReadInt64_Int32MaxPlusTen() + { + Int64 input = (Int64)Int32.MaxValue + 10; + byte[] bytes = BitConverter.GetBytes(input); + long actual = 0; + using (MemoryStream memStream = new MemoryStream(bytes)) + { + OpenMcdf.StreamRW reader = new OpenMcdf.StreamRW(memStream); + actual = reader.ReadInt64(); + } + Assert.AreEqual((long)input, actual); + } + } +} diff --git a/src/CFStorage.cs b/src/CFStorage.cs index c0290c94..7e15ed83 100644 --- a/src/CFStorage.cs +++ b/src/CFStorage.cs @@ -158,10 +158,6 @@ public CFStream AddStream(String streamName) { // Add object to Siblings tree this.Children.Insert(dirEntry); - //Trace.WriteLine("**** INSERT STREAM " + cfo.Name + "******"); - //this.Children.Print(); - //Rethread children tree... - // CompoundFile.RefreshIterative(Children.Root); //... and set the root of the tree as new child of the current item directory entry this.DirEntry.Child = (Children.Root as IDirectoryEntry).SID; @@ -298,9 +294,7 @@ IDirectoryEntry cfo try { // Add object to Siblings tree - //Trace.WriteLine("**** INSERT STORAGE " + cfo.Name + "******"); Children.Insert(cfo); - //Children.Print(); } catch (RBTreeDuplicatedItemException) { @@ -467,7 +461,7 @@ public void Delete(String entryName) this.CompoundFile.InvalidateDirectoryEntry(((IDirectoryEntry)foundObj).SID); - this.Children.Print(); + break; } diff --git a/src/DirectoryEntry.cs b/src/DirectoryEntry.cs index ebed604e..90c95c9f 100644 --- a/src/DirectoryEntry.cs +++ b/src/DirectoryEntry.cs @@ -504,34 +504,6 @@ public RedBlackTree.IRBNode Uncle() return parent != null ? Parent.Sibling() : null; } - public object Clone() - { - DirectoryEntry d = new DirectoryEntry(this.Name, this.stgType, this.dirRepository); - d.child = this.child; - d.Color = this.Color; - - d.creationDate = new byte[this.creationDate.Length]; - this.creationDate.CopyTo(d.creationDate, 0); - - d.leftSibling = this.leftSibling; - - d.modifyDate = new byte[this.modifyDate.Length]; - this.modifyDate.CopyTo(d.modifyDate, 0); - - d.nameLength = this.nameLength; - d.parent = this.parent; - d.rightSibling = this.rightSibling; - - d.size = this.size; - d.startSetc = this.startSetc; - d.stateBits = this.stateBits; - d.stgColor = this.stgColor; - d.stgType = this.stgType; - d.storageCLSID = new Guid(this.storageCLSID.ToByteArray()); - - return d; - } - internal static IDirectoryEntry New(String name, StgType stgType, IList dirRepository) { DirectoryEntry de = null; @@ -582,28 +554,7 @@ internal static IDirectoryEntry TryNew(String name, StgType stgType, IList directoryEntries) - //{ - // // If we are not adding an invalid dirEntry as - // // in a normal loading from file (invalid dirs MAY pad a sector) - // if (de != null) - // { - // // Find first available invalid slot (if any) to reuse it - // for (int i = 0; i < directoryEntries.Count; i++) - // { - // if (directoryEntries[i].StgType == StgType.StgInvalid) - // { - // directoryEntries[i] = de; - // de.SID = i; - // return; - // } - // } - // } - - // // No invalid directory entry found - // directoryEntries.Add(de); - // de.SID = directoryEntries.Count - 1; - //} + public override string ToString() diff --git a/src/DirectoryFactory.cs b/src/DirectoryFactory.cs deleted file mode 100644 index ccd2bc85..00000000 --- a/src/DirectoryFactory.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace OpenMcdf -{ - internal class DirectoryCollection - { - public void Add(IDirectoryEntry d) - { - - } - } -} diff --git a/src/OpenMcdf.csproj b/src/OpenMcdf.csproj index 5038b706..982e7c04 100644 --- a/src/OpenMcdf.csproj +++ b/src/OpenMcdf.csproj @@ -67,7 +67,6 @@ - diff --git a/src/Properties/AssemblyInfo.cs b/src/Properties/AssemblyInfo.cs index 06d3266e..1d73da04 100644 --- a/src/Properties/AssemblyInfo.cs +++ b/src/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ [assembly: AssemblyDescription("MS Compound File Storage .NET Implementation")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Federico Blaseotto")] -[assembly: AssemblyProduct("OpenMcdf 2.0 (prerelease)")] +[assembly: AssemblyProduct("OpenMcdf 2.0 beta 1")] [assembly: AssemblyCopyright("Copyright © 2010-2014, Federico Blaseotto")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/src/StreamRW.cs b/src/StreamRW.cs index eb82d664..4f853a59 100644 --- a/src/StreamRW.cs +++ b/src/StreamRW.cs @@ -50,7 +50,7 @@ public long ReadInt64() this.stream.Read(buffer, 0, 8); uint ls = (uint)(buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24)); uint ms = (uint)((buffer[4]) | (buffer[5] << 8) | (buffer[6] << 16) | (buffer[7] << 24)); - return (long)((ms << 32) | ls); + return (long)(((ulong)ms << 32) | ls); } public ulong ReadUInt64() From 2619226bdd33a31402672d648d234520ff0e00c4 Mon Sep 17 00:00:00 2001 From: ironfede Date: Sun, 7 Dec 2014 16:38:25 +0000 Subject: [PATCH 08/18] Beta 1 --- License.txt | 472 +++++++++++++++++++++++++++++++++++++++++++ MakeRelease.cmd | 5 + PRE_RELEASE_note.txt | 14 ++ Release notes.txt | 86 ++++++++ Support.txt | 5 + src/CFStorage.cs | 11 - src/CFStream.cs | 2 +- src/RBTree/RBTree.cs | 3 +- 8 files changed, 584 insertions(+), 14 deletions(-) create mode 100644 License.txt create mode 100644 MakeRelease.cmd create mode 100644 PRE_RELEASE_note.txt create mode 100644 Release notes.txt create mode 100644 Support.txt diff --git a/License.txt b/License.txt new file mode 100644 index 00000000..fd46400e --- /dev/null +++ b/License.txt @@ -0,0 +1,472 @@ + MOZILLA PUBLIC LICENSE + Version 1.1 + + --------------- + +1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the + Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to + the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Code, prior Modifications used by a Contributor, and the Modifications + made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the + combination of the Original Code and Modifications, in each case + including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally + accepted in the software development community for the electronic + transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source + Code. + + 1.6. "Initial Developer" means the individual or entity identified + as the Initial Developer in the Source Code notice required by Exhibit + A. + + 1.7. "Larger Work" means a work which combines Covered Code or + portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the + substance or structure of either the Original Code or any previous + Modifications. When Covered Code is released as a series of files, a + Modification is: + + A. Any addition to or deletion from the contents of a file + containing Original Code or previous Modifications. + + B. Any new file that contains any part of the Original Code or + previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code + which is described in the Source Code notice required by Exhibit A as + Original Code, and which, at the time of its release under this + License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for + making modifications to it, including all modules it contains, plus + any associated interface definition files, scripts used to control + compilation and installation of an Executable, or source code + differential comparisons against either the Original Code or another + well known, available Covered Code of the Contributor's choice. The + Source Code can be in a compressed or archival form, provided the + appropriate decompression or de-archiving software is widely available + for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, this + License or a future version of this License issued under Section 6.1. + For legal entities, "You" includes any entity which controls, is + controlled by, or is under common control with You. For purposes of + this definition, "control" means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty percent + (50%) of the outstanding shares or beneficial ownership of such + entity. + +2. Source Code License. + + 2.1. The Initial Developer Grant. + The Initial Developer hereby grants You a world-wide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Code (or portions thereof) with or without Modifications, and/or + as part of a Larger Work; and + + (b) under Patents Claims infringed by the making, using or + selling of Original Code, to make, have made, use, practice, + sell, and offer for sale, and/or otherwise dispose of the + Original Code (or portions thereof). + + (c) the licenses granted in this Section 2.1(a) and (b) are + effective on the date Initial Developer first distributes + Original Code under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: 1) for code that You delete from the Original Code; 2) + separate from the Original Code; or 3) for infringements caused + by: i) the modification of the Original Code or ii) the + combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. + Subject to third party intellectual property claims, each Contributor + hereby grants You a world-wide, royalty-free, non-exclusive license + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor, to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof) either on an + unmodified basis, with other Modifications, as Covered Code + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either alone + and/or in combination with its Contributor Version (or portions + of such combination), to make, use, sell, offer for sale, have + made, and/or otherwise dispose of: 1) Modifications made by that + Contributor (or portions thereof); and 2) the combination of + Modifications made by that Contributor with its Contributor + Version (or portions of such combination). + + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first makes Commercial Use of + the Covered Code. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: 1) for any code that Contributor has deleted from the + Contributor Version; 2) separate from the Contributor Version; + 3) for infringements caused by: i) third party modifications of + Contributor Version or ii) the combination of Modifications made + by that Contributor with other software (except as part of the + Contributor Version) or other devices; or 4) under Patent Claims + infringed by Covered Code in the absence of Modifications made by + that Contributor. + +3. Distribution Obligations. + + 3.1. Application of License. + The Modifications which You create or to which You contribute are + governed by the terms of this License, including without limitation + Section 2.2. The Source Code version of Covered Code may be + distributed only under the terms of this License or a future version + of this License released under Section 6.1, and You must include a + copy of this License with every copy of the Source Code You + distribute. You may not offer or impose any terms on any Source Code + version that alters or restricts the applicable version of this + License or the recipients' rights hereunder. However, You may include + an additional document offering the additional rights described in + Section 3.5. + + 3.2. Availability of Source Code. + Any Modification which You create or to which You contribute must be + made available in Source Code form under the terms of this License + either on the same media as an Executable version or via an accepted + Electronic Distribution Mechanism to anyone to whom you made an + Executable version available; and if made available via Electronic + Distribution Mechanism, must remain available for at least twelve (12) + months after the date it initially became available, or at least six + (6) months after a subsequent version of that particular Modification + has been made available to such recipients. You are responsible for + ensuring that the Source Code version remains available even if the + Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. + You must cause all Covered Code to which You contribute to contain a + file documenting the changes You made to create that Covered Code and + the date of any change. You must include a prominent statement that + the Modification is derived, directly or indirectly, from Original + Code provided by the Initial Developer and including the name of the + Initial Developer in (a) the Source Code, and (b) in any notice in an + Executable version or related documentation in which You describe the + origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + + (a) Third Party Claims. + If Contributor has knowledge that a license under a third party's + intellectual property rights is required to exercise the rights + granted by such Contributor under Sections 2.1 or 2.2, + Contributor must include a text file with the Source Code + distribution titled "LEGAL" which describes the claim and the + party making the claim in sufficient detail that a recipient will + know whom to contact. If Contributor obtains such knowledge after + the Modification is made available as described in Section 3.2, + Contributor shall promptly modify the LEGAL file in all copies + Contributor makes available thereafter and shall take other steps + (such as notifying appropriate mailing lists or newsgroups) + reasonably calculated to inform those who received the Covered + Code that new knowledge has been obtained. + + (b) Contributor APIs. + If Contributor's Modifications include an application programming + interface and Contributor has knowledge of patent licenses which + are reasonably necessary to implement that API, Contributor must + also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to + Section 3.4(a) above, Contributor believes that Contributor's + Modifications are Contributor's original creation(s) and/or + Contributor has sufficient rights to grant the rights conveyed by + this License. + + 3.5. Required Notices. + You must duplicate the notice in Exhibit A in each file of the Source + Code. If it is not possible to put such notice in a particular Source + Code file due to its structure, then You must include such notice in a + location (such as a relevant directory) where a user would be likely + to look for such a notice. If You created one or more Modification(s) + You may add your name as a Contributor to the notice described in + Exhibit A. You must also duplicate this License in any documentation + for the Source Code where You describe recipients' rights or ownership + rights relating to Covered Code. You may choose to offer, and to + charge a fee for, warranty, support, indemnity or liability + obligations to one or more recipients of Covered Code. However, You + may do so only on Your own behalf, and not on behalf of the Initial + Developer or any Contributor. You must make it absolutely clear than + any such warranty, support, indemnity or liability obligation is + offered by You alone, and You hereby agree to indemnify the Initial + Developer and every Contributor for any liability incurred by the + Initial Developer or such Contributor as a result of warranty, + support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. + You may distribute Covered Code in Executable form only if the + requirements of Section 3.1-3.5 have been met for that Covered Code, + and if You include a notice stating that the Source Code version of + the Covered Code is available under the terms of this License, + including a description of how and where You have fulfilled the + obligations of Section 3.2. The notice must be conspicuously included + in any notice in an Executable version, related documentation or + collateral in which You describe recipients' rights relating to the + Covered Code. You may distribute the Executable version of Covered + Code or ownership rights under a license of Your choice, which may + contain terms different from this License, provided that You are in + compliance with the terms of this License and that the license for the + Executable version does not attempt to limit or alter the recipient's + rights in the Source Code version from the rights set forth in this + License. If You distribute the Executable version under a different + license You must make it absolutely clear that any terms which differ + from this License are offered by You alone, not by the Initial + Developer or any Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred by + the Initial Developer or such Contributor as a result of any such + terms You offer. + + 3.7. Larger Works. + You may create a Larger Work by combining Covered Code with other code + not governed by the terms of this License and distribute the Larger + Work as a single product. In such a case, You must make sure the + requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Code due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description + must be included in the LEGAL file described in Section 3.4 and must + be included with all distributions of the Source Code. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Application of this License. + + This License applies to code to which the Initial Developer has + attached the notice in Exhibit A and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions. + Netscape Communications Corporation ("Netscape") may publish revised + and/or new versions of the License from time to time. Each version + will be given a distinguishing version number. + + 6.2. Effect of New Versions. + Once Covered Code has been published under a particular version of the + License, You may always continue to use it under the terms of that + version. You may also choose to use such Covered Code under the terms + of any subsequent version of the License published by Netscape. No one + other than Netscape has the right to modify the terms applicable to + Covered Code created under this License. + + 6.3. Derivative Works. + If You create or use a modified version of this License (which you may + only do in order to apply it to code which is not already Covered Code + governed by this License), You must (a) rename Your license so that + the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", + "MPL", "NPL" or any confusingly similar phrase do not appear in your + license (except to note that your license differs from this License) + and (b) otherwise make it clear that Your version of the license + contains terms which differ from the Mozilla Public License and + Netscape Public License. (Filling in the name of the Initial + Developer, Original Code or Contributor in the notice described in + Exhibit A shall not of themselves be deemed to be modifications of + this License.) + +7. DISCLAIMER OF WARRANTY. + + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE + IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, + YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE + COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER + OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. TERMINATION. + + 8.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to cure + such breach within 30 days of becoming aware of the breach. All + sublicenses to the Covered Code which are properly granted shall + survive any termination of this License. Provisions which, by their + nature, must remain in effect beyond the termination of this License + shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement + claim (excluding declatory judgment actions) against Initial Developer + or a Contributor (the Initial Developer or Contributor against whom + You file such action is referred to as "Participant") alleging that: + + (a) such Participant's Contributor Version directly or indirectly + infringes any patent, then any and all rights granted by such + Participant to You under Sections 2.1 and/or 2.2 of this License + shall, upon 60 days notice from Participant terminate prospectively, + unless if within 60 days after receipt of notice You either: (i) + agree in writing to pay Participant a mutually agreeable reasonable + royalty for Your past and future use of Modifications made by such + Participant, or (ii) withdraw Your litigation claim with respect to + the Contributor Version against such Participant. If within 60 days + of notice, a reasonable royalty and payment arrangement are not + mutually agreed upon in writing by the parties or the litigation claim + is not withdrawn, the rights granted by Participant to You under + Sections 2.1 and/or 2.2 automatically terminate at the expiration of + the 60 day notice period specified above. + + (b) any software, hardware, or device, other than such Participant's + Contributor Version, directly or indirectly infringes any patent, then + any rights granted to You by such Participant under Sections 2.1(b) + and 2.2(b) are revoked effective as of the date You first made, used, + sold, distributed, or had made, Modifications made by that + Participant. + + 8.3. If You assert a patent infringement claim against Participant + alleging that such Participant's Contributor Version directly or + indirectly infringes any patent where such claim is resolved (such as + by license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, + all end user license agreements (excluding distributors and resellers) + which have been validly granted by You or any distributor hereunder + prior to termination shall survive termination. + +9. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR + ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY + CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, + WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. GOVERNMENT END USERS. + + The Covered Code is a "commercial item," as that term is defined in + 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" and "commercial computer software documentation," as such + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), + all U.S. Government End Users acquire Covered Code with only those + rights set forth herein. + +11. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + California law provisions (except to the extent applicable law, if + any, provides otherwise), excluding its conflict-of-law provisions. + With respect to disputes in which at least one party is a citizen of, + or an entity chartered or registered to do business in the United + States of America, any litigation relating to this License shall be + subject to the jurisdiction of the Federal Courts of the Northern + District of California, with venue lying in Santa Clara County, + California, with the losing party responsible for costs, including + without limitation, court costs and reasonable attorneys' fees and + expenses. The application of the United Nations Convention on + Contracts for the International Sale of Goods is expressly excluded. + Any law or regulation which provides that the language of a contract + shall be construed against the drafter shall not apply to this + License. + +12. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + +13. MULTIPLE-LICENSED CODE. + + Initial Developer may designate portions of the Covered Code as + "Multiple-Licensed". "Multiple-Licensed" means that the Initial + Developer permits you to utilize portions of the Covered Code under + Your choice of the NPL or the alternative licenses, if any, specified + by the Initial Developer in the file described in Exhibit A. + +EXHIBIT A -Mozilla Public License. + + ``The contents of this file are subject to the Mozilla Public License + Version 1.1 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + License for the specific language governing rights and limitations + under the License. + + The Original Code is ______________________________________. + + The Initial Developer of the Original Code is ________________________. + Portions created by ______________________ are Copyright (C) ______ + _______________________. All Rights Reserved. + + Contributor(s): ______________________________________. + + Alternatively, the contents of this file may be used under the terms + of the _____ license (the "[___] License"), in which case the + provisions of [______] License are applicable instead of those + above. If you wish to allow use of your version of this file only + under the terms of the [____] License and not to allow others to use + your version of this file under the MPL, indicate your decision by + deleting the provisions above and replace them with the notice and + other provisions required by the [___] License. If you do not delete + the provisions above, a recipient may use your version of this file + under either the MPL or the [___] License." + + [NOTE: The text of this Exhibit A may differ slightly from the text of + the notices in the Source Code files of the Original Code. You should + use the text of this Exhibit A rather than the text found in the + Original Code Source Code for Your Modifications.] + diff --git a/MakeRelease.cmd b/MakeRelease.cmd new file mode 100644 index 00000000..cbbb987d --- /dev/null +++ b/MakeRelease.cmd @@ -0,0 +1,5 @@ +msbuild OpenMcdf.sln /property:Configuration=Release +robocopy ./src NEW_RELEASE/src /MIR /xd bin obj +robocopy ./src/bin/Release NEW_RELEASE *.* +robocopy "./Structured Storage Explorer\bin\Release" NEW_RELEASE\StructuredStorageExplorer\ StucturedStorageExplorer.exe Be.Windows.Forms.HexBox.dll OpenMcdf.dll +robocopy ./ NEW_RELEASE "PRE_RELEASE_note.txt" "Release notes.txt" "Support.txt" "License.txt" \ No newline at end of file diff --git a/PRE_RELEASE_note.txt b/PRE_RELEASE_note.txt new file mode 100644 index 00000000..fe1943e3 --- /dev/null +++ b/PRE_RELEASE_note.txt @@ -0,0 +1,14 @@ +This is a prerelease package of OpenMcdf not aimed to production use. + +Please, feel free to use it for testing purpose, bug checking and reporting and new/missing feature requests. + +There are ony little changes in API but a lot of things have changed internally: + +-RedBlack tree structure for directory items allow OpenMcdf to handle thousands of stream and storage objects. +-Extension methods provide access to stream items as native Stream object and +-Extension for OLE properties handling is 'work in progress' (still unreleased) + +Enjoy OpenMcdf 2.0 ! + +Best Regards, +Federico Blaseotto \ No newline at end of file diff --git a/Release notes.txt b/Release notes.txt new file mode 100644 index 00000000..8bd0be81 --- /dev/null +++ b/Release notes.txt @@ -0,0 +1,86 @@ +ver 2.0 beta 1 (NOT FOR PRODUCTION) +FIXED: Issues with StreamRW in reading Int64 +FIXED: Issue with poor random naming policy for directory invalidation +FIXED: Redundancy of rethreading a RBTree after insertion/removal operations +NOTE: This is a technical preview not aimed to production use. + +--------- +ver 2.0 pre-release (NOT FOR PRODUCTION) +ADD: Red-Black tree full implementation to speed up large data structure read access (thousands of stream/storage objects) +ADD: Enhanced Stream resizing +ADD: Extensions to use native .net framework Stream object +ADD: Code has been ported to .net 4.0 framework +NOTE: This is a technical preview not aimed to production use. + +--------- +ver 1.5.4 +FIXED: In particular conditions, an opened file could be left opened after a loading exception +FIXED: Circular references of corrupted files could lead to stack overflows +FIXED: Enanched standard compliance: corrupted file loading defaults to abort operation. +ADD: Version property +ADD: New overloaded constructors to force the load of possibly corrrupted files. + +--------- +ver 1.5.3 +ADD: 'GetAllNamedEntries' Method to access structured files without tree-loading performance penalties +ADD: New hex editor for stuctured storage explorer sample application + +--------- +ver 1.5.2 +FIXED: Math error in sector number recognition caused exception when reading some streams +FIXED: Saving twice caused OutOfMemoryException +FIXED: Error when using names of exactly 31 characters for streams or storages + +--------- +ver: 1.5.1. +FIXED: Casting error when removing uncommitted-added Stream. +ADDED: CFDuplicatedItem exception thrown when trying to add duplicated items (previously item addition was silently failing). + +--------- +ver: 1.5.0 +FIXED: Exception thrown when removing a stream of length equals to zero. + +--------- +ver: 1.5.0 - RC1 +ADD: New Update mode to commit changes to the underlying stream +ADD: Sector recycle to reuse unallocated sectors +ADD: File shrinking to compact compound files +ADD: Support for version 4 of specs (4096 bytes sectors) +ADD: Partial stream data reading to read data from a specified offset +ADD: Advanced lazy loading to reduce memory footprint of application + +!! FIXED: CHANGED NAMESPACE to OpenMcdf !! + +-------- +ver: 1.4.1 +FIXED: ERROR, internal modifier applied to Delete method +FIXED: Redundant method call for DIFAT chain + +ADD: 'Delete' feature for sample project + +-------- +ver. 1.4.0 +ADD: 'Remove' feature for storage and stream objects. +FIXED: ERROR in manipulation of streams with a length of 4096 bytes (cutoff bug) (Thx to meddingt) +FIXED: ERROR in zero sized streams + +-------- +ver. 1.3.1 +FIXED: Error in DIFAT sectors manipulation + +-------- +ver. 1.3 +FIXED: Null pointer in traversal with empty storages; + +-------- +ver. 1.2 +FIXED: Fixed ministream (<4096 bytes) bug; + +-------- +ver. 1.1 +ADD: Added traversal of Compound file method (VisitEntries); +FIXED: Fixed bug when multiple storage added; + +-------- +ver. 1.0 +Initial release \ No newline at end of file diff --git a/Support.txt b/Support.txt new file mode 100644 index 00000000..d92d69e5 --- /dev/null +++ b/Support.txt @@ -0,0 +1,5 @@ +Please, use sourceforge bug-tracker to get support at http://sourceforge.net/projects/openmcdf/ + +Thank You in advance for bug reporting and for You interest in OpenMCDF ! + +Federico Blaseotto \ No newline at end of file diff --git a/src/CFStorage.cs b/src/CFStorage.cs index 7e15ed83..aec365af 100644 --- a/src/CFStorage.cs +++ b/src/CFStorage.cs @@ -78,17 +78,6 @@ internal RBTree Children } } - /// - /// Create a new CFStorage - /// - /// The Storage Owner - CompoundFile - //internal CFStorage(CompoundFile compFile, String name) - // : base(compFile) - //{ - // this.DirEntry = new DirectoryEntry(name, StgType.StgStorage, compFile.GetDirectories()); - // this.DirEntry.StgColor = StgColor.Black; - // compFile.InsertNewDirectoryEntry(this.DirEntry); - //} /// /// Create a CFStorage using an existing directory (previously loaded). diff --git a/src/CFStream.cs b/src/CFStream.cs index ff875b3a..509f05d5 100644 --- a/src/CFStream.cs +++ b/src/CFStream.cs @@ -73,7 +73,7 @@ public void Write(byte[] data, long position) } /// - /// Write Count bytes of a data buffer to a specific position into + /// Write count bytes of a data buffer to a specific position into /// the current CFStream object starting from the specified position. /// /// Data buffer to copy bytes from diff --git a/src/RBTree/RBTree.cs b/src/RBTree/RBTree.cs index 1d764d91..e883f7a2 100644 --- a/src/RBTree/RBTree.cs +++ b/src/RBTree/RBTree.cs @@ -36,9 +36,8 @@ public RBTreeDuplicatedItemException(String msg) public enum Color { RED = 0, BLACK = 1 } /// - /// Red Black Node class + /// Red Black Node interface /// - /// public interface IRBNode : IComparable { From 7ca6b9d1ea875b42a3f04b0fc5c05c646ecf087f Mon Sep 17 00:00:00 2001 From: ironfede Date: Sat, 13 Dec 2014 14:39:13 +0000 Subject: [PATCH 09/18] Bugfix #21 --- Unit Test/CFSStreamTest.cs | 2 +- src/CompoundFile.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Unit Test/CFSStreamTest.cs b/Unit Test/CFSStreamTest.cs index 0c9f8f8a..484b4150 100644 --- a/Unit Test/CFSStreamTest.cs +++ b/Unit Test/CFSStreamTest.cs @@ -822,7 +822,7 @@ public void Test_RESIZE_STREAM_NO_TRANSITION() CFStream item = cf.RootStorage.GetStream("AStream"); item.Resize(item.Size / 2); //cf.RootStorage.AddStream("BStream").SetData(b); - cf.Commit(); + cf.Commit(true); cf.Close(); } diff --git a/src/CompoundFile.cs b/src/CompoundFile.cs index d2378606..2ca7041a 100644 --- a/src/CompoundFile.cs +++ b/src/CompoundFile.cs @@ -554,16 +554,14 @@ public void Commit(bool releaseMemory) else { gap = true; - continue; } + if (releaseMemory) { s.ReleaseData(); s = null; sectors[i] = null; - - //GC.Collect(); } @@ -658,6 +656,8 @@ public void Commit(bool releaseMemory) sourceStream.SetLength((sectors.Count + 1) * sSize); sourceStream.Flush(); + if (releaseMemory) + GC.Collect(); //} //catch (Exception ex) From d7ff0637cf963733e6b9943564a245b7baaf7f05 Mon Sep 17 00:00:00 2001 From: ironfede Date: Sat, 13 Dec 2014 15:13:44 +0000 Subject: [PATCH 10/18] Bug fixing #23 --- src/CompoundFile.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/CompoundFile.cs b/src/CompoundFile.cs index 2ca7041a..f3de2520 100644 --- a/src/CompoundFile.cs +++ b/src/CompoundFile.cs @@ -912,7 +912,7 @@ StreamView FATView } // Update FAT marking unallocated sectors ---------- - for (int i = nth_sector_to_remove; i < sectorChain.Count - 1; i++) + for (int i = nth_sector_to_remove; i < sectorChain.Count; i++) { Int32 currentId = sectorChain[i].Id; @@ -966,7 +966,7 @@ StreamView miniStreamView } // Update miniFAT --------------------------------------- - for (int i = nth_sector_to_remove; i < sectorChain.Count - 1; i++) + for (int i = nth_sector_to_remove; i < sectorChain.Count; i++) { Int32 currentId = sectorChain[i].Id; @@ -975,9 +975,15 @@ StreamView miniStreamView } // Write End of Chain in MiniFAT --------------------------------------- - miniFATView.Seek(sectorChain[(sectorChain.Count - 1) - nth_sector_to_remove].Id * SIZE_OF_SID, SeekOrigin.Begin); - miniFATView.Write(BitConverter.GetBytes(Sector.ENDOFCHAIN), 0, 4); + //miniFATView.Seek(sectorChain[(sectorChain.Count - 1) - nth_sector_to_remove].Id * SIZE_OF_SID, SeekOrigin.Begin); + //miniFATView.Write(BitConverter.GetBytes(Sector.ENDOFCHAIN), 0, 4); + // Write End of Chain in MiniFAT --------------------------------------- + if (nth_sector_to_remove > 0 && sectorChain.Count > 0) + { + miniFATView.Seek(sectorChain[nth_sector_to_remove - 1].Id * 4, SeekOrigin.Begin); + miniFATView.Write(BitConverter.GetBytes(Sector.ENDOFCHAIN), 0, 4); + } // Update sector chains --------------------------------------- AllocateSectorChain(miniStreamView.BaseSectorChain); From 33b841904ac4c37d06426a652a9b4e581631c11f Mon Sep 17 00:00:00 2001 From: ironfede Date: Wed, 24 Dec 2014 12:13:35 +0000 Subject: [PATCH 11/18] BUGFIX 24, added cyclic reference validation in siblings loading. Added unit test. --- OpenMcdf.sln | 3 ++- TestFiles/_thumbs_bug_24.db | Bin 0 -> 61440 bytes Unit Test/CompoundFileTest.cs | 43 ++++++++++++++++++++++++++-------- src/CompoundFile.cs | 17 +++++++++++++- 4 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 TestFiles/_thumbs_bug_24.db diff --git a/OpenMcdf.sln b/OpenMcdf.sln index cc13710f..796e741a 100644 --- a/OpenMcdf.sln +++ b/OpenMcdf.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 -VisualStudioVersion = 12.0.30501.0 +VisualStudioVersion = 12.0.21005.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6C619B4F-100F-4D60-BEF1-60B770D24E5E}" ProjectSection(SolutionItems) = preProject @@ -13,6 +13,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestFiles", "TestFiles", "{AC082D72-85BB-4FE8-AE0A-DB12A5729317}" ProjectSection(SolutionItems) = preProject TestFiles\2_MB-W.ppt = TestFiles\2_MB-W.ppt + TestFiles\_thumbs_bug_24.db = TestFiles\_thumbs_bug_24.db TestFiles\BUG_16_.xls = TestFiles\BUG_16_.xls TestFiles\CorruptedDoc_bug3547815.doc = TestFiles\CorruptedDoc_bug3547815.doc TestFiles\CorruptedDoc_bug3547815_B.doc = TestFiles\CorruptedDoc_bug3547815_B.doc diff --git a/TestFiles/_thumbs_bug_24.db b/TestFiles/_thumbs_bug_24.db new file mode 100644 index 0000000000000000000000000000000000000000..ffe469ff77092e3d7a4e050ecb8ad4ef660b6ebe GIT binary patch literal 61440 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 literal 0 HcmV?d00001 diff --git a/Unit Test/CompoundFileTest.cs b/Unit Test/CompoundFileTest.cs index 2eb8238d..94398834 100644 --- a/Unit Test/CompoundFileTest.cs +++ b/Unit Test/CompoundFileTest.cs @@ -17,7 +17,7 @@ public class CompoundFileTest { public CompoundFileTest() { - + } private TestContext testContextInstance; @@ -400,16 +400,16 @@ public void Test_FUNCTIONAL_BEHAVIOUR() //Test Phase 3 - + cfTest = new CompoundFile("6_Streams.cfs"); - + bool catched = false; try { testSt = cfTest.RootStorage.GetStream("D"); - + } catch (Exception ex) { @@ -489,7 +489,7 @@ public void Test_FUNCTIONAL_BEHAVIOUR() cf.RootStorage.AddStorage("AnotherStorage").AddStream("ANS").Append(bE); cf.RootStorage.Delete("MyStorage"); - + cf.Commit(); cf.Close(); @@ -501,9 +501,9 @@ public void Test_FUNCTIONAL_BEHAVIOUR() cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); CFStorage root = cf.RootStorage; - + root.AddStorage("MiniStorage").AddStream("miniSt").Append(bMini); - + cf.RootStorage.GetStorage("MiniStorage").AddStream("miniSt2").Append(bMini); cf.Commit(); cf.Close(); @@ -673,12 +673,12 @@ public void Test_ADD_LARGE_NUMBER_OF_ITEMS() f.Save("$ItemsLargeNumber.cfs"); f.Close(); - + f = new CompoundFile("$ItemsLargeNumber.cfs"); CFStream cfs = f.RootStorage.GetStream("Stream" + (ITEM_NUMBER / 2).ToString()); - Assert.IsTrue(cfs != null,"Item is null"); - Assert.IsTrue(Helpers.CompareBuffer(cfs.GetData(), buffer),"Items are different"); + Assert.IsTrue(cfs != null, "Item is null"); + Assert.IsTrue(Helpers.CompareBuffer(cfs.GetData(), buffer), "Items are different"); f.Close(); } catch (Exception ex) @@ -727,6 +727,29 @@ public void Test_FIX_BUG_17_CORRUPTED_PPT_FILE() } } + [TestMethod] + public void Test_FIX_BUG_24_CORRUPTED_THUMBS_DB_FILE() + { + try + { + using (var cf = new CompoundFile("_thumbs_bug_24.db")) + { + cf.RootStorage.VisitEntries(item => Console.WriteLine(item.Name), recursive: false); + } + } + catch (Exception exc) + { + Assert.IsInstanceOfType(exc, typeof(CFCorruptedFileException)); + } + + using (var cf = new CompoundFile("report.xls")) + { + cf.RootStorage.VisitEntries(item => Console.WriteLine(item.Name), recursive: false); + } + + } + + //[TestMethod] //public void Test_CORRUPTED_CYCLIC_DIFAT_VALIDATION_CHECK() //{ diff --git a/src/CompoundFile.cs b/src/CompoundFile.cs index f3de2520..67d647e8 100644 --- a/src/CompoundFile.cs +++ b/src/CompoundFile.cs @@ -1675,12 +1675,18 @@ private void NullifyChildNodes(IDirectoryEntry de) de.Right = null; } + private List levelSIDs = new List(); + // Doubling methods allows iterative behavior while avoiding // to insert duplicate items private void LoadSiblings(RBTree bst, IDirectoryEntry de) { + levelSIDs.Clear(); + if (de.LeftSibling != DirectoryEntry.NOSTREAM) { + + // If there're more left siblings load them... DoLoadSiblings(bst, directoryEntries[de.LeftSibling]); //NullifyChildNodes(directoryEntries[de.LeftSibling]); @@ -1688,6 +1694,8 @@ private void LoadSiblings(RBTree bst, IDirectoryEntry de) if (de.RightSibling != DirectoryEntry.NOSTREAM) { + levelSIDs.Add(de.RightSibling); + // If there're more right siblings load them... DoLoadSiblings(bst, directoryEntries[de.RightSibling]); //NullifyChildNodes(directoryEntries[de.RightSibling]); @@ -1698,12 +1706,16 @@ private void DoLoadSiblings(RBTree bst, IDirectoryEntry de) { if (ValidateSibling(de.LeftSibling)) { + levelSIDs.Add(de.LeftSibling); + // If there're more left siblings load them... DoLoadSiblings(bst, directoryEntries[de.LeftSibling]); } if (ValidateSibling(de.RightSibling)) { + levelSIDs.Add(de.RightSibling); + // If there're more right siblings load them... DoLoadSiblings(bst, directoryEntries[de.RightSibling]); } @@ -1752,6 +1764,9 @@ private bool ValidateSibling(int sid) return false; } + if (levelSIDs.Contains(sid)) + throw new CFCorruptedFileException("Cyclic reference of directory item"); + return true; //No fault condition encountered for sid being validated } @@ -2524,7 +2539,7 @@ protected virtual void Dispose(bool disposing) this.directoryEntries.Clear(); this.directoryEntries = null; this.fileName = null; - this.lockObject = null; + //this.lockObject = null; #if !FLAT_WRITE this.buffer = null; #endif From bcf44f429e5eefe02bb206b6c55ac97b5f6d88eb Mon Sep 17 00:00:00 2001 From: ironfede Date: Wed, 24 Dec 2014 12:31:45 +0000 Subject: [PATCH 12/18] Added Close() overload to leave stream open. (Bug 25) --- src/CompoundFile.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/CompoundFile.cs b/src/CompoundFile.cs index 67d647e8..01ac3327 100644 --- a/src/CompoundFile.cs +++ b/src/CompoundFile.cs @@ -2487,13 +2487,14 @@ List chain /// public void Close() { - ((IDisposable)this).Dispose(); + this.Close(true); } private bool closeStream = true; - internal void Close(bool closeStream) + public void Close(bool closeStream) { + this.closeStream = closeStream; ((IDisposable)this).Dispose(); } From 679913bdc3b6369f1ea2ebe0d13f8cb028875792 Mon Sep 17 00:00:00 2001 From: ironfede Date: Fri, 18 Sep 2015 16:43:35 +0000 Subject: [PATCH 13/18] Refactoring of sources layout. Added some unit test for 2 new methods TryGetStorage and TryGetStream. --- License.txt | 843 ++++++++---------- LocalTestRun.testrunconfig | 2 +- MakeRelease.cmd | 6 +- OpenMcdf.sln | 79 +- .../Html Help}/OpenMcdfHelp.shfbproj | 27 +- .../CFStreamExtensions.cs | 0 .../OpenMcdf.Extensions.csproj | 17 +- .../OpenMcdf.Extensions.csproj.user | 6 + .../Properties/AssemblyInfo.cs | 0 {src => sources/OpenMcdf}/CFException.cs | 28 +- {src => sources/OpenMcdf}/CFItem.cs | 30 +- {src => sources/OpenMcdf}/CFStorage.cs | 128 ++- {src => sources/OpenMcdf}/CFStream.cs | 26 +- {src => sources/OpenMcdf}/CompoundFile.cs | 27 +- {src => sources/OpenMcdf}/Directory.cs | 0 {src => sources/OpenMcdf}/DirectoryEntry.cs | 32 +- {src => sources/OpenMcdf}/Header.cs | 26 +- {src => sources/OpenMcdf}/IDirectoryEntry.cs | 25 +- {src => sources/OpenMcdf}/OpenMcdf.csproj | 18 +- .../OpenMcdf}/OpenMcdfClassDiagram.cd | 0 .../OpenMcdf}/Properties/AssemblyInfo.cs | 6 +- {src => sources/OpenMcdf}/RBTree/RBTree.cs | 0 {src => sources/OpenMcdf}/Sector.cs | 28 +- {src => sources/OpenMcdf}/SectorCollection.cs | 11 +- {src => sources/OpenMcdf}/StreamRW.cs | 10 +- {src => sources/OpenMcdf}/StreamView.cs | 27 +- .../Structured Storage Explorer}/InputBox.cs | 0 .../MainForm.Designer.cs | 0 .../Structured Storage Explorer}/MainForm.cs | 0 .../MainForm.resx | 0 .../Structured Storage Explorer}/Program.cs | 0 .../Properties/AssemblyInfo.cs | 2 +- .../Properties/Resources.Designer.cs | 0 .../Properties/Resources.resx | 0 .../Properties/Settings.Designer.cs | 0 .../Properties/Settings.settings | 0 .../StreamDataProvider.cs | 0 .../StructuredStorageExplorer.csproj | 26 +- .../Structured Storage Explorer}/Utils.cs | 0 .../Structured Storage Explorer}/app.config | 0 .../Structured Storage Explorer}/img/disk.png | Bin .../img/door_out.png | Bin .../img/folder.png | Bin .../img/page_white.png | Bin .../img/storage.png | Bin .../img/stream.png | Bin .../lib/Be.Windows.Forms.HexBox.dll | Bin .../CFSStreamExtensionsTest.cs | 7 +- .../Test/OpenMcdf.Extensions.Test}/Helpers.cs | 4 +- .../OpenMcdf.Extensions.Test.csproj | 20 +- .../Properties/AssemblyInfo.cs | 2 +- .../OpenMcdf.MemTest/OpenMcdf.MemTest.csproj | 12 +- .../Test/OpenMcdf.MemTest}/Program.cs | 2 +- .../Properties/AssemblyInfo.cs | 0 .../Test/OpenMcdf.MemTest}/app.config | 0 .../OpenMcdf.MemTest}/testfile/report.xls | Bin .../testfile/reportOverwriteMultiple.xls | Bin .../Test/OpenMcdf.PerfTest}/Helpers.cs | 2 +- .../OpenMcdf.PerfTest.csproj | 16 +- .../Test/OpenMcdf.PerfTest}/Program.cs | 2 +- .../Properties/AssemblyInfo.cs | 0 .../Test/OpenMcdf.PerfTest}/app.config | 0 .../Test/OpenMcdf.Test}/AuthoringTests.txt | 0 .../Test/OpenMcdf.Test}/CFSStreamTest.cs | 42 +- .../Test/OpenMcdf.Test}/CFSTorageTest.cs | 34 +- .../Test/OpenMcdf.Test}/CompoundFileTest.cs | 17 +- .../Test/OpenMcdf.Test}/Helpers.cs | 2 +- .../Test/OpenMcdf.Test/OpenMcdf.Test.csproj | 23 +- .../OpenMcdf.Test}/Properties/AssemblyInfo.cs | 0 .../Test/OpenMcdf.Test}/RBTreeTest.cs | 2 +- .../OpenMcdf.Test}/SectorCollectionTest.cs | 2 +- .../Test/OpenMcdf.Test}/StreamRWTest.cs | 2 +- .../Test/TestFiles}/2_MB-W.ppt | Bin .../Test/TestFiles}/BUG_16_.xls | Bin .../TestFiles}/CorruptedDoc_bug3547815.doc | Bin .../TestFiles}/CorruptedDoc_bug3547815_B.doc | Bin .../Test/TestFiles}/CyclicFAT.cfs | Bin .../Test/TestFiles}/MultipleStorage.cfs | Bin .../Test/TestFiles}/MultipleStorage2.cfs | Bin .../Test/TestFiles}/MultipleStorage3.cfs | Bin .../Test/TestFiles}/MultipleStorage4.cfs | Bin .../Test/TestFiles}/_thumbs_bug_24.db | Bin .../Test/TestFiles}/report.xls | Bin .../Test/TestFiles}/reportREAD.xls | Bin .../Test/TestFiles}/report_name_fix.xls | Bin .../Test/TestFiles}/testbad.ole | Bin src/CFMock.cs | 40 - 87 files changed, 813 insertions(+), 848 deletions(-) rename {Html Help => sources/Html Help}/OpenMcdfHelp.shfbproj (69%) rename {OpenMcdf.Extensions => sources/OpenMcdf.Extensions}/CFStreamExtensions.cs (100%) rename {OpenMcdf.Extensions => sources/OpenMcdf.Extensions}/OpenMcdf.Extensions.csproj (76%) create mode 100644 sources/OpenMcdf.Extensions/OpenMcdf.Extensions.csproj.user rename {OpenMcdf.Extensions => sources/OpenMcdf.Extensions}/Properties/AssemblyInfo.cs (100%) rename {src => sources/OpenMcdf}/CFException.cs (84%) rename {src => sources/OpenMcdf}/CFItem.cs (87%) rename {src => sources/OpenMcdf}/CFStorage.cs (80%) rename {src => sources/OpenMcdf}/CFStream.cs (90%) rename {src => sources/OpenMcdf}/CompoundFile.cs (96%) rename {src => sources/OpenMcdf}/Directory.cs (100%) rename {src => sources/OpenMcdf}/DirectoryEntry.cs (91%) rename {src => sources/OpenMcdf}/Header.cs (89%) rename {src => sources/OpenMcdf}/IDirectoryEntry.cs (53%) rename {src => sources/OpenMcdf}/OpenMcdf.csproj (88%) rename {src => sources/OpenMcdf}/OpenMcdfClassDiagram.cd (100%) rename {src => sources/OpenMcdf}/Properties/AssemblyInfo.cs (89%) rename {src => sources/OpenMcdf}/RBTree/RBTree.cs (100%) rename {src => sources/OpenMcdf}/Sector.cs (80%) rename {src => sources/OpenMcdf}/SectorCollection.cs (89%) rename {src => sources/OpenMcdf}/StreamRW.cs (87%) rename {src => sources/OpenMcdf}/StreamView.cs (90%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/InputBox.cs (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/MainForm.Designer.cs (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/MainForm.cs (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/MainForm.resx (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/Program.cs (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/Properties/AssemblyInfo.cs (93%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/Properties/Resources.Designer.cs (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/Properties/Resources.resx (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/Properties/Settings.Designer.cs (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/Properties/Settings.settings (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/StreamDataProvider.cs (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/StructuredStorageExplorer.csproj (86%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/Utils.cs (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/app.config (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/img/disk.png (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/img/door_out.png (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/img/folder.png (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/img/page_white.png (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/img/storage.png (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/img/stream.png (100%) rename {Structured Storage Explorer => sources/Structured Storage Explorer}/lib/Be.Windows.Forms.HexBox.dll (100%) rename {OpenMcdfExtensionsTest => sources/Test/OpenMcdf.Extensions.Test}/CFSStreamExtensionsTest.cs (91%) rename {OpenMcdfExtensionsTest => sources/Test/OpenMcdf.Extensions.Test}/Helpers.cs (88%) rename OpenMcdfExtensionsTest/OpenMcdfExtensionsTest.csproj => sources/Test/OpenMcdf.Extensions.Test/OpenMcdf.Extensions.Test.csproj (85%) rename {OpenMcdfExtensionsTest => sources/Test/OpenMcdf.Extensions.Test}/Properties/AssemblyInfo.cs (92%) rename Memory Test/OpenMcdfMemTest.csproj => sources/Test/OpenMcdf.MemTest/OpenMcdf.MemTest.csproj (94%) rename {Memory Test => sources/Test/OpenMcdf.MemTest}/Program.cs (96%) rename {Memory Test => sources/Test/OpenMcdf.MemTest}/Properties/AssemblyInfo.cs (100%) rename {Memory Test => sources/Test/OpenMcdf.MemTest}/app.config (100%) rename {Memory Test => sources/Test/OpenMcdf.MemTest}/testfile/report.xls (100%) rename {Memory Test => sources/Test/OpenMcdf.MemTest}/testfile/reportOverwriteMultiple.xls (100%) rename {Performance Test => sources/Test/OpenMcdf.PerfTest}/Helpers.cs (93%) rename Performance Test/OpenMcdfPerfTest.csproj => sources/Test/OpenMcdf.PerfTest/OpenMcdf.PerfTest.csproj (92%) rename {Performance Test => sources/Test/OpenMcdf.PerfTest}/Program.cs (94%) rename {Performance Test => sources/Test/OpenMcdf.PerfTest}/Properties/AssemblyInfo.cs (100%) rename {Performance Test => sources/Test/OpenMcdf.PerfTest}/app.config (100%) rename {Unit Test => sources/Test/OpenMcdf.Test}/AuthoringTests.txt (100%) rename {Unit Test => sources/Test/OpenMcdf.Test}/CFSStreamTest.cs (94%) rename {Unit Test => sources/Test/OpenMcdf.Test}/CFSTorageTest.cs (88%) rename {Unit Test => sources/Test/OpenMcdf.Test}/CompoundFileTest.cs (94%) rename {Unit Test => sources/Test/OpenMcdf.Test}/Helpers.cs (94%) rename Unit Test/OpenMcdfTest.csproj => sources/Test/OpenMcdf.Test/OpenMcdf.Test.csproj (89%) rename {Unit Test => sources/Test/OpenMcdf.Test}/Properties/AssemblyInfo.cs (100%) rename {Unit Test => sources/Test/OpenMcdf.Test}/RBTreeTest.cs (96%) rename {Unit Test => sources/Test/OpenMcdf.Test}/SectorCollectionTest.cs (95%) rename {Unit Test => sources/Test/OpenMcdf.Test}/StreamRWTest.cs (95%) rename {TestFiles => sources/Test/TestFiles}/2_MB-W.ppt (100%) rename {TestFiles => sources/Test/TestFiles}/BUG_16_.xls (100%) rename {TestFiles => sources/Test/TestFiles}/CorruptedDoc_bug3547815.doc (100%) rename {TestFiles => sources/Test/TestFiles}/CorruptedDoc_bug3547815_B.doc (100%) rename {TestFiles => sources/Test/TestFiles}/CyclicFAT.cfs (100%) rename {TestFiles => sources/Test/TestFiles}/MultipleStorage.cfs (100%) rename {TestFiles => sources/Test/TestFiles}/MultipleStorage2.cfs (100%) rename {TestFiles => sources/Test/TestFiles}/MultipleStorage3.cfs (100%) rename {TestFiles => sources/Test/TestFiles}/MultipleStorage4.cfs (100%) rename {TestFiles => sources/Test/TestFiles}/_thumbs_bug_24.db (100%) rename {TestFiles => sources/Test/TestFiles}/report.xls (100%) rename {TestFiles => sources/Test/TestFiles}/reportREAD.xls (100%) rename {TestFiles => sources/Test/TestFiles}/report_name_fix.xls (100%) rename {TestFiles => sources/Test/TestFiles}/testbad.ole (100%) delete mode 100644 src/CFMock.cs diff --git a/License.txt b/License.txt index fd46400e..016b985c 100644 --- a/License.txt +++ b/License.txt @@ -1,472 +1,373 @@ - MOZILLA PUBLIC LICENSE - Version 1.1 - - --------------- - -1. Definitions. - - 1.0.1. "Commercial Use" means distribution or otherwise making the - Covered Code available to a third party. - - 1.1. "Contributor" means each entity that creates or contributes to - the creation of Modifications. - - 1.2. "Contributor Version" means the combination of the Original - Code, prior Modifications used by a Contributor, and the Modifications - made by that particular Contributor. - - 1.3. "Covered Code" means the Original Code or Modifications or the - combination of the Original Code and Modifications, in each case - including portions thereof. - - 1.4. "Electronic Distribution Mechanism" means a mechanism generally - accepted in the software development community for the electronic - transfer of data. - - 1.5. "Executable" means Covered Code in any form other than Source - Code. - - 1.6. "Initial Developer" means the individual or entity identified - as the Initial Developer in the Source Code notice required by Exhibit - A. - - 1.7. "Larger Work" means a work which combines Covered Code or - portions thereof with code not governed by the terms of this License. - - 1.8. "License" means this document. - - 1.8.1. "Licensable" means having the right to grant, to the maximum - extent possible, whether at the time of the initial grant or - subsequently acquired, any and all of the rights conveyed herein. - - 1.9. "Modifications" means any addition to or deletion from the - substance or structure of either the Original Code or any previous - Modifications. When Covered Code is released as a series of files, a - Modification is: - - A. Any addition to or deletion from the contents of a file - containing Original Code or previous Modifications. - - B. Any new file that contains any part of the Original Code or - previous Modifications. - - 1.10. "Original Code" means Source Code of computer software code - which is described in the Source Code notice required by Exhibit A as - Original Code, and which, at the time of its release under this - License is not already Covered Code governed by this License. - - 1.10.1. "Patent Claims" means any patent claim(s), now owned or - hereafter acquired, including without limitation, method, process, - and apparatus claims, in any patent Licensable by grantor. - - 1.11. "Source Code" means the preferred form of the Covered Code for - making modifications to it, including all modules it contains, plus - any associated interface definition files, scripts used to control - compilation and installation of an Executable, or source code - differential comparisons against either the Original Code or another - well known, available Covered Code of the Contributor's choice. The - Source Code can be in a compressed or archival form, provided the - appropriate decompression or de-archiving software is widely available - for no charge. - - 1.12. "You" (or "Your") means an individual or a legal entity - exercising rights under, and complying with all of the terms of, this - License or a future version of this License issued under Section 6.1. - For legal entities, "You" includes any entity which controls, is - controlled by, or is under common control with You. For purposes of - this definition, "control" means (a) the power, direct or indirect, - to cause the direction or management of such entity, whether by - contract or otherwise, or (b) ownership of more than fifty percent - (50%) of the outstanding shares or beneficial ownership of such - entity. - -2. Source Code License. - - 2.1. The Initial Developer Grant. - The Initial Developer hereby grants You a world-wide, royalty-free, - non-exclusive license, subject to third party intellectual property - claims: - (a) under intellectual property rights (other than patent or - trademark) Licensable by Initial Developer to use, reproduce, - modify, display, perform, sublicense and distribute the Original - Code (or portions thereof) with or without Modifications, and/or - as part of a Larger Work; and - - (b) under Patents Claims infringed by the making, using or - selling of Original Code, to make, have made, use, practice, - sell, and offer for sale, and/or otherwise dispose of the - Original Code (or portions thereof). - - (c) the licenses granted in this Section 2.1(a) and (b) are - effective on the date Initial Developer first distributes - Original Code under the terms of this License. - - (d) Notwithstanding Section 2.1(b) above, no patent license is - granted: 1) for code that You delete from the Original Code; 2) - separate from the Original Code; or 3) for infringements caused - by: i) the modification of the Original Code or ii) the - combination of the Original Code with other software or devices. - - 2.2. Contributor Grant. - Subject to third party intellectual property claims, each Contributor - hereby grants You a world-wide, royalty-free, non-exclusive license - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Contributor, to use, reproduce, modify, - display, perform, sublicense and distribute the Modifications - created by such Contributor (or portions thereof) either on an - unmodified basis, with other Modifications, as Covered Code - and/or as part of a Larger Work; and - - (b) under Patent Claims infringed by the making, using, or - selling of Modifications made by that Contributor either alone - and/or in combination with its Contributor Version (or portions - of such combination), to make, use, sell, offer for sale, have - made, and/or otherwise dispose of: 1) Modifications made by that - Contributor (or portions thereof); and 2) the combination of - Modifications made by that Contributor with its Contributor - Version (or portions of such combination). - - (c) the licenses granted in Sections 2.2(a) and 2.2(b) are - effective on the date Contributor first makes Commercial Use of - the Covered Code. - - (d) Notwithstanding Section 2.2(b) above, no patent license is - granted: 1) for any code that Contributor has deleted from the - Contributor Version; 2) separate from the Contributor Version; - 3) for infringements caused by: i) third party modifications of - Contributor Version or ii) the combination of Modifications made - by that Contributor with other software (except as part of the - Contributor Version) or other devices; or 4) under Patent Claims - infringed by Covered Code in the absence of Modifications made by - that Contributor. - -3. Distribution Obligations. - - 3.1. Application of License. - The Modifications which You create or to which You contribute are - governed by the terms of this License, including without limitation - Section 2.2. The Source Code version of Covered Code may be - distributed only under the terms of this License or a future version - of this License released under Section 6.1, and You must include a - copy of this License with every copy of the Source Code You - distribute. You may not offer or impose any terms on any Source Code - version that alters or restricts the applicable version of this - License or the recipients' rights hereunder. However, You may include - an additional document offering the additional rights described in - Section 3.5. - - 3.2. Availability of Source Code. - Any Modification which You create or to which You contribute must be - made available in Source Code form under the terms of this License - either on the same media as an Executable version or via an accepted - Electronic Distribution Mechanism to anyone to whom you made an - Executable version available; and if made available via Electronic - Distribution Mechanism, must remain available for at least twelve (12) - months after the date it initially became available, or at least six - (6) months after a subsequent version of that particular Modification - has been made available to such recipients. You are responsible for - ensuring that the Source Code version remains available even if the - Electronic Distribution Mechanism is maintained by a third party. - - 3.3. Description of Modifications. - You must cause all Covered Code to which You contribute to contain a - file documenting the changes You made to create that Covered Code and - the date of any change. You must include a prominent statement that - the Modification is derived, directly or indirectly, from Original - Code provided by the Initial Developer and including the name of the - Initial Developer in (a) the Source Code, and (b) in any notice in an - Executable version or related documentation in which You describe the - origin or ownership of the Covered Code. - - 3.4. Intellectual Property Matters - - (a) Third Party Claims. - If Contributor has knowledge that a license under a third party's - intellectual property rights is required to exercise the rights - granted by such Contributor under Sections 2.1 or 2.2, - Contributor must include a text file with the Source Code - distribution titled "LEGAL" which describes the claim and the - party making the claim in sufficient detail that a recipient will - know whom to contact. If Contributor obtains such knowledge after - the Modification is made available as described in Section 3.2, - Contributor shall promptly modify the LEGAL file in all copies - Contributor makes available thereafter and shall take other steps - (such as notifying appropriate mailing lists or newsgroups) - reasonably calculated to inform those who received the Covered - Code that new knowledge has been obtained. - - (b) Contributor APIs. - If Contributor's Modifications include an application programming - interface and Contributor has knowledge of patent licenses which - are reasonably necessary to implement that API, Contributor must - also include this information in the LEGAL file. - - (c) Representations. - Contributor represents that, except as disclosed pursuant to - Section 3.4(a) above, Contributor believes that Contributor's - Modifications are Contributor's original creation(s) and/or - Contributor has sufficient rights to grant the rights conveyed by - this License. - - 3.5. Required Notices. - You must duplicate the notice in Exhibit A in each file of the Source - Code. If it is not possible to put such notice in a particular Source - Code file due to its structure, then You must include such notice in a - location (such as a relevant directory) where a user would be likely - to look for such a notice. If You created one or more Modification(s) - You may add your name as a Contributor to the notice described in - Exhibit A. You must also duplicate this License in any documentation - for the Source Code where You describe recipients' rights or ownership - rights relating to Covered Code. You may choose to offer, and to - charge a fee for, warranty, support, indemnity or liability - obligations to one or more recipients of Covered Code. However, You - may do so only on Your own behalf, and not on behalf of the Initial - Developer or any Contributor. You must make it absolutely clear than - any such warranty, support, indemnity or liability obligation is - offered by You alone, and You hereby agree to indemnify the Initial - Developer and every Contributor for any liability incurred by the - Initial Developer or such Contributor as a result of warranty, - support, indemnity or liability terms You offer. - - 3.6. Distribution of Executable Versions. - You may distribute Covered Code in Executable form only if the - requirements of Section 3.1-3.5 have been met for that Covered Code, - and if You include a notice stating that the Source Code version of - the Covered Code is available under the terms of this License, - including a description of how and where You have fulfilled the - obligations of Section 3.2. The notice must be conspicuously included - in any notice in an Executable version, related documentation or - collateral in which You describe recipients' rights relating to the - Covered Code. You may distribute the Executable version of Covered - Code or ownership rights under a license of Your choice, which may - contain terms different from this License, provided that You are in - compliance with the terms of this License and that the license for the - Executable version does not attempt to limit or alter the recipient's - rights in the Source Code version from the rights set forth in this - License. If You distribute the Executable version under a different - license You must make it absolutely clear that any terms which differ - from this License are offered by You alone, not by the Initial - Developer or any Contributor. You hereby agree to indemnify the - Initial Developer and every Contributor for any liability incurred by - the Initial Developer or such Contributor as a result of any such - terms You offer. - - 3.7. Larger Works. - You may create a Larger Work by combining Covered Code with other code - not governed by the terms of this License and distribute the Larger - Work as a single product. In such a case, You must make sure the - requirements of this License are fulfilled for the Covered Code. - -4. Inability to Comply Due to Statute or Regulation. - - If it is impossible for You to comply with any of the terms of this - License with respect to some or all of the Covered Code due to - statute, judicial order, or regulation then You must: (a) comply with - the terms of this License to the maximum extent possible; and (b) - describe the limitations and the code they affect. Such description - must be included in the LEGAL file described in Section 3.4 and must - be included with all distributions of the Source Code. Except to the - extent prohibited by statute or regulation, such description must be - sufficiently detailed for a recipient of ordinary skill to be able to - understand it. - -5. Application of this License. - - This License applies to code to which the Initial Developer has - attached the notice in Exhibit A and to related Covered Code. - -6. Versions of the License. - - 6.1. New Versions. - Netscape Communications Corporation ("Netscape") may publish revised - and/or new versions of the License from time to time. Each version - will be given a distinguishing version number. - - 6.2. Effect of New Versions. - Once Covered Code has been published under a particular version of the - License, You may always continue to use it under the terms of that - version. You may also choose to use such Covered Code under the terms - of any subsequent version of the License published by Netscape. No one - other than Netscape has the right to modify the terms applicable to - Covered Code created under this License. - - 6.3. Derivative Works. - If You create or use a modified version of this License (which you may - only do in order to apply it to code which is not already Covered Code - governed by this License), You must (a) rename Your license so that - the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", - "MPL", "NPL" or any confusingly similar phrase do not appear in your - license (except to note that your license differs from this License) - and (b) otherwise make it clear that Your version of the license - contains terms which differ from the Mozilla Public License and - Netscape Public License. (Filling in the name of the Initial - Developer, Original Code or Contributor in the notice described in - Exhibit A shall not of themselves be deemed to be modifications of - this License.) - -7. DISCLAIMER OF WARRANTY. - - COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, - WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF - DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. - THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE - IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, - YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE - COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER - OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF - ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. - -8. TERMINATION. - - 8.1. This License and the rights granted hereunder will terminate - automatically if You fail to comply with terms herein and fail to cure - such breach within 30 days of becoming aware of the breach. All - sublicenses to the Covered Code which are properly granted shall - survive any termination of this License. Provisions which, by their - nature, must remain in effect beyond the termination of this License - shall survive. - - 8.2. If You initiate litigation by asserting a patent infringement - claim (excluding declatory judgment actions) against Initial Developer - or a Contributor (the Initial Developer or Contributor against whom - You file such action is referred to as "Participant") alleging that: - - (a) such Participant's Contributor Version directly or indirectly - infringes any patent, then any and all rights granted by such - Participant to You under Sections 2.1 and/or 2.2 of this License - shall, upon 60 days notice from Participant terminate prospectively, - unless if within 60 days after receipt of notice You either: (i) - agree in writing to pay Participant a mutually agreeable reasonable - royalty for Your past and future use of Modifications made by such - Participant, or (ii) withdraw Your litigation claim with respect to - the Contributor Version against such Participant. If within 60 days - of notice, a reasonable royalty and payment arrangement are not - mutually agreed upon in writing by the parties or the litigation claim - is not withdrawn, the rights granted by Participant to You under - Sections 2.1 and/or 2.2 automatically terminate at the expiration of - the 60 day notice period specified above. - - (b) any software, hardware, or device, other than such Participant's - Contributor Version, directly or indirectly infringes any patent, then - any rights granted to You by such Participant under Sections 2.1(b) - and 2.2(b) are revoked effective as of the date You first made, used, - sold, distributed, or had made, Modifications made by that - Participant. - - 8.3. If You assert a patent infringement claim against Participant - alleging that such Participant's Contributor Version directly or - indirectly infringes any patent where such claim is resolved (such as - by license or settlement) prior to the initiation of patent - infringement litigation, then the reasonable value of the licenses - granted by such Participant under Sections 2.1 or 2.2 shall be taken - into account in determining the amount or value of any payment or - license. - - 8.4. In the event of termination under Sections 8.1 or 8.2 above, - all end user license agreements (excluding distributors and resellers) - which have been validly granted by You or any distributor hereunder - prior to termination shall survive termination. - -9. LIMITATION OF LIABILITY. - - UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT - (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL - DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, - OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR - ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY - CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, - WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER - COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN - INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF - LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY - RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW - PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE - EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO - THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. - -10. U.S. GOVERNMENT END USERS. - - The Covered Code is a "commercial item," as that term is defined in - 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer - software" and "commercial computer software documentation," as such - terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 - C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), - all U.S. Government End Users acquire Covered Code with only those - rights set forth herein. - -11. MISCELLANEOUS. - - This License represents the complete agreement concerning subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. This License shall be governed by - California law provisions (except to the extent applicable law, if - any, provides otherwise), excluding its conflict-of-law provisions. - With respect to disputes in which at least one party is a citizen of, - or an entity chartered or registered to do business in the United - States of America, any litigation relating to this License shall be - subject to the jurisdiction of the Federal Courts of the Northern - District of California, with venue lying in Santa Clara County, - California, with the losing party responsible for costs, including - without limitation, court costs and reasonable attorneys' fees and - expenses. The application of the United Nations Convention on - Contracts for the International Sale of Goods is expressly excluded. - Any law or regulation which provides that the language of a contract - shall be construed against the drafter shall not apply to this - License. - -12. RESPONSIBILITY FOR CLAIMS. - - As between Initial Developer and the Contributors, each party is - responsible for claims and damages arising, directly or indirectly, - out of its utilization of rights under this License and You agree to - work with Initial Developer and Contributors to distribute such - responsibility on an equitable basis. Nothing herein is intended or - shall be deemed to constitute any admission of liability. - -13. MULTIPLE-LICENSED CODE. - - Initial Developer may designate portions of the Covered Code as - "Multiple-Licensed". "Multiple-Licensed" means that the Initial - Developer permits you to utilize portions of the Covered Code under - Your choice of the NPL or the alternative licenses, if any, specified - by the Initial Developer in the file described in Exhibit A. - -EXHIBIT A -Mozilla Public License. - - ``The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - - The Original Code is ______________________________________. - - The Initial Developer of the Original Code is ________________________. - Portions created by ______________________ are Copyright (C) ______ - _______________________. All Rights Reserved. - - Contributor(s): ______________________________________. - - Alternatively, the contents of this file may be used under the terms - of the _____ license (the "[___] License"), in which case the - provisions of [______] License are applicable instead of those - above. If you wish to allow use of your version of this file only - under the terms of the [____] License and not to allow others to use - your version of this file under the MPL, indicate your decision by - deleting the provisions above and replace them with the notice and - other provisions required by the [___] License. If you do not delete - the provisions above, a recipient may use your version of this file - under either the MPL or the [___] License." - - [NOTE: The text of this Exhibit A may differ slightly from the text of - the notices in the Source Code files of the Original Code. You should - use the text of this Exhibit A rather than the text found in the - Original Code Source Code for Your Modifications.] +Mozilla Public License Version 2.0 +================================== +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. \ No newline at end of file diff --git a/LocalTestRun.testrunconfig b/LocalTestRun.testrunconfig index b066323e..72f80404 100644 --- a/LocalTestRun.testrunconfig +++ b/LocalTestRun.testrunconfig @@ -2,7 +2,7 @@ This is a default test run configuration for a local test run. - + diff --git a/MakeRelease.cmd b/MakeRelease.cmd index cbbb987d..c5c8952c 100644 --- a/MakeRelease.cmd +++ b/MakeRelease.cmd @@ -1,5 +1 @@ -msbuild OpenMcdf.sln /property:Configuration=Release -robocopy ./src NEW_RELEASE/src /MIR /xd bin obj -robocopy ./src/bin/Release NEW_RELEASE *.* -robocopy "./Structured Storage Explorer\bin\Release" NEW_RELEASE\StructuredStorageExplorer\ StucturedStorageExplorer.exe Be.Windows.Forms.HexBox.dll OpenMcdf.dll -robocopy ./ NEW_RELEASE "PRE_RELEASE_note.txt" "Release notes.txt" "Support.txt" "License.txt" \ No newline at end of file +msbuild OpenMcdf.sln /property:Configuration=Release \ No newline at end of file diff --git a/OpenMcdf.sln b/OpenMcdf.sln index 796e741a..5ec4a440 100644 --- a/OpenMcdf.sln +++ b/OpenMcdf.sln @@ -1,44 +1,47 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.21005.1 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6C619B4F-100F-4D60-BEF1-60B770D24E5E}" ProjectSection(SolutionItems) = preProject LocalTestRun.testrunconfig = LocalTestRun.testrunconfig OpenMcdf.vsmdi = OpenMcdf.vsmdi - OpenMcdf2.vsmdi = OpenMcdf2.vsmdi EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestFiles", "TestFiles", "{AC082D72-85BB-4FE8-AE0A-DB12A5729317}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestFiles", "TestFiles", "{8DC8730A-F254-4848-B272-BDFFCB5FDC00}" ProjectSection(SolutionItems) = preProject - TestFiles\2_MB-W.ppt = TestFiles\2_MB-W.ppt - TestFiles\_thumbs_bug_24.db = TestFiles\_thumbs_bug_24.db - TestFiles\BUG_16_.xls = TestFiles\BUG_16_.xls - TestFiles\CorruptedDoc_bug3547815.doc = TestFiles\CorruptedDoc_bug3547815.doc - TestFiles\CorruptedDoc_bug3547815_B.doc = TestFiles\CorruptedDoc_bug3547815_B.doc - TestFiles\CyclicFAT.cfs = TestFiles\CyclicFAT.cfs - TestFiles\MultipleStorage.cfs = TestFiles\MultipleStorage.cfs - TestFiles\MultipleStorage2.cfs = TestFiles\MultipleStorage2.cfs - TestFiles\MultipleStorage3.cfs = TestFiles\MultipleStorage3.cfs - TestFiles\MultipleStorage4.cfs = TestFiles\MultipleStorage4.cfs - TestFiles\report.xls = TestFiles\report.xls - TestFiles\report_name_fix.xls = TestFiles\report_name_fix.xls + sources\TestFiles\2_MB-W.ppt = sources\TestFiles\2_MB-W.ppt + sources\TestFiles\_thumbs_bug_24.db = sources\TestFiles\_thumbs_bug_24.db + sources\TestFiles\BUG_16_.xls = sources\TestFiles\BUG_16_.xls + sources\TestFiles\CorruptedDoc_bug3547815.doc = sources\TestFiles\CorruptedDoc_bug3547815.doc + sources\TestFiles\CorruptedDoc_bug3547815_B.doc = sources\TestFiles\CorruptedDoc_bug3547815_B.doc + sources\TestFiles\CyclicFAT.cfs = sources\TestFiles\CyclicFAT.cfs + sources\TestFiles\MultipleStorage.cfs = sources\TestFiles\MultipleStorage.cfs + sources\TestFiles\MultipleStorage2.cfs = sources\TestFiles\MultipleStorage2.cfs + sources\TestFiles\MultipleStorage3.cfs = sources\TestFiles\MultipleStorage3.cfs + sources\TestFiles\MultipleStorage4.cfs = sources\TestFiles\MultipleStorage4.cfs + sources\TestFiles\report.xls = sources\TestFiles\report.xls + sources\TestFiles\report_name_fix.xls = sources\TestFiles\report_name_fix.xls + sources\TestFiles\reportREAD.xls = sources\TestFiles\reportREAD.xls + sources\TestFiles\testbad.ole = sources\TestFiles\testbad.ole EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMcdf", "src\OpenMcdf.csproj", "{56E15D4A-8A37-4C7C-BB44-FD59AFF220C1}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMcdf", "sources\OpenMcdf\OpenMcdf.csproj", "{56E15D4A-8A37-4C7C-BB44-FD59AFF220C1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMcdfMemTest", "Memory Test\OpenMcdfMemTest.csproj", "{E2BAD82D-3040-462B-BAA2-6E608A9054F4}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMcdf.Extensions", "sources\OpenMcdf.Extensions\OpenMcdf.Extensions.csproj", "{DB748C1D-D71C-442B-832D-2E33BE816CBB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMcdfPerfTest", "Performance Test\OpenMcdfPerfTest.csproj", "{7077508F-B313-4DF6-8855-4764911BE161}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StructuredStorageExplorer", "sources\Structured Storage Explorer\StructuredStorageExplorer.csproj", "{4F6323A8-9C06-4D94-808F-EBD69B8370D7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMcdfTest", "Unit Test\OpenMcdfTest.csproj", "{FD339266-8842-40B4-9230-F8E84FC42AC2}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{73814657-FC73-4066-AABD-86062F2A132E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StructuredStorageExplorer", "Structured Storage Explorer\StructuredStorageExplorer.csproj", "{4F6323A8-9C06-4D94-808F-EBD69B8370D7}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMcdf.Extensions.Test", "sources\Test\OpenMcdf.Extensions.Test\OpenMcdf.Extensions.Test.csproj", "{B9CB103F-0AA3-486D-9C9C-672924B6169C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMcdf.Extensions", "OpenMcdf.Extensions\OpenMcdf.Extensions.csproj", "{DB748C1D-D71C-442B-832D-2E33BE816CBB}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMcdf.MemTest", "sources\Test\OpenMcdf.MemTest\OpenMcdf.MemTest.csproj", "{E2BAD82D-3040-462B-BAA2-6E608A9054F4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMcdfExtensionsTest", "OpenMcdfExtensionsTest\OpenMcdfExtensionsTest.csproj", "{B9CB103F-0AA3-486D-9C9C-672924B6169C}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMcdf.PerfTest", "sources\Test\OpenMcdf.PerfTest\OpenMcdf.PerfTest.csproj", "{7077508F-B313-4DF6-8855-4764911BE161}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenMcdf.Test", "sources\Test\OpenMcdf.Test\OpenMcdf.Test.csproj", "{FD339266-8842-40B4-9230-F8E84FC42AC2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -50,6 +53,18 @@ Global {56E15D4A-8A37-4C7C-BB44-FD59AFF220C1}.Debug|Any CPU.Build.0 = Debug|Any CPU {56E15D4A-8A37-4C7C-BB44-FD59AFF220C1}.Release|Any CPU.ActiveCfg = Release|Any CPU {56E15D4A-8A37-4C7C-BB44-FD59AFF220C1}.Release|Any CPU.Build.0 = Release|Any CPU + {DB748C1D-D71C-442B-832D-2E33BE816CBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB748C1D-D71C-442B-832D-2E33BE816CBB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB748C1D-D71C-442B-832D-2E33BE816CBB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB748C1D-D71C-442B-832D-2E33BE816CBB}.Release|Any CPU.Build.0 = Release|Any CPU + {4F6323A8-9C06-4D94-808F-EBD69B8370D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4F6323A8-9C06-4D94-808F-EBD69B8370D7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4F6323A8-9C06-4D94-808F-EBD69B8370D7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4F6323A8-9C06-4D94-808F-EBD69B8370D7}.Release|Any CPU.Build.0 = Release|Any CPU + {B9CB103F-0AA3-486D-9C9C-672924B6169C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B9CB103F-0AA3-486D-9C9C-672924B6169C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B9CB103F-0AA3-486D-9C9C-672924B6169C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B9CB103F-0AA3-486D-9C9C-672924B6169C}.Release|Any CPU.Build.0 = Release|Any CPU {E2BAD82D-3040-462B-BAA2-6E608A9054F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E2BAD82D-3040-462B-BAA2-6E608A9054F4}.Debug|Any CPU.Build.0 = Debug|Any CPU {E2BAD82D-3040-462B-BAA2-6E608A9054F4}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -62,24 +77,16 @@ Global {FD339266-8842-40B4-9230-F8E84FC42AC2}.Debug|Any CPU.Build.0 = Debug|Any CPU {FD339266-8842-40B4-9230-F8E84FC42AC2}.Release|Any CPU.ActiveCfg = Release|Any CPU {FD339266-8842-40B4-9230-F8E84FC42AC2}.Release|Any CPU.Build.0 = Release|Any CPU - {4F6323A8-9C06-4D94-808F-EBD69B8370D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4F6323A8-9C06-4D94-808F-EBD69B8370D7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4F6323A8-9C06-4D94-808F-EBD69B8370D7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4F6323A8-9C06-4D94-808F-EBD69B8370D7}.Release|Any CPU.Build.0 = Release|Any CPU - {DB748C1D-D71C-442B-832D-2E33BE816CBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DB748C1D-D71C-442B-832D-2E33BE816CBB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DB748C1D-D71C-442B-832D-2E33BE816CBB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DB748C1D-D71C-442B-832D-2E33BE816CBB}.Release|Any CPU.Build.0 = Release|Any CPU - {B9CB103F-0AA3-486D-9C9C-672924B6169C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B9CB103F-0AA3-486D-9C9C-672924B6169C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B9CB103F-0AA3-486D-9C9C-672924B6169C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B9CB103F-0AA3-486D-9C9C-672924B6169C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {AC082D72-85BB-4FE8-AE0A-DB12A5729317} = {6C619B4F-100F-4D60-BEF1-60B770D24E5E} + {8DC8730A-F254-4848-B272-BDFFCB5FDC00} = {73814657-FC73-4066-AABD-86062F2A132E} + {B9CB103F-0AA3-486D-9C9C-672924B6169C} = {73814657-FC73-4066-AABD-86062F2A132E} + {E2BAD82D-3040-462B-BAA2-6E608A9054F4} = {73814657-FC73-4066-AABD-86062F2A132E} + {7077508F-B313-4DF6-8855-4764911BE161} = {73814657-FC73-4066-AABD-86062F2A132E} + {FD339266-8842-40B4-9230-F8E84FC42AC2} = {73814657-FC73-4066-AABD-86062F2A132E} EndGlobalSection GlobalSection(TestCaseManagementSettings) = postSolution CategoryFile = OpenMcdf2.vsmdi diff --git a/Html Help/OpenMcdfHelp.shfbproj b/sources/Html Help/OpenMcdfHelp.shfbproj similarity index 69% rename from Html Help/OpenMcdfHelp.shfbproj rename to sources/Html Help/OpenMcdfHelp.shfbproj index 658fb826..969ca075 100644 --- a/Html Help/OpenMcdfHelp.shfbproj +++ b/sources/Html Help/OpenMcdfHelp.shfbproj @@ -1,4 +1,5 @@ - + + Documentation @@ -16,14 +17,14 @@ .\Help\ OpenMCDF - Copyright 2010 - 2012 &#169%3b Federico Blaseotto + Copyright 2010 - 2015 &#169%3b Federico Blaseotto Open MCDF Open MCDF Open MCDF Summary, AutoDocumentCtors - - + + ironfede%40users.sourceforge.net @@ -53,6 +54,22 @@ 1.5.4.0 Hierarchical + 2 + False + Standard + Blank + False + False + Guid + AboveNamespaces + OnlyWarningsAndErrors + Website + False + .NET Framework 4.0 + True + False + False + True diff --git a/OpenMcdf.Extensions/CFStreamExtensions.cs b/sources/OpenMcdf.Extensions/CFStreamExtensions.cs similarity index 100% rename from OpenMcdf.Extensions/CFStreamExtensions.cs rename to sources/OpenMcdf.Extensions/CFStreamExtensions.cs diff --git a/OpenMcdf.Extensions/OpenMcdf.Extensions.csproj b/sources/OpenMcdf.Extensions/OpenMcdf.Extensions.csproj similarity index 76% rename from OpenMcdf.Extensions/OpenMcdf.Extensions.csproj rename to sources/OpenMcdf.Extensions/OpenMcdf.Extensions.csproj index 25e3accd..329b2b13 100644 --- a/OpenMcdf.Extensions/OpenMcdf.Extensions.csproj +++ b/sources/OpenMcdf.Extensions/OpenMcdf.Extensions.csproj @@ -17,18 +17,27 @@ true full false - bin\Debug\ + ..\..\bin\Debug\OpenMcdf.Extensions\ DEBUG;TRACE prompt 4 + ..\..\bin\Debug\OpenMcdf.Extensions\OpenMcdf.Extensions.XML pdbonly true - bin\Release\ + ..\..\bin\Release\OpenMcdf.Extensions\ TRACE prompt 4 + ..\..\bin\Release\OpenMcdf.Extensions\OpenMcdf.Extensions.XML + + + false + + + + @@ -44,8 +53,8 @@ - - {56E15D4A-8A37-4C7C-BB44-FD59AFF220C1} + + {56e15d4a-8a37-4c7c-bb44-fd59aff220c1} OpenMcdf diff --git a/sources/OpenMcdf.Extensions/OpenMcdf.Extensions.csproj.user b/sources/OpenMcdf.Extensions/OpenMcdf.Extensions.csproj.user new file mode 100644 index 00000000..1efe784d --- /dev/null +++ b/sources/OpenMcdf.Extensions/OpenMcdf.Extensions.csproj.user @@ -0,0 +1,6 @@ + + + + ProjectFiles + + \ No newline at end of file diff --git a/OpenMcdf.Extensions/Properties/AssemblyInfo.cs b/sources/OpenMcdf.Extensions/Properties/AssemblyInfo.cs similarity index 100% rename from OpenMcdf.Extensions/Properties/AssemblyInfo.cs rename to sources/OpenMcdf.Extensions/Properties/AssemblyInfo.cs diff --git a/src/CFException.cs b/sources/OpenMcdf/CFException.cs similarity index 84% rename from src/CFException.cs rename to sources/OpenMcdf/CFException.cs index b806dac5..196d45d1 100644 --- a/src/CFException.cs +++ b/sources/OpenMcdf/CFException.cs @@ -1,24 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Text; +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The Original Code is OpenMCDF - Compound Document Format library. + * + * The Initial Developer of the Original Code is Federico Blaseotto.*/ + +using System; using System.Runtime.Serialization; -/* - The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - - The Original Code is OpenMCDF - Compound Document Format library. - - The Initial Developer of the Original Code is Federico Blaseotto. -*/ - namespace OpenMcdf { /// diff --git a/src/CFItem.cs b/sources/OpenMcdf/CFItem.cs similarity index 87% rename from src/CFItem.cs rename to sources/OpenMcdf/CFItem.cs index 0aaacc4c..06ba3885 100644 --- a/src/CFItem.cs +++ b/sources/OpenMcdf/CFItem.cs @@ -1,23 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Text; - -/* - The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - - The Original Code is OpenMCDF - Compound Document Format library. - - The Initial Developer of the Original Code is Federico Blaseotto. -*/ - + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The Original Code is OpenMCDF - Compound Document Format library. + * + * The Initial Developer of the Original Code is Federico Blaseotto.*/ + +using System; namespace OpenMcdf { diff --git a/src/CFStorage.cs b/sources/OpenMcdf/CFStorage.cs similarity index 80% rename from src/CFStorage.cs rename to sources/OpenMcdf/CFStorage.cs index aec365af..a19d13c2 100644 --- a/src/CFStorage.cs +++ b/sources/OpenMcdf/CFStorage.cs @@ -1,24 +1,16 @@ -using System; -using System.Collections.Generic; -using System.Text; -using RedBlackTree; -using System.Diagnostics; - -/* - The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The Original Code is OpenMCDF - Compound Document Format library. + * + * The Initial Developer of the Original Code is Federico Blaseotto.*/ - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - The Original Code is OpenMCDF - Compound Document Format library. +using System; +using System.Collections.Generic; +using RedBlackTree; - The Initial Developer of the Original Code is Federico Blaseotto. -*/ namespace OpenMcdf { @@ -64,11 +56,12 @@ internal RBTree Children // Lazy loading of children tree. if (children == null) { - if (this.CompoundFile.HasSourceStream) - { - children = LoadChildren(this.DirEntry.SID); - } - else + //if (this.CompoundFile.HasSourceStream) + //{ + children = LoadChildren(this.DirEntry.SID); + //} + //else + if (children == null) { children = this.CompoundFile.CreateNewTree(); } @@ -206,6 +199,51 @@ public CFStream GetStream(String streamName) } } + + /// + /// Get a named stream contained in the current storage if existing. + /// + /// Name of the stream to look for + /// A stream reference if found, else null + /// Raised if trying to delete item from a closed compound file + /// + /// + /// String filename = "report.xls"; + /// + /// CompoundFile cf = new CompoundFile(filename); + /// CFStream foundStream = cf.RootStorage.TryGetStream("Workbook"); + /// + /// byte[] temp = foundStream.GetData(); + /// + /// Assert.IsNotNull(temp); + /// + /// cf.Close(); + /// + /// + public CFStream TryGetStream(String streamName) + { + CheckDisposed(); + + IDirectoryEntry tmp = DirectoryEntry.Mock(streamName, StgType.StgStream); + + //if (children == null) + //{ + // children = compoundFile.GetChildrenTree(SID); + //} + + IRBNode outDe = null; + + if (Children.TryLookup(tmp, out outDe) && (((IDirectoryEntry)outDe).StgType == StgType.StgStream)) + { + return new CFStream(this.CompoundFile, (IDirectoryEntry)outDe); + } + else + { + return null; + } + } + + /// /// Get a named storage contained in the current one if existing. /// @@ -242,6 +280,41 @@ public CFStorage GetStorage(String storageName) } } + /// + /// Get a named storage contained in the current one if existing. + /// + /// Name of the storage to look for + /// A storage reference if found else null + /// Raised if trying to delete item from a closed compound file + /// + /// + /// + /// String FILENAME = "MultipleStorage2.cfs"; + /// CompoundFile cf = new CompoundFile(FILENAME, UpdateMode.ReadOnly, false, false); + /// + /// CFStorage st = cf.RootStorage.TryGetStorage("MyStorage"); + /// + /// Assert.IsNotNull(st); + /// cf.Close(); + /// + /// + public CFStorage TryGetStorage(String storageName) + { + CheckDisposed(); + + IDirectoryEntry template = DirectoryEntry.Mock(storageName, StgType.StgInvalid); + IRBNode outDe = null; + + if (Children.TryLookup(template, out outDe) && ((IDirectoryEntry)outDe).StgType == StgType.StgStorage) + { + return new CFStorage(this.CompoundFile, outDe as IDirectoryEntry); + } + else + { + return null; + } + } + /// /// Create new child storage directory inside the current storage. @@ -392,7 +465,7 @@ public void Delete(String entryName) if (((IDirectoryEntry)foundObj).StgType == StgType.StgRoot) throw new CFException("Root storage cannot be removed"); - + IRBNode altDel = null; switch (((IDirectoryEntry)foundObj).StgType) { @@ -407,6 +480,9 @@ public void Delete(String entryName) temp.Delete(ded.Name); } + + + // ...then we need to rethread the root of siblings tree... if (this.Children.Root != null) this.DirEntry.Child = (this.Children.Root as IDirectoryEntry).SID; @@ -433,7 +509,7 @@ public void Delete(String entryName) CompoundFile.FreeAssociatedData((foundObj as IDirectoryEntry).SID); // Remove item from children tree - this.Children.Delete(foundObj,out altDel); + this.Children.Delete(foundObj, out altDel); // Rethread the root of siblings tree... if (this.Children.Root != null) @@ -450,7 +526,7 @@ public void Delete(String entryName) this.CompoundFile.InvalidateDirectoryEntry(((IDirectoryEntry)foundObj).SID); - + break; } diff --git a/src/CFStream.cs b/sources/OpenMcdf/CFStream.cs similarity index 90% rename from src/CFStream.cs rename to sources/OpenMcdf/CFStream.cs index 509f05d5..80544d45 100644 --- a/src/CFStream.cs +++ b/sources/OpenMcdf/CFStream.cs @@ -1,23 +1,15 @@ -using System; -using System.Collections.Generic; -using System.Text; +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The Original Code is OpenMCDF - Compound Document Format library. + * + * The Initial Developer of the Original Code is Federico Blaseotto.*/ + +using System; using System.IO; -/* - The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/ - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - - The Original Code is OpenMCDF - Compound Document Format library. - - The Initial Developer of the Original Code is Federico Blaseotto. -*/ namespace OpenMcdf { diff --git a/src/CompoundFile.cs b/sources/OpenMcdf/CompoundFile.cs similarity index 96% rename from src/CompoundFile.cs rename to sources/OpenMcdf/CompoundFile.cs index 01ac3327..4f708b18 100644 --- a/src/CompoundFile.cs +++ b/sources/OpenMcdf/CompoundFile.cs @@ -1,30 +1,17 @@ -/* - The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - - The Original Code is OpenMCDF - Compound Document Format library. - - The Initial Developer of the Original Code is Federico Blaseotto. -*/ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The Original Code is OpenMCDF - Compound Document Format library. + * + * The Initial Developer of the Original Code is Federico Blaseotto.*/ #define FLAT_WRITE // No optimization on the number of write operations using System; using System.Collections.Generic; -using System.Text; using System.IO; -using System.Collections; -using System.Security.AccessControl; -using System.Threading; using RedBlackTree; -using System.Diagnostics; namespace OpenMcdf { diff --git a/src/Directory.cs b/sources/OpenMcdf/Directory.cs similarity index 100% rename from src/Directory.cs rename to sources/OpenMcdf/Directory.cs diff --git a/src/DirectoryEntry.cs b/sources/OpenMcdf/DirectoryEntry.cs similarity index 91% rename from src/DirectoryEntry.cs rename to sources/OpenMcdf/DirectoryEntry.cs index 90c95c9f..818c6b70 100644 --- a/src/DirectoryEntry.cs +++ b/sources/OpenMcdf/DirectoryEntry.cs @@ -1,24 +1,15 @@ -using System; +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The Original Code is OpenMCDF - Compound Document Format library. + * + * The Initial Developer of the Original Code is Federico Blaseotto.*/ + +using System; using System.Collections.Generic; using System.Text; using System.IO; -using System.Globalization; - -/* - The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - - The Original Code is OpenMCDF - Compound Document Format library. - - The Initial Developer of the Original Code is Federico Blaseotto. -*/ namespace OpenMcdf { @@ -38,7 +29,7 @@ public enum StgColor : int Black = 1 } - public class DirectoryEntry : IDirectoryEntry + internal class DirectoryEntry : IDirectoryEntry { internal const int THIS_IS_GREATER = 1; internal const int OTHER_IS_GREATER = -1; @@ -559,7 +550,7 @@ internal static IDirectoryEntry TryNew(String name, StgType stgType, IListtrue full false - bin\Debug\ + ..\..\bin\Debug\OpenMcdf\ DEBUG;TRACE prompt 4 - bin\Debug\OpenMcdf.xml + ..\..\bin\Debug\OpenMcdf\OpenMcdf.xml 1591,1592,1573,1571,1570,1572 AllRules.ruleset pdbonly true - bin\Release\ + ..\..\bin\Release\OpenMcdf\ TRACE prompt 4 - bin\Release\OpenMcdf.xml + ..\..\bin\Release\OpenMcdf\OpenMcdf.xml 1591,1592,1573,1571,1570,1572 AllRules.ruleset + + false + + + + + - - - diff --git a/src/OpenMcdfClassDiagram.cd b/sources/OpenMcdf/OpenMcdfClassDiagram.cd similarity index 100% rename from src/OpenMcdfClassDiagram.cd rename to sources/OpenMcdf/OpenMcdfClassDiagram.cd diff --git a/src/Properties/AssemblyInfo.cs b/sources/OpenMcdf/Properties/AssemblyInfo.cs similarity index 89% rename from src/Properties/AssemblyInfo.cs rename to sources/OpenMcdf/Properties/AssemblyInfo.cs index 1d73da04..f9830460 100644 --- a/src/Properties/AssemblyInfo.cs +++ b/sources/OpenMcdf/Properties/AssemblyInfo.cs @@ -9,8 +9,8 @@ [assembly: AssemblyDescription("MS Compound File Storage .NET Implementation")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Federico Blaseotto")] -[assembly: AssemblyProduct("OpenMcdf 2.0 beta 1")] -[assembly: AssemblyCopyright("Copyright © 2010-2014, Federico Blaseotto")] +[assembly: AssemblyProduct("OpenMcdf 2.0")] +[assembly: AssemblyCopyright("Copyright © 2010-2015, Federico Blaseotto")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -34,5 +34,5 @@ // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("2.0.*")] -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("OpenMcdfTest")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("OpenMcdf.Test")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("OpenMcdf.Extensions")] \ No newline at end of file diff --git a/src/RBTree/RBTree.cs b/sources/OpenMcdf/RBTree/RBTree.cs similarity index 100% rename from src/RBTree/RBTree.cs rename to sources/OpenMcdf/RBTree/RBTree.cs diff --git a/src/Sector.cs b/sources/OpenMcdf/Sector.cs similarity index 80% rename from src/Sector.cs rename to sources/OpenMcdf/Sector.cs index 4807f7c6..48f410e9 100644 --- a/src/Sector.cs +++ b/sources/OpenMcdf/Sector.cs @@ -1,25 +1,15 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Collections; -using System.IO; -using System.Collections.Specialized; - -/* - The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The Original Code is OpenMCDF - Compound Document Format library. + * + * The Initial Developer of the Original Code is Federico Blaseotto.*/ - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - The Original Code is OpenMCDF - Compound Document Format library. +using System; +using System.IO; - The Initial Developer of the Original Code is Federico Blaseotto. -*/ namespace OpenMcdf { diff --git a/src/SectorCollection.cs b/sources/OpenMcdf/SectorCollection.cs similarity index 89% rename from src/SectorCollection.cs rename to sources/OpenMcdf/SectorCollection.cs index df4ad902..0212d591 100644 --- a/src/SectorCollection.cs +++ b/sources/OpenMcdf/SectorCollection.cs @@ -1,9 +1,16 @@ -using System; +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The Original Code is OpenMCDF - Compound Document Format library. + * + * The Initial Developer of the Original Code is Federico Blaseotto.*/ + +using System; using System.Text; using System.Collections; using System.Collections.Generic; - namespace OpenMcdf { /// diff --git a/src/StreamRW.cs b/sources/OpenMcdf/StreamRW.cs similarity index 87% rename from src/StreamRW.cs rename to sources/OpenMcdf/StreamRW.cs index 4f853a59..557d7b71 100644 --- a/src/StreamRW.cs +++ b/sources/OpenMcdf/StreamRW.cs @@ -1,4 +1,12 @@ -using System; +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The Original Code is OpenMCDF - Compound Document Format library. + * + * The Initial Developer of the Original Code is Federico Blaseotto.*/ + +using System; using System.Collections.Generic; using System.Text; using System.IO; diff --git a/src/StreamView.cs b/sources/OpenMcdf/StreamView.cs similarity index 90% rename from src/StreamView.cs rename to sources/OpenMcdf/StreamView.cs index fa38d9e3..f3afad7b 100644 --- a/src/StreamView.cs +++ b/sources/OpenMcdf/StreamView.cs @@ -1,4 +1,13 @@ -using System; +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The Original Code is OpenMCDF - Compound Document Format library. + * + * The Initial Developer of the Original Code is Federico Blaseotto.*/ + + +using System; using System.Collections.Generic; using System.Text; using System.Collections; @@ -6,22 +15,6 @@ using System.Collections.Specialized; using System.Diagnostics; -/* - The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - - The Original Code is OpenMCDF - Compound Document Format library. - - The Initial Developer of the Original Code is Federico Blaseotto. -*/ - namespace OpenMcdf { /// diff --git a/Structured Storage Explorer/InputBox.cs b/sources/Structured Storage Explorer/InputBox.cs similarity index 100% rename from Structured Storage Explorer/InputBox.cs rename to sources/Structured Storage Explorer/InputBox.cs diff --git a/Structured Storage Explorer/MainForm.Designer.cs b/sources/Structured Storage Explorer/MainForm.Designer.cs similarity index 100% rename from Structured Storage Explorer/MainForm.Designer.cs rename to sources/Structured Storage Explorer/MainForm.Designer.cs diff --git a/Structured Storage Explorer/MainForm.cs b/sources/Structured Storage Explorer/MainForm.cs similarity index 100% rename from Structured Storage Explorer/MainForm.cs rename to sources/Structured Storage Explorer/MainForm.cs diff --git a/Structured Storage Explorer/MainForm.resx b/sources/Structured Storage Explorer/MainForm.resx similarity index 100% rename from Structured Storage Explorer/MainForm.resx rename to sources/Structured Storage Explorer/MainForm.resx diff --git a/Structured Storage Explorer/Program.cs b/sources/Structured Storage Explorer/Program.cs similarity index 100% rename from Structured Storage Explorer/Program.cs rename to sources/Structured Storage Explorer/Program.cs diff --git a/Structured Storage Explorer/Properties/AssemblyInfo.cs b/sources/Structured Storage Explorer/Properties/AssemblyInfo.cs similarity index 93% rename from Structured Storage Explorer/Properties/AssemblyInfo.cs rename to sources/Structured Storage Explorer/Properties/AssemblyInfo.cs index 531ad50c..ac92070f 100644 --- a/Structured Storage Explorer/Properties/AssemblyInfo.cs +++ b/sources/Structured Storage Explorer/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("StucturedStorageExplorer")] -[assembly: AssemblyCopyright("Copyright © 2010-2011, Federico Blaseotto")] +[assembly: AssemblyCopyright("Copyright © 2010-2015, Federico Blaseotto")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/Structured Storage Explorer/Properties/Resources.Designer.cs b/sources/Structured Storage Explorer/Properties/Resources.Designer.cs similarity index 100% rename from Structured Storage Explorer/Properties/Resources.Designer.cs rename to sources/Structured Storage Explorer/Properties/Resources.Designer.cs diff --git a/Structured Storage Explorer/Properties/Resources.resx b/sources/Structured Storage Explorer/Properties/Resources.resx similarity index 100% rename from Structured Storage Explorer/Properties/Resources.resx rename to sources/Structured Storage Explorer/Properties/Resources.resx diff --git a/Structured Storage Explorer/Properties/Settings.Designer.cs b/sources/Structured Storage Explorer/Properties/Settings.Designer.cs similarity index 100% rename from Structured Storage Explorer/Properties/Settings.Designer.cs rename to sources/Structured Storage Explorer/Properties/Settings.Designer.cs diff --git a/Structured Storage Explorer/Properties/Settings.settings b/sources/Structured Storage Explorer/Properties/Settings.settings similarity index 100% rename from Structured Storage Explorer/Properties/Settings.settings rename to sources/Structured Storage Explorer/Properties/Settings.settings diff --git a/Structured Storage Explorer/StreamDataProvider.cs b/sources/Structured Storage Explorer/StreamDataProvider.cs similarity index 100% rename from Structured Storage Explorer/StreamDataProvider.cs rename to sources/Structured Storage Explorer/StreamDataProvider.cs diff --git a/Structured Storage Explorer/StructuredStorageExplorer.csproj b/sources/Structured Storage Explorer/StructuredStorageExplorer.csproj similarity index 86% rename from Structured Storage Explorer/StructuredStorageExplorer.csproj rename to sources/Structured Storage Explorer/StructuredStorageExplorer.csproj index 076dceb9..c82777a8 100644 --- a/Structured Storage Explorer/StructuredStorageExplorer.csproj +++ b/sources/Structured Storage Explorer/StructuredStorageExplorer.csproj @@ -37,20 +37,30 @@ true full false - bin\Debug\ + ..\..\bin\Debug\StructuredStorageXplorer\ DEBUG;TRACE prompt 4 AllRules.ruleset + false + ..\..\bin\Debug\StructuredStorageXplorer\StucturedStorageExplorer.XML pdbonly true - bin\Release\ + ..\..\bin\Release\StructuredStorageXplorer\ TRACE prompt 4 AllRules.ruleset + ..\..\bin\Release\StructuredStorageXplorer\StucturedStorageExplorer.XML + + + false + + + + @@ -107,12 +117,6 @@ - - - {56E15D4A-8A37-4C7C-BB44-FD59AFF220C1} - OpenMcdf - - False @@ -133,6 +137,12 @@ + + + {56e15d4a-8a37-4c7c-bb44-fd59aff220c1} + OpenMcdf + + Documentation @@ -23,8 +23,8 @@ Open MCDF Summary, AutoDocumentCtors - - + + ironfede%40users.sourceforge.net @@ -36,7 +36,7 @@ - Prototype + VS2013 en-US @@ -52,18 +52,18 @@ - 1.5.4.0 + 2.0 Hierarchical 2 False - Standard + C# Blank False False Guid AboveNamespaces OnlyWarningsAndErrors - Website + HtmlHelp1 False .NET Framework 4.0 True From 695d35cafd0834f27938cb248e476c8ea491237b Mon Sep 17 00:00:00 2001 From: ironfede Date: Sat, 3 Oct 2015 19:55:03 +0000 Subject: [PATCH 15/18] Fixed bug 31 (NullReference Exception when adding same name stream). Added test for fix. Rebooted version number for 2.0.1 (no more auto build number increment). --- .../Properties/AssemblyInfo.cs | 5 +- sources/OpenMcdf/CFStorage.cs | 6 +-- sources/OpenMcdf/Properties/AssemblyInfo.cs | 2 +- sources/Test/OpenMcdf.Test/CFSTorageTest.cs | 50 ++++++++++++++----- 4 files changed, 44 insertions(+), 19 deletions(-) diff --git a/sources/OpenMcdf.Extensions/Properties/AssemblyInfo.cs b/sources/OpenMcdf.Extensions/Properties/AssemblyInfo.cs index 0426b51b..cc869928 100644 --- a/sources/OpenMcdf.Extensions/Properties/AssemblyInfo.cs +++ b/sources/OpenMcdf.Extensions/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("-")] [assembly: AssemblyProduct("OpenMcdf.Extensions")] -[assembly: AssemblyCopyright("Copyright © - 2013")] +[assembly: AssemblyCopyright("Copyright © Federico Blaseotto, 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,5 +32,4 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("2.0.*")] diff --git a/sources/OpenMcdf/CFStorage.cs b/sources/OpenMcdf/CFStorage.cs index a19d13c2..552b2276 100644 --- a/sources/OpenMcdf/CFStorage.cs +++ b/sources/OpenMcdf/CFStorage.cs @@ -129,7 +129,7 @@ public CFStream AddStream(String streamName) if (String.IsNullOrEmpty(streamName)) throw new CFException("Stream name cannot be null or empty"); - CFStream cfo = null; + IDirectoryEntry dirEntry = DirectoryEntry.TryNew(streamName, StgType.StgStream, this.CompoundFile.GetDirectories()); @@ -146,8 +146,8 @@ public CFStream AddStream(String streamName) } catch (RBTreeException) { - CompoundFile.ResetDirectoryEntry(cfo.DirEntry.SID); - cfo = null; + CompoundFile.ResetDirectoryEntry(dirEntry.SID); + throw new CFDuplicatedItemException("An entry with name '" + streamName + "' is already present in storage '" + this.Name + "' "); } diff --git a/sources/OpenMcdf/Properties/AssemblyInfo.cs b/sources/OpenMcdf/Properties/AssemblyInfo.cs index f9830460..20a0a309 100644 --- a/sources/OpenMcdf/Properties/AssemblyInfo.cs +++ b/sources/OpenMcdf/Properties/AssemblyInfo.cs @@ -32,7 +32,7 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.0.*")] +[assembly: AssemblyVersion("2.0.1.*")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("OpenMcdf.Test")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("OpenMcdf.Extensions")] \ No newline at end of file diff --git a/sources/Test/OpenMcdf.Test/CFSTorageTest.cs b/sources/Test/OpenMcdf.Test/CFSTorageTest.cs index 7a5c425e..cb0b631e 100644 --- a/sources/Test/OpenMcdf.Test/CFSTorageTest.cs +++ b/sources/Test/OpenMcdf.Test/CFSTorageTest.cs @@ -16,7 +16,7 @@ public class CFSTorageTest public CFSTorageTest() { - + } private TestContext testContextInstance; @@ -97,7 +97,7 @@ public void Test_VISIT_ENTRIES() FileStream output = new FileStream("LogEntries.txt", FileMode.Create); TextWriter tw = new StreamWriter(output); - Action va = delegate(CFItem item) + Action va = delegate (CFItem item) { tw.WriteLine(item.Name); }; @@ -128,11 +128,12 @@ public void Test_TRY_GET_STREAM_STORAGE() Assert.Fail("Exception raised for try_get method"); } - try { - CFStream s = st.TryGetStream("MyStream"); - Assert.IsNotNull(s); - CFStream ns = st.TryGetStream("IDONTEXIST2"); - Assert.IsNull(ns); + try + { + CFStream s = st.TryGetStream("MyStream"); + Assert.IsNotNull(s); + CFStream ns = st.TryGetStream("IDONTEXIST2"); + Assert.IsNull(ns); } catch (Exception) { @@ -163,7 +164,7 @@ public void Test_VISIT_ENTRIES_CORRUPTED_FILE_VALIDATION_ON() using (TextWriter tw = new StreamWriter(output)) { - Action va = delegate(CFItem item) + Action va = delegate (CFItem item) { tw.WriteLine(item.Name); }; @@ -213,7 +214,7 @@ public void Test_VISIT_ENTRIES_CORRUPTED_FILE_VALIDATION_OFF_BUT_CAN_LOAD() using (TextWriter tw = new StreamWriter(output)) { - Action va = delegate(CFItem item) + Action va = delegate (CFItem item) { tw.WriteLine(item.Name); }; @@ -271,7 +272,7 @@ public void Test_VISIT_STORAGE() Console.SetOut(sw); - Action va = delegate(CFItem target) + Action va = delegate (CFItem target) { sw.WriteLine(target.Name); }; @@ -306,7 +307,7 @@ public void Test_DELETE_MINISTREAM_STREAM() CompoundFile cf = new CompoundFile(FILENAME); CFStorage found = null; - Action action = delegate(CFItem item) { if (item.Name == "AnotherStorage") found = item as CFStorage; }; + Action action = delegate (CFItem item) { if (item.Name == "AnotherStorage") found = item as CFStorage; }; cf.RootStorage.VisitEntries(action, true); Assert.IsNotNull(found); @@ -324,7 +325,7 @@ public void Test_DELETE_STREAM() CompoundFile cf = new CompoundFile(FILENAME); CFStorage found = null; - Action action = delegate(CFItem item) + Action action = delegate (CFItem item) { if (item.Name == "AnotherStorage") found = item as CFStorage; @@ -390,5 +391,30 @@ public void Test_LAZY_LOAD_CHILDREN_() File.Delete("$Hel2"); } } + + [TestMethod] + public void Test_FIX_BUG_31() + { + CompoundFile cf = new CompoundFile(); + cf.RootStorage.AddStorage("Level_1") + + .AddStream("Level2Stream") + .SetData(Helpers.GetBuffer(100)); + + cf.Save("$Hel1"); + + cf.Close(); + + CompoundFile cf1 = new CompoundFile("$Hel1"); + try + { + CFStream cs = cf1.RootStorage.GetStorage("Level_1").AddStream("Level2Stream"); + } + catch (Exception ex) + { + Assert.IsTrue(ex.GetType() == typeof(CFDuplicatedItemException)); + } + + } } } From bc675d536be42023b706f1f275a18b00489230c0 Mon Sep 17 00:00:00 2001 From: ironfede Date: Thu, 15 Dec 2016 23:00:10 +0000 Subject: [PATCH 16/18] Bug fix 36, corrupted doc not triggering CFCorruptedFileException --- OpenMcdf.sln | 3 ++- sources/OpenMcdf/CompoundFile.cs | 3 +++ sources/Test/OpenMcdf.Test/CFSTorageTest.cs | 9 +++++++++ sources/Test/TestFiles/CorruptedDoc_bug36.doc | Bin 0 -> 21137 bytes 4 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 sources/Test/TestFiles/CorruptedDoc_bug36.doc diff --git a/OpenMcdf.sln b/OpenMcdf.sln index 5ec4a440..4c7cf72e 100644 --- a/OpenMcdf.sln +++ b/OpenMcdf.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6C619B4F-100F-4D60-BEF1-60B770D24E5E}" ProjectSection(SolutionItems) = preProject @@ -16,6 +16,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestFiles", "TestFiles", "{ sources\TestFiles\BUG_16_.xls = sources\TestFiles\BUG_16_.xls sources\TestFiles\CorruptedDoc_bug3547815.doc = sources\TestFiles\CorruptedDoc_bug3547815.doc sources\TestFiles\CorruptedDoc_bug3547815_B.doc = sources\TestFiles\CorruptedDoc_bug3547815_B.doc + sources\Test\TestFiles\CorruptedDoc_bug36.doc = sources\Test\TestFiles\CorruptedDoc_bug36.doc sources\TestFiles\CyclicFAT.cfs = sources\TestFiles\CyclicFAT.cfs sources\TestFiles\MultipleStorage.cfs = sources\TestFiles\MultipleStorage.cfs sources\TestFiles\MultipleStorage2.cfs = sources\TestFiles\MultipleStorage2.cfs diff --git a/sources/OpenMcdf/CompoundFile.cs b/sources/OpenMcdf/CompoundFile.cs index 4f708b18..8516d936 100644 --- a/sources/OpenMcdf/CompoundFile.cs +++ b/sources/OpenMcdf/CompoundFile.cs @@ -1415,6 +1415,9 @@ StreamView fatStream { if (nextSecID == Sector.ENDOFCHAIN) break; + if (nextSecID < 0) + throw new CFCorruptedFileException(String.Format("Next Sector ID reference is below zero. NextID : {0}", nextSecID)); + if (nextSecID >= sectors.Count) throw new CFCorruptedFileException(String.Format("Next Sector ID reference an out of range sector. NextID : {0} while sector count {1}", nextSecID, sectors.Count)); diff --git a/sources/Test/OpenMcdf.Test/CFSTorageTest.cs b/sources/Test/OpenMcdf.Test/CFSTorageTest.cs index cb0b631e..d8f4bbb0 100644 --- a/sources/Test/OpenMcdf.Test/CFSTorageTest.cs +++ b/sources/Test/OpenMcdf.Test/CFSTorageTest.cs @@ -416,5 +416,14 @@ public void Test_FIX_BUG_31() } } + + [TestMethod] + [ExpectedException(typeof(OpenMcdf.CFCorruptedFileException))] + public void Test_CORRUPTEDDOC_BUG36_SHOULD_THROW_CORRUPTED_FILE_EXCEPTION() + { + using (CompoundFile file = new CompoundFile("CorruptedDoc_bug36.doc", CFSUpdateMode.ReadOnly, CFSConfiguration.NoValidationException) ) { + //Many thanks to theseus for bug reporting + } + } } } diff --git a/sources/Test/TestFiles/CorruptedDoc_bug36.doc b/sources/Test/TestFiles/CorruptedDoc_bug36.doc new file mode 100644 index 0000000000000000000000000000000000000000..ab9ed4a9730ed6069ba4848666f3b2b9bc91454a GIT binary patch literal 21137 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 U=)?U&;bzCeS1^(V{*)T{H{(wLwg3PC literal 0 HcmV?d00001 From 22efb7409090f62dc31bea154128a9f7113bda2b Mon Sep 17 00:00:00 2001 From: ironfede Date: Fri, 30 Dec 2016 14:28:28 +0000 Subject: [PATCH 17/18] Pre github migration, ver 2.1.0.33051 - bug fixing --- sources/Html Help/OpenMcdfHelp.shfbproj | 28 +- .../OpenMcdf.Extensions/CFStreamExtensions.cs | 14 + .../Interfaces/IBinarySerializable.cs | 14 + .../Interfaces/ITypedPropertyValue.cs | 34 + .../OLEProperties/PropertyFactory.cs | 310 +++ .../PropertyIdentifierAndOffset.cs | 13 + .../OLEProperties/PropertyReader.cs | 116 + .../OLEProperties/PropertySet.cs | 37 + .../OLEProperties/PropertySetStream.cs | 88 + .../OLEProperties/ProperyIdentifiers.cs | 118 + .../OLEProperties/TypedPropertyValue.cs | 74 + .../OLEProperties/VTPropertyType.cs | 45 + .../OLEProperties/VTVectorHeader.cs | 10 + .../OpenMcdf.Extensions.csproj | 23 +- .../Properties/AssemblyInfo.cs | 70 +- sources/OpenMcdf/CompoundFile.cs | 69 +- sources/OpenMcdf/Properties/AssemblyInfo.cs | 74 +- sources/OpenMcdf/RBTree/RBTree.cs | 1268 +++++----- sources/OpenMcdf/Sector.cs | 394 +-- sources/OpenMcdf/StreamView.cs | 739 +++--- .../Structured Storage Explorer/InputBox.cs | 106 +- .../MainForm.Designer.cs | 730 +++--- .../Structured Storage Explorer/MainForm.cs | 942 +++---- .../Structured Storage Explorer/MainForm.resx | 280 +-- .../Structured Storage Explorer/Program.cs | 40 +- .../Properties/AssemblyInfo.cs | 70 +- .../Properties/Resources.Designer.cs | 238 +- .../Properties/Resources.resx | 279 +-- .../Properties/Settings.Designer.cs | 76 +- .../Properties/Settings.settings | 16 +- .../StreamDataProvider.cs | 356 +-- .../StructuredStorageExplorer.csproj | 17 +- sources/Structured Storage Explorer/Utils.cs | 126 +- .../Structured Storage Explorer/app.config | 30 +- .../CFSStreamExtensionsTest.cs | 178 +- .../Test/OpenMcdf.Extensions.Test/Helpers.cs | 98 +- .../OpenMcdf.Extensions.Test.csproj | 16 +- .../Properties/AssemblyInfo.cs | 70 +- .../OpenMcdf.MemTest/OpenMcdf.MemTest.csproj | 196 +- sources/Test/OpenMcdf.MemTest/Program.cs | 650 ++--- .../Properties/AssemblyInfo.cs | 70 +- sources/Test/OpenMcdf.MemTest/app.config | 6 +- sources/Test/OpenMcdf.PerfTest/Helpers.cs | 102 +- .../OpenMcdf.PerfTest.csproj | 196 +- sources/Test/OpenMcdf.PerfTest/Program.cs | 82 +- .../Properties/AssemblyInfo.cs | 72 +- sources/Test/OpenMcdf.PerfTest/app.config | 6 +- sources/Test/OpenMcdf.Test/AuthoringTests.txt | 272 +-- sources/Test/OpenMcdf.Test/CFSStreamTest.cs | 2172 ++++++++--------- sources/Test/OpenMcdf.Test/CFSTorageTest.cs | 858 +++---- .../Test/OpenMcdf.Test/CompoundFileTest.cs | 20 +- sources/Test/OpenMcdf.Test/Helpers.cs | 112 +- .../Test/OpenMcdf.Test/OpenMcdf.Test.csproj | 238 +- .../OpenMcdf.Test/Properties/AssemblyInfo.cs | 68 +- sources/Test/OpenMcdf.Test/RBTreeTest.cs | 466 ++-- .../OpenMcdf.Test/SectorCollectionTest.cs | 396 +-- sources/Test/OpenMcdf.Test/StreamRWTest.cs | 104 +- sources/Test/TestFiles/BUG_16_.xls | Bin 31232 -> 31232 bytes 58 files changed, 7171 insertions(+), 6121 deletions(-) create mode 100644 sources/OpenMcdf.Extensions/OLEProperties/Interfaces/IBinarySerializable.cs create mode 100644 sources/OpenMcdf.Extensions/OLEProperties/Interfaces/ITypedPropertyValue.cs create mode 100644 sources/OpenMcdf.Extensions/OLEProperties/PropertyFactory.cs create mode 100644 sources/OpenMcdf.Extensions/OLEProperties/PropertyIdentifierAndOffset.cs create mode 100644 sources/OpenMcdf.Extensions/OLEProperties/PropertyReader.cs create mode 100644 sources/OpenMcdf.Extensions/OLEProperties/PropertySet.cs create mode 100644 sources/OpenMcdf.Extensions/OLEProperties/PropertySetStream.cs create mode 100644 sources/OpenMcdf.Extensions/OLEProperties/ProperyIdentifiers.cs create mode 100644 sources/OpenMcdf.Extensions/OLEProperties/TypedPropertyValue.cs create mode 100644 sources/OpenMcdf.Extensions/OLEProperties/VTPropertyType.cs create mode 100644 sources/OpenMcdf.Extensions/OLEProperties/VTVectorHeader.cs diff --git a/sources/Html Help/OpenMcdfHelp.shfbproj b/sources/Html Help/OpenMcdfHelp.shfbproj index 432f22fb..16775b96 100644 --- a/sources/Html Help/OpenMcdfHelp.shfbproj +++ b/sources/Html Help/OpenMcdfHelp.shfbproj @@ -1,15 +1,15 @@  - Debug AnyCPU 2.0 {6b2e0fe5-8246-4f87-9663-d72ebadfc53f} 2015.6.5.0 - Documentation Documentation @@ -17,14 +17,14 @@ .\Help\ OpenMCDF - Copyright 2010 - 2015 &#169%3b Federico Blaseotto + Copyright 2010 - 2016 &#169%3b Federico Blaseotto Open MCDF Open MCDF Open MCDF Summary, AutoDocumentCtors - - + + ironfede%40users.sourceforge.net @@ -44,15 +44,13 @@ InheritedMembers, InheritedFrameworkMembers - - - - - - - - 2.0 + + + + + + 2.1 Hierarchical 2 False @@ -71,7 +69,7 @@ False True - diff --git a/sources/OpenMcdf.Extensions/CFStreamExtensions.cs b/sources/OpenMcdf.Extensions/CFStreamExtensions.cs index 7b95ed9c..4e922089 100644 --- a/sources/OpenMcdf.Extensions/CFStreamExtensions.cs +++ b/sources/OpenMcdf.Extensions/CFStreamExtensions.cs @@ -121,5 +121,19 @@ public static Stream AsIOStream(this CFStream cfStream) { return new StreamDecorator(cfStream); } + + /// + /// Return the current CFStream object + /// as a OLE properties Stream. + /// + /// + /// A OLE Propertie stream + public static OLEProperties.PropertySetStream AsOLEProperties(this CFStream cfStream) + { + var result = new OLEProperties.PropertySetStream(); + result.Read(new BinaryReader(new StreamDecorator(cfStream))); + return result; + } + } } diff --git a/sources/OpenMcdf.Extensions/OLEProperties/Interfaces/IBinarySerializable.cs b/sources/OpenMcdf.Extensions/OLEProperties/Interfaces/IBinarySerializable.cs new file mode 100644 index 00000000..67966584 --- /dev/null +++ b/sources/OpenMcdf.Extensions/OLEProperties/Interfaces/IBinarySerializable.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace OpenMcdf.Extensions.OLEProperties.Interfaces +{ + public interface IBinarySerializable + { + void Write(BinaryWriter bw); + void Read(BinaryReader br); + } +} diff --git a/sources/OpenMcdf.Extensions/OLEProperties/Interfaces/ITypedPropertyValue.cs b/sources/OpenMcdf.Extensions/OLEProperties/Interfaces/ITypedPropertyValue.cs new file mode 100644 index 00000000..011bf8e2 --- /dev/null +++ b/sources/OpenMcdf.Extensions/OLEProperties/Interfaces/ITypedPropertyValue.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenMcdf.Extensions.OLEProperties.Interfaces +{ + public interface ITypedPropertyValue : IBinarySerializable + { + bool IsArray + { + get; + set; + } + + bool IsVector + { + get; + set; + } + + object PropertyValue + { + get; + set; + } + + VTPropertyType VTType + { + get; + //set; + } + } +} diff --git a/sources/OpenMcdf.Extensions/OLEProperties/PropertyFactory.cs b/sources/OpenMcdf.Extensions/OLEProperties/PropertyFactory.cs new file mode 100644 index 00000000..ebc0351b --- /dev/null +++ b/sources/OpenMcdf.Extensions/OLEProperties/PropertyFactory.cs @@ -0,0 +1,310 @@ +using OpenMcdf.Extensions.OLEProperties.Interfaces; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace OpenMcdf.Extensions.OLEProperties +{ + internal class PropertyFactory + { + private PropertyContext ctx; + + public PropertyFactory(PropertyContext ctx) + { + this.ctx = ctx; + } + + private PropertyFactory() + { + + } + + public ITypedPropertyValue NewProperty(VTPropertyType vType, PropertyContext ctx) + { + ITypedPropertyValue pr = null; + + switch (vType) + { + case VTPropertyType.VT_I2: + pr = new VT_I2_Property(vType); + break; + case VTPropertyType.VT_I4: + pr = new VT_I4_Property(vType); + break; + case VTPropertyType.VT_R4: + pr = new VT_R4_Property(vType); + break; + case VTPropertyType.VT_LPSTR: + pr = new VT_LPSTR_Property(vType, ctx.CodePage); + break; + case VTPropertyType.VT_FILETIME: + pr = new VT_FILETIME_Property(vType); + break; + case VTPropertyType.VT_DECIMAL: + pr = new VT_DECIMAL_Property(vType); + break; + case VTPropertyType.VT_BOOL: + pr = new VT_BOOL_Property(vType); + break; + case VTPropertyType.VT_VECTOR_HEADER: + pr = new VT_VectorHeader(vType); + break; + case VTPropertyType.VT_EMPTY: + pr = new VT_EMPTY_Property(vType); + break; + default: + throw new Exception("Unrecognized property type"); + } + + return pr; + } + + + #region Property implementations + private class VT_EMPTY_Property : TypedPropertyValue + { + public VT_EMPTY_Property(VTPropertyType vType) : base(vType) + { + + } + + public override void Read(System.IO.BinaryReader br) + { + this.propertyValue = null; + } + + public override void Write(System.IO.BinaryWriter bw) + { + + } + } + + private class VT_I2_Property : TypedPropertyValue + { + public VT_I2_Property(VTPropertyType vType) : base(vType) + { + + } + + public override void Read(System.IO.BinaryReader br) + { + this.propertyValue = br.ReadInt16(); + } + + public override void Write(System.IO.BinaryWriter bw) + { + bw.Write((short)propertyValue); + } + } + + private class VT_I4_Property : TypedPropertyValue + { + public VT_I4_Property(VTPropertyType vType) : base(vType) + { + + } + + public override void Read(System.IO.BinaryReader br) + { + this.propertyValue = br.ReadInt32(); + } + + public override void Write(System.IO.BinaryWriter bw) + { + bw.Write((int)propertyValue); + } + } + + private class VT_R4_Property : TypedPropertyValue + { + public VT_R4_Property(VTPropertyType vType) : base(vType) + { + + } + + public override void Read(System.IO.BinaryReader br) + { + this.propertyValue = br.ReadSingle(); + } + + public override void Write(System.IO.BinaryWriter bw) + { + bw.Write((Single)propertyValue); + } + } + + private class VT_R8_Property : TypedPropertyValue + { + public VT_R8_Property(VTPropertyType vType) : base(vType) + { + + } + + public override void Read(System.IO.BinaryReader br) + { + this.propertyValue = br.ReadDouble(); + } + + public override void Write(System.IO.BinaryWriter bw) + { + bw.Write((Double)propertyValue); + } + } + + private class VT_CY_Property : TypedPropertyValue + { + public VT_CY_Property(VTPropertyType vType) : base(vType) + { + } + + public override void Read(System.IO.BinaryReader br) + { + Int64 temp = br.ReadInt64(); + + this.propertyValue = (double)(temp /= 10000); + } + + public override void Write(System.IO.BinaryWriter bw) + { + bw.Write((Int64)propertyValue * 10000); + } + } + + private class VT_DATE_Property : TypedPropertyValue + { + public VT_DATE_Property(VTPropertyType vType) : base(vType) + { + + } + + public override void Read(System.IO.BinaryReader br) + { + Double temp = br.ReadDouble(); + + this.propertyValue = DateTime.FromOADate(temp); + } + + public override void Write(System.IO.BinaryWriter bw) + { + bw.Write(((DateTime)propertyValue).ToOADate()); + } + } + + private class VT_LPSTR_Property : TypedPropertyValue + { + private uint size = 0; + private byte[] data; + private int codePage; + + public VT_LPSTR_Property(VTPropertyType vType, int codePage) : base(vType) + { + this.codePage = codePage; + + } + + public override void Read(System.IO.BinaryReader br) + { + size = br.ReadUInt32(); + data = br.ReadBytes((int)size); + this.propertyValue = Encoding.GetEncoding(codePage).GetString(data); + int m = (int)size % 4; + br.ReadBytes(m); // padding + } + + public override void Write(System.IO.BinaryWriter bw) + { + data = Encoding.GetEncoding(codePage).GetBytes((String)propertyValue); + size = (uint)data.Length; + int m = (int)size % 4; + bw.Write(data); + for (int i = 0; i < m; i++) // padding + bw.Write(0); + } + } + + private class VT_FILETIME_Property : TypedPropertyValue + { + + public VT_FILETIME_Property(VTPropertyType vType) : base(vType) + { + + } + + public override void Read(System.IO.BinaryReader br) + { + Int64 tmp = br.ReadInt64(); + propertyValue = DateTime.FromFileTime(tmp); + } + + public override void Write(System.IO.BinaryWriter bw) + { + bw.Write(((DateTime)propertyValue).ToFileTime()); + } + } + + private class VT_DECIMAL_Property : TypedPropertyValue + { + + public VT_DECIMAL_Property(VTPropertyType vType) : base(vType) + { + + } + + public override void Read(System.IO.BinaryReader br) + { + Decimal d; + + br.ReadInt16(); // wReserved + byte scale = br.ReadByte(); + byte sign = br.ReadByte(); + + uint u = br.ReadUInt32(); + d = Convert.ToDecimal(Math.Pow(2, 64)) * u; + d += br.ReadUInt64(); + + if (sign != 0) + d = -d; + d /= (10 << scale); + + this.propertyValue = d; + } + + public override void Write(System.IO.BinaryWriter bw) + { + bw.Write((short)propertyValue); + } + } + + private class VT_BOOL_Property : TypedPropertyValue + { + public VT_BOOL_Property(VTPropertyType vType) : base(vType) + { + + } + + public override void Read(BinaryReader br) + { + this.propertyValue = br.ReadUInt16() == (ushort)0xFFFF ? true : false; + //br.ReadUInt16();//padding + } + } + + private class VT_VectorHeader : TypedPropertyValue + { + public VT_VectorHeader(VTPropertyType vType) : base(vType) + { + + } + + public override void Read(BinaryReader br) + { + propertyValue = br.ReadUInt32(); + } + } + + #endregion + + } +} diff --git a/sources/OpenMcdf.Extensions/OLEProperties/PropertyIdentifierAndOffset.cs b/sources/OpenMcdf.Extensions/OLEProperties/PropertyIdentifierAndOffset.cs new file mode 100644 index 00000000..588d4c5d --- /dev/null +++ b/sources/OpenMcdf.Extensions/OLEProperties/PropertyIdentifierAndOffset.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenMcdf.Extensions.OLEProperties +{ + public class PropertyIdentifierAndOffset + { + public PropertyIdentifiersSummaryInfo PropertyIdentifier { get; set; } + public uint Offset { get; set; } + } +} diff --git a/sources/OpenMcdf.Extensions/OLEProperties/PropertyReader.cs b/sources/OpenMcdf.Extensions/OLEProperties/PropertyReader.cs new file mode 100644 index 00000000..ccc643ad --- /dev/null +++ b/sources/OpenMcdf.Extensions/OLEProperties/PropertyReader.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using OpenMcdf.Extensions.OLEProperties.Interfaces; +using System.Collections; + +namespace OpenMcdf.Extensions.OLEProperties +{ + public enum Behavior + { + CaseSensitive, CaseInsensitive + } + + public class PropertyContext + { + + public Int32 CodePage { get; set; } + public Behavior Behavior { get; set; } + public UInt32 Locale { get; set; } + } + + public enum PropertyDimensions + { + IsScalar, IsVector, IsArray + } + + //public class PropertyResult + //{ + // public PropertyDimensions Dimensions { get; set; } + // public uint[] DimSizes { get; set; } + // public List DimValues { get; set; } + //} + + public class PropertyReader + { + + private PropertyContext ctx = new PropertyContext(); + private PropertyFactory factory = null; + + public PropertyReader() + { + factory = new PropertyFactory(ctx); + } + + public List ReadProperty(PropertyIdentifiersSummaryInfo propertyIdentifier, BinaryReader br) + { + List res = new List(); + bool isVariant = false; + PropertyDimensions dim = PropertyDimensions.IsScalar; + + UInt16 pVal = br.ReadUInt16(); + + VTPropertyType vType = (VTPropertyType)(pVal & 0x00FF); + + if ((pVal & 0x1000) != 0) + dim = PropertyDimensions.IsVector; + else if ((pVal & 0x2000) != 0) + dim = PropertyDimensions.IsArray; + + isVariant = ((pVal & 0x00FF) == 0x000C); + + br.ReadUInt16(); // Ushort Padding + + switch (dim) + { + case PropertyDimensions.IsVector: + + ITypedPropertyValue vectorHeader = factory.NewProperty(VTPropertyType.VT_VECTOR_HEADER, ctx); + vectorHeader.Read(br); + + uint nItems = (uint)vectorHeader.PropertyValue; + + for (int i = 0; i < nItems; i++) + { + VTPropertyType vTypeItem = VTPropertyType.VT_EMPTY; + + if (isVariant) + { + UInt16 pValItem = br.ReadUInt16(); + vTypeItem = (VTPropertyType)(pValItem & 0x00FF); + br.ReadUInt16(); // Ushort Padding + } + else + { + vTypeItem = vType; + } + + var p = factory.NewProperty(vTypeItem, ctx); + + p.Read(br); + res.Add(p); + } + + break; + default: + + //Scalar property + ITypedPropertyValue pr = factory.NewProperty(vType, ctx); + + pr.Read(br); + + if (propertyIdentifier == PropertyIdentifiersSummaryInfo.CodePageString) + { + this.ctx.CodePage = (short)pr.PropertyValue; + } + + res.Add(pr); + break; + } + + return res; + } + } +} diff --git a/sources/OpenMcdf.Extensions/OLEProperties/PropertySet.cs b/sources/OpenMcdf.Extensions/OLEProperties/PropertySet.cs new file mode 100644 index 00000000..d7014b25 --- /dev/null +++ b/sources/OpenMcdf.Extensions/OLEProperties/PropertySet.cs @@ -0,0 +1,37 @@ +using OpenMcdf.Extensions.OLEProperties.Interfaces; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenMcdf.Extensions.OLEProperties +{ + public class PropertySet + { + public uint Size { get; set; } + public uint NumProperties { get; set; } + + List propertyIdentifierAndOffsets + = new List(); + + public List PropertyIdentifierAndOffsets + { + get { return propertyIdentifierAndOffsets; } + set { propertyIdentifierAndOffsets = value; } + } + + List properties = new List(); + public List Properties + { + get + { + return properties; + } + set + { + properties = value; + } + } + + } +} diff --git a/sources/OpenMcdf.Extensions/OLEProperties/PropertySetStream.cs b/sources/OpenMcdf.Extensions/OLEProperties/PropertySetStream.cs new file mode 100644 index 00000000..1c1d3767 --- /dev/null +++ b/sources/OpenMcdf.Extensions/OLEProperties/PropertySetStream.cs @@ -0,0 +1,88 @@ +using OpenMcdf.Extensions.OLEProperties.Interfaces; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenMcdf.Extensions.OLEProperties +{ + public class PropertySetStream + { + public ushort ByteOrder { get; set; } + public ushort Version { get; set; } + public uint SystemIdentifier { get; set; } + public Guid CLSID { get; set; } + public uint NumPropertySets { get; set; } + public Guid FMTID0 { get; set; } + public uint Offset0 { get; set; } + public Guid FMTID1 { get; set; } + public uint Offset1 { get; set; } + public PropertySet PropertySet0 { get; set; } + public PropertySet PropertySet1 { get; set; } + + public void Read(System.IO.BinaryReader br) + { + ByteOrder = br.ReadUInt16(); + Version = br.ReadUInt16(); + SystemIdentifier = br.ReadUInt32(); + CLSID = new Guid(br.ReadBytes(16)); + NumPropertySets = br.ReadUInt32(); + FMTID0 = new Guid(br.ReadBytes(16)); + Offset0 = br.ReadUInt32(); + + if (NumPropertySets == 2) + { + FMTID1 = new Guid(br.ReadBytes(16)); + Offset1 = br.ReadUInt32(); + } + + PropertySet0 = new PropertySet(); + PropertySet0.Size = br.ReadUInt32(); + PropertySet0.NumProperties = br.ReadUInt32(); + + // Read property offsets + for (int i = 0; i < PropertySet0.NumProperties; i++) + { + PropertyIdentifierAndOffset pio = new PropertyIdentifierAndOffset(); + pio.PropertyIdentifier = (PropertyIdentifiersSummaryInfo)br.ReadUInt32(); + pio.Offset = br.ReadUInt32(); + PropertySet0.PropertyIdentifierAndOffsets.Add(pio); + } + + // Read properties + PropertyReader pr = new PropertyReader(); + for (int i = 0; i < PropertySet0.NumProperties; i++) + { + br.BaseStream.Seek(Offset0 + PropertySet0.PropertyIdentifierAndOffsets[i].Offset, System.IO.SeekOrigin.Begin); + PropertySet0.Properties.AddRange(pr.ReadProperty(PropertySet0.PropertyIdentifierAndOffsets[i].PropertyIdentifier, br)); + } + } + + public void Write(System.IO.BinaryWriter bw) + { + throw new NotImplementedException(); + } + + // private void LoadFromStream(Stream inStream) + // { + // BinaryReader br = new BinaryReader(inStream); + // PropertySetStream psStream = new PropertySetStream(); + // psStream.Read(br); + // br.Close(); + + // propertySets.Clear(); + + // if (psStream.NumPropertySets == 1) + // { + // propertySets.Add(psStream.PropertySet0); + // } + // else + // { + // propertySets.Add(psStream.PropertySet0); + // propertySets.Add(psStream.PropertySet1); + // } + + // return; + // } + } +} diff --git a/sources/OpenMcdf.Extensions/OLEProperties/ProperyIdentifiers.cs b/sources/OpenMcdf.Extensions/OLEProperties/ProperyIdentifiers.cs new file mode 100644 index 00000000..d5e3a4fa --- /dev/null +++ b/sources/OpenMcdf.Extensions/OLEProperties/ProperyIdentifiers.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenMcdf.Extensions.OLEProperties +{ + public enum PropertyIdentifiersSummaryInfo : uint + { + CodePageString = 0x00000001, + PIDSI_TITLE = 0x00000002, + PIDSI_SUBJECT = 0x00000003, + PIDSI_AUTHOR = 0x00000004, + PIDSI_KEYWORDS = 0x00000005, + PIDSI_COMMENTS = 0x00000006, + PIDSI_TEMPLATE = 0x00000007, + PIDSI_LASTAUTHOR = 0x00000008, + PIDSI_REVNUMBER = 0x00000009, + PIDSI_APPNAME = 0x00000012, + PIDSI_EDITTIME = 0x0000000A, + PIDSI_LASTPRINTED = 0x0000000B, + PIDSI_CREATE_DTM = 0x0000000C, + PIDSI_LASTSAVE_DTM = 0x0000000D, + PIDSI_PAGECOUNT = 0x0000000E, + PIDSI_WORDCOUNT = 0x0000000F, + PIDSI_CHARCOUNT = 0x00000010, + PIDSI_DOC_SECURITY = 0x00000013 + } + + public enum PropertyIdentifiersDocumentSummaryInfo : uint + { + CodePageString = 0x00000001, + PIDDSI_CATEGORY = 0x00000002, //Category VT_LPSTR + PIDDSI_PRESFORMAT = 0x00000003,//PresentationTarget VT_LPSTR + PIDDSI_BYTECOUNT = 0x00000004,//Bytes VT_I4 + PIDDSI_LINECOUNT = 0x00000005,// Lines VT_I4 + PIDDSI_PARCOUNT = 0x00000006,// Paragraphs VT_I4 + PIDDSI_SLIDECOUNT = 0x00000007,// Slides VT_I4 + PIDDSI_NOTECOUNT = 0x00000008,// Notes VT_I4 + PIDDSI_HIDDENCOUNT = 0x00000009,// HiddenSlides VT_I4 + PIDDSI_MMCLIPCOUNT = 0x0000000A,// MMClips VT_I4 + PIDDSI_SCALE = 0x0000000B,//ScaleCrop VT_BOOL + PIDDSI_HEADINGPAIR = 0x0000000C,// HeadingPairs VT_VARIANT | VT_VECTOR + PIDDSI_DOCPARTS = 0x0000000D,//TitlesofParts VT_VECTOR | VT_LPSTR + PIDDSI_MANAGER = 0x0000000E,// Manager VT_LPSTR + PIDDSI_COMPANY = 0x0000000F,// Company VT_LPSTR + PIDDSI_LINKSDIRTY = 0x00000010,//LinksUpToDate VT_BOOL + } + + public static class Extensions + { + public static String GetDescription(this PropertyIdentifiersSummaryInfo identifier) + { + switch (identifier) + { + case PropertyIdentifiersSummaryInfo.CodePageString: + return "CodePage"; + case PropertyIdentifiersSummaryInfo.PIDSI_TITLE: + return "Title"; + case PropertyIdentifiersSummaryInfo.PIDSI_SUBJECT: + return "Subject"; + case PropertyIdentifiersSummaryInfo.PIDSI_AUTHOR: + return "Author"; + case PropertyIdentifiersSummaryInfo.PIDSI_LASTAUTHOR: + return "Last Author"; + case PropertyIdentifiersSummaryInfo.PIDSI_APPNAME: + return "Application Name"; + case PropertyIdentifiersSummaryInfo.PIDSI_CREATE_DTM: + return "Create Time"; + case PropertyIdentifiersSummaryInfo.PIDSI_LASTSAVE_DTM: + return "Last Modified Time"; + case PropertyIdentifiersSummaryInfo.PIDSI_KEYWORDS: + return "Keywords"; + case PropertyIdentifiersSummaryInfo.PIDSI_DOC_SECURITY: + return "Document Security"; + default: return String.Empty; + } + } + + public static String GetDescription(this PropertyIdentifiersDocumentSummaryInfo identifier) + { + switch (identifier) + { + case PropertyIdentifiersDocumentSummaryInfo.CodePageString: + return "CodePage"; + case PropertyIdentifiersDocumentSummaryInfo.PIDDSI_CATEGORY: + return "Category"; + case PropertyIdentifiersDocumentSummaryInfo.PIDDSI_COMPANY: + return "Company"; + case PropertyIdentifiersDocumentSummaryInfo.PIDDSI_DOCPARTS: + return "Titles of Parts"; + case PropertyIdentifiersDocumentSummaryInfo.PIDDSI_HEADINGPAIR: + return "Heading Pairs"; + case PropertyIdentifiersDocumentSummaryInfo.PIDDSI_HIDDENCOUNT: + return "Hidden Slides"; + case PropertyIdentifiersDocumentSummaryInfo.PIDDSI_LINECOUNT: + return "Line Count"; + case PropertyIdentifiersDocumentSummaryInfo.PIDDSI_LINKSDIRTY: + return "Links up to date"; + case PropertyIdentifiersDocumentSummaryInfo.PIDDSI_MANAGER: + return "Manager"; + case PropertyIdentifiersDocumentSummaryInfo.PIDDSI_MMCLIPCOUNT: + return "MMClips"; + case PropertyIdentifiersDocumentSummaryInfo.PIDDSI_NOTECOUNT: + return "Notes"; + case PropertyIdentifiersDocumentSummaryInfo.PIDDSI_PARCOUNT: + return "Paragraphs"; + case PropertyIdentifiersDocumentSummaryInfo.PIDDSI_PRESFORMAT: + return "Presenteation Target"; + case PropertyIdentifiersDocumentSummaryInfo.PIDDSI_SCALE: + return "Scale"; + case PropertyIdentifiersDocumentSummaryInfo.PIDDSI_SLIDECOUNT: + return "Slides"; + default: return String.Empty; + } + } + } +} diff --git a/sources/OpenMcdf.Extensions/OLEProperties/TypedPropertyValue.cs b/sources/OpenMcdf.Extensions/OLEProperties/TypedPropertyValue.cs new file mode 100644 index 00000000..fd489451 --- /dev/null +++ b/sources/OpenMcdf.Extensions/OLEProperties/TypedPropertyValue.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenMcdf.Extensions.OLEProperties.Interfaces; + +namespace OpenMcdf.Extensions.OLEProperties +{ + public class TypedPropertyValue : ITypedPropertyValue, IBinarySerializable + { + private VTPropertyType _VTType; + + public VTPropertyType VTType + { + get { return _VTType; } + //set { _VTType = value; } + } + + protected object propertyValue = null; + public TypedPropertyValue(VTPropertyType vtType) + { + this._VTType = vtType; + } + public virtual object PropertyValue + { + get + { + return propertyValue; + } + + set + { + propertyValue = value; + } + } + + + public bool IsArray + { + get + { + throw new NotImplementedException(); + } + + set + { + throw new NotImplementedException(); + } + } + + public bool IsVector + { + get + { + throw new NotImplementedException(); + } + + set + { + throw new NotImplementedException(); + } + } + + public virtual void Read(System.IO.BinaryReader br) + { + + } + + public virtual void Write(System.IO.BinaryWriter bw) + { + + } + } +} diff --git a/sources/OpenMcdf.Extensions/OLEProperties/VTPropertyType.cs b/sources/OpenMcdf.Extensions/OLEProperties/VTPropertyType.cs new file mode 100644 index 00000000..14aa46fe --- /dev/null +++ b/sources/OpenMcdf.Extensions/OLEProperties/VTPropertyType.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenMcdf.Extensions.OLEProperties +{ + public enum VTPropertyType : ushort + { + VT_EMPTY = 0x0000, + VT_NULL = 0x0001, + VT_I2 = 0x0002, + VT_I4 = 0x0003, + VT_R4 = 0x0004, + VT_R8 = 0x0005, + VT_CY = 0x0006, + VT_DATE = 0x0007, + VT_BSTR = 0x0008, + VT_ERROR = 0x000A, + VT_BOOL = 0x000B, + VT_DECIMAL = 0x000E, + VT_I1 = 0x0010, + VT_UI1 = 0x0011, + VT_UI2 = 0x0012, + VT_UI4 = 0x0013, + VT_I8 = 0x0014, // MUST be an 8-byte signed integer. + VT_UI8 = 0x0015, // MUST be an 8-byte unsigned integer. + VT_INT = 0x0016, // MUST be a 4-byte signed integer. + VT_UINT = 0x0017, // MUST be a 4-byte unsigned integer. + VT_LPSTR = 0x001E, // MUST be a CodePageString. + VT_LPWSTR = 0x001F, // MUST be a UnicodeString. + VT_FILETIME = 0x0040, // MUST be a FILETIME (Packet Version). + VT_BLOB = 0x0041, // MUST be a BLOB. + VT_STREAM = 0x0042, // MUST be an IndirectPropertyName. The storage representing the (non-simple) property set MUST have a stream element with this name. + VT_STORAGE = 0x0043, // MUST be an IndirectPropertyName. The storage representing the (non-simple) property set MUST have a storage element with this name. + VT_STREAMED_OBJECT = 0x0044, // MUST be an IndirectPropertyName. The storage representing the (non-simple) property set MUST have a stream element with this name. + VT_STORED_OBJECT = 0x0045, // MUST be an IndirectPropertyName. The storage representing the (non-simple) property set MUST have a storage element with this name. + VT_BLOB_OBJECT = 0x0046, //MUST be a BLOB. + VT_CF = 0x0047, //MUST be a ClipboardData. + VT_CLSID = 0x0048, //MUST be a GUID (Packet Version) + VT_VERSIONED_STREAM = 0x0049, //MUST be a Verisoned Stream, NOT allowed in simple property + VT_VECTOR_HEADER =0x1000, //--- NOT NORMATIVE + VT_ARRAY_HEADER = 0x2000, //--- NOT NORMATIVE + } +} diff --git a/sources/OpenMcdf.Extensions/OLEProperties/VTVectorHeader.cs b/sources/OpenMcdf.Extensions/OLEProperties/VTVectorHeader.cs new file mode 100644 index 00000000..0cabf687 --- /dev/null +++ b/sources/OpenMcdf.Extensions/OLEProperties/VTVectorHeader.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace OpenMcdf.Extensions.OLEProperties +{ + +} diff --git a/sources/OpenMcdf.Extensions/OpenMcdf.Extensions.csproj b/sources/OpenMcdf.Extensions/OpenMcdf.Extensions.csproj index 329b2b13..a2278fca 100644 --- a/sources/OpenMcdf.Extensions/OpenMcdf.Extensions.csproj +++ b/sources/OpenMcdf.Extensions/OpenMcdf.Extensions.csproj @@ -50,6 +50,17 @@ + + + + + + + + + + + @@ -59,11 +70,11 @@ - \ No newline at end of file diff --git a/sources/OpenMcdf.Extensions/Properties/AssemblyInfo.cs b/sources/OpenMcdf.Extensions/Properties/AssemblyInfo.cs index cc869928..43f70fc1 100644 --- a/sources/OpenMcdf.Extensions/Properties/AssemblyInfo.cs +++ b/sources/OpenMcdf.Extensions/Properties/AssemblyInfo.cs @@ -1,35 +1,35 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenMcdf.Extensions")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("-")] -[assembly: AssemblyProduct("OpenMcdf.Extensions")] -[assembly: AssemblyCopyright("Copyright © Federico Blaseotto, 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("a514ea5e-b163-4a07-b742-fc4f91c6cbb0")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.0.*")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenMcdf.Extensions")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("-")] +[assembly: AssemblyProduct("OpenMcdf.Extensions")] +[assembly: AssemblyCopyright("Copyright © Federico Blaseotto, 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a514ea5e-b163-4a07-b742-fc4f91c6cbb0")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("2.0.*")] diff --git a/sources/OpenMcdf/CompoundFile.cs b/sources/OpenMcdf/CompoundFile.cs index 8516d936..698ac9e8 100644 --- a/sources/OpenMcdf/CompoundFile.cs +++ b/sources/OpenMcdf/CompoundFile.cs @@ -59,7 +59,13 @@ public enum CFSConfiguration /// This can possibly lead to a security issue but gives /// a chance to corrupted files to load. /// - NoValidationException = 8 + NoValidationException = 8, + + /// + /// If this flag is set true, + /// backing stream is kept open after CompoundFile disposal + /// + LeaveOpen = 16, } /// @@ -413,6 +419,7 @@ public CompoundFile(Stream stream, CFSUpdateMode updateMode, CFSConfiguration co this.validationExceptionEnabled = !configParameters.HasFlag(CFSConfiguration.NoValidationException); this.sectorRecycle = configParameters.HasFlag(CFSConfiguration.SectorRecycle); this.eraseFreeSectors = configParameters.HasFlag(CFSConfiguration.EraseFreeSectors); + this.closeStream = !configParameters.HasFlag(CFSConfiguration.LeaveOpen); this.updateMode = updateMode; LoadStream(stream); @@ -688,7 +695,7 @@ private void Load(Stream stream) } catch (Exception) { - if (stream != null) + if (stream != null && closeStream) stream.Close(); throw; @@ -760,6 +767,7 @@ StreamView miniStreamView miniStream, GetSectorSize(), this.rootStorage.Size, + null, sourceStream); for (int i = 0; i < miniSectorChain.Count; i++) @@ -793,7 +801,9 @@ StreamView miniFATView miniFAT, GetSectorSize(), header.MiniFATSectorsNumber * Sector.MINISECTOR_SIZE, - this.sourceStream + null, + this.sourceStream, + true ); StreamView miniStreamView @@ -801,6 +811,7 @@ StreamView miniStreamView miniStream, GetSectorSize(), this.rootStorage.Size, + null, sourceStream); @@ -886,7 +897,7 @@ List FAT = GetSectorChain(-1, SectorType.FAT); StreamView FATView - = new StreamView(FAT, GetSectorSize(), FAT.Count * GetSectorSize(), sourceStream); + = new StreamView(FAT, GetSectorSize(), FAT.Count * GetSectorSize(), null, sourceStream); // Zeroes out sector data (if required)------------- if (zeroSector) @@ -931,10 +942,10 @@ List miniStream = GetSectorChain(RootEntry.StartSetc, SectorType.Normal); StreamView miniFATView - = new StreamView(miniFAT, GetSectorSize(), header.MiniFATSectorsNumber * Sector.MINISECTOR_SIZE, sourceStream); + = new StreamView(miniFAT, GetSectorSize(), header.MiniFATSectorsNumber * Sector.MINISECTOR_SIZE, null, sourceStream); StreamView miniStreamView - = new StreamView(miniStream, GetSectorSize(), this.rootStorage.Size, sourceStream); + = new StreamView(miniStream, GetSectorSize(), this.rootStorage.Size, null, sourceStream); // Set updated/new sectors within the ministream ---------- if (zeroSector) @@ -1014,6 +1025,7 @@ private void SetSectorChain(List sectorChain) /// The new or updated generic sector chain private void AllocateSectorChain(List sectorChain) { + foreach (Sector s in sectorChain) { if (s.Id == -1) @@ -1061,7 +1073,10 @@ private void AllocateFATSectorChain(List sectorChain) new StreamView( fatSectors, GetSectorSize(), - header.FATSectorsNumber * GetSectorSize(), sourceStream + header.FATSectorsNumber * GetSectorSize(), + null, + sourceStream, + true ); // Write FAT chain values -- @@ -1219,7 +1234,7 @@ StreamView difatStream // Mark DIFAT Sectors in FAT StreamView fatSv = - new StreamView(FATsectorChain, GetSectorSize(), header.FATSectorsNumber * GetSectorSize(), sourceStream); + new StreamView(FATsectorChain, GetSectorSize(), header.FATSectorsNumber * GetSectorSize(), null, sourceStream); for (int i = 0; i < header.DIFATSectorsNumber; i++) { @@ -1352,6 +1367,7 @@ StreamView difatStream header.FATSectorsNumber > N_HEADER_FAT_ENTRY ? (header.FATSectorsNumber - N_HEADER_FAT_ENTRY) * 4 : 0, + null, sourceStream ); @@ -1409,7 +1425,7 @@ List result List fatSectors = GetFatSectorChain(); StreamView fatStream - = new StreamView(fatSectors, GetSectorSize(), fatSectors.Count * GetSectorSize(), sourceStream); + = new StreamView(fatSectors, GetSectorSize(), fatSectors.Count * GetSectorSize(), null, sourceStream); while (true) { @@ -1463,10 +1479,10 @@ List result List miniStream = GetNormalSectorChain(RootEntry.StartSetc); StreamView miniFATView - = new StreamView(miniFAT, GetSectorSize(), header.MiniFATSectorsNumber * Sector.MINISECTOR_SIZE, sourceStream); + = new StreamView(miniFAT, GetSectorSize(), header.MiniFATSectorsNumber * Sector.MINISECTOR_SIZE, null, sourceStream); StreamView miniStreamView = - new StreamView(miniStream, GetSectorSize(), rootStorage.Size, sourceStream); + new StreamView(miniStream, GetSectorSize(), rootStorage.Size, null, sourceStream); BinaryReader miniFATReader = new BinaryReader(miniFATView); @@ -1776,7 +1792,7 @@ List directoryChain header.FirstDirectorySectorID = directoryChain[0].Id; StreamView dirReader - = new StreamView(directoryChain, GetSectorSize(), directoryChain.Count * GetSectorSize(), sourceStream); + = new StreamView(directoryChain, GetSectorSize(), directoryChain.Count * GetSectorSize(), null, sourceStream); while (dirReader.Position < directoryChain.Count * GetSectorSize()) @@ -1802,7 +1818,7 @@ private void CommitDirectory() List directorySectors = GetSectorChain(header.FirstDirectorySectorID, SectorType.Normal); - StreamView sv = new StreamView(directorySectors, GetSectorSize(), 0, sourceStream); + StreamView sv = new StreamView(directorySectors, GetSectorSize(), 0, null, sourceStream); foreach (IDirectoryEntry di in directoryEntries) { @@ -1960,7 +1976,7 @@ internal Queue FindFreeSectors(SectorType sType) { List FatChain = GetSectorChain(-1, SectorType.FAT); - StreamView fatStream = new StreamView(FatChain, GetSectorSize(), header.FATSectorsNumber * GetSectorSize(), sourceStream); + StreamView fatStream = new StreamView(FatChain, GetSectorSize(), header.FATSectorsNumber * GetSectorSize(), null, sourceStream); int idx = 0; @@ -1990,13 +2006,13 @@ List miniFAT = GetSectorChain(header.FirstMiniFATSectorID, SectorType.Normal); StreamView miniFATView - = new StreamView(miniFAT, GetSectorSize(), header.MiniFATSectorsNumber * Sector.MINISECTOR_SIZE, sourceStream); + = new StreamView(miniFAT, GetSectorSize(), header.MiniFATSectorsNumber * Sector.MINISECTOR_SIZE, null, sourceStream); List miniStream = GetSectorChain(RootEntry.StartSetc, SectorType.Normal); StreamView miniStreamView - = new StreamView(miniStream, GetSectorSize(), rootStorage.Size, sourceStream); + = new StreamView(miniStream, GetSectorSize(), rootStorage.Size, null, sourceStream); int idx = 0; @@ -2152,7 +2168,7 @@ internal void SetStreamLength(CFItem cfItem, long length) if (this.sectorRecycle) freeList = FindFreeSectors(SectorType.Mini); - sv = new StreamView(oldChain, oldSectorSize, oldSize, sourceStream); + sv = new StreamView(oldChain, oldSectorSize, oldSize, null, sourceStream); // Reset start sector and size of dir entry cfItem.DirEntry.StartSetc = Sector.ENDOFCHAIN; @@ -2206,7 +2222,7 @@ internal void SetStreamLength(CFItem cfItem, long length) if (this.sectorRecycle) freeList = FindFreeSectors(SectorType.Normal); // Collect available Normal free sectors - sv = new StreamView(oldChain, oldSectorSize, oldSize, sourceStream); + sv = new StreamView(oldChain, oldSectorSize, oldSize, null, sourceStream); List newChain = GetNormalSectorChain(Sector.ENDOFCHAIN); StreamView destSv = new StreamView(newChain, GetSectorSize(), length, freeList, sourceStream); @@ -2322,12 +2338,12 @@ internal int ReadData(CFStream cFStream, long position, byte[] buffer, int count if (de.Size < header.MinSizeStandardStream) { sView - = new StreamView(GetSectorChain(de.StartSetc, SectorType.Mini), Sector.MINISECTOR_SIZE, de.Size, sourceStream); + = new StreamView(GetSectorChain(de.StartSetc, SectorType.Mini), Sector.MINISECTOR_SIZE, de.Size, null, sourceStream); } else { - sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Normal), GetSectorSize(), de.Size, sourceStream); + sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Normal), GetSectorSize(), de.Size, null, sourceStream); } @@ -2350,12 +2366,12 @@ internal int ReadData(CFStream cFStream, long position, byte[] buffer, int offse if (de.Size < header.MinSizeStandardStream) { sView - = new StreamView(GetSectorChain(de.StartSetc, SectorType.Mini), Sector.MINISECTOR_SIZE, de.Size, sourceStream); + = new StreamView(GetSectorChain(de.StartSetc, SectorType.Mini), Sector.MINISECTOR_SIZE, de.Size, null, sourceStream); } else { - sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Normal), GetSectorSize(), de.Size, sourceStream); + sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Normal), GetSectorSize(), de.Size, null, sourceStream); } @@ -2382,7 +2398,7 @@ internal byte[] GetData(CFStream cFStream) { StreamView miniView - = new StreamView(GetSectorChain(de.StartSetc, SectorType.Mini), Sector.MINISECTOR_SIZE, de.Size, sourceStream); + = new StreamView(GetSectorChain(de.StartSetc, SectorType.Mini), Sector.MINISECTOR_SIZE, de.Size, null, sourceStream); BinaryReader br = new BinaryReader(miniView); @@ -2393,7 +2409,7 @@ StreamView miniView else { StreamView sView - = new StreamView(GetSectorChain(de.StartSetc, SectorType.Normal), GetSectorSize(), de.Size, sourceStream); + = new StreamView(GetSectorChain(de.StartSetc, SectorType.Normal), GetSectorSize(), de.Size, null, sourceStream); result = new byte[(int)de.Size]; @@ -2482,6 +2498,7 @@ public void Close() private bool closeStream = true; + [Obsolete("Use flag LeaveOpen in CompoundFile constructor")] public void Close(bool closeStream) { this.closeStream = closeStream; @@ -2536,7 +2553,7 @@ protected virtual void Dispose(bool disposing) #endif } - if (this.sourceStream != null && closeStream) + if (this.sourceStream != null && closeStream && !configuration.HasFlag(CFSConfiguration.LeaveOpen)) this.sourceStream.Close(); } } @@ -2739,7 +2756,7 @@ public static void ShrinkCompoundFile(String fileName) private static void DoCompression(CFStorage currSrcStorage, CFStorage currDstStorage) { Action va = - delegate(CFItem item) + delegate (CFItem item) { if (item.IsStream) { diff --git a/sources/OpenMcdf/Properties/AssemblyInfo.cs b/sources/OpenMcdf/Properties/AssemblyInfo.cs index 20a0a309..62fed8f0 100644 --- a/sources/OpenMcdf/Properties/AssemblyInfo.cs +++ b/sources/OpenMcdf/Properties/AssemblyInfo.cs @@ -1,38 +1,38 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenMcdf")] -[assembly: AssemblyDescription("MS Compound File Storage .NET Implementation")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Federico Blaseotto")] -[assembly: AssemblyProduct("OpenMcdf 2.0")] -[assembly: AssemblyCopyright("Copyright © 2010-2015, Federico Blaseotto")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("ffc13791-ddf0-4d14-bd64-575aba119190")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.0.1.*")] - -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("OpenMcdf.Test")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenMcdf")] +[assembly: AssemblyDescription("MS Compound File Storage .NET Implementation")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Federico Blaseotto")] +[assembly: AssemblyProduct("OpenMcdf 2.1")] +[assembly: AssemblyCopyright("Copyright © 2010-2016, Federico Blaseotto")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ffc13791-ddf0-4d14-bd64-575aba119190")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("2.1.0.*")] + +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("OpenMcdf.Test")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("OpenMcdf.Extensions")] \ No newline at end of file diff --git a/sources/OpenMcdf/RBTree/RBTree.cs b/sources/OpenMcdf/RBTree/RBTree.cs index e883f7a2..da4564c8 100644 --- a/sources/OpenMcdf/RBTree/RBTree.cs +++ b/sources/OpenMcdf/RBTree/RBTree.cs @@ -1,634 +1,634 @@ -#define ASSERT - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -#if ASSERT -using System.Diagnostics; -#endif - -// ------------------------------------------------------------- -// This is a porting from java code, under MIT license of | -// the beautiful Red-Black Tree implementation you can find at | -// http://en.literateprograms.org/Red-black_tree_(Java)#chunk | -// Many Thanks to original Implementors. | -// ------------------------------------------------------------- - -namespace RedBlackTree -{ - public class RBTreeException : Exception - { - public RBTreeException(String msg) - : base(msg) - { - } - } - public class RBTreeDuplicatedItemException : RBTreeException - { - public RBTreeDuplicatedItemException(String msg) - : base(msg) - { - } - } - - public enum Color { RED = 0, BLACK = 1 } - - /// - /// Red Black Node interface - /// - public interface IRBNode : IComparable - { - - IRBNode Left - { - get; - set; - } - - IRBNode Right - { - get; - set; - } - - - Color Color - - { get; set; } - - - - IRBNode Parent { get; set; } - - - IRBNode Grandparent(); - - - IRBNode Sibling(); - // { - //#if ASSERT - // Debug.Assert(Parent != null); // Root node has no sibling - //#endif - // if (this == Parent.Left) - // return Parent.Right; - // else - // return Parent.Left; - // } - - IRBNode Uncle(); - // { - //#if ASSERT - // Debug.Assert(Parent != null); // Root node has no uncle - // Debug.Assert(Parent.Parent != null); // Children of root have no uncle - //#endif - // return Parent.Sibling(); - // } - // } - - void AssignValueTo(IRBNode other); - } - - public class RBTree - { - public IRBNode Root { get; set; } - - private static Color NodeColor(IRBNode n) - { - return n == null ? Color.BLACK : n.Color; - } - - public RBTree() - { - - } - - public RBTree(IRBNode root) - { - this.Root = root; - } - - - private IRBNode LookupNode(IRBNode template) - { - IRBNode n = Root; - - while (n != null) - { - int compResult = template.CompareTo(n); - - if (compResult == 0) - { - return n; - } - else if (compResult < 0) - { - n = n.Left; - } - else - { - //assert compResult > 0; - n = n.Right; - } - } - - return n; - } - - public bool TryLookup(IRBNode template, out IRBNode val) - { - IRBNode n = LookupNode(template); - - if (n == null) - { - val = null; - return false; - } - else - { - val = n; - return true; - } - } - - private void ReplaceNode(IRBNode oldn, IRBNode newn) - { - if (oldn.Parent == null) - { - Root = newn; - } - else - { - if (oldn == oldn.Parent.Left) - oldn.Parent.Left = newn; - else - oldn.Parent.Right = newn; - } - if (newn != null) - { - newn.Parent = oldn.Parent; - } - } - - private void RotateLeft(IRBNode n) - { - IRBNode r = n.Right; - ReplaceNode(n, r); - n.Right = r.Left; - if (r.Left != null) - { - r.Left.Parent = n; - } - r.Left = n; - n.Parent = r; - } - - private void RotateRight(IRBNode n) - { - IRBNode l = n.Left; - ReplaceNode(n, l); - n.Left = l.Right; - - if (l.Right != null) - { - l.Right.Parent = n; - } - - l.Right = n; - n.Parent = l; - } - - - - public void Insert(IRBNode newNode) - { - newNode.Color = Color.RED; - IRBNode insertedNode = newNode; - - if (Root == null) - { - Root = insertedNode; - } - else - { - IRBNode n = Root; - while (true) - { - int compResult = newNode.CompareTo(n); - if (compResult == 0) - { - throw new RBTreeDuplicatedItemException("RBNode " + newNode.ToString() + " already present in tree"); - //n.Value = value; - //return; - } - else if (compResult < 0) - { - if (n.Left == null) - { - n.Left = insertedNode; - - break; - } - else - { - n = n.Left; - } - } - else - { - //assert compResult > 0; - if (n.Right == null) - { - n.Right = insertedNode; - - break; - } - else - { - n = n.Right; - } - } - } - insertedNode.Parent = n; - } - - InsertCase1(insertedNode); - - if (NodeInserted != null) - { - NodeInserted(insertedNode); - } - - //Trace.WriteLine(" "); - //Print(); - } - - //------------------------------------ - private void InsertCase1(IRBNode n) - { - if (n.Parent == null) - n.Color = Color.BLACK; - else - InsertCase2(n); - } - - //----------------------------------- - private void InsertCase2(IRBNode n) - { - if (NodeColor(n.Parent) == Color.BLACK) - return; // Tree is still valid - else - InsertCase3(n); - } - - //---------------------------- - private void InsertCase3(IRBNode n) - { - if (NodeColor(n.Uncle()) == Color.RED) - { - n.Parent.Color = Color.BLACK; - n.Uncle().Color = Color.BLACK; - n.Grandparent().Color = Color.RED; - InsertCase1(n.Grandparent()); - } - else - { - InsertCase4(n); - } - } - - //---------------------------- - private void InsertCase4(IRBNode n) - { - if (n == n.Parent.Right && n.Parent == n.Grandparent().Left) - { - RotateLeft(n.Parent); - n = n.Left; - } - else if (n == n.Parent.Left && n.Parent == n.Grandparent().Right) - { - RotateRight(n.Parent); - n = n.Right; - } - - InsertCase5(n); - } - - //---------------------------- - private void InsertCase5(IRBNode n) - { - n.Parent.Color = Color.BLACK; - n.Grandparent().Color = Color.RED; - if (n == n.Parent.Left && n.Parent == n.Grandparent().Left) - { - RotateRight(n.Grandparent()); - } - else - { - //assert n == n.parent.right && n.parent == n.grandparent().right; - RotateLeft(n.Grandparent()); - } - } - - private static IRBNode MaximumNode(IRBNode n) - { - //assert n != null; - while (n.Right != null) - { - n = n.Right; - } - - return n; - } - - - public void Delete(IRBNode template, out IRBNode deletedAlt) - { - deletedAlt = null; - IRBNode n = LookupNode(template); - template = n; - if (n == null) - return; // Key not found, do nothing - if (n.Left != null && n.Right != null) - { - // Copy key/value from predecessor and then delete it instead - IRBNode pred = MaximumNode(n.Left); - pred.AssignValueTo(n); - n = pred; - deletedAlt = pred; - } - - //assert n.left == null || n.right == null; - IRBNode child = (n.Right == null) ? n.Left : n.Right; - if (NodeColor(n) == Color.BLACK) - { - n.Color = NodeColor(child); - DeleteCase1(n); - } - - ReplaceNode(n, child); - - if (NodeColor(Root) == Color.RED) - { - Root.Color = Color.BLACK; - } - - - return; - } - - private void DeleteCase1(IRBNode n) - { - if (n.Parent == null) - return; - else - DeleteCase2(n); - } - - - private void DeleteCase2(IRBNode n) - { - if (NodeColor(n.Sibling()) == Color.RED) - { - n.Parent.Color = Color.RED; - n.Sibling().Color = Color.BLACK; - if (n == n.Parent.Left) - RotateLeft(n.Parent); - else - RotateRight(n.Parent); - } - - DeleteCase3(n); - } - - private void DeleteCase3(IRBNode n) - { - if (NodeColor(n.Parent) == Color.BLACK && - NodeColor(n.Sibling()) == Color.BLACK && - NodeColor(n.Sibling().Left) == Color.BLACK && - NodeColor(n.Sibling().Right) == Color.BLACK) - { - n.Sibling().Color = Color.RED; - DeleteCase1(n.Parent); - } - else - DeleteCase4(n); - } - - private void DeleteCase4(IRBNode n) - { - if (NodeColor(n.Parent) == Color.RED && - NodeColor(n.Sibling()) == Color.BLACK && - NodeColor(n.Sibling().Left) == Color.BLACK && - NodeColor(n.Sibling().Right) == Color.BLACK) - { - n.Sibling().Color = Color.RED; - n.Parent.Color = Color.BLACK; - } - else - DeleteCase5(n); - } - - private void DeleteCase5(IRBNode n) - { - if (n == n.Parent.Left && - NodeColor(n.Sibling()) == Color.BLACK && - NodeColor(n.Sibling().Left) == Color.RED && - NodeColor(n.Sibling().Right) == Color.BLACK) - { - n.Sibling().Color = Color.RED; - n.Sibling().Left.Color = Color.BLACK; - RotateRight(n.Sibling()); - } - else if (n == n.Parent.Right && - NodeColor(n.Sibling()) == Color.BLACK && - NodeColor(n.Sibling().Right) == Color.RED && - NodeColor(n.Sibling().Left) == Color.BLACK) - { - n.Sibling().Color = Color.RED; - n.Sibling().Right.Color = Color.BLACK; - RotateLeft(n.Sibling()); - } - - DeleteCase6(n); - } - - private void DeleteCase6(IRBNode n) - { - n.Sibling().Color = NodeColor(n.Parent); - n.Parent.Color = Color.BLACK; - if (n == n.Parent.Left) - { - //assert nodeColor(n.sibling().right) == Color.RED; - n.Sibling().Right.Color = Color.BLACK; - RotateLeft(n.Parent); - } - else - { - //assert nodeColor(n.sibling().left) == Color.RED; - n.Sibling().Left.Color = Color.BLACK; - RotateRight(n.Parent); - } - } - - public void VisitTree(Action action) - { - //IN Order visit - IRBNode walker = Root; - - if (walker != null) - DoVisitTree(action, walker); - } - - private void DoVisitTree(Action action, IRBNode walker) - { - if (walker.Left != null) - { - DoVisitTree(action, walker.Left); - } - - if (action != null) - action(walker); - - if (walker.Right != null) - { - DoVisitTree(action, walker.Right); - } - - } - - internal void VisitTreeNodes(Action action) - { - //IN Order visit - IRBNode walker = Root; - - if (walker != null) - DoVisitTreeNodes(action, walker); - } - - private void DoVisitTreeNodes(Action action, IRBNode walker) - { - if (walker.Left != null) - { - DoVisitTreeNodes(action, walker.Left); - } - - if (action != null) - action(walker); - - if (walker.Right != null) - { - - DoVisitTreeNodes(action, walker.Right); - } - - } - - public class RBTreeEnumerator : IEnumerator - { - int position = -1; - private Queue heap = new Queue(); - - internal RBTreeEnumerator(RBTree tree) - { - tree.VisitTreeNodes(item => heap.Enqueue(item)); - } - - public IRBNode Current - { - get - { - return heap.ElementAt(position); - } - } - - public void Dispose() - { - } - - object System.Collections.IEnumerator.Current - { - get - { - return heap.ElementAt(position); - } - } - - public bool MoveNext() - { - position++; - return (position < heap.Count); - } - - public void Reset() - { - position = -1; - } - } - - public RBTreeEnumerator GetEnumerator() - { - return new RBTreeEnumerator(this); - } - - private static int INDENT_STEP = 15; - - public void Print() - { - PrintHelper(Root, 0); - } - - private static void PrintHelper(IRBNode n, int indent) - { - if (n == null) - { - Trace.WriteLine(""); - return; - } - - if (n.Left != null) - { - PrintHelper(n.Left, indent + INDENT_STEP); - } - - for (int i = 0; i < indent; i++) - Trace.Write(" "); - if (n.Color == Color.BLACK) - Trace.WriteLine(" " + n.ToString() + " "); - else - Trace.WriteLine("<" + n.ToString() + ">"); - - if (n.Right != null) - { - PrintHelper(n.Right, indent + INDENT_STEP); - } - } - - internal void FireNodeOperation(IRBNode node, NodeOperation operation) - { - if (NodeOperation != null) - NodeOperation(node, operation); - } - - //internal void FireValueAssigned(RBNode node, V value) - //{ - // if (ValueAssignedAction != null) - // ValueAssignedAction(node, value); - //} - - internal event Action NodeInserted; - //internal event Action> NodeDeleted; - internal event Action NodeOperation; - - - } - - internal enum NodeOperation - { - LeftAssigned, RightAssigned, ColorAssigned, ParentAssigned, - ValueAssigned - } - - -} +#define ASSERT + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +#if ASSERT +using System.Diagnostics; +#endif + +// ------------------------------------------------------------- +// This is a porting from java code, under MIT license of | +// the beautiful Red-Black Tree implementation you can find at | +// http://en.literateprograms.org/Red-black_tree_(Java)#chunk | +// Many Thanks to original Implementors. | +// ------------------------------------------------------------- + +namespace RedBlackTree +{ + public class RBTreeException : Exception + { + public RBTreeException(String msg) + : base(msg) + { + } + } + public class RBTreeDuplicatedItemException : RBTreeException + { + public RBTreeDuplicatedItemException(String msg) + : base(msg) + { + } + } + + public enum Color { RED = 0, BLACK = 1 } + + /// + /// Red Black Node interface + /// + public interface IRBNode : IComparable + { + + IRBNode Left + { + get; + set; + } + + IRBNode Right + { + get; + set; + } + + + Color Color + + { get; set; } + + + + IRBNode Parent { get; set; } + + + IRBNode Grandparent(); + + + IRBNode Sibling(); + // { + //#if ASSERT + // Debug.Assert(Parent != null); // Root node has no sibling + //#endif + // if (this == Parent.Left) + // return Parent.Right; + // else + // return Parent.Left; + // } + + IRBNode Uncle(); + // { + //#if ASSERT + // Debug.Assert(Parent != null); // Root node has no uncle + // Debug.Assert(Parent.Parent != null); // Children of root have no uncle + //#endif + // return Parent.Sibling(); + // } + // } + + void AssignValueTo(IRBNode other); + } + + public class RBTree + { + public IRBNode Root { get; set; } + + private static Color NodeColor(IRBNode n) + { + return n == null ? Color.BLACK : n.Color; + } + + public RBTree() + { + + } + + public RBTree(IRBNode root) + { + this.Root = root; + } + + + private IRBNode LookupNode(IRBNode template) + { + IRBNode n = Root; + + while (n != null) + { + int compResult = template.CompareTo(n); + + if (compResult == 0) + { + return n; + } + else if (compResult < 0) + { + n = n.Left; + } + else + { + //assert compResult > 0; + n = n.Right; + } + } + + return n; + } + + public bool TryLookup(IRBNode template, out IRBNode val) + { + IRBNode n = LookupNode(template); + + if (n == null) + { + val = null; + return false; + } + else + { + val = n; + return true; + } + } + + private void ReplaceNode(IRBNode oldn, IRBNode newn) + { + if (oldn.Parent == null) + { + Root = newn; + } + else + { + if (oldn == oldn.Parent.Left) + oldn.Parent.Left = newn; + else + oldn.Parent.Right = newn; + } + if (newn != null) + { + newn.Parent = oldn.Parent; + } + } + + private void RotateLeft(IRBNode n) + { + IRBNode r = n.Right; + ReplaceNode(n, r); + n.Right = r.Left; + if (r.Left != null) + { + r.Left.Parent = n; + } + r.Left = n; + n.Parent = r; + } + + private void RotateRight(IRBNode n) + { + IRBNode l = n.Left; + ReplaceNode(n, l); + n.Left = l.Right; + + if (l.Right != null) + { + l.Right.Parent = n; + } + + l.Right = n; + n.Parent = l; + } + + + + public void Insert(IRBNode newNode) + { + newNode.Color = Color.RED; + IRBNode insertedNode = newNode; + + if (Root == null) + { + Root = insertedNode; + } + else + { + IRBNode n = Root; + while (true) + { + int compResult = newNode.CompareTo(n); + if (compResult == 0) + { + throw new RBTreeDuplicatedItemException("RBNode " + newNode.ToString() + " already present in tree"); + //n.Value = value; + //return; + } + else if (compResult < 0) + { + if (n.Left == null) + { + n.Left = insertedNode; + + break; + } + else + { + n = n.Left; + } + } + else + { + //assert compResult > 0; + if (n.Right == null) + { + n.Right = insertedNode; + + break; + } + else + { + n = n.Right; + } + } + } + insertedNode.Parent = n; + } + + InsertCase1(insertedNode); + + if (NodeInserted != null) + { + NodeInserted(insertedNode); + } + + //Trace.WriteLine(" "); + //Print(); + } + + //------------------------------------ + private void InsertCase1(IRBNode n) + { + if (n.Parent == null) + n.Color = Color.BLACK; + else + InsertCase2(n); + } + + //----------------------------------- + private void InsertCase2(IRBNode n) + { + if (NodeColor(n.Parent) == Color.BLACK) + return; // Tree is still valid + else + InsertCase3(n); + } + + //---------------------------- + private void InsertCase3(IRBNode n) + { + if (NodeColor(n.Uncle()) == Color.RED) + { + n.Parent.Color = Color.BLACK; + n.Uncle().Color = Color.BLACK; + n.Grandparent().Color = Color.RED; + InsertCase1(n.Grandparent()); + } + else + { + InsertCase4(n); + } + } + + //---------------------------- + private void InsertCase4(IRBNode n) + { + if (n == n.Parent.Right && n.Parent == n.Grandparent().Left) + { + RotateLeft(n.Parent); + n = n.Left; + } + else if (n == n.Parent.Left && n.Parent == n.Grandparent().Right) + { + RotateRight(n.Parent); + n = n.Right; + } + + InsertCase5(n); + } + + //---------------------------- + private void InsertCase5(IRBNode n) + { + n.Parent.Color = Color.BLACK; + n.Grandparent().Color = Color.RED; + if (n == n.Parent.Left && n.Parent == n.Grandparent().Left) + { + RotateRight(n.Grandparent()); + } + else + { + //assert n == n.parent.right && n.parent == n.grandparent().right; + RotateLeft(n.Grandparent()); + } + } + + private static IRBNode MaximumNode(IRBNode n) + { + //assert n != null; + while (n.Right != null) + { + n = n.Right; + } + + return n; + } + + + public void Delete(IRBNode template, out IRBNode deletedAlt) + { + deletedAlt = null; + IRBNode n = LookupNode(template); + template = n; + if (n == null) + return; // Key not found, do nothing + if (n.Left != null && n.Right != null) + { + // Copy key/value from predecessor and then delete it instead + IRBNode pred = MaximumNode(n.Left); + pred.AssignValueTo(n); + n = pred; + deletedAlt = pred; + } + + //assert n.left == null || n.right == null; + IRBNode child = (n.Right == null) ? n.Left : n.Right; + if (NodeColor(n) == Color.BLACK) + { + n.Color = NodeColor(child); + DeleteCase1(n); + } + + ReplaceNode(n, child); + + if (NodeColor(Root) == Color.RED) + { + Root.Color = Color.BLACK; + } + + + return; + } + + private void DeleteCase1(IRBNode n) + { + if (n.Parent == null) + return; + else + DeleteCase2(n); + } + + + private void DeleteCase2(IRBNode n) + { + if (NodeColor(n.Sibling()) == Color.RED) + { + n.Parent.Color = Color.RED; + n.Sibling().Color = Color.BLACK; + if (n == n.Parent.Left) + RotateLeft(n.Parent); + else + RotateRight(n.Parent); + } + + DeleteCase3(n); + } + + private void DeleteCase3(IRBNode n) + { + if (NodeColor(n.Parent) == Color.BLACK && + NodeColor(n.Sibling()) == Color.BLACK && + NodeColor(n.Sibling().Left) == Color.BLACK && + NodeColor(n.Sibling().Right) == Color.BLACK) + { + n.Sibling().Color = Color.RED; + DeleteCase1(n.Parent); + } + else + DeleteCase4(n); + } + + private void DeleteCase4(IRBNode n) + { + if (NodeColor(n.Parent) == Color.RED && + NodeColor(n.Sibling()) == Color.BLACK && + NodeColor(n.Sibling().Left) == Color.BLACK && + NodeColor(n.Sibling().Right) == Color.BLACK) + { + n.Sibling().Color = Color.RED; + n.Parent.Color = Color.BLACK; + } + else + DeleteCase5(n); + } + + private void DeleteCase5(IRBNode n) + { + if (n == n.Parent.Left && + NodeColor(n.Sibling()) == Color.BLACK && + NodeColor(n.Sibling().Left) == Color.RED && + NodeColor(n.Sibling().Right) == Color.BLACK) + { + n.Sibling().Color = Color.RED; + n.Sibling().Left.Color = Color.BLACK; + RotateRight(n.Sibling()); + } + else if (n == n.Parent.Right && + NodeColor(n.Sibling()) == Color.BLACK && + NodeColor(n.Sibling().Right) == Color.RED && + NodeColor(n.Sibling().Left) == Color.BLACK) + { + n.Sibling().Color = Color.RED; + n.Sibling().Right.Color = Color.BLACK; + RotateLeft(n.Sibling()); + } + + DeleteCase6(n); + } + + private void DeleteCase6(IRBNode n) + { + n.Sibling().Color = NodeColor(n.Parent); + n.Parent.Color = Color.BLACK; + if (n == n.Parent.Left) + { + //assert nodeColor(n.sibling().right) == Color.RED; + n.Sibling().Right.Color = Color.BLACK; + RotateLeft(n.Parent); + } + else + { + //assert nodeColor(n.sibling().left) == Color.RED; + n.Sibling().Left.Color = Color.BLACK; + RotateRight(n.Parent); + } + } + + public void VisitTree(Action action) + { + //IN Order visit + IRBNode walker = Root; + + if (walker != null) + DoVisitTree(action, walker); + } + + private void DoVisitTree(Action action, IRBNode walker) + { + if (walker.Left != null) + { + DoVisitTree(action, walker.Left); + } + + if (action != null) + action(walker); + + if (walker.Right != null) + { + DoVisitTree(action, walker.Right); + } + + } + + internal void VisitTreeNodes(Action action) + { + //IN Order visit + IRBNode walker = Root; + + if (walker != null) + DoVisitTreeNodes(action, walker); + } + + private void DoVisitTreeNodes(Action action, IRBNode walker) + { + if (walker.Left != null) + { + DoVisitTreeNodes(action, walker.Left); + } + + if (action != null) + action(walker); + + if (walker.Right != null) + { + + DoVisitTreeNodes(action, walker.Right); + } + + } + + public class RBTreeEnumerator : IEnumerator + { + int position = -1; + private Queue heap = new Queue(); + + internal RBTreeEnumerator(RBTree tree) + { + tree.VisitTreeNodes(item => heap.Enqueue(item)); + } + + public IRBNode Current + { + get + { + return heap.ElementAt(position); + } + } + + public void Dispose() + { + } + + object System.Collections.IEnumerator.Current + { + get + { + return heap.ElementAt(position); + } + } + + public bool MoveNext() + { + position++; + return (position < heap.Count); + } + + public void Reset() + { + position = -1; + } + } + + public RBTreeEnumerator GetEnumerator() + { + return new RBTreeEnumerator(this); + } + + private static int INDENT_STEP = 15; + + public void Print() + { + PrintHelper(Root, 0); + } + + private static void PrintHelper(IRBNode n, int indent) + { + if (n == null) + { + Trace.WriteLine(""); + return; + } + + if (n.Left != null) + { + PrintHelper(n.Left, indent + INDENT_STEP); + } + + for (int i = 0; i < indent; i++) + Trace.Write(" "); + if (n.Color == Color.BLACK) + Trace.WriteLine(" " + n.ToString() + " "); + else + Trace.WriteLine("<" + n.ToString() + ">"); + + if (n.Right != null) + { + PrintHelper(n.Right, indent + INDENT_STEP); + } + } + + internal void FireNodeOperation(IRBNode node, NodeOperation operation) + { + if (NodeOperation != null) + NodeOperation(node, operation); + } + + //internal void FireValueAssigned(RBNode node, V value) + //{ + // if (ValueAssignedAction != null) + // ValueAssignedAction(node, value); + //} + + internal event Action NodeInserted; + //internal event Action> NodeDeleted; + internal event Action NodeOperation; + + + } + + internal enum NodeOperation + { + LeftAssigned, RightAssigned, ColorAssigned, ParentAssigned, + ValueAssigned + } + + +} diff --git a/sources/OpenMcdf/Sector.cs b/sources/OpenMcdf/Sector.cs index 48f410e9..7eca9cc2 100644 --- a/sources/OpenMcdf/Sector.cs +++ b/sources/OpenMcdf/Sector.cs @@ -1,192 +1,202 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * The Original Code is OpenMCDF - Compound Document Format library. - * - * The Initial Developer of the Original Code is Federico Blaseotto.*/ - - -using System; -using System.IO; - - -namespace OpenMcdf -{ - internal enum SectorType - { - Normal, Mini, FAT, DIFAT, RangeLockSector, Directory - } - - internal class Sector : IDisposable - { - public static int MINISECTOR_SIZE = 64; - - public const int FREESECT = unchecked((int)0xFFFFFFFF); - public const int ENDOFCHAIN = unchecked((int)0xFFFFFFFE); - public const int FATSECT = unchecked((int)0xFFFFFFFD); - public const int DIFSECT = unchecked((int)0xFFFFFFFC); - - private bool dirtyFlag = false; - - public bool DirtyFlag - { - get { return dirtyFlag; } - set { dirtyFlag = value; } - } - - public bool IsStreamed - { - get { return (stream != null && size != MINISECTOR_SIZE) ? (this.id * size) + size < stream.Length : false; } - } - - private int size = 0; - private Stream stream; - - - public Sector(int size, Stream stream) - { - this.size = size; - this.stream = stream; - } - - public Sector(int size, byte[] data) - { - this.size = size; - this.data = data; - this.stream = null; - } - - public Sector(int size) - { - this.size = size; - this.data = null; - this.stream = null; - } - - private SectorType type; - - internal SectorType Type - { - get { return type; } - set { type = value; } - } - - private int id = -1; - - public int Id - { - get { return id; } - set - { - id = value; - } - } - - public int Size - { - get - { - return size; - } - } - - private byte[] data; - - public byte[] GetData() - { - if (this.data == null) - { - data = new byte[size]; - - if (IsStreamed) - { - stream.Seek((long)size + (long)this.id * (long)size, SeekOrigin.Begin); - stream.Read(data, 0, size); - } - } - - return data; - } - - //public void SetSectorData(byte[] b) - //{ - // this.data = b; - //} - - //public void FillData(byte b) - //{ - // if (data != null) - // { - // for (int i = 0; i < data.Length; i++) - // { - // data[i] = b; - // } - // } - //} - - public void ZeroData() - { - data = new byte[size]; - dirtyFlag = true; - } - - internal void ReleaseData() - { - this.data = null; - } - - private object lockObject = new Object(); - - /// - /// When called from user code, release all resources, otherwise, in the case runtime called it, - /// only unmanagd 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) - { - try - { - if (!_disposed) - { - lock (lockObject) - { - if (disposing) - { - // Call from user code... - - - } - - this.data = null; - this.dirtyFlag = false; - this.id = Sector.ENDOFCHAIN; - this.size = 0; - - } - } - } - finally - { - _disposed = true; - } - - } - - #region IDisposable Members - - private bool _disposed;//false - - void IDisposable.Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - #endregion - } - - - - -} +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The Original Code is OpenMCDF - Compound Document Format library. + * + * The Initial Developer of the Original Code is Federico Blaseotto.*/ + + +using System; +using System.IO; + + +namespace OpenMcdf +{ + internal enum SectorType + { + Normal, Mini, FAT, DIFAT, RangeLockSector, Directory + } + + internal class Sector : IDisposable + { + public static int MINISECTOR_SIZE = 64; + + public const int FREESECT = unchecked((int)0xFFFFFFFF); + public const int ENDOFCHAIN = unchecked((int)0xFFFFFFFE); + public const int FATSECT = unchecked((int)0xFFFFFFFD); + public const int DIFSECT = unchecked((int)0xFFFFFFFC); + + private bool dirtyFlag = false; + + public bool DirtyFlag + { + get { return dirtyFlag; } + set { dirtyFlag = value; } + } + + public bool IsStreamed + { + get { return (stream != null && size != MINISECTOR_SIZE) ? (this.id * size) + size < stream.Length : false; } + } + + private int size = 0; + private Stream stream; + + + public Sector(int size, Stream stream) + { + this.size = size; + this.stream = stream; + } + + public Sector(int size, byte[] data) + { + this.size = size; + this.data = data; + this.stream = null; + } + + public Sector(int size) + { + this.size = size; + this.data = null; + this.stream = null; + } + + private SectorType type; + + internal SectorType Type + { + get { return type; } + set { type = value; } + } + + private int id = -1; + + public int Id + { + get { return id; } + set + { + id = value; + } + } + + public int Size + { + get + { + return size; + } + } + + private byte[] data; + + public byte[] GetData() + { + if (this.data == null) + { + data = new byte[size]; + + if (IsStreamed) + { + stream.Seek((long)size + (long)this.id * (long)size, SeekOrigin.Begin); + stream.Read(data, 0, size); + } + } + + return data; + } + + //public void SetSectorData(byte[] b) + //{ + // this.data = b; + //} + + //public void FillData(byte b) + //{ + // if (data != null) + // { + // for (int i = 0; i < data.Length; i++) + // { + // data[i] = b; + // } + // } + //} + + public void ZeroData() + { + data = new byte[size]; + dirtyFlag = true; + } + + public void InitFATData() + { + data = new byte[size]; + + for (int i = 0; i < size; i++) + data[i] = 0xFF; + + dirtyFlag = true; + } + + internal void ReleaseData() + { + this.data = null; + } + + private object lockObject = new Object(); + + /// + /// When called from user code, release all resources, otherwise, in the case runtime called it, + /// only unmanagd 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) + { + try + { + if (!_disposed) + { + lock (lockObject) + { + if (disposing) + { + // Call from user code... + + + } + + this.data = null; + this.dirtyFlag = false; + this.id = Sector.ENDOFCHAIN; + this.size = 0; + + } + } + } + finally + { + _disposed = true; + } + + } + + #region IDisposable Members + + private bool _disposed;//false + + void IDisposable.Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + #endregion + } + + + + +} diff --git a/sources/OpenMcdf/StreamView.cs b/sources/OpenMcdf/StreamView.cs index f3afad7b..c58d0f32 100644 --- a/sources/OpenMcdf/StreamView.cs +++ b/sources/OpenMcdf/StreamView.cs @@ -1,377 +1,378 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * The Original Code is OpenMCDF - Compound Document Format library. - * - * The Initial Developer of the Original Code is Federico Blaseotto.*/ - - -using System; -using System.Collections.Generic; -using System.Text; -using System.Collections; -using System.IO; -using System.Collections.Specialized; -using System.Diagnostics; - -namespace OpenMcdf -{ - /// - /// Stream decorator for a Sector or miniSector chain - /// - internal class StreamView : Stream - { - private int sectorSize; - - private long position; - - private List sectorChain; - private Stream stream; - - private List freeSectors = new List(); - public IEnumerable FreeSectors - { - get { return freeSectors; } - } - - public StreamView(List sectorChain, int sectorSize, Stream stream) - { - if (sectorChain == null) - throw new CFException("Sector Chain cannot be null"); - - if (sectorSize <= 0) - throw new CFException("Sector size must be greater than zero"); - - this.sectorChain = sectorChain; - this.sectorSize = sectorSize; - this.stream = stream; - } - - public StreamView(List sectorChain, int sectorSize, long length, Queue availableSectors, Stream stream) - : this(sectorChain, sectorSize, stream) - { - adjustLength(length, availableSectors); - } - - - public StreamView(List sectorChain, int sectorSize, long length, Stream stream) - : this(sectorChain, sectorSize, stream) - { - adjustLength(length); - } - - public List BaseSectorChain - { - get { return sectorChain; } - } - - public override bool CanRead - { - get { return true; } - } - - public override bool CanSeek - { - get { return true; } - } - - public override bool CanWrite - { - get { return true; } - } - - public override void Flush() - { - - } - - private long length; - - public override long Length - { - get - { - return length; - } - } - - public override long Position - { - get - { - return position; - } - - set - { - if (position > length - 1) - throw new ArgumentOutOfRangeException("value"); - - position = value; - } - } - - public override void Close() - { - base.Close(); - } - - private byte[] buf = new byte[4]; - - public int ReadInt32() - { - this.Read(buf, 0, 4); - return (((this.buf[0] | (this.buf[1] << 8)) | (this.buf[2] << 16)) | (this.buf[3] << 24)); - } - - public override int Read(byte[] buffer, int offset, int count) - { - int nRead = 0; - int nToRead = 0; - - if (sectorChain != null && sectorChain.Count > 0) - { - // First sector - int secIndex = (int)(position / (long)sectorSize); - - // Bytes to read count is the min between request count - // and sector border - - nToRead = Math.Min( - sectorChain[0].Size - ((int)position % sectorSize), - count); - - if (secIndex < sectorChain.Count) - { - Buffer.BlockCopy( - sectorChain[secIndex].GetData(), - (int)(position % sectorSize), - buffer, - offset, - nToRead - ); - } - - nRead += nToRead; - - secIndex++; - - // Central sectors - while (nRead < (count - sectorSize)) - { - nToRead = sectorSize; - - Buffer.BlockCopy( - sectorChain[secIndex].GetData(), - 0, - buffer, - offset + nRead, - nToRead - ); - - nRead += nToRead; - secIndex++; - } - - // Last sector - nToRead = count - nRead; - - if (nToRead != 0) - { - Buffer.BlockCopy( - sectorChain[secIndex].GetData(), - 0, - buffer, - offset + nRead, - nToRead - ); - - nRead += nToRead; - } - - position += nRead; - - return nRead; - - } - else - return 0; - - } - - public override long Seek(long offset, SeekOrigin origin) - { - switch (origin) - { - case SeekOrigin.Begin: - position = offset; - break; - - case SeekOrigin.Current: - position += offset; - break; - - case SeekOrigin.End: - position = Length - offset; - break; - } - - adjustLength(position); - - return position; - } - - private void adjustLength(long value) - { - adjustLength(value, null); +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The Original Code is OpenMCDF - Compound Document Format library. + * + * The Initial Developer of the Original Code is Federico Blaseotto.*/ + + +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections; +using System.IO; +using System.Collections.Specialized; +using System.Diagnostics; + +namespace OpenMcdf +{ + /// + /// Stream decorator for a Sector or miniSector chain + /// + internal class StreamView : Stream + { + private int sectorSize; + + private long position; + + private List sectorChain; + private Stream stream; + private bool isFatStream = false; + private List freeSectors = new List(); + public IEnumerable FreeSectors + { + get { return freeSectors; } + } + + public StreamView(List sectorChain, int sectorSize, Stream stream) + { + if (sectorChain == null) + throw new CFException("Sector Chain cannot be null"); + + if (sectorSize <= 0) + throw new CFException("Sector size must be greater than zero"); + + this.sectorChain = sectorChain; + this.sectorSize = sectorSize; + this.stream = stream; + } + + public StreamView(List sectorChain, int sectorSize, long length, Queue availableSectors, Stream stream, bool isFatStream = false) + : this(sectorChain, sectorSize, stream) + { + this.isFatStream = isFatStream; + adjustLength(length, availableSectors); } - private void adjustLength(long value, Queue availableSectors) - { - this.length = value; - - long delta = value - ((long)this.sectorChain.Count * (long)sectorSize); - - if (delta > 0) - { - // enlargment required - int nSec = (int)Math.Ceiling(((double)delta / sectorSize)); - while (nSec > 0) - { - Sector t = null; - if (availableSectors == null || availableSectors.Count == 0) + public List BaseSectorChain + { + get { return sectorChain; } + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return true; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override void Flush() + { + + } + + private long length; + + public override long Length + { + get + { + return length; + } + } + + public override long Position + { + get + { + return position; + } + + set + { + if (position > length - 1) + throw new ArgumentOutOfRangeException("value"); + + position = value; + } + } + + public override void Close() + { + base.Close(); + } + + private byte[] buf = new byte[4]; + + public int ReadInt32() + { + this.Read(buf, 0, 4); + return (((this.buf[0] | (this.buf[1] << 8)) | (this.buf[2] << 16)) | (this.buf[3] << 24)); + } + + public override int Read(byte[] buffer, int offset, int count) + { + int nRead = 0; + int nToRead = 0; + + if (sectorChain != null && sectorChain.Count > 0) + { + // First sector + int secIndex = (int)(position / (long)sectorSize); + + // Bytes to read count is the min between request count + // and sector border + + nToRead = Math.Min( + sectorChain[0].Size - ((int)position % sectorSize), + count); + + if (secIndex < sectorChain.Count) + { + Buffer.BlockCopy( + sectorChain[secIndex].GetData(), + (int)(position % sectorSize), + buffer, + offset, + nToRead + ); + } + + nRead += nToRead; + + secIndex++; + + // Central sectors + while (nRead < (count - sectorSize)) + { + nToRead = sectorSize; + + Buffer.BlockCopy( + sectorChain[secIndex].GetData(), + 0, + buffer, + offset + nRead, + nToRead + ); + + nRead += nToRead; + secIndex++; + } + + // Last sector + nToRead = count - nRead; + + if (nToRead != 0) + { + Buffer.BlockCopy( + sectorChain[secIndex].GetData(), + 0, + buffer, + offset + nRead, + nToRead + ); + + nRead += nToRead; + } + + position += nRead; + + return nRead; + + } + else + return 0; + + } + + public override long Seek(long offset, SeekOrigin origin) + { + switch (origin) + { + case SeekOrigin.Begin: + position = offset; + break; + + case SeekOrigin.Current: + position += offset; + break; + + case SeekOrigin.End: + position = Length - offset; + break; + } + + adjustLength(position); + + return position; + } + + private void adjustLength(long value) + { + adjustLength(value, null); + } + + private void adjustLength(long value, Queue availableSectors) + { + this.length = value; + + long delta = value - ((long)this.sectorChain.Count * (long)sectorSize); + + if (delta > 0) + { + // enlargment required + + int nSec = (int)Math.Ceiling(((double)delta / sectorSize)); + + while (nSec > 0) + { + Sector t = null; + + if (availableSectors == null || availableSectors.Count == 0) + { + t = new Sector(sectorSize, stream); + + if (sectorSize == Sector.MINISECTOR_SIZE) + t.Type = SectorType.Mini; + } + else + { + t = availableSectors.Dequeue(); + } + + if (isFatStream) { - t = new Sector(sectorSize, stream); - - if (sectorSize == Sector.MINISECTOR_SIZE) - t.Type = SectorType.Mini; - } - else - { - t = availableSectors.Dequeue(); + t.InitFATData(); } - - sectorChain.Add(t); - nSec--; - } - - //if (((int)delta % sectorSize) != 0) - //{ - // Sector t = new Sector(sectorSize); - // sectorChain.Add(t); - //} - } - //else - //{ - // // FREE Sectors - // delta = Math.Abs(delta); - - // int nSec = (int)Math.Floor(((double)delta / sectorSize)); - - // while (nSec > 0) - // { - // freeSectors.Add(sectorChain[sectorChain.Count - 1]); - // sectorChain.RemoveAt(sectorChain.Count - 1); - // nSec--; - // } - //} - } - - public override void SetLength(long value) - { - adjustLength(value); - } - - public void WriteInt32(int val) - { - byte[] buffer = new byte[4]; - buffer[0] = (byte)val; - buffer[1] = (byte)(val << 8); - buffer[2] = (byte)(val << 16); - buffer[3] = (byte)(val << 32); - Write(buffer, 0, 4); - } - - public override void Write(byte[] buffer, int offset, int count) - { - int byteWritten = 0; - int roundByteWritten = 0; - - // Assure length - if ((position + count) > length) - adjustLength((position + count)); - - if (sectorChain != null) - { - // First sector - int secOffset = (int)(position / (long)sectorSize); - int secShift = (int)position % sectorSize; - - roundByteWritten = (int)Math.Min(sectorSize - (int)(position % (long)sectorSize), count); - - if (secOffset < sectorChain.Count) - { - Buffer.BlockCopy( - buffer, - offset, - sectorChain[secOffset].GetData(), - secShift, - roundByteWritten - ); - - sectorChain[secOffset].DirtyFlag = true; - } - - byteWritten += roundByteWritten; - offset += roundByteWritten; - secOffset++; - - // Central sectors - while (byteWritten < (count - sectorSize)) - { - roundByteWritten = sectorSize; - - Buffer.BlockCopy( - buffer, - offset, - sectorChain[secOffset].GetData(), - 0, - roundByteWritten - ); - - sectorChain[secOffset].DirtyFlag = true; - - byteWritten += roundByteWritten; - offset += roundByteWritten; - secOffset++; - } - - // Last sector - roundByteWritten = count - byteWritten; - - if (roundByteWritten != 0) - { - Buffer.BlockCopy( - buffer, - offset, - sectorChain[secOffset].GetData(), - 0, - roundByteWritten - ); - - sectorChain[secOffset].DirtyFlag = true; - - offset += roundByteWritten; - byteWritten += roundByteWritten; - } - - position += count; - - } - } - } + sectorChain.Add(t); + nSec--; + } + + //if (((int)delta % sectorSize) != 0) + //{ + // Sector t = new Sector(sectorSize); + // sectorChain.Add(t); + //} + } + //else + //{ + // // FREE Sectors + // delta = Math.Abs(delta); + + // int nSec = (int)Math.Floor(((double)delta / sectorSize)); + + // while (nSec > 0) + // { + // freeSectors.Add(sectorChain[sectorChain.Count - 1]); + // sectorChain.RemoveAt(sectorChain.Count - 1); + // nSec--; + // } + //} + } + + public override void SetLength(long value) + { + adjustLength(value); + } + + public void WriteInt32(int val) + { + byte[] buffer = new byte[4]; + buffer[0] = (byte)val; + buffer[1] = (byte)(val << 8); + buffer[2] = (byte)(val << 16); + buffer[3] = (byte)(val << 32); + Write(buffer, 0, 4); + } + + public override void Write(byte[] buffer, int offset, int count) + { + int byteWritten = 0; + int roundByteWritten = 0; + + // Assure length + if ((position + count) > length) + adjustLength((position + count)); + + if (sectorChain != null) + { + // First sector + int secOffset = (int)(position / (long)sectorSize); + int secShift = (int)position % sectorSize; + + roundByteWritten = (int)Math.Min(sectorSize - (int)(position % (long)sectorSize), count); + + if (secOffset < sectorChain.Count) + { + Buffer.BlockCopy( + buffer, + offset, + sectorChain[secOffset].GetData(), + secShift, + roundByteWritten + ); + + sectorChain[secOffset].DirtyFlag = true; + } + + byteWritten += roundByteWritten; + offset += roundByteWritten; + secOffset++; + + // Central sectors + while (byteWritten < (count - sectorSize)) + { + roundByteWritten = sectorSize; + + Buffer.BlockCopy( + buffer, + offset, + sectorChain[secOffset].GetData(), + 0, + roundByteWritten + ); + + sectorChain[secOffset].DirtyFlag = true; + + byteWritten += roundByteWritten; + offset += roundByteWritten; + secOffset++; + } + + // Last sector + roundByteWritten = count - byteWritten; + + if (roundByteWritten != 0) + { + Buffer.BlockCopy( + buffer, + offset, + sectorChain[secOffset].GetData(), + 0, + roundByteWritten + ); + + sectorChain[secOffset].DirtyFlag = true; + + offset += roundByteWritten; + byteWritten += roundByteWritten; + } + + position += count; + + } + } + } } \ No newline at end of file diff --git a/sources/Structured Storage Explorer/InputBox.cs b/sources/Structured Storage Explorer/InputBox.cs index f3e97b18..f088942b 100644 --- a/sources/Structured Storage Explorer/InputBox.cs +++ b/sources/Structured Storage Explorer/InputBox.cs @@ -1,53 +1,53 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows.Forms; -using System.Drawing; - -namespace StructuredStorageExplorer -{ - class Utils - { - public static DialogResult InputBox(string title, string promptText, ref string value) - { - Form form = new Form(); - Label label = new Label(); - TextBox textBox = new TextBox(); - Button buttonOk = new Button(); - Button buttonCancel = new Button(); - - form.Text = title; - label.Text = promptText; - textBox.Text = value; - - buttonOk.Text = "OK"; - buttonCancel.Text = "Cancel"; - buttonOk.DialogResult = DialogResult.OK; - buttonCancel.DialogResult = DialogResult.Cancel; - - label.SetBounds(9, 20, 372, 13); - textBox.SetBounds(12, 36, 372, 20); - buttonOk.SetBounds(228, 72, 75, 23); - buttonCancel.SetBounds(309, 72, 75, 23); - - label.AutoSize = true; - textBox.Anchor = textBox.Anchor | AnchorStyles.Right; - buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; - buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; - - form.ClientSize = new Size(396, 107); - form.Controls.AddRange(new Control[] { label, textBox, buttonOk, buttonCancel }); - form.ClientSize = new Size(Math.Max(300, label.Right + 10), form.ClientSize.Height); - form.FormBorderStyle = FormBorderStyle.FixedDialog; - form.StartPosition = FormStartPosition.CenterScreen; - form.MinimizeBox = false; - form.MaximizeBox = false; - form.AcceptButton = buttonOk; - form.CancelButton = buttonCancel; - - DialogResult dialogResult = form.ShowDialog(); - value = textBox.Text; - return dialogResult; - } - } -} +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; + +namespace StructuredStorageExplorer +{ + class Utils + { + public static DialogResult InputBox(string title, string promptText, ref string value) + { + Form form = new Form(); + Label label = new Label(); + TextBox textBox = new TextBox(); + Button buttonOk = new Button(); + Button buttonCancel = new Button(); + + form.Text = title; + label.Text = promptText; + textBox.Text = value; + + buttonOk.Text = "OK"; + buttonCancel.Text = "Cancel"; + buttonOk.DialogResult = DialogResult.OK; + buttonCancel.DialogResult = DialogResult.Cancel; + + label.SetBounds(9, 20, 372, 13); + textBox.SetBounds(12, 36, 372, 20); + buttonOk.SetBounds(228, 72, 75, 23); + buttonCancel.SetBounds(309, 72, 75, 23); + + label.AutoSize = true; + textBox.Anchor = textBox.Anchor | AnchorStyles.Right; + buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + + form.ClientSize = new Size(396, 107); + form.Controls.AddRange(new Control[] { label, textBox, buttonOk, buttonCancel }); + form.ClientSize = new Size(Math.Max(300, label.Right + 10), form.ClientSize.Height); + form.FormBorderStyle = FormBorderStyle.FixedDialog; + form.StartPosition = FormStartPosition.CenterScreen; + form.MinimizeBox = false; + form.MaximizeBox = false; + form.AcceptButton = buttonOk; + form.CancelButton = buttonCancel; + + DialogResult dialogResult = form.ShowDialog(); + value = textBox.Text; + return dialogResult; + } + } +} diff --git a/sources/Structured Storage Explorer/MainForm.Designer.cs b/sources/Structured Storage Explorer/MainForm.Designer.cs index 165486a1..dd87e900 100644 --- a/sources/Structured Storage Explorer/MainForm.Designer.cs +++ b/sources/Structured Storage Explorer/MainForm.Designer.cs @@ -1,334 +1,396 @@ -namespace StructuredStorageExplorer -{ - partial class MainForm - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); - this.treeView1 = new System.Windows.Forms.TreeView(); - this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); - this.importDataStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); - this.exportDataToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.addStorageStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); - this.addStreamToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.removeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog(); - this.menuStrip1 = new System.Windows.Forms.MenuStrip(); - this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.openFileMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.newStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); - this.closeStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); - this.updateCurrentFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.saveAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.openDataFileDialog = new System.Windows.Forms.OpenFileDialog(); - this.statusStrip1 = new System.Windows.Forms.StatusStrip(); - this.fileNameLabel = new System.Windows.Forms.ToolStripStatusLabel(); - this.splitContainer1 = new System.Windows.Forms.SplitContainer(); - this.propertyGrid1 = new System.Windows.Forms.PropertyGrid(); - this.splitContainer2 = new System.Windows.Forms.SplitContainer(); - this.hexEditor = new Be.Windows.Forms.HexBox(); - this.contextMenuStrip1.SuspendLayout(); - this.menuStrip1.SuspendLayout(); - this.statusStrip1.SuspendLayout(); - this.splitContainer1.Panel1.SuspendLayout(); - this.splitContainer1.Panel2.SuspendLayout(); - this.splitContainer1.SuspendLayout(); - this.splitContainer2.Panel1.SuspendLayout(); - this.splitContainer2.Panel2.SuspendLayout(); - this.splitContainer2.SuspendLayout(); - this.SuspendLayout(); - // - // openFileDialog1 - // - this.openFileDialog1.Filter = "Office files (*.xls *.doc *.ppt)|*.xls;*.doc;*.ppt|Thumbs db files (Thumbs.db)|*." + - "db|MSI Setup files (*.msi)|*.msi|All files (*.*)|*.*"; - this.openFileDialog1.Title = "Open OLE Structured Storae file"; - // - // treeView1 - // - this.treeView1.ContextMenuStrip = this.contextMenuStrip1; - this.treeView1.Dock = System.Windows.Forms.DockStyle.Fill; - this.treeView1.HideSelection = false; - this.treeView1.Location = new System.Drawing.Point(0, 0); - this.treeView1.Name = "treeView1"; - this.treeView1.Size = new System.Drawing.Size(241, 240); - this.treeView1.TabIndex = 4; - this.treeView1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.treeView1_MouseUp); - // - // contextMenuStrip1 - // - this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.importDataStripMenuItem1, - this.exportDataToolStripMenuItem, - this.addStorageStripMenuItem1, - this.addStreamToolStripMenuItem, - this.removeToolStripMenuItem}); - this.contextMenuStrip1.Name = "contextMenuStrip1"; - this.contextMenuStrip1.Size = new System.Drawing.Size(157, 114); - this.contextMenuStrip1.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuStrip1_Opening); - // - // importDataStripMenuItem1 - // - this.importDataStripMenuItem1.Name = "importDataStripMenuItem1"; - this.importDataStripMenuItem1.Size = new System.Drawing.Size(156, 22); - this.importDataStripMenuItem1.Text = "Import data..."; - this.importDataStripMenuItem1.Click += new System.EventHandler(this.importDataStripMenuItem1_Click); - // - // exportDataToolStripMenuItem - // - this.exportDataToolStripMenuItem.Name = "exportDataToolStripMenuItem"; - this.exportDataToolStripMenuItem.Size = new System.Drawing.Size(156, 22); - this.exportDataToolStripMenuItem.Text = "Export data..."; - this.exportDataToolStripMenuItem.Click += new System.EventHandler(this.exportDataToolStripMenuItem_Click); - // - // addStorageStripMenuItem1 - // - this.addStorageStripMenuItem1.Name = "addStorageStripMenuItem1"; - this.addStorageStripMenuItem1.Size = new System.Drawing.Size(156, 22); - this.addStorageStripMenuItem1.Text = "Add storage..."; - this.addStorageStripMenuItem1.Click += new System.EventHandler(this.addStorageStripMenuItem1_Click); - // - // addStreamToolStripMenuItem - // - this.addStreamToolStripMenuItem.Name = "addStreamToolStripMenuItem"; - this.addStreamToolStripMenuItem.Size = new System.Drawing.Size(156, 22); - this.addStreamToolStripMenuItem.Text = "Add stream..."; - this.addStreamToolStripMenuItem.Click += new System.EventHandler(this.addStreamToolStripMenuItem_Click); - // - // removeToolStripMenuItem - // - this.removeToolStripMenuItem.Name = "removeToolStripMenuItem"; - this.removeToolStripMenuItem.Size = new System.Drawing.Size(156, 22); - this.removeToolStripMenuItem.Text = "Remove"; - this.removeToolStripMenuItem.Click += new System.EventHandler(this.removeToolStripMenuItem_Click); - // - // saveFileDialog1 - // - this.saveFileDialog1.DefaultExt = "*.bin"; - this.saveFileDialog1.Filter = "Exported data files (*.bin)|*.bin|All files (*.*)|*.*"; - // - // menuStrip1 - // - this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.fileToolStripMenuItem}); - this.menuStrip1.Location = new System.Drawing.Point(0, 0); - this.menuStrip1.Name = "menuStrip1"; - this.menuStrip1.Size = new System.Drawing.Size(729, 24); - this.menuStrip1.TabIndex = 5; - this.menuStrip1.Text = "menuStrip1"; - // - // fileToolStripMenuItem - // - this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.openFileMenuItem, - this.newStripMenuItem1, - this.closeStripMenuItem1, - this.toolStripSeparator2, - this.updateCurrentFileToolStripMenuItem, - this.saveAsToolStripMenuItem}); - this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; - this.fileToolStripMenuItem.Size = new System.Drawing.Size(35, 20); - this.fileToolStripMenuItem.Text = "File"; - // - // openFileMenuItem - // - this.openFileMenuItem.Image = global::StructuredStorageExplorer.Properties.Resources.folder; - this.openFileMenuItem.Name = "openFileMenuItem"; - this.openFileMenuItem.Size = new System.Drawing.Size(179, 22); - this.openFileMenuItem.Text = "Open..."; - this.openFileMenuItem.Click += new System.EventHandler(this.openFileMenuItem_Click); - // - // newStripMenuItem1 - // - this.newStripMenuItem1.Image = global::StructuredStorageExplorer.Properties.Resources.page_white; - this.newStripMenuItem1.Name = "newStripMenuItem1"; - this.newStripMenuItem1.Size = new System.Drawing.Size(179, 22); - this.newStripMenuItem1.Text = "New Compound File"; - this.newStripMenuItem1.Click += new System.EventHandler(this.newStripMenuItem1_Click); - // - // closeStripMenuItem1 - // - this.closeStripMenuItem1.Name = "closeStripMenuItem1"; - this.closeStripMenuItem1.Size = new System.Drawing.Size(179, 22); - this.closeStripMenuItem1.Text = "Close file"; - this.closeStripMenuItem1.Click += new System.EventHandler(this.closeStripMenuItem1_Click); - // - // toolStripSeparator2 - // - this.toolStripSeparator2.Name = "toolStripSeparator2"; - this.toolStripSeparator2.Size = new System.Drawing.Size(176, 6); - // - // updateCurrentFileToolStripMenuItem - // - this.updateCurrentFileToolStripMenuItem.Image = global::StructuredStorageExplorer.Properties.Resources.disk; - this.updateCurrentFileToolStripMenuItem.Name = "updateCurrentFileToolStripMenuItem"; - this.updateCurrentFileToolStripMenuItem.Size = new System.Drawing.Size(179, 22); - this.updateCurrentFileToolStripMenuItem.Text = "Save"; - this.updateCurrentFileToolStripMenuItem.Click += new System.EventHandler(this.updateCurrentFileToolStripMenuItem_Click); - // - // saveAsToolStripMenuItem - // - this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem"; - this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(179, 22); - this.saveAsToolStripMenuItem.Text = "Save As..."; - this.saveAsToolStripMenuItem.Click += new System.EventHandler(this.saveAsToolStripMenuItem_Click); - // - // statusStrip1 - // - this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.fileNameLabel}); - this.statusStrip1.Location = new System.Drawing.Point(0, 509); - this.statusStrip1.Name = "statusStrip1"; - this.statusStrip1.Size = new System.Drawing.Size(729, 22); - this.statusStrip1.TabIndex = 6; - this.statusStrip1.Text = "statusStrip1"; - // - // fileNameLabel - // - this.fileNameLabel.Name = "fileNameLabel"; - this.fileNameLabel.Size = new System.Drawing.Size(0, 17); - // - // splitContainer1 - // - this.splitContainer1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; - this.splitContainer1.Location = new System.Drawing.Point(0, 0); - this.splitContainer1.Name = "splitContainer1"; - this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; - // - // splitContainer1.Panel1 - // - this.splitContainer1.Panel1.Controls.Add(this.treeView1); - // - // splitContainer1.Panel2 - // - this.splitContainer1.Panel2.Controls.Add(this.propertyGrid1); - this.splitContainer1.Size = new System.Drawing.Size(243, 485); - this.splitContainer1.SplitterDistance = 242; - this.splitContainer1.TabIndex = 5; - // - // propertyGrid1 - // - this.propertyGrid1.Dock = System.Windows.Forms.DockStyle.Fill; - this.propertyGrid1.Location = new System.Drawing.Point(0, 0); - this.propertyGrid1.Name = "propertyGrid1"; - this.propertyGrid1.Size = new System.Drawing.Size(241, 237); - this.propertyGrid1.TabIndex = 0; - this.propertyGrid1.ToolbarVisible = false; - // - // splitContainer2 - // - this.splitContainer2.Dock = System.Windows.Forms.DockStyle.Fill; - this.splitContainer2.Location = new System.Drawing.Point(0, 24); - this.splitContainer2.Name = "splitContainer2"; - // - // splitContainer2.Panel1 - // - this.splitContainer2.Panel1.Controls.Add(this.splitContainer1); - // - // splitContainer2.Panel2 - // - this.splitContainer2.Panel2.Controls.Add(this.hexEditor); - this.splitContainer2.Size = new System.Drawing.Size(729, 485); - this.splitContainer2.SplitterDistance = 243; - this.splitContainer2.TabIndex = 7; - // - // hexEditor - // - this.hexEditor.BackColor = System.Drawing.Color.WhiteSmoke; - this.hexEditor.Dock = System.Windows.Forms.DockStyle.Fill; - this.hexEditor.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.hexEditor.LineInfoForeColor = System.Drawing.Color.Empty; - this.hexEditor.LineInfoVisible = true; - this.hexEditor.Location = new System.Drawing.Point(0, 0); - this.hexEditor.Name = "hexEditor"; - this.hexEditor.ShadowSelectionColor = System.Drawing.Color.FromArgb(((int)(((byte)(100)))), ((int)(((byte)(60)))), ((int)(((byte)(188)))), ((int)(((byte)(255))))); - this.hexEditor.Size = new System.Drawing.Size(482, 485); - this.hexEditor.StringViewVisible = true; - this.hexEditor.TabIndex = 0; - this.hexEditor.UseFixedBytesPerLine = true; - this.hexEditor.VScrollBarVisible = true; - // - // MainForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(729, 531); - this.Controls.Add(this.splitContainer2); - this.Controls.Add(this.statusStrip1); - this.Controls.Add(this.menuStrip1); - this.MainMenuStrip = this.menuStrip1; - this.Name = "MainForm"; - this.Text = "Structured Storage eXplorer"; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing); - this.contextMenuStrip1.ResumeLayout(false); - this.menuStrip1.ResumeLayout(false); - this.menuStrip1.PerformLayout(); - this.statusStrip1.ResumeLayout(false); - this.statusStrip1.PerformLayout(); - this.splitContainer1.Panel1.ResumeLayout(false); - this.splitContainer1.Panel2.ResumeLayout(false); - this.splitContainer1.ResumeLayout(false); - this.splitContainer2.Panel1.ResumeLayout(false); - this.splitContainer2.Panel2.ResumeLayout(false); - this.splitContainer2.ResumeLayout(false); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.OpenFileDialog openFileDialog1; - private System.Windows.Forms.TreeView treeView1; - private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; - private System.Windows.Forms.ToolStripMenuItem exportDataToolStripMenuItem; - private System.Windows.Forms.SaveFileDialog saveFileDialog1; - private System.Windows.Forms.ToolStripMenuItem removeToolStripMenuItem; - private System.Windows.Forms.MenuStrip menuStrip1; - private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem saveAsToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem updateCurrentFileToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem addStreamToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem importDataStripMenuItem1; - private System.Windows.Forms.OpenFileDialog openDataFileDialog; - private System.Windows.Forms.ToolStripMenuItem addStorageStripMenuItem1; - private System.Windows.Forms.ToolStripMenuItem newStripMenuItem1; - private System.Windows.Forms.ToolStripMenuItem openFileMenuItem; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; - private System.Windows.Forms.StatusStrip statusStrip1; - private System.Windows.Forms.ToolStripStatusLabel fileNameLabel; - private System.Windows.Forms.SplitContainer splitContainer1; - private System.Windows.Forms.PropertyGrid propertyGrid1; - private System.Windows.Forms.SplitContainer splitContainer2; - private Be.Windows.Forms.HexBox hexEditor; - private System.Windows.Forms.ToolStripMenuItem closeStripMenuItem1; - } -} - +namespace StructuredStorageExplorer +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); + this.treeView1 = new System.Windows.Forms.TreeView(); + this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); + this.importDataStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.exportDataToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.addStorageStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.addStreamToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.removeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog(); + this.menuStrip1 = new System.Windows.Forms.MenuStrip(); + this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.openFileMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.newStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.closeStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); + this.updateCurrentFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.saveAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.openDataFileDialog = new System.Windows.Forms.OpenFileDialog(); + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); + this.fileNameLabel = new System.Windows.Forms.ToolStripStatusLabel(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.propertyGrid1 = new System.Windows.Forms.PropertyGrid(); + this.splitContainer2 = new System.Windows.Forms.SplitContainer(); + this.hexEditor = new Be.Windows.Forms.HexBox(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.dgvOLEProps = new System.Windows.Forms.DataGridView(); + this.contextMenuStrip1.SuspendLayout(); + this.menuStrip1.SuspendLayout(); + this.statusStrip1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).BeginInit(); + this.splitContainer2.Panel1.SuspendLayout(); + this.splitContainer2.Panel2.SuspendLayout(); + this.splitContainer2.SuspendLayout(); + this.tabControl1.SuspendLayout(); + this.tabPage1.SuspendLayout(); + this.tabPage2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.dgvOLEProps)).BeginInit(); + this.SuspendLayout(); + // + // openFileDialog1 + // + this.openFileDialog1.Filter = "Office files (*.xls *.doc *.ppt)|*.xls;*.doc;*.ppt|Thumbs db files (Thumbs.db)|*." + + "db|MSI Setup files (*.msi)|*.msi|All files (*.*)|*.*"; + this.openFileDialog1.Title = "Open OLE Structured Storae file"; + // + // treeView1 + // + this.treeView1.ContextMenuStrip = this.contextMenuStrip1; + this.treeView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.treeView1.HideSelection = false; + this.treeView1.Location = new System.Drawing.Point(0, 0); + this.treeView1.Name = "treeView1"; + this.treeView1.Size = new System.Drawing.Size(275, 264); + this.treeView1.TabIndex = 4; + this.treeView1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.treeView1_MouseUp); + // + // contextMenuStrip1 + // + this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.importDataStripMenuItem1, + this.exportDataToolStripMenuItem, + this.addStorageStripMenuItem1, + this.addStreamToolStripMenuItem, + this.removeToolStripMenuItem}); + this.contextMenuStrip1.Name = "contextMenuStrip1"; + this.contextMenuStrip1.Size = new System.Drawing.Size(148, 114); + this.contextMenuStrip1.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuStrip1_Opening); + // + // importDataStripMenuItem1 + // + this.importDataStripMenuItem1.Name = "importDataStripMenuItem1"; + this.importDataStripMenuItem1.Size = new System.Drawing.Size(147, 22); + this.importDataStripMenuItem1.Text = "Import data..."; + this.importDataStripMenuItem1.Click += new System.EventHandler(this.importDataStripMenuItem1_Click); + // + // exportDataToolStripMenuItem + // + this.exportDataToolStripMenuItem.Name = "exportDataToolStripMenuItem"; + this.exportDataToolStripMenuItem.Size = new System.Drawing.Size(147, 22); + this.exportDataToolStripMenuItem.Text = "Export data..."; + this.exportDataToolStripMenuItem.Click += new System.EventHandler(this.exportDataToolStripMenuItem_Click); + // + // addStorageStripMenuItem1 + // + this.addStorageStripMenuItem1.Name = "addStorageStripMenuItem1"; + this.addStorageStripMenuItem1.Size = new System.Drawing.Size(147, 22); + this.addStorageStripMenuItem1.Text = "Add storage..."; + this.addStorageStripMenuItem1.Click += new System.EventHandler(this.addStorageStripMenuItem1_Click); + // + // addStreamToolStripMenuItem + // + this.addStreamToolStripMenuItem.Name = "addStreamToolStripMenuItem"; + this.addStreamToolStripMenuItem.Size = new System.Drawing.Size(147, 22); + this.addStreamToolStripMenuItem.Text = "Add stream..."; + this.addStreamToolStripMenuItem.Click += new System.EventHandler(this.addStreamToolStripMenuItem_Click); + // + // removeToolStripMenuItem + // + this.removeToolStripMenuItem.Name = "removeToolStripMenuItem"; + this.removeToolStripMenuItem.Size = new System.Drawing.Size(147, 22); + this.removeToolStripMenuItem.Text = "Remove"; + this.removeToolStripMenuItem.Click += new System.EventHandler(this.removeToolStripMenuItem_Click); + // + // saveFileDialog1 + // + this.saveFileDialog1.DefaultExt = "*.bin"; + this.saveFileDialog1.Filter = "Exported data files (*.bin)|*.bin|All files (*.*)|*.*"; + // + // menuStrip1 + // + this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.fileToolStripMenuItem}); + this.menuStrip1.Location = new System.Drawing.Point(0, 0); + this.menuStrip1.Name = "menuStrip1"; + this.menuStrip1.Size = new System.Drawing.Size(833, 24); + this.menuStrip1.TabIndex = 5; + this.menuStrip1.Text = "menuStrip1"; + // + // fileToolStripMenuItem + // + this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.openFileMenuItem, + this.newStripMenuItem1, + this.closeStripMenuItem1, + this.toolStripSeparator2, + this.updateCurrentFileToolStripMenuItem, + this.saveAsToolStripMenuItem}); + this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; + this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); + this.fileToolStripMenuItem.Text = "File"; + // + // openFileMenuItem + // + this.openFileMenuItem.Image = global::StructuredStorageExplorer.Properties.Resources.folder; + this.openFileMenuItem.Name = "openFileMenuItem"; + this.openFileMenuItem.Size = new System.Drawing.Size(183, 22); + this.openFileMenuItem.Text = "Open..."; + this.openFileMenuItem.Click += new System.EventHandler(this.openFileMenuItem_Click); + // + // newStripMenuItem1 + // + this.newStripMenuItem1.Image = global::StructuredStorageExplorer.Properties.Resources.page_white; + this.newStripMenuItem1.Name = "newStripMenuItem1"; + this.newStripMenuItem1.Size = new System.Drawing.Size(183, 22); + this.newStripMenuItem1.Text = "New Compound File"; + this.newStripMenuItem1.Click += new System.EventHandler(this.newStripMenuItem1_Click); + // + // closeStripMenuItem1 + // + this.closeStripMenuItem1.Name = "closeStripMenuItem1"; + this.closeStripMenuItem1.Size = new System.Drawing.Size(183, 22); + this.closeStripMenuItem1.Text = "Close file"; + this.closeStripMenuItem1.Click += new System.EventHandler(this.closeStripMenuItem1_Click); + // + // toolStripSeparator2 + // + this.toolStripSeparator2.Name = "toolStripSeparator2"; + this.toolStripSeparator2.Size = new System.Drawing.Size(180, 6); + // + // updateCurrentFileToolStripMenuItem + // + this.updateCurrentFileToolStripMenuItem.Image = global::StructuredStorageExplorer.Properties.Resources.disk; + this.updateCurrentFileToolStripMenuItem.Name = "updateCurrentFileToolStripMenuItem"; + this.updateCurrentFileToolStripMenuItem.Size = new System.Drawing.Size(183, 22); + this.updateCurrentFileToolStripMenuItem.Text = "Save"; + this.updateCurrentFileToolStripMenuItem.Click += new System.EventHandler(this.updateCurrentFileToolStripMenuItem_Click); + // + // saveAsToolStripMenuItem + // + this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem"; + this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(183, 22); + this.saveAsToolStripMenuItem.Text = "Save As..."; + this.saveAsToolStripMenuItem.Click += new System.EventHandler(this.saveAsToolStripMenuItem_Click); + // + // statusStrip1 + // + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.fileNameLabel}); + this.statusStrip1.Location = new System.Drawing.Point(0, 559); + this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.Size = new System.Drawing.Size(833, 22); + this.statusStrip1.TabIndex = 6; + this.statusStrip1.Text = "statusStrip1"; + // + // fileNameLabel + // + this.fileNameLabel.Name = "fileNameLabel"; + this.fileNameLabel.Size = new System.Drawing.Size(0, 17); + // + // splitContainer1 + // + this.splitContainer1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.Controls.Add(this.treeView1); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.propertyGrid1); + this.splitContainer1.Size = new System.Drawing.Size(277, 535); + this.splitContainer1.SplitterDistance = 266; + this.splitContainer1.TabIndex = 5; + // + // propertyGrid1 + // + this.propertyGrid1.Dock = System.Windows.Forms.DockStyle.Fill; + this.propertyGrid1.Location = new System.Drawing.Point(0, 0); + this.propertyGrid1.Name = "propertyGrid1"; + this.propertyGrid1.Size = new System.Drawing.Size(275, 263); + this.propertyGrid1.TabIndex = 0; + this.propertyGrid1.ToolbarVisible = false; + // + // splitContainer2 + // + this.splitContainer2.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer2.Location = new System.Drawing.Point(0, 24); + this.splitContainer2.Name = "splitContainer2"; + // + // splitContainer2.Panel1 + // + this.splitContainer2.Panel1.Controls.Add(this.splitContainer1); + // + // splitContainer2.Panel2 + // + this.splitContainer2.Panel2.Controls.Add(this.tabControl1); + this.splitContainer2.Size = new System.Drawing.Size(833, 535); + this.splitContainer2.SplitterDistance = 277; + this.splitContainer2.TabIndex = 7; + // + // hexEditor + // + this.hexEditor.BackColor = System.Drawing.Color.WhiteSmoke; + this.hexEditor.Dock = System.Windows.Forms.DockStyle.Fill; + this.hexEditor.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.hexEditor.LineInfoForeColor = System.Drawing.Color.Empty; + this.hexEditor.LineInfoVisible = true; + this.hexEditor.Location = new System.Drawing.Point(3, 3); + this.hexEditor.Name = "hexEditor"; + this.hexEditor.ShadowSelectionColor = System.Drawing.Color.FromArgb(((int)(((byte)(100)))), ((int)(((byte)(60)))), ((int)(((byte)(188)))), ((int)(((byte)(255))))); + this.hexEditor.Size = new System.Drawing.Size(538, 503); + this.hexEditor.StringViewVisible = true; + this.hexEditor.TabIndex = 0; + this.hexEditor.UseFixedBytesPerLine = true; + this.hexEditor.VScrollBarVisible = true; + // + // tabControl1 + // + this.tabControl1.Controls.Add(this.tabPage1); + this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl1.Location = new System.Drawing.Point(0, 0); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(552, 535); + this.tabControl1.TabIndex = 1; + // + // tabPage1 + // + this.tabPage1.Controls.Add(this.hexEditor); + this.tabPage1.Location = new System.Drawing.Point(4, 22); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.Padding = new System.Windows.Forms.Padding(3); + this.tabPage1.Size = new System.Drawing.Size(544, 509); + this.tabPage1.TabIndex = 0; + this.tabPage1.Text = "Raw Data"; + this.tabPage1.UseVisualStyleBackColor = true; + // + // tabPage2 + // + this.tabPage2.Controls.Add(this.dgvOLEProps); + this.tabPage2.Location = new System.Drawing.Point(4, 22); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.Padding = new System.Windows.Forms.Padding(3); + this.tabPage2.Size = new System.Drawing.Size(544, 509); + this.tabPage2.TabIndex = 1; + this.tabPage2.Text = "OLE Properties"; + this.tabPage2.UseVisualStyleBackColor = true; + // + // dgvOLEProps + // + this.dgvOLEProps.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.dgvOLEProps.Dock = System.Windows.Forms.DockStyle.Fill; + this.dgvOLEProps.Location = new System.Drawing.Point(3, 3); + this.dgvOLEProps.Name = "dgvOLEProps"; + this.dgvOLEProps.Size = new System.Drawing.Size(538, 503); + this.dgvOLEProps.TabIndex = 0; + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(833, 581); + this.Controls.Add(this.splitContainer2); + this.Controls.Add(this.statusStrip1); + this.Controls.Add(this.menuStrip1); + this.MainMenuStrip = this.menuStrip1; + this.Name = "MainForm"; + this.Text = "Structured Storage eXplorer"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing); + this.contextMenuStrip1.ResumeLayout(false); + this.menuStrip1.ResumeLayout(false); + this.menuStrip1.PerformLayout(); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.splitContainer2.Panel1.ResumeLayout(false); + this.splitContainer2.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).EndInit(); + this.splitContainer2.ResumeLayout(false); + this.tabControl1.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.tabPage2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.dgvOLEProps)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.OpenFileDialog openFileDialog1; + private System.Windows.Forms.TreeView treeView1; + private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; + private System.Windows.Forms.ToolStripMenuItem exportDataToolStripMenuItem; + private System.Windows.Forms.SaveFileDialog saveFileDialog1; + private System.Windows.Forms.ToolStripMenuItem removeToolStripMenuItem; + private System.Windows.Forms.MenuStrip menuStrip1; + private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem saveAsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem updateCurrentFileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem addStreamToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem importDataStripMenuItem1; + private System.Windows.Forms.OpenFileDialog openDataFileDialog; + private System.Windows.Forms.ToolStripMenuItem addStorageStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem newStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem openFileMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; + private System.Windows.Forms.StatusStrip statusStrip1; + private System.Windows.Forms.ToolStripStatusLabel fileNameLabel; + private System.Windows.Forms.SplitContainer splitContainer1; + private System.Windows.Forms.PropertyGrid propertyGrid1; + private System.Windows.Forms.SplitContainer splitContainer2; + private Be.Windows.Forms.HexBox hexEditor; + private System.Windows.Forms.ToolStripMenuItem closeStripMenuItem1; + private System.Windows.Forms.TabControl tabControl1; + private System.Windows.Forms.TabPage tabPage1; + private System.Windows.Forms.TabPage tabPage2; + private System.Windows.Forms.DataGridView dgvOLEProps; + } +} + diff --git a/sources/Structured Storage Explorer/MainForm.cs b/sources/Structured Storage Explorer/MainForm.cs index 4d11d5eb..64ea3d6d 100644 --- a/sources/Structured Storage Explorer/MainForm.cs +++ b/sources/Structured Storage Explorer/MainForm.cs @@ -1,457 +1,485 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Text; -using System.Windows.Forms; -using OpenMcdf; -using System.IO; -using System.Resources; -using System.Globalization; -using StructuredStorageExplorer.Properties; -using Be.Windows.Forms; - -// Author Federico Blaseotto - -namespace StructuredStorageExplorer -{ - - /// - /// Sample Structured Storage viewer to - /// demonstrate use of OpenMCDF - /// - public partial class MainForm : Form - { - private CompoundFile cf; - private FileStream fs; - - public MainForm() - { - InitializeComponent(); - - //Load images for icons from resx - Image folderImage = (Image)Properties.Resources.ResourceManager.GetObject("storage"); - Image streamImage = (Image)Properties.Resources.ResourceManager.GetObject("stream"); - - treeView1.ImageList = new ImageList(); - treeView1.ImageList.Images.Add(folderImage); - treeView1.ImageList.Images.Add(streamImage); - - saveAsToolStripMenuItem.Enabled = false; - updateCurrentFileToolStripMenuItem.Enabled = false; - - } - - - - private void OpenFile() - { - if (!String.IsNullOrEmpty(openFileDialog1.FileName)) - { - CloseCurrentFile(); - - treeView1.Nodes.Clear(); - fileNameLabel.Text = openFileDialog1.FileName; - LoadFile(openFileDialog1.FileName, true); - canUpdate = true; - saveAsToolStripMenuItem.Enabled = true; - updateCurrentFileToolStripMenuItem.Enabled = true; - } - } - - private void CloseCurrentFile() - { - if (cf != null) - cf.Close(); - - if (fs != null) - fs.Close(); - - treeView1.Nodes.Clear(); - fileNameLabel.Text = String.Empty; - saveAsToolStripMenuItem.Enabled = false; - updateCurrentFileToolStripMenuItem.Enabled = false; - - propertyGrid1.SelectedObject = null; - hexEditor.ByteProvider = null; - } - - private bool canUpdate = false; - - private void CreateNewFile() - { - CloseCurrentFile(); - - cf = new CompoundFile(); - canUpdate = false; - saveAsToolStripMenuItem.Enabled = true; - - updateCurrentFileToolStripMenuItem.Enabled = false; - - RefreshTree(); - } - - private void RefreshTree() - { - treeView1.Nodes.Clear(); - - TreeNode root = null; - root = treeView1.Nodes.Add("Root Entry", "Root"); - root.ImageIndex = 0; - root.Tag = cf.RootStorage; - - //Recursive function to get all storage and streams - AddNodes(root, cf.RootStorage); - } - - private void LoadFile(string fileName, bool enableCommit) - { - - fs = new FileStream( - fileName, - FileMode.Open, - enableCommit ? - FileAccess.ReadWrite - : FileAccess.Read - ); - - try - { - if (cf != null) - { - cf.Close(); - cf = null; - } - - //Load file - if (enableCommit) - { - cf = new CompoundFile(fs, CFSUpdateMode.Update, CFSConfiguration.SectorRecycle | CFSConfiguration.NoValidationException | CFSConfiguration.EraseFreeSectors); - } - else - { - cf = new CompoundFile(fs); - } - - RefreshTree(); - } - catch (Exception ex) - { - treeView1.Nodes.Clear(); - fileNameLabel.Text = String.Empty; - MessageBox.Show("Internal error: " + ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - - /// - /// Recursive addition of tree nodes foreach child of current item in the storage - /// - /// Current TreeNode - /// Current storage associated with node - private void AddNodes(TreeNode node, CFStorage cfs) - { - Action va = delegate(CFItem target) - { - TreeNode temp = node.Nodes.Add( - target.Name, - target.Name + (target.IsStream ? " (" + target.Size + " bytes )" : "") - ); - - temp.Tag = target; - - if (target.IsStream) - { - //Stream - temp.ImageIndex = 1; - temp.SelectedImageIndex = 1; - - } - else - { - //Storage - temp.ImageIndex = 0; - temp.SelectedImageIndex = 0; - - //Recursion into the storage - AddNodes(temp, (CFStorage)target); - } - }; - - //Visit NON-recursively (first level only) - cfs.VisitEntries(va, false); - } - - - - private void exportDataToolStripMenuItem_Click(object sender, EventArgs e) - { - //No export if storage - if (treeView1.SelectedNode == null || !((CFItem)treeView1.SelectedNode.Tag).IsStream) - { - MessageBox.Show("Only stream data can be exported", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - - return; - } - - CFStream target = (CFStream)treeView1.SelectedNode.Tag; - - // A lot of stream and storage have only non-printable characters. - // We need to sanitize filename. - - String sanitizedFileName = String.Empty; - - foreach (char c in target.Name) - { - if ( - Char.GetUnicodeCategory(c) == UnicodeCategory.LetterNumber - || Char.GetUnicodeCategory(c) == UnicodeCategory.LowercaseLetter - || Char.GetUnicodeCategory(c) == UnicodeCategory.UppercaseLetter - ) - - sanitizedFileName += c; - } - - if (String.IsNullOrEmpty(sanitizedFileName)) - { - sanitizedFileName = "tempFileName"; - } - - saveFileDialog1.FileName = sanitizedFileName + ".bin"; - - if (saveFileDialog1.ShowDialog() == DialogResult.OK) - { - FileStream fs = null; - - try - { - fs = new FileStream(saveFileDialog1.FileName, FileMode.CreateNew, FileAccess.ReadWrite); - fs.Write(target.GetData(), 0, (int)target.Size); - } - catch (Exception ex) - { - treeView1.Nodes.Clear(); - MessageBox.Show("Internal error: " + ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - finally - { - if (fs != null) - { - fs.Flush(); - fs.Close(); - fs = null; - } - } - } - } - - private void removeToolStripMenuItem_Click(object sender, EventArgs e) - { - TreeNode n = treeView1.SelectedNode; - ((CFStorage)n.Parent.Tag).Delete(n.Name); - - RefreshTree(); - } - - private void saveAsToolStripMenuItem_Click(object sender, EventArgs e) - { - saveFileDialog1.FilterIndex = 2; - if (saveFileDialog1.ShowDialog() == DialogResult.OK) - { - cf.Save(saveFileDialog1.FileName); - } - } - - private void updateCurrentFileToolStripMenuItem_Click(object sender, EventArgs e) - { - if (canUpdate) - { - if (hexEditor.ByteProvider != null && hexEditor.ByteProvider.HasChanges()) - hexEditor.ByteProvider.ApplyChanges(); - cf.Commit(); - } - else - MessageBox.Show("Cannot update a compound document that is not based on a stream or on a file", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - - } - - private void addStreamToolStripMenuItem_Click(object sender, EventArgs e) - { - string streamName = String.Empty; - - if (Utils.InputBox("Add stream", "Insert stream name", ref streamName) == DialogResult.OK) - { - CFItem cfs = treeView1.SelectedNode.Tag as CFItem; - - if (cfs != null && (cfs.IsStorage || cfs.IsRoot)) - { - try - { - ((CFStorage)cfs).AddStream(streamName); - } - catch (CFDuplicatedItemException) - { - MessageBox.Show("Cannot insert a duplicated item", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - - - RefreshTree(); - } - } - - private void addStorageStripMenuItem1_Click(object sender, EventArgs e) - { - string storage = String.Empty; - - if (Utils.InputBox("Add storage", "Insert storage name", ref storage) == DialogResult.OK) - { - CFItem cfs = treeView1.SelectedNode.Tag as CFItem; - - if (cfs != null && (cfs.IsStorage || cfs.IsRoot)) - { - try - { - ((CFStorage)cfs).AddStorage(storage); - } - catch (CFDuplicatedItemException) - { - MessageBox.Show("Cannot insert a duplicated item", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - - RefreshTree(); - } - } - - private void importDataStripMenuItem1_Click(object sender, EventArgs e) - { - string fileName = String.Empty; - - if (openDataFileDialog.ShowDialog() == DialogResult.OK) - { - CFStream s = treeView1.SelectedNode.Tag as CFStream; - - if (s != null) - { - FileStream f = new FileStream(openDataFileDialog.FileName, FileMode.Open, FileAccess.Read, FileShare.Read); - byte[] data = new byte[f.Length]; - f.Read(data, 0, (int)f.Length); - f.Flush(); - f.Close(); - s.SetData(data); - - RefreshTree(); - } - } - } - - private void MainForm_FormClosing(object sender, FormClosingEventArgs e) - { - if (cf != null) - cf.Close(); - } - - private void contextMenuStrip1_Opening(object sender, CancelEventArgs e) - { - - } - - private void newStripMenuItem1_Click(object sender, EventArgs e) - { - - CreateNewFile(); - } - - private void openFileMenuItem_Click(object sender, EventArgs e) - { - if (openFileDialog1.ShowDialog() == DialogResult.OK) - { - try - { - OpenFile(); - } - catch - { - - } - } - } - - - private void treeView1_MouseUp(object sender, MouseEventArgs e) - { - // Get the node under the mouse cursor. - // We intercept both left and right mouse clicks - // and set the selected treenode according. - - TreeNode n = treeView1.GetNodeAt(e.X, e.Y); - - if (n != null) - { - if (this.hexEditor.ByteProvider != null && this.hexEditor.ByteProvider.HasChanges()) - { - if (MessageBox.Show("Do you want to save pending changes ?", "Save changes", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) - { - this.hexEditor.ByteProvider.ApplyChanges(); - } - } - - treeView1.SelectedNode = n; - - - // The tag property contains the underlying CFItem. - CFItem target = (CFItem)n.Tag; - - if (target.IsStream) - { - addStorageStripMenuItem1.Enabled = false; - addStreamToolStripMenuItem.Enabled = false; - importDataStripMenuItem1.Enabled = true; - exportDataToolStripMenuItem.Enabled = true; - } - else - { - addStorageStripMenuItem1.Enabled = true; - addStreamToolStripMenuItem.Enabled = true; - importDataStripMenuItem1.Enabled = false; - exportDataToolStripMenuItem.Enabled = false; - } - - propertyGrid1.SelectedObject = n.Tag; - - - - CFStream targetStream = n.Tag as CFStream; - if (targetStream != null) - { - this.hexEditor.ByteProvider = new StreamDataProvider(targetStream); - } - else - { - this.hexEditor.ByteProvider = null; - } - } - } - - void hexEditor_ByteProviderChanged(object sender, EventArgs e) - { - - } - - private void closeStripMenuItem1_Click(object sender, EventArgs e) - { - if (this.hexEditor.ByteProvider != null && this.hexEditor.ByteProvider.HasChanges()) - { - if (MessageBox.Show("Do you want to save pending changes ?", "Save changes", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) - { - this.hexEditor.ByteProvider.ApplyChanges(); - } - } - - CloseCurrentFile(); - } - - - } -} +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using OpenMcdf; +using System.IO; +using System.Resources; +using System.Globalization; +using StructuredStorageExplorer.Properties; +using Be.Windows.Forms; +using OpenMcdf.Extensions.OLEProperties; +using OpenMcdf.Extensions.OLEProperties.Interfaces; +using OpenMcdf.Extensions; + +// Author Federico Blaseotto + +namespace StructuredStorageExplorer +{ + + /// + /// Sample Structured Storage viewer to + /// demonstrate use of OpenMCDF + /// + public partial class MainForm : Form + { + private CompoundFile cf; + private FileStream fs; + + public MainForm() + { + InitializeComponent(); + + //Load images for icons from resx + Image folderImage = (Image)Properties.Resources.ResourceManager.GetObject("storage"); + Image streamImage = (Image)Properties.Resources.ResourceManager.GetObject("stream"); + Image olePropsImage = (Image)Properties.Resources.ResourceManager.GetObject("oleprops"); + + treeView1.ImageList = new ImageList(); + treeView1.ImageList.Images.Add(folderImage); + treeView1.ImageList.Images.Add(streamImage); + treeView1.ImageList.Images.Add(olePropsImage); + + saveAsToolStripMenuItem.Enabled = false; + updateCurrentFileToolStripMenuItem.Enabled = false; + + } + + + + private void OpenFile() + { + if (!String.IsNullOrEmpty(openFileDialog1.FileName)) + { + CloseCurrentFile(); + + treeView1.Nodes.Clear(); + fileNameLabel.Text = openFileDialog1.FileName; + LoadFile(openFileDialog1.FileName, true); + canUpdate = true; + saveAsToolStripMenuItem.Enabled = true; + updateCurrentFileToolStripMenuItem.Enabled = true; + } + } + + private void CloseCurrentFile() + { + if (cf != null) + cf.Close(); + + if (fs != null) + fs.Close(); + + treeView1.Nodes.Clear(); + fileNameLabel.Text = String.Empty; + saveAsToolStripMenuItem.Enabled = false; + updateCurrentFileToolStripMenuItem.Enabled = false; + + propertyGrid1.SelectedObject = null; + hexEditor.ByteProvider = null; + } + + private bool canUpdate = false; + + private void CreateNewFile() + { + CloseCurrentFile(); + + cf = new CompoundFile(); + canUpdate = false; + saveAsToolStripMenuItem.Enabled = true; + + updateCurrentFileToolStripMenuItem.Enabled = false; + + RefreshTree(); + } + + private void RefreshTree() + { + treeView1.Nodes.Clear(); + + TreeNode root = null; + root = treeView1.Nodes.Add("Root Entry", "Root"); + root.ImageIndex = 0; + root.Tag = cf.RootStorage; + + //Recursive function to get all storage and streams + AddNodes(root, cf.RootStorage); + } + + private void LoadFile(string fileName, bool enableCommit) + { + + fs = new FileStream( + fileName, + FileMode.Open, + enableCommit ? + FileAccess.ReadWrite + : FileAccess.Read + ); + + try + { + if (cf != null) + { + cf.Close(); + cf = null; + } + + //Load file + if (enableCommit) + { + cf = new CompoundFile(fs, CFSUpdateMode.Update, CFSConfiguration.SectorRecycle | CFSConfiguration.NoValidationException | CFSConfiguration.EraseFreeSectors); + } + else + { + cf = new CompoundFile(fs); + } + + RefreshTree(); + } + catch (Exception ex) + { + treeView1.Nodes.Clear(); + fileNameLabel.Text = String.Empty; + MessageBox.Show("Internal error: " + ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + /// + /// Recursive addition of tree nodes foreach child of current item in the storage + /// + /// Current TreeNode + /// Current storage associated with node + private void AddNodes(TreeNode node, CFStorage cfs) + { + Action va = delegate (CFItem target) + { + TreeNode temp = node.Nodes.Add( + target.Name, + target.Name + (target.IsStream ? " (" + target.Size + " bytes )" : "") + ); + + temp.Tag = target; + + if (target.IsStream) + { + + //Stream + temp.ImageIndex = 1; + temp.SelectedImageIndex = 1; + } + else + { + //Storage + temp.ImageIndex = 0; + temp.SelectedImageIndex = 0; + + //Recursion into the storage + AddNodes(temp, (CFStorage)target); + } + }; + + //Visit NON-recursively (first level only) + cfs.VisitEntries(va, false); + } + + + + private void exportDataToolStripMenuItem_Click(object sender, EventArgs e) + { + //No export if storage + if (treeView1.SelectedNode == null || !((CFItem)treeView1.SelectedNode.Tag).IsStream) + { + MessageBox.Show("Only stream data can be exported", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + + return; + } + + CFStream target = (CFStream)treeView1.SelectedNode.Tag; + + // A lot of stream and storage have only non-printable characters. + // We need to sanitize filename. + + String sanitizedFileName = String.Empty; + + foreach (char c in target.Name) + { + if ( + Char.GetUnicodeCategory(c) == UnicodeCategory.LetterNumber + || Char.GetUnicodeCategory(c) == UnicodeCategory.LowercaseLetter + || Char.GetUnicodeCategory(c) == UnicodeCategory.UppercaseLetter + ) + + sanitizedFileName += c; + } + + if (String.IsNullOrEmpty(sanitizedFileName)) + { + sanitizedFileName = "tempFileName"; + } + + saveFileDialog1.FileName = sanitizedFileName + ".bin"; + + if (saveFileDialog1.ShowDialog() == DialogResult.OK) + { + FileStream fs = null; + + try + { + fs = new FileStream(saveFileDialog1.FileName, FileMode.CreateNew, FileAccess.ReadWrite); + fs.Write(target.GetData(), 0, (int)target.Size); + } + catch (Exception ex) + { + treeView1.Nodes.Clear(); + MessageBox.Show("Internal error: " + ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + finally + { + if (fs != null) + { + fs.Flush(); + fs.Close(); + fs = null; + } + } + } + } + + private void removeToolStripMenuItem_Click(object sender, EventArgs e) + { + TreeNode n = treeView1.SelectedNode; + ((CFStorage)n.Parent.Tag).Delete(n.Name); + + RefreshTree(); + } + + private void saveAsToolStripMenuItem_Click(object sender, EventArgs e) + { + saveFileDialog1.FilterIndex = 2; + if (saveFileDialog1.ShowDialog() == DialogResult.OK) + { + cf.Save(saveFileDialog1.FileName); + } + } + + private void updateCurrentFileToolStripMenuItem_Click(object sender, EventArgs e) + { + if (canUpdate) + { + if (hexEditor.ByteProvider != null && hexEditor.ByteProvider.HasChanges()) + hexEditor.ByteProvider.ApplyChanges(); + cf.Commit(); + } + else + MessageBox.Show("Cannot update a compound document that is not based on a stream or on a file", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + + } + + private void addStreamToolStripMenuItem_Click(object sender, EventArgs e) + { + string streamName = String.Empty; + + if (Utils.InputBox("Add stream", "Insert stream name", ref streamName) == DialogResult.OK) + { + CFItem cfs = treeView1.SelectedNode.Tag as CFItem; + + if (cfs != null && (cfs.IsStorage || cfs.IsRoot)) + { + try + { + ((CFStorage)cfs).AddStream(streamName); + } + catch (CFDuplicatedItemException) + { + MessageBox.Show("Cannot insert a duplicated item", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + + RefreshTree(); + } + } + + private void addStorageStripMenuItem1_Click(object sender, EventArgs e) + { + string storage = String.Empty; + + if (Utils.InputBox("Add storage", "Insert storage name", ref storage) == DialogResult.OK) + { + CFItem cfs = treeView1.SelectedNode.Tag as CFItem; + + if (cfs != null && (cfs.IsStorage || cfs.IsRoot)) + { + try + { + ((CFStorage)cfs).AddStorage(storage); + } + catch (CFDuplicatedItemException) + { + MessageBox.Show("Cannot insert a duplicated item", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + RefreshTree(); + } + } + + private void importDataStripMenuItem1_Click(object sender, EventArgs e) + { + string fileName = String.Empty; + + if (openDataFileDialog.ShowDialog() == DialogResult.OK) + { + CFStream s = treeView1.SelectedNode.Tag as CFStream; + + if (s != null) + { + FileStream f = new FileStream(openDataFileDialog.FileName, FileMode.Open, FileAccess.Read, FileShare.Read); + byte[] data = new byte[f.Length]; + f.Read(data, 0, (int)f.Length); + f.Flush(); + f.Close(); + s.SetData(data); + + RefreshTree(); + } + } + } + + private void MainForm_FormClosing(object sender, FormClosingEventArgs e) + { + if (cf != null) + cf.Close(); + } + + private void contextMenuStrip1_Opening(object sender, CancelEventArgs e) + { + + } + + private void newStripMenuItem1_Click(object sender, EventArgs e) + { + + CreateNewFile(); + } + + private void openFileMenuItem_Click(object sender, EventArgs e) + { + if (openFileDialog1.ShowDialog() == DialogResult.OK) + { + try + { + OpenFile(); + } + catch + { + + } + } + } + + + private void treeView1_MouseUp(object sender, MouseEventArgs e) + { + // Get the node under the mouse cursor. + // We intercept both left and right mouse clicks + // and set the selected treenode according. + + TreeNode n = treeView1.GetNodeAt(e.X, e.Y); + + if (n != null) + { + if (this.hexEditor.ByteProvider != null && this.hexEditor.ByteProvider.HasChanges()) + { + if (MessageBox.Show("Do you want to save pending changes ?", "Save changes", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) + { + this.hexEditor.ByteProvider.ApplyChanges(); + } + } + + treeView1.SelectedNode = n; + + + // The tag property contains the underlying CFItem. + CFItem target = (CFItem)n.Tag; + + if (target.IsStream) + { + addStorageStripMenuItem1.Enabled = false; + addStreamToolStripMenuItem.Enabled = false; + importDataStripMenuItem1.Enabled = true; + exportDataToolStripMenuItem.Enabled = true; + + if (target.Name == "\u0005SummaryInformation" || target.Name == "\u0005DocumentSummaryInformation") + { + PropertySetStream mgr = ((CFStream)target).AsOLEProperties(); + + DataTable ds = new DataTable(); + ds.Columns.Add("Name", typeof(String)); + ds.Columns.Add("Type", typeof(String)); + ds.Columns.Add("Value", typeof(String)); + + for (int i = 0; i < mgr.PropertySet0.NumProperties; i++) + { + ITypedPropertyValue p = mgr.PropertySet0.Properties[i]; + + DataRow dr = ds.NewRow(); + dr.ItemArray = new Object[] { mgr.PropertySet0.PropertyIdentifierAndOffsets[i].PropertyIdentifier.GetDescription(), p.VTType, p.PropertyValue }; + ds.Rows.Add(dr); + } + + ds.AcceptChanges(); + dgvOLEProps.DataSource = ds; + } + } + } + else + { + addStorageStripMenuItem1.Enabled = true; + addStreamToolStripMenuItem.Enabled = true; + importDataStripMenuItem1.Enabled = false; + exportDataToolStripMenuItem.Enabled = false; + } + + propertyGrid1.SelectedObject = n.Tag; + + + + CFStream targetStream = n.Tag as CFStream; + if (targetStream != null) + { + this.hexEditor.ByteProvider = new StreamDataProvider(targetStream); + } + else + { + this.hexEditor.ByteProvider = null; + } + + } + + void hexEditor_ByteProviderChanged(object sender, EventArgs e) + { + + } + + private void closeStripMenuItem1_Click(object sender, EventArgs e) + { + if (this.hexEditor.ByteProvider != null && this.hexEditor.ByteProvider.HasChanges()) + { + if (MessageBox.Show("Do you want to save pending changes ?", "Save changes", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) + { + this.hexEditor.ByteProvider.ApplyChanges(); + } + } + + CloseCurrentFile(); + } + + + } +} diff --git a/sources/Structured Storage Explorer/MainForm.resx b/sources/Structured Storage Explorer/MainForm.resx index c2d7ab61..38dc0d6f 100644 --- a/sources/Structured Storage Explorer/MainForm.resx +++ b/sources/Structured Storage Explorer/MainForm.resx @@ -1,141 +1,141 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 17, 17 - - - 147, 17 - - - 292, 17 - - - 420, 17 - - - 529, 17 - - - 676, 17 - - - 42 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 147, 17 + + + 292, 17 + + + 420, 17 + + + 529, 17 + + + 676, 17 + + + 42 + \ No newline at end of file diff --git a/sources/Structured Storage Explorer/Program.cs b/sources/Structured Storage Explorer/Program.cs index 87927eb4..be515da4 100644 --- a/sources/Structured Storage Explorer/Program.cs +++ b/sources/Structured Storage Explorer/Program.cs @@ -1,20 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Windows.Forms; - -namespace StructuredStorageExplorer -{ - static class Program - { - /// - /// The main entry point for the application. - /// - [STAThread] - static void Main() - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new MainForm()); - } - } -} +using System; +using System.Collections.Generic; +using System.Windows.Forms; + +namespace StructuredStorageExplorer +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new MainForm()); + } + } +} diff --git a/sources/Structured Storage Explorer/Properties/AssemblyInfo.cs b/sources/Structured Storage Explorer/Properties/AssemblyInfo.cs index ac92070f..93e68e9b 100644 --- a/sources/Structured Storage Explorer/Properties/AssemblyInfo.cs +++ b/sources/Structured Storage Explorer/Properties/AssemblyInfo.cs @@ -1,35 +1,35 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("StucturedStorageExplorer")] -[assembly: AssemblyDescription("COM/OLE Stuctured Storage Viewer - Sample application for OpenMCDF component.")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("StucturedStorageExplorer")] -[assembly: AssemblyCopyright("Copyright © 2010-2015, Federico Blaseotto")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("aaf2d359-361e-47a3-883e-194bb63c7930")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.0.0.*")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("StucturedStorageExplorer")] +[assembly: AssemblyDescription("COM/OLE Stuctured Storage Viewer - Sample application for OpenMCDF component.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("StucturedStorageExplorer")] +[assembly: AssemblyCopyright("Copyright © 2010-2015, Federico Blaseotto")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("aaf2d359-361e-47a3-883e-194bb63c7930")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("2.0.0.*")] diff --git a/sources/Structured Storage Explorer/Properties/Resources.Designer.cs b/sources/Structured Storage Explorer/Properties/Resources.Designer.cs index 4747a906..dd55a353 100644 --- a/sources/Structured Storage Explorer/Properties/Resources.Designer.cs +++ b/sources/Structured Storage Explorer/Properties/Resources.Designer.cs @@ -1,105 +1,133 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.296 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace StructuredStorageExplorer.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("StructuredStorageExplorer.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - internal static System.Drawing.Bitmap disk { - get { - object obj = ResourceManager.GetObject("disk", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - internal static System.Drawing.Bitmap door_out { - get { - object obj = ResourceManager.GetObject("door_out", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - internal static System.Drawing.Bitmap folder { - get { - object obj = ResourceManager.GetObject("folder", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - internal static System.Drawing.Bitmap page_white { - get { - object obj = ResourceManager.GetObject("page_white", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - internal static System.Drawing.Bitmap storage { - get { - object obj = ResourceManager.GetObject("storage", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - internal static System.Drawing.Bitmap stream { - get { - object obj = ResourceManager.GetObject("stream", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace StructuredStorageExplorer.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("StructuredStorageExplorer.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap disk { + get { + object obj = ResourceManager.GetObject("disk", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap door_out { + get { + object obj = ResourceManager.GetObject("door_out", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap folder { + get { + object obj = ResourceManager.GetObject("folder", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap oleprops { + get { + object obj = ResourceManager.GetObject("oleprops", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap page_white { + get { + object obj = ResourceManager.GetObject("page_white", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap storage { + get { + object obj = ResourceManager.GetObject("storage", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap stream { + get { + object obj = ResourceManager.GetObject("stream", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/sources/Structured Storage Explorer/Properties/Resources.resx b/sources/Structured Storage Explorer/Properties/Resources.resx index 24ff768b..df7f48ea 100644 --- a/sources/Structured Storage Explorer/Properties/Resources.resx +++ b/sources/Structured Storage Explorer/Properties/Resources.resx @@ -1,139 +1,142 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - ..\img\disk.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\img\door_out.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\img\folder.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\img\page_white.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\img\storage.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\img\stream.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\img\disk.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\img\door_out.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\img\folder.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\img\application_view_detail.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\img\page_white.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\img\storage.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\img\stream.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/sources/Structured Storage Explorer/Properties/Settings.Designer.cs b/sources/Structured Storage Explorer/Properties/Settings.Designer.cs index eda65303..ae6feeb5 100644 --- a/sources/Structured Storage Explorer/Properties/Settings.Designer.cs +++ b/sources/Structured Storage Explorer/Properties/Settings.Designer.cs @@ -1,38 +1,38 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.296 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace StructuredStorageExplorer.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("True")] - public bool CommitEnabled { - get { - return ((bool)(this["CommitEnabled"])); - } - set { - this["CommitEnabled"] = value; - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.296 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace StructuredStorageExplorer.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool CommitEnabled { + get { + return ((bool)(this["CommitEnabled"])); + } + set { + this["CommitEnabled"] = value; + } + } + } +} diff --git a/sources/Structured Storage Explorer/Properties/Settings.settings b/sources/Structured Storage Explorer/Properties/Settings.settings index 9dcf7035..8fa6102b 100644 --- a/sources/Structured Storage Explorer/Properties/Settings.settings +++ b/sources/Structured Storage Explorer/Properties/Settings.settings @@ -1,9 +1,9 @@ - - - - - - True - - + + + + + + True + + \ No newline at end of file diff --git a/sources/Structured Storage Explorer/StreamDataProvider.cs b/sources/Structured Storage Explorer/StreamDataProvider.cs index 1b5b25a3..59adb868 100644 --- a/sources/Structured Storage Explorer/StreamDataProvider.cs +++ b/sources/Structured Storage Explorer/StreamDataProvider.cs @@ -1,178 +1,178 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Be.Windows.Forms; -using OpenMcdf; - -namespace StructuredStorageExplorer -{ - public class StreamDataProvider : IByteProvider - { - /// - /// Modifying stream - /// - CFStream _modifiedStream; - - /// - /// Contains information about changes. - /// - bool _hasChanges; - - /// - /// Contains a byte collection. - /// - ByteCollection _bytes; - - - /// - /// Initializes a new instance of the DynamicByteProvider class. - /// - /// - public StreamDataProvider(CFStream modifiedStream) - { - _bytes = new ByteCollection(modifiedStream.GetData()); - _modifiedStream = modifiedStream; - } - - /// - /// Raises the Changed event. - /// - void OnChanged(EventArgs e) - { - _hasChanges = true; - - if (Changed != null) - Changed(this, e); - } - - /// - /// Raises the LengthChanged event. - /// - void OnLengthChanged(EventArgs e) - { - if (LengthChanged != null) - LengthChanged(this, e); - } - - /// - /// Gets the byte collection. - /// - public ByteCollection Bytes - { - get { return _bytes; } - } - - #region IByteProvider Members - /// - /// True, when changes are done. - /// - public bool HasChanges() - { - return _hasChanges; - } - - /// - /// Applies changes. - /// - public void ApplyChanges() - { - _hasChanges = false; - - _modifiedStream.SetData(this._bytes.ToArray()); - } - - /// - /// Occurs, when the write buffer contains new changes. - /// - public event EventHandler Changed; - - /// - /// Occurs, when InsertBytes or DeleteBytes method is called. - /// - public event EventHandler LengthChanged; - - - /// - /// Reads a byte from the byte collection. - /// - /// the index of the byte to read - /// the byte - public byte ReadByte(long index) - { return _bytes[(int)index]; } - - /// - /// Write a byte into the byte collection. - /// - /// the index of the byte to write. - /// the byte - public void WriteByte(long index, byte value) - { - _bytes[(int)index] = value; - OnChanged(EventArgs.Empty); - } - - /// - /// Deletes bytes from the byte collection. - /// - /// the start index of the bytes to delete. - /// the length of bytes to delete. - public void DeleteBytes(long index, long length) - { - int internal_index = (int)Math.Max(0, index); - int internal_length = (int)Math.Min((int)Length, length); - _bytes.RemoveRange(internal_index, internal_length); - - OnLengthChanged(EventArgs.Empty); - OnChanged(EventArgs.Empty); - } - - /// - /// Inserts byte into the byte collection. - /// - /// the start index of the bytes in the byte collection - /// the byte array to insert - public void InsertBytes(long index, byte[] bs) - { - _bytes.InsertRange((int)index, bs); - - OnLengthChanged(EventArgs.Empty); - OnChanged(EventArgs.Empty); - } - - /// - /// Gets the length of the bytes in the byte collection. - /// - public long Length - { - get - { - return _bytes.Count; - } - } - - /// - /// Returns true - /// - public bool SupportsWriteByte() - { - return true; - } - - /// - /// Returns true - /// - public bool SupportsInsertBytes() - { - return true; - } - - /// - /// Returns true - /// - public bool SupportsDeleteBytes() - { - return true; - } - #endregion - } -} +using System; +using System.Collections.Generic; +using System.Text; +using Be.Windows.Forms; +using OpenMcdf; + +namespace StructuredStorageExplorer +{ + public class StreamDataProvider : IByteProvider + { + /// + /// Modifying stream + /// + CFStream _modifiedStream; + + /// + /// Contains information about changes. + /// + bool _hasChanges; + + /// + /// Contains a byte collection. + /// + ByteCollection _bytes; + + + /// + /// Initializes a new instance of the DynamicByteProvider class. + /// + /// + public StreamDataProvider(CFStream modifiedStream) + { + _bytes = new ByteCollection(modifiedStream.GetData()); + _modifiedStream = modifiedStream; + } + + /// + /// Raises the Changed event. + /// + void OnChanged(EventArgs e) + { + _hasChanges = true; + + if (Changed != null) + Changed(this, e); + } + + /// + /// Raises the LengthChanged event. + /// + void OnLengthChanged(EventArgs e) + { + if (LengthChanged != null) + LengthChanged(this, e); + } + + /// + /// Gets the byte collection. + /// + public ByteCollection Bytes + { + get { return _bytes; } + } + + #region IByteProvider Members + /// + /// True, when changes are done. + /// + public bool HasChanges() + { + return _hasChanges; + } + + /// + /// Applies changes. + /// + public void ApplyChanges() + { + _hasChanges = false; + + _modifiedStream.SetData(this._bytes.ToArray()); + } + + /// + /// Occurs, when the write buffer contains new changes. + /// + public event EventHandler Changed; + + /// + /// Occurs, when InsertBytes or DeleteBytes method is called. + /// + public event EventHandler LengthChanged; + + + /// + /// Reads a byte from the byte collection. + /// + /// the index of the byte to read + /// the byte + public byte ReadByte(long index) + { return _bytes[(int)index]; } + + /// + /// Write a byte into the byte collection. + /// + /// the index of the byte to write. + /// the byte + public void WriteByte(long index, byte value) + { + _bytes[(int)index] = value; + OnChanged(EventArgs.Empty); + } + + /// + /// Deletes bytes from the byte collection. + /// + /// the start index of the bytes to delete. + /// the length of bytes to delete. + public void DeleteBytes(long index, long length) + { + int internal_index = (int)Math.Max(0, index); + int internal_length = (int)Math.Min((int)Length, length); + _bytes.RemoveRange(internal_index, internal_length); + + OnLengthChanged(EventArgs.Empty); + OnChanged(EventArgs.Empty); + } + + /// + /// Inserts byte into the byte collection. + /// + /// the start index of the bytes in the byte collection + /// the byte array to insert + public void InsertBytes(long index, byte[] bs) + { + _bytes.InsertRange((int)index, bs); + + OnLengthChanged(EventArgs.Empty); + OnChanged(EventArgs.Empty); + } + + /// + /// Gets the length of the bytes in the byte collection. + /// + public long Length + { + get + { + return _bytes.Count; + } + } + + /// + /// Returns true + /// + public bool SupportsWriteByte() + { + return true; + } + + /// + /// Returns true + /// + public bool SupportsInsertBytes() + { + return true; + } + + /// + /// Returns true + /// + public bool SupportsDeleteBytes() + { + return true; + } + #endregion + } +} diff --git a/sources/Structured Storage Explorer/StructuredStorageExplorer.csproj b/sources/Structured Storage Explorer/StructuredStorageExplorer.csproj index c82777a8..43ce1295 100644 --- a/sources/Structured Storage Explorer/StructuredStorageExplorer.csproj +++ b/sources/Structured Storage Explorer/StructuredStorageExplorer.csproj @@ -110,6 +110,7 @@ + @@ -138,17 +139,21 @@ + + {db748c1d-d71c-442b-832d-2e33be816cbb} + OpenMcdf.Extensions + {56e15d4a-8a37-4c7c-bb44-fd59aff220c1} OpenMcdf - \ No newline at end of file diff --git a/sources/Structured Storage Explorer/Utils.cs b/sources/Structured Storage Explorer/Utils.cs index af4f289f..4c53406d 100644 --- a/sources/Structured Storage Explorer/Utils.cs +++ b/sources/Structured Storage Explorer/Utils.cs @@ -1,63 +1,63 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows.Forms; -using System.Drawing; -using OpenMcdf; - -namespace StructuredStorageExplorer -{ - class Utils - { - public static DialogResult InputBox(string title, string promptText, ref string value) - { - Form form = new Form(); - Label label = new Label(); - TextBox textBox = new TextBox(); - Button buttonOk = new Button(); - Button buttonCancel = new Button(); - - form.Text = title; - label.Text = promptText; - textBox.Text = value; - - buttonOk.Text = "OK"; - buttonCancel.Text = "Cancel"; - buttonOk.DialogResult = DialogResult.OK; - buttonCancel.DialogResult = DialogResult.Cancel; - - label.SetBounds(9, 20, 372, 13); - textBox.SetBounds(12, 36, 372, 20); - buttonOk.SetBounds(228, 72, 75, 23); - buttonCancel.SetBounds(309, 72, 75, 23); - - label.AutoSize = true; - textBox.Anchor = textBox.Anchor | AnchorStyles.Right; - buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; - buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; - - form.ClientSize = new Size(396, 107); - form.Controls.AddRange(new Control[] { label, textBox, buttonOk, buttonCancel }); - form.ClientSize = new Size(Math.Max(300, label.Right + 10), form.ClientSize.Height); - form.FormBorderStyle = FormBorderStyle.FixedDialog; - form.StartPosition = FormStartPosition.CenterScreen; - form.MinimizeBox = false; - form.MaximizeBox = false; - form.AcceptButton = buttonOk; - form.CancelButton = buttonCancel; - - DialogResult dialogResult = form.ShowDialog(); - value = textBox.Text; - return dialogResult; - } - - public static bool IsStreamTreeNode(TreeNode node) - { - return ((CFItem)node.Tag).IsStream; - } - } - - - - -} +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using OpenMcdf; + +namespace StructuredStorageExplorer +{ + class Utils + { + public static DialogResult InputBox(string title, string promptText, ref string value) + { + Form form = new Form(); + Label label = new Label(); + TextBox textBox = new TextBox(); + Button buttonOk = new Button(); + Button buttonCancel = new Button(); + + form.Text = title; + label.Text = promptText; + textBox.Text = value; + + buttonOk.Text = "OK"; + buttonCancel.Text = "Cancel"; + buttonOk.DialogResult = DialogResult.OK; + buttonCancel.DialogResult = DialogResult.Cancel; + + label.SetBounds(9, 20, 372, 13); + textBox.SetBounds(12, 36, 372, 20); + buttonOk.SetBounds(228, 72, 75, 23); + buttonCancel.SetBounds(309, 72, 75, 23); + + label.AutoSize = true; + textBox.Anchor = textBox.Anchor | AnchorStyles.Right; + buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + + form.ClientSize = new Size(396, 107); + form.Controls.AddRange(new Control[] { label, textBox, buttonOk, buttonCancel }); + form.ClientSize = new Size(Math.Max(300, label.Right + 10), form.ClientSize.Height); + form.FormBorderStyle = FormBorderStyle.FixedDialog; + form.StartPosition = FormStartPosition.CenterScreen; + form.MinimizeBox = false; + form.MaximizeBox = false; + form.AcceptButton = buttonOk; + form.CancelButton = buttonCancel; + + DialogResult dialogResult = form.ShowDialog(); + value = textBox.Text; + return dialogResult; + } + + public static bool IsStreamTreeNode(TreeNode node) + { + return ((CFItem)node.Tag).IsStream; + } + } + + + + +} diff --git a/sources/Structured Storage Explorer/app.config b/sources/Structured Storage Explorer/app.config index 2f7c4d35..150f7756 100644 --- a/sources/Structured Storage Explorer/app.config +++ b/sources/Structured Storage Explorer/app.config @@ -1,15 +1,15 @@ - - - - -
- - - - - - True - - - - + + + + +
+ + + + + + True + + + + diff --git a/sources/Test/OpenMcdf.Extensions.Test/CFSStreamExtensionsTest.cs b/sources/Test/OpenMcdf.Extensions.Test/CFSStreamExtensionsTest.cs index db0f63e3..5ab0c428 100644 --- a/sources/Test/OpenMcdf.Extensions.Test/CFSStreamExtensionsTest.cs +++ b/sources/Test/OpenMcdf.Extensions.Test/CFSStreamExtensionsTest.cs @@ -1,89 +1,89 @@ -using System; -using System.IO; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace OpenMcdf.Extensions.Test -{ - /// - /// Summary description for UnitTest1 - /// - [TestClass] - public class CFSStreamExtensionsTest - { - public CFSStreamExtensionsTest() - { - - } - - - private TestContext testContextInstance; - - /// - ///Gets or sets the test context which provides - ///information about and functionality for the current test run. - /// - public TestContext TestContext - { - get - { - return testContextInstance; - } - set - { - testContextInstance = value; - } - } - - #region Additional test attributes - // - // You can use the following additional attributes as you write your tests: - // - // Use ClassInitialize to run code before running the first test in the class - // [ClassInitialize()] - // public static void MyClassInitialize(TestContext testContext) { } - // - // Use ClassCleanup to run code after all tests in a class have run - // [ClassCleanup()] - // public static void MyClassCleanup() { } - // - // Use TestInitialize to run code before running each test - // [TestInitialize()] - // public void MyTestInitialize() { } - // - // Use TestCleanup to run code after each test has run - // [TestCleanup()] - // public void MyTestCleanup() { } - // - #endregion - - [TestMethod] - public void Test_AS_IOSTREAM_READ() - { - CompoundFile cf = new CompoundFile("MultipleStorage.cfs"); - - Stream s = cf.RootStorage.GetStorage("MyStorage").GetStream("MyStream").AsIOStream(); - BinaryReader br = new BinaryReader(s); - byte[] result = br.ReadBytes(32); - Assert.IsTrue(Helpers.CompareBuffer(Helpers.GetBuffer(32, 1), result)); - } - - [TestMethod] - public void Test_AS_IOSTREAM_WRITE() - { - const String cmp = "Hello World of BinaryWriter !"; - - CompoundFile cf = new CompoundFile(); - Stream s = cf.RootStorage.AddStream("ANewStream").AsIOStream(); - BinaryWriter bw = new BinaryWriter(s); - bw.Write(cmp); - cf.Save("$ACFFile.cfs"); - cf.Close(); - - cf = new CompoundFile("$ACFFile.cfs"); - BinaryReader br = new BinaryReader(cf.RootStorage.GetStream("ANewStream").AsIOStream()); - String st = br.ReadString(); - Assert.IsTrue(st == cmp); - cf.Close(); - } - } -} +using System; +using System.IO; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace OpenMcdf.Extensions.Test +{ + /// + /// Summary description for UnitTest1 + /// + [TestClass] + public class CFSStreamExtensionsTest + { + public CFSStreamExtensionsTest() + { + + } + + + private TestContext testContextInstance; + + /// + ///Gets or sets the test context which provides + ///information about and functionality for the current test run. + /// + public TestContext TestContext + { + get + { + return testContextInstance; + } + set + { + testContextInstance = value; + } + } + + #region Additional test attributes + // + // You can use the following additional attributes as you write your tests: + // + // Use ClassInitialize to run code before running the first test in the class + // [ClassInitialize()] + // public static void MyClassInitialize(TestContext testContext) { } + // + // Use ClassCleanup to run code after all tests in a class have run + // [ClassCleanup()] + // public static void MyClassCleanup() { } + // + // Use TestInitialize to run code before running each test + // [TestInitialize()] + // public void MyTestInitialize() { } + // + // Use TestCleanup to run code after each test has run + // [TestCleanup()] + // public void MyTestCleanup() { } + // + #endregion + + [TestMethod] + public void Test_AS_IOSTREAM_READ() + { + CompoundFile cf = new CompoundFile("MultipleStorage.cfs"); + + Stream s = cf.RootStorage.GetStorage("MyStorage").GetStream("MyStream").AsIOStream(); + BinaryReader br = new BinaryReader(s); + byte[] result = br.ReadBytes(32); + Assert.IsTrue(Helpers.CompareBuffer(Helpers.GetBuffer(32, 1), result)); + } + + [TestMethod] + public void Test_AS_IOSTREAM_WRITE() + { + const String cmp = "Hello World of BinaryWriter !"; + + CompoundFile cf = new CompoundFile(); + Stream s = cf.RootStorage.AddStream("ANewStream").AsIOStream(); + BinaryWriter bw = new BinaryWriter(s); + bw.Write(cmp); + cf.Save("$ACFFile.cfs"); + cf.Close(); + + cf = new CompoundFile("$ACFFile.cfs"); + BinaryReader br = new BinaryReader(cf.RootStorage.GetStream("ANewStream").AsIOStream()); + String st = br.ReadString(); + Assert.IsTrue(st == cmp); + cf.Close(); + } + } +} diff --git a/sources/Test/OpenMcdf.Extensions.Test/Helpers.cs b/sources/Test/OpenMcdf.Extensions.Test/Helpers.cs index 458c24d1..8910e56e 100644 --- a/sources/Test/OpenMcdf.Extensions.Test/Helpers.cs +++ b/sources/Test/OpenMcdf.Extensions.Test/Helpers.cs @@ -1,49 +1,49 @@ -using System; - -namespace OpenMcdf.Extensions.Test -{ - public static class Helpers - { - public static byte[] GetBuffer(int count) - { - Random r = new Random(); - byte[] b = new byte[count]; - r.NextBytes(b); - return b; - } - - public static byte[] GetBuffer(int count, byte c) - { - byte[] b = new byte[count]; - for (int i = 0; i < b.Length; i++) - { - b[i] = c; - } - - return b; - } - - public static bool CompareBuffer(byte[] b, byte[] p) - { - if (b == null && p == null) - throw new Exception("Null buffers"); - - if (b == null && p != null) - return false; - - if (b != null && p == null) - return false; - - if (b.Length != p.Length) - return false; - - for (int i = 0; i < b.Length; i++) - { - if (b[i] != p[i]) - return false; - } - - return true; - } - } -} +using System; + +namespace OpenMcdf.Extensions.Test +{ + public static class Helpers + { + public static byte[] GetBuffer(int count) + { + Random r = new Random(); + byte[] b = new byte[count]; + r.NextBytes(b); + return b; + } + + public static byte[] GetBuffer(int count, byte c) + { + byte[] b = new byte[count]; + for (int i = 0; i < b.Length; i++) + { + b[i] = c; + } + + return b; + } + + public static bool CompareBuffer(byte[] b, byte[] p) + { + if (b == null && p == null) + throw new Exception("Null buffers"); + + if (b == null && p != null) + return false; + + if (b != null && p == null) + return false; + + if (b.Length != p.Length) + return false; + + for (int i = 0; i < b.Length; i++) + { + if (b[i] != p[i]) + return false; + } + + return true; + } + } +} diff --git a/sources/Test/OpenMcdf.Extensions.Test/OpenMcdf.Extensions.Test.csproj b/sources/Test/OpenMcdf.Extensions.Test/OpenMcdf.Extensions.Test.csproj index ad68c6be..b42be158 100644 --- a/sources/Test/OpenMcdf.Extensions.Test/OpenMcdf.Extensions.Test.csproj +++ b/sources/Test/OpenMcdf.Extensions.Test/OpenMcdf.Extensions.Test.csproj @@ -49,10 +49,6 @@ - - - - {db748c1d-d71c-442b-832d-2e33be816cbb} @@ -64,11 +60,11 @@ - \ No newline at end of file diff --git a/sources/Test/OpenMcdf.Extensions.Test/Properties/AssemblyInfo.cs b/sources/Test/OpenMcdf.Extensions.Test/Properties/AssemblyInfo.cs index 19e8e3b4..57080022 100644 --- a/sources/Test/OpenMcdf.Extensions.Test/Properties/AssemblyInfo.cs +++ b/sources/Test/OpenMcdf.Extensions.Test/Properties/AssemblyInfo.cs @@ -1,35 +1,35 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenMcdfExtensionsTest")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("-")] -[assembly: AssemblyProduct("OpenMcdfExtensionsTest")] -[assembly: AssemblyCopyright("Copyright © Federico Blaseotto - 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("80a1f6c3-2533-4e2b-9c49-46dd8e3a1e33")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenMcdfExtensionsTest")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("-")] +[assembly: AssemblyProduct("OpenMcdfExtensionsTest")] +[assembly: AssemblyCopyright("Copyright © Federico Blaseotto - 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("80a1f6c3-2533-4e2b-9c49-46dd8e3a1e33")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/sources/Test/OpenMcdf.MemTest/OpenMcdf.MemTest.csproj b/sources/Test/OpenMcdf.MemTest/OpenMcdf.MemTest.csproj index 1343c3a2..b5552a61 100644 --- a/sources/Test/OpenMcdf.MemTest/OpenMcdf.MemTest.csproj +++ b/sources/Test/OpenMcdf.MemTest/OpenMcdf.MemTest.csproj @@ -1,99 +1,99 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {E2BAD82D-3040-462B-BAA2-6E608A9054F4} - Exe - Properties - OpenMcdfMemTest - OpenMcdfMemTest - v4.0 - 512 - - - 3.5 - - http://localhost/OpenMcdfMemTest/ - true - Web - true - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - true - false - true - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - - - - - - - - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - {56e15d4a-8a37-4c7c-bb44-fd59aff220c1} - OpenMcdf - - - - + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {E2BAD82D-3040-462B-BAA2-6E608A9054F4} + Exe + Properties + OpenMcdfMemTest + OpenMcdfMemTest + v4.0 + 512 + + + 3.5 + + http://localhost/OpenMcdfMemTest/ + true + Web + true + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + true + false + true + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + {56e15d4a-8a37-4c7c-bb44-fd59aff220c1} + OpenMcdf + + + + \ No newline at end of file diff --git a/sources/Test/OpenMcdf.MemTest/Program.cs b/sources/Test/OpenMcdf.MemTest/Program.cs index 22e2e8a1..f1a2c072 100644 --- a/sources/Test/OpenMcdf.MemTest/Program.cs +++ b/sources/Test/OpenMcdf.MemTest/Program.cs @@ -1,325 +1,325 @@ -using System; -using System.IO; -using System.Diagnostics; - -using OpenMcdf; -//This project is used for profiling memory and performances of OpenMCDF . - -namespace OpenMcdf.MemTest -{ - class Program - { - static void Main(string[] args) - { - - //TestMultipleStreamCommit(); - TestCode(); - //StressMemory(); - //DummyFile(); - //Console.WriteLine("CLOSED"); - //Console.ReadKey(); - } - - private static void TestCode() - { - const int N_FACTOR = 1000; - - byte[] bA = GetBuffer(20 * 1024 * N_FACTOR, 0x0A); - byte[] bB = GetBuffer(5 * 1024, 0x0B); - byte[] bC = GetBuffer(5 * 1024, 0x0C); - byte[] bD = GetBuffer(5 * 1024, 0x0D); - byte[] bE = GetBuffer(8 * 1024 * N_FACTOR + 1, 0x1A); - byte[] bF = GetBuffer(16 * 1024 * N_FACTOR, 0x1B); - byte[] bG = GetBuffer(14 * 1024 * N_FACTOR, 0x1C); - byte[] bH = GetBuffer(12 * 1024 * N_FACTOR, 0x1D); - byte[] bE2 = GetBuffer(8 * 1024 * N_FACTOR, 0x2A); - byte[] bMini = GetBuffer(1027, 0xEE); - - Stopwatch sw = new Stopwatch(); - sw.Start(); - - var cf = new CompoundFile(CFSVersion.Ver_3, CFSConfiguration.SectorRecycle); - cf.RootStorage.AddStream("A").SetData(bA); - cf.Save("OneStream.cfs"); - - cf.Close(); - - cf = new CompoundFile("OneStream.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.SectorRecycle); - - cf.RootStorage.AddStream("B").SetData(bB); - cf.RootStorage.AddStream("C").SetData(bC); - cf.RootStorage.AddStream("D").SetData(bD); - cf.RootStorage.AddStream("E").SetData(bE); - cf.RootStorage.AddStream("F").SetData(bF); - cf.RootStorage.AddStream("G").SetData(bG); - cf.RootStorage.AddStream("H").SetData(bH); - - cf.Save("8_Streams.cfs"); - - cf.Close(); - - File.Copy("8_Streams.cfs", "6_Streams.cfs", true); - - cf = new CompoundFile("6_Streams.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle|CFSConfiguration.EraseFreeSectors); - cf.RootStorage.Delete("D"); - cf.RootStorage.Delete("G"); - cf.Commit(); - - cf.Close(); - - File.Copy("6_Streams.cfs", "6_Streams_Shrinked.cfs", true); - - cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); - cf.RootStorage.AddStream("ZZZ").SetData(bF); - cf.RootStorage.GetStream("E").Append(bE2); - cf.Commit(); - cf.Close(); - - cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); - cf.RootStorage.CLSID = new Guid("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"); - cf.Commit(); - cf.Close(); - - cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); - cf.RootStorage.AddStorage("MyStorage").AddStream("ANS").Append(bE); - cf.Commit(); - cf.Close(); - - cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); - cf.RootStorage.AddStorage("AnotherStorage").AddStream("ANS").Append(bE); - cf.RootStorage.Delete("MyStorage"); - cf.Commit(); - cf.Close(); - - CompoundFile.ShrinkCompoundFile("6_Streams_Shrinked.cfs"); - - cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); - cf.RootStorage.AddStorage("MiniStorage").AddStream("miniSt").Append(bMini); - cf.RootStorage.GetStorage("MiniStorage").AddStream("miniSt2").Append(bMini); - cf.Commit(); - cf.Close(); - - cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); - cf.RootStorage.GetStorage("MiniStorage").Delete("miniSt"); - - - cf.RootStorage.GetStorage("MiniStorage").GetStream("miniSt2").Append(bE); - cf.Commit(); - cf.Close(); - - cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.SectorRecycle); - - var myStream = cf.RootStorage.GetStream("C"); - var data = myStream.GetData(); - Console.WriteLine(data[0] + " : " + data[data.Length - 1]); - - myStream = cf.RootStorage.GetStream("B"); - data = myStream.GetData(); - Console.WriteLine(data[0] + " : " + data[data.Length - 1]); - - cf.Close(); - - sw.Stop(); - Console.WriteLine(sw.ElapsedMilliseconds); - - Console.ReadKey(); - } - - private static void StressMemory() - { - const int N_LOOP = 20; - const int MB_SIZE = 10; - - byte[] b = GetBuffer(1024 * 1024 * MB_SIZE); //2GB buffer - byte[] cmp = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }; - - CompoundFile cf = new CompoundFile(CFSVersion.Ver_4, CFSConfiguration.Default); - CFStream st = cf.RootStorage.AddStream("MySuperLargeStream"); - cf.Save("LARGE.cfs"); - cf.Close(); - - //Console.WriteLine("Closed save"); - //Console.ReadKey(); - - cf = new CompoundFile("LARGE.cfs", CFSUpdateMode.Update, CFSConfiguration.Default); - CFStream cfst = cf.RootStorage.GetStream("MySuperLargeStream"); - - Stopwatch sw = new Stopwatch(); - sw.Start(); - for (int i = 0; i < N_LOOP; i++) - { - - cfst.Append(b); - cf.Commit(true); - - Console.WriteLine(" Updated " + i.ToString()); - //Console.ReadKey(); - } - - cfst.Append(cmp); - cf.Commit(true); - sw.Stop(); - - - cf.Close(); - - Console.WriteLine(sw.Elapsed.TotalMilliseconds); - sw.Reset(); - - //Console.WriteLine(sw.Elapsed.TotalMilliseconds); - - //Console.WriteLine("Closed Transacted"); - //Console.ReadKey(); - - cf = new CompoundFile("LARGE.cfs"); - int count = 8; - sw.Reset(); - sw.Start(); - byte[] data = new byte[count]; - count = cf.RootStorage.GetStream("MySuperLargeStream").Read(data, b.Length * (long)N_LOOP, count); - sw.Stop(); - Console.Write(count); - cf.Close(); - - Console.WriteLine("Closed Final " + sw.ElapsedMilliseconds); - Console.ReadKey(); - - } - - private static void DummyFile() - { - Console.WriteLine("Start"); - FileStream fs = new FileStream("myDummyFile", FileMode.Create); - fs.Close(); - - Stopwatch sw = new Stopwatch(); - - byte[] b = GetBuffer(1024 * 1024 * 50); //2GB buffer - - fs = new FileStream("myDummyFile", FileMode.Open); - sw.Start(); - for (int i = 0; i < 42; i++) - { - - fs.Seek(b.Length * i, SeekOrigin.Begin); - fs.Write(b, 0, b.Length); - - } - - fs.Close(); - sw.Stop(); - Console.WriteLine("Stop - " + sw.ElapsedMilliseconds); - sw.Reset(); - - Console.ReadKey(); - } - - private static void AddNodes(String depth, CFStorage cfs) - { - - Action va = delegate(CFItem target) - { - - String temp = target.Name + (target is CFStorage ? "" : " (" + target.Size + " bytes )"); - - //Stream - - Console.WriteLine(depth + temp); - - if (target is CFStorage) - { //Storage - - String newDepth = depth + " "; - - //Recursion into the storage - AddNodes(newDepth, (CFStorage)target); - - } - }; - - //Visit NON-recursively (first level only) - cfs.VisitEntries(va, false); - } - - public static void TestMultipleStreamCommit() - { - String srcFilename = Directory.GetCurrentDirectory() + @"\testfile\report.xls"; - String dstFilename = Directory.GetCurrentDirectory() + @"\testfile\reportOverwriteMultiple.xls"; - //Console.WriteLine(Directory.GetCurrentDirectory()); - //Console.ReadKey(); - File.Copy(srcFilename, dstFilename, true); - - CompoundFile cf = new CompoundFile(dstFilename, CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); - - Random r = new Random(); - - DateTime start = DateTime.Now; - - for (int i = 0; i < 1000; i++) - { - byte[] buffer = GetBuffer(r.Next(100, 3500), 0x0A); - - if (i > 0) - { - if (r.Next(0, 100) > 50) - { - cf.RootStorage.Delete("MyNewStream" + (i - 1).ToString()); - } - } - - CFStream addedStream = cf.RootStorage.AddStream("MyNewStream" + i.ToString()); - - addedStream.SetData(buffer); - - // Random commit, not on single addition - if (r.Next(0, 100) > 50) - cf.Commit(); - } - - cf.Close(); - - TimeSpan sp = (DateTime.Now - start); - Console.WriteLine(sp.TotalMilliseconds); - - } - - private static byte[] GetBuffer(int count) - { - Random r = new Random(); - byte[] b = new byte[count]; - r.NextBytes(b); - return b; - } - - private static byte[] GetBuffer(int count, byte c) - { - byte[] b = new byte[count]; - for (int i = 0; i < b.Length; i++) - { - b[i] = c; - } - - return b; - } - - private static bool CompareBuffer(byte[] b, byte[] p) - { - if (b == null && p == null) - throw new Exception("Null buffers"); - - if (b == null && p != null) return false; - if (b != null && p == null) return false; - - if (b.Length != p.Length) - return false; - - for (int i = 0; i < b.Length; i++) - { - if (b[i] != p[i]) - return false; - } - - return true; - } - } -} +using System; +using System.IO; +using System.Diagnostics; + +using OpenMcdf; +//This project is used for profiling memory and performances of OpenMCDF . + +namespace OpenMcdf.MemTest +{ + class Program + { + static void Main(string[] args) + { + + //TestMultipleStreamCommit(); + TestCode(); + //StressMemory(); + //DummyFile(); + //Console.WriteLine("CLOSED"); + //Console.ReadKey(); + } + + private static void TestCode() + { + const int N_FACTOR = 1000; + + byte[] bA = GetBuffer(20 * 1024 * N_FACTOR, 0x0A); + byte[] bB = GetBuffer(5 * 1024, 0x0B); + byte[] bC = GetBuffer(5 * 1024, 0x0C); + byte[] bD = GetBuffer(5 * 1024, 0x0D); + byte[] bE = GetBuffer(8 * 1024 * N_FACTOR + 1, 0x1A); + byte[] bF = GetBuffer(16 * 1024 * N_FACTOR, 0x1B); + byte[] bG = GetBuffer(14 * 1024 * N_FACTOR, 0x1C); + byte[] bH = GetBuffer(12 * 1024 * N_FACTOR, 0x1D); + byte[] bE2 = GetBuffer(8 * 1024 * N_FACTOR, 0x2A); + byte[] bMini = GetBuffer(1027, 0xEE); + + Stopwatch sw = new Stopwatch(); + sw.Start(); + + var cf = new CompoundFile(CFSVersion.Ver_3, CFSConfiguration.SectorRecycle); + cf.RootStorage.AddStream("A").SetData(bA); + cf.Save("OneStream.cfs"); + + cf.Close(); + + cf = new CompoundFile("OneStream.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.SectorRecycle); + + cf.RootStorage.AddStream("B").SetData(bB); + cf.RootStorage.AddStream("C").SetData(bC); + cf.RootStorage.AddStream("D").SetData(bD); + cf.RootStorage.AddStream("E").SetData(bE); + cf.RootStorage.AddStream("F").SetData(bF); + cf.RootStorage.AddStream("G").SetData(bG); + cf.RootStorage.AddStream("H").SetData(bH); + + cf.Save("8_Streams.cfs"); + + cf.Close(); + + File.Copy("8_Streams.cfs", "6_Streams.cfs", true); + + cf = new CompoundFile("6_Streams.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle|CFSConfiguration.EraseFreeSectors); + cf.RootStorage.Delete("D"); + cf.RootStorage.Delete("G"); + cf.Commit(); + + cf.Close(); + + File.Copy("6_Streams.cfs", "6_Streams_Shrinked.cfs", true); + + cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); + cf.RootStorage.AddStream("ZZZ").SetData(bF); + cf.RootStorage.GetStream("E").Append(bE2); + cf.Commit(); + cf.Close(); + + cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); + cf.RootStorage.CLSID = new Guid("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"); + cf.Commit(); + cf.Close(); + + cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); + cf.RootStorage.AddStorage("MyStorage").AddStream("ANS").Append(bE); + cf.Commit(); + cf.Close(); + + cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); + cf.RootStorage.AddStorage("AnotherStorage").AddStream("ANS").Append(bE); + cf.RootStorage.Delete("MyStorage"); + cf.Commit(); + cf.Close(); + + CompoundFile.ShrinkCompoundFile("6_Streams_Shrinked.cfs"); + + cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); + cf.RootStorage.AddStorage("MiniStorage").AddStream("miniSt").Append(bMini); + cf.RootStorage.GetStorage("MiniStorage").AddStream("miniSt2").Append(bMini); + cf.Commit(); + cf.Close(); + + cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); + cf.RootStorage.GetStorage("MiniStorage").Delete("miniSt"); + + + cf.RootStorage.GetStorage("MiniStorage").GetStream("miniSt2").Append(bE); + cf.Commit(); + cf.Close(); + + cf = new CompoundFile("6_Streams_Shrinked.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.SectorRecycle); + + var myStream = cf.RootStorage.GetStream("C"); + var data = myStream.GetData(); + Console.WriteLine(data[0] + " : " + data[data.Length - 1]); + + myStream = cf.RootStorage.GetStream("B"); + data = myStream.GetData(); + Console.WriteLine(data[0] + " : " + data[data.Length - 1]); + + cf.Close(); + + sw.Stop(); + Console.WriteLine(sw.ElapsedMilliseconds); + + Console.ReadKey(); + } + + private static void StressMemory() + { + const int N_LOOP = 20; + const int MB_SIZE = 10; + + byte[] b = GetBuffer(1024 * 1024 * MB_SIZE); //2GB buffer + byte[] cmp = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }; + + CompoundFile cf = new CompoundFile(CFSVersion.Ver_4, CFSConfiguration.Default); + CFStream st = cf.RootStorage.AddStream("MySuperLargeStream"); + cf.Save("LARGE.cfs"); + cf.Close(); + + //Console.WriteLine("Closed save"); + //Console.ReadKey(); + + cf = new CompoundFile("LARGE.cfs", CFSUpdateMode.Update, CFSConfiguration.Default); + CFStream cfst = cf.RootStorage.GetStream("MySuperLargeStream"); + + Stopwatch sw = new Stopwatch(); + sw.Start(); + for (int i = 0; i < N_LOOP; i++) + { + + cfst.Append(b); + cf.Commit(true); + + Console.WriteLine(" Updated " + i.ToString()); + //Console.ReadKey(); + } + + cfst.Append(cmp); + cf.Commit(true); + sw.Stop(); + + + cf.Close(); + + Console.WriteLine(sw.Elapsed.TotalMilliseconds); + sw.Reset(); + + //Console.WriteLine(sw.Elapsed.TotalMilliseconds); + + //Console.WriteLine("Closed Transacted"); + //Console.ReadKey(); + + cf = new CompoundFile("LARGE.cfs"); + int count = 8; + sw.Reset(); + sw.Start(); + byte[] data = new byte[count]; + count = cf.RootStorage.GetStream("MySuperLargeStream").Read(data, b.Length * (long)N_LOOP, count); + sw.Stop(); + Console.Write(count); + cf.Close(); + + Console.WriteLine("Closed Final " + sw.ElapsedMilliseconds); + Console.ReadKey(); + + } + + private static void DummyFile() + { + Console.WriteLine("Start"); + FileStream fs = new FileStream("myDummyFile", FileMode.Create); + fs.Close(); + + Stopwatch sw = new Stopwatch(); + + byte[] b = GetBuffer(1024 * 1024 * 50); //2GB buffer + + fs = new FileStream("myDummyFile", FileMode.Open); + sw.Start(); + for (int i = 0; i < 42; i++) + { + + fs.Seek(b.Length * i, SeekOrigin.Begin); + fs.Write(b, 0, b.Length); + + } + + fs.Close(); + sw.Stop(); + Console.WriteLine("Stop - " + sw.ElapsedMilliseconds); + sw.Reset(); + + Console.ReadKey(); + } + + private static void AddNodes(String depth, CFStorage cfs) + { + + Action va = delegate(CFItem target) + { + + String temp = target.Name + (target is CFStorage ? "" : " (" + target.Size + " bytes )"); + + //Stream + + Console.WriteLine(depth + temp); + + if (target is CFStorage) + { //Storage + + String newDepth = depth + " "; + + //Recursion into the storage + AddNodes(newDepth, (CFStorage)target); + + } + }; + + //Visit NON-recursively (first level only) + cfs.VisitEntries(va, false); + } + + public static void TestMultipleStreamCommit() + { + String srcFilename = Directory.GetCurrentDirectory() + @"\testfile\report.xls"; + String dstFilename = Directory.GetCurrentDirectory() + @"\testfile\reportOverwriteMultiple.xls"; + //Console.WriteLine(Directory.GetCurrentDirectory()); + //Console.ReadKey(); + File.Copy(srcFilename, dstFilename, true); + + CompoundFile cf = new CompoundFile(dstFilename, CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); + + Random r = new Random(); + + DateTime start = DateTime.Now; + + for (int i = 0; i < 1000; i++) + { + byte[] buffer = GetBuffer(r.Next(100, 3500), 0x0A); + + if (i > 0) + { + if (r.Next(0, 100) > 50) + { + cf.RootStorage.Delete("MyNewStream" + (i - 1).ToString()); + } + } + + CFStream addedStream = cf.RootStorage.AddStream("MyNewStream" + i.ToString()); + + addedStream.SetData(buffer); + + // Random commit, not on single addition + if (r.Next(0, 100) > 50) + cf.Commit(); + } + + cf.Close(); + + TimeSpan sp = (DateTime.Now - start); + Console.WriteLine(sp.TotalMilliseconds); + + } + + private static byte[] GetBuffer(int count) + { + Random r = new Random(); + byte[] b = new byte[count]; + r.NextBytes(b); + return b; + } + + private static byte[] GetBuffer(int count, byte c) + { + byte[] b = new byte[count]; + for (int i = 0; i < b.Length; i++) + { + b[i] = c; + } + + return b; + } + + private static bool CompareBuffer(byte[] b, byte[] p) + { + if (b == null && p == null) + throw new Exception("Null buffers"); + + if (b == null && p != null) return false; + if (b != null && p == null) return false; + + if (b.Length != p.Length) + return false; + + for (int i = 0; i < b.Length; i++) + { + if (b[i] != p[i]) + return false; + } + + return true; + } + } +} diff --git a/sources/Test/OpenMcdf.MemTest/Properties/AssemblyInfo.cs b/sources/Test/OpenMcdf.MemTest/Properties/AssemblyInfo.cs index 7b97f2fa..f90c663e 100644 --- a/sources/Test/OpenMcdf.MemTest/Properties/AssemblyInfo.cs +++ b/sources/Test/OpenMcdf.MemTest/Properties/AssemblyInfo.cs @@ -1,35 +1,35 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenMcdfMemTest")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Federico Blaseotto")] -[assembly: AssemblyProduct("OpenMcdfMemTest")] -[assembly: AssemblyCopyright("Copyright © 2010-2011, Federico Blaseotto")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("6be95c7d-5e29-4e84-b1d0-ac5a0de6bfe2")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.5.0.*")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenMcdfMemTest")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Federico Blaseotto")] +[assembly: AssemblyProduct("OpenMcdfMemTest")] +[assembly: AssemblyCopyright("Copyright © 2010-2011, Federico Blaseotto")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("6be95c7d-5e29-4e84-b1d0-ac5a0de6bfe2")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.5.0.*")] diff --git a/sources/Test/OpenMcdf.MemTest/app.config b/sources/Test/OpenMcdf.MemTest/app.config index cb2586be..e3656033 100644 --- a/sources/Test/OpenMcdf.MemTest/app.config +++ b/sources/Test/OpenMcdf.MemTest/app.config @@ -1,3 +1,3 @@ - - - + + + diff --git a/sources/Test/OpenMcdf.PerfTest/Helpers.cs b/sources/Test/OpenMcdf.PerfTest/Helpers.cs index a2ef9800..84bbed00 100644 --- a/sources/Test/OpenMcdf.PerfTest/Helpers.cs +++ b/sources/Test/OpenMcdf.PerfTest/Helpers.cs @@ -1,51 +1,51 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace OpenMcdf.PerfTest -{ - public static class Helpers - { - public static byte[] GetBuffer(int count) - { - Random r = new Random(); - byte[] b = new byte[count]; - r.NextBytes(b); - return b; - } - - public static byte[] GetBuffer(int count, byte c) - { - byte[] b = new byte[count]; - for (int i = 0; i < b.Length; i++) - { - b[i] = c; - } - - return b; - } - - public static bool CompareBuffer(byte[] b, byte[] p) - { - if (b == null && p == null) - throw new Exception("Null buffers"); - - if (b == null && p != null) - return false; - - if (b != null && p == null) - return false; - - if (b.Length != p.Length) - return false; - - for (int i = 0; i < b.Length; i++) - { - if (b[i] != p[i]) - return false; - } - - return true; - } - } -} +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenMcdf.PerfTest +{ + public static class Helpers + { + public static byte[] GetBuffer(int count) + { + Random r = new Random(); + byte[] b = new byte[count]; + r.NextBytes(b); + return b; + } + + public static byte[] GetBuffer(int count, byte c) + { + byte[] b = new byte[count]; + for (int i = 0; i < b.Length; i++) + { + b[i] = c; + } + + return b; + } + + public static bool CompareBuffer(byte[] b, byte[] p) + { + if (b == null && p == null) + throw new Exception("Null buffers"); + + if (b == null && p != null) + return false; + + if (b != null && p == null) + return false; + + if (b.Length != p.Length) + return false; + + for (int i = 0; i < b.Length; i++) + { + if (b[i] != p[i]) + return false; + } + + return true; + } + } +} diff --git a/sources/Test/OpenMcdf.PerfTest/OpenMcdf.PerfTest.csproj b/sources/Test/OpenMcdf.PerfTest/OpenMcdf.PerfTest.csproj index f2c13d23..c6f51fd4 100644 --- a/sources/Test/OpenMcdf.PerfTest/OpenMcdf.PerfTest.csproj +++ b/sources/Test/OpenMcdf.PerfTest/OpenMcdf.PerfTest.csproj @@ -1,99 +1,99 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {7077508F-B313-4DF6-8855-4764911BE161} - Exe - Properties - OpenMcdf.PerfTest - OpenMcdf.PerfTest - v4.0 - 512 - - - 3.5 - - http://localhost/OpenMcdfPerfTest/ - true - Web - true - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - true - false - true - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - - - - - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - - - - {56e15d4a-8a37-4c7c-bb44-fd59aff220c1} - OpenMcdf - - - - + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {7077508F-B313-4DF6-8855-4764911BE161} + Exe + Properties + OpenMcdf.PerfTest + OpenMcdf.PerfTest + v4.0 + 512 + + + 3.5 + + http://localhost/OpenMcdfPerfTest/ + true + Web + true + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + true + false + true + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + + + + {56e15d4a-8a37-4c7c-bb44-fd59aff220c1} + OpenMcdf + + + + \ No newline at end of file diff --git a/sources/Test/OpenMcdf.PerfTest/Program.cs b/sources/Test/OpenMcdf.PerfTest/Program.cs index 2097d047..54586b68 100644 --- a/sources/Test/OpenMcdf.PerfTest/Program.cs +++ b/sources/Test/OpenMcdf.PerfTest/Program.cs @@ -1,41 +1,41 @@ -using System; -using System.Collections.Generic; -using System.Text; -using OpenMcdf; -using System.IO; - -namespace OpenMcdf.PerfTest -{ - class Program - { - static int MAX_STREAM_COUNT = 5000; - static String fileName = "PerfLoad.cfs"; - - static void Main(string[] args) - { - File.Delete(fileName); - if (!File.Exists(fileName)) - { - CreateFile(fileName); - } - - CompoundFile cf = new CompoundFile(fileName); - DateTime dt = DateTime.Now; - CFStream s = cf.RootStorage.GetStream("Test1"); - TimeSpan ts = DateTime.Now.Subtract(dt); - Console.WriteLine(ts.TotalMilliseconds.ToString()); - Console.Read(); - } - - private static void CreateFile(String fn) - { - CompoundFile cf = new CompoundFile(); - for (int i = 0; i < MAX_STREAM_COUNT; i++) - { - cf.RootStorage.AddStream("Test" + i.ToString()).SetData(Helpers.GetBuffer(300)); - } - cf.Save(fileName); - cf.Close(); - } - } -} +using System; +using System.Collections.Generic; +using System.Text; +using OpenMcdf; +using System.IO; + +namespace OpenMcdf.PerfTest +{ + class Program + { + static int MAX_STREAM_COUNT = 5000; + static String fileName = "PerfLoad.cfs"; + + static void Main(string[] args) + { + File.Delete(fileName); + if (!File.Exists(fileName)) + { + CreateFile(fileName); + } + + CompoundFile cf = new CompoundFile(fileName); + DateTime dt = DateTime.Now; + CFStream s = cf.RootStorage.GetStream("Test1"); + TimeSpan ts = DateTime.Now.Subtract(dt); + Console.WriteLine(ts.TotalMilliseconds.ToString()); + Console.Read(); + } + + private static void CreateFile(String fn) + { + CompoundFile cf = new CompoundFile(); + for (int i = 0; i < MAX_STREAM_COUNT; i++) + { + cf.RootStorage.AddStream("Test" + i.ToString()).SetData(Helpers.GetBuffer(300)); + } + cf.Save(fileName); + cf.Close(); + } + } +} diff --git a/sources/Test/OpenMcdf.PerfTest/Properties/AssemblyInfo.cs b/sources/Test/OpenMcdf.PerfTest/Properties/AssemblyInfo.cs index fd5bf289..de9d7003 100644 --- a/sources/Test/OpenMcdf.PerfTest/Properties/AssemblyInfo.cs +++ b/sources/Test/OpenMcdf.PerfTest/Properties/AssemblyInfo.cs @@ -1,36 +1,36 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenMcdfPerfTest")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("-")] -[assembly: AssemblyProduct("OpenMcdfPerfTest")] -[assembly: AssemblyCopyright("Copyright © - 2012")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("c3a84d86-d1be-4fdc-8294-169e1f6747d8")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenMcdfPerfTest")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("-")] +[assembly: AssemblyProduct("OpenMcdfPerfTest")] +[assembly: AssemblyCopyright("Copyright © - 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c3a84d86-d1be-4fdc-8294-169e1f6747d8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/sources/Test/OpenMcdf.PerfTest/app.config b/sources/Test/OpenMcdf.PerfTest/app.config index cb2586be..e3656033 100644 --- a/sources/Test/OpenMcdf.PerfTest/app.config +++ b/sources/Test/OpenMcdf.PerfTest/app.config @@ -1,3 +1,3 @@ - - - + + + diff --git a/sources/Test/OpenMcdf.Test/AuthoringTests.txt b/sources/Test/OpenMcdf.Test/AuthoringTests.txt index 64bab948..c94b3cfd 100644 --- a/sources/Test/OpenMcdf.Test/AuthoringTests.txt +++ b/sources/Test/OpenMcdf.Test/AuthoringTests.txt @@ -1,136 +1,136 @@ -========================================================================== - Visual Studio Team System: Overview of Authoring and Running Tests -========================================================================== - -This overview describes the features for authoring and running tests in -Visual Studio Team System and Visual Studio Team Edition for Software Testers. - -Opening Tests -------------- -To open a test, open a test project or a test metadata file (a file with -extension .vsmdi) that contains the definition of the test. You can find -test projects and metadata files in Solution Explorer. - -Viewing Tests -------------- -To see which tests are available to you, open the Test View window. Or, -if you have installed Team Edition for Software Testers, you can also open -the Test List Editor window to view tests. - -To open the Test View window, click the Test menu, point to Windows, and -then click Test View. To open the Test List Editor window (if you have -installed Team Edition for Software Testers), click Test, point to Windows, -and then click Test List Editor. - -Running Tests -------------- -You can run tests from the Test View window and the Test List Editor window. -See Viewing Tests to learn how to open these windows. To run one or more -tests displayed in the Test View window, first select the tests in that -window; to select multiple tests, hold either the Shift or CTRL key while -clicking tests. Then click the Run Tests button in the Test View window -toolbar. - -If you have installed Visual Studio Team Edition for Software Testers, you can -also use the Test List Editor window to run tests. To run tests in Test List Editor, -select the check box next to each test that you want to run. Then click the -Run Tests button in the Test List Editor window toolbar. - -Viewing Test Results --------------------- -When you run a test or a series of tests, the results of the test run will be -shown in the Test Results window. Each individual test in the run is shown on -a separate line so that you can see its status. The window contains an -embedded status bar in the top half of the window that provides you with -summary details of the complete test run. - -To see more detailed results for a particular test result, double-click it in -the Test Results window. This opens a window that provides more information -about the particular test result, such as any specific error messages returned -by the test. - -Changing the way that tests are run ------------------------------------ -Each time you run one or more tests, a collection of settings is used to -determine how those tests are run. These settings are contained in a “test -run configuration” file. - -Here is a partial list of the changes you can make with a test run -configuration file: - - - Change the naming scheme for each test run. - - Change the test controller that the tests are run on so that you can run - tests remotely. - - Gather code coverage data for the code being tested so that you can see - which lines of code are covered by your tests. - - Enable and disable test deployment. - - Specify additional files to deploy before tests are run. - - Select a different host, ASP.NET, for running ASP.NET unit tests. - - Select a different host, the smart device test host, for running smart device unit tests. - - Set various properties for the test agents that run your tests. - - Run custom scripts at the start and end of each test run so that you can - set up the test environment exactly as required each time tests are run. - - Set time limits for tests and test runs. - - Set the browser mix and the number of times to repeat Web tests in the - test run. - -By default, a test run configuration file is created whenever you create a -new test project. You make changes to this file by double-clicking it in -Solution Explorer and then changing its settings. (Test run configuration -files have the extension .testrunconfig.) - -A solution can contain multiple test run configuration files. Only one of -those files, known as the “Active” test run configuration file, is used to -determine the settings that are currently used for test runs. You select -the active test run configuration by clicking Select Active Test Run -Configuration on the Test menu. - -------------------------------------------------------------------------------- - -Test Types ----------- -Using Visual Studio Team Edition for Software Testers, you can create a number -of different test types: - -Unit test: Use a unit test to create a programmatic test in C++, Visual C# or -Visual Basic that exercises source code. A unit test calls the methods of a -class, passing suitable parameters, and verifies that the returned value is -what you expect. -There are three specialized variants of unit tests: - - Data-driven unit tests are created when you configure a unit test to be - called repeatedly for each row of a data source. The data from each row - is used by the unit test as input data. - - ASP.NET unit tests are unit tests that exercise code in an ASP.NET Web - application. - - Smart device unit tests are unit tests that are deployed to a smart device - or emulator and then executed by the smart device test host. - -Web Test: Web tests consist of an ordered series of HTTP requests that you -record in a browser session using Microsoft Internet Explorer. You can have -the test report specific details about the pages or sites it requests, such -as whether a particular page contains a specified string. - -Load Test: You use a load test to encapsulate non-manual tests, such as -unit, Web, and generic tests, and then run them simultaneously by using -virtual users. Running these tests under load generates test results, -including performance and other counters, in tables and in graphs. - -Generic test: A generic test is an existing program wrapped to function as a -test in Visual Studio. The following are examples of tests or programs that -you can turn into generic tests: - - An existing test that uses process exit codes to communicate whether the - test passed or failed. 0 indicates passing and any other value indicates - a failure. - - A general program to obtain specific functionality during a test scenario. - - A test or program that uses a special XML file (called a “summary results - file”), to communicate detailed results. - -Manual test: The manual test type is used when the test tasks are to be -completed by a test engineer as opposed to an automated script. - -Ordered test: Use an ordered test to execute a set of tests in an order you -specify. - -------------------------------------------------------------------------------- - - +========================================================================== + Visual Studio Team System: Overview of Authoring and Running Tests +========================================================================== + +This overview describes the features for authoring and running tests in +Visual Studio Team System and Visual Studio Team Edition for Software Testers. + +Opening Tests +------------- +To open a test, open a test project or a test metadata file (a file with +extension .vsmdi) that contains the definition of the test. You can find +test projects and metadata files in Solution Explorer. + +Viewing Tests +------------- +To see which tests are available to you, open the Test View window. Or, +if you have installed Team Edition for Software Testers, you can also open +the Test List Editor window to view tests. + +To open the Test View window, click the Test menu, point to Windows, and +then click Test View. To open the Test List Editor window (if you have +installed Team Edition for Software Testers), click Test, point to Windows, +and then click Test List Editor. + +Running Tests +------------- +You can run tests from the Test View window and the Test List Editor window. +See Viewing Tests to learn how to open these windows. To run one or more +tests displayed in the Test View window, first select the tests in that +window; to select multiple tests, hold either the Shift or CTRL key while +clicking tests. Then click the Run Tests button in the Test View window +toolbar. + +If you have installed Visual Studio Team Edition for Software Testers, you can +also use the Test List Editor window to run tests. To run tests in Test List Editor, +select the check box next to each test that you want to run. Then click the +Run Tests button in the Test List Editor window toolbar. + +Viewing Test Results +-------------------- +When you run a test or a series of tests, the results of the test run will be +shown in the Test Results window. Each individual test in the run is shown on +a separate line so that you can see its status. The window contains an +embedded status bar in the top half of the window that provides you with +summary details of the complete test run. + +To see more detailed results for a particular test result, double-click it in +the Test Results window. This opens a window that provides more information +about the particular test result, such as any specific error messages returned +by the test. + +Changing the way that tests are run +----------------------------------- +Each time you run one or more tests, a collection of settings is used to +determine how those tests are run. These settings are contained in a “test +run configuration” file. + +Here is a partial list of the changes you can make with a test run +configuration file: + + - Change the naming scheme for each test run. + - Change the test controller that the tests are run on so that you can run + tests remotely. + - Gather code coverage data for the code being tested so that you can see + which lines of code are covered by your tests. + - Enable and disable test deployment. + - Specify additional files to deploy before tests are run. + - Select a different host, ASP.NET, for running ASP.NET unit tests. + - Select a different host, the smart device test host, for running smart device unit tests. + - Set various properties for the test agents that run your tests. + - Run custom scripts at the start and end of each test run so that you can + set up the test environment exactly as required each time tests are run. + - Set time limits for tests and test runs. + - Set the browser mix and the number of times to repeat Web tests in the + test run. + +By default, a test run configuration file is created whenever you create a +new test project. You make changes to this file by double-clicking it in +Solution Explorer and then changing its settings. (Test run configuration +files have the extension .testrunconfig.) + +A solution can contain multiple test run configuration files. Only one of +those files, known as the “Active” test run configuration file, is used to +determine the settings that are currently used for test runs. You select +the active test run configuration by clicking Select Active Test Run +Configuration on the Test menu. + +------------------------------------------------------------------------------- + +Test Types +---------- +Using Visual Studio Team Edition for Software Testers, you can create a number +of different test types: + +Unit test: Use a unit test to create a programmatic test in C++, Visual C# or +Visual Basic that exercises source code. A unit test calls the methods of a +class, passing suitable parameters, and verifies that the returned value is +what you expect. +There are three specialized variants of unit tests: + - Data-driven unit tests are created when you configure a unit test to be + called repeatedly for each row of a data source. The data from each row + is used by the unit test as input data. + - ASP.NET unit tests are unit tests that exercise code in an ASP.NET Web + application. + - Smart device unit tests are unit tests that are deployed to a smart device + or emulator and then executed by the smart device test host. + +Web Test: Web tests consist of an ordered series of HTTP requests that you +record in a browser session using Microsoft Internet Explorer. You can have +the test report specific details about the pages or sites it requests, such +as whether a particular page contains a specified string. + +Load Test: You use a load test to encapsulate non-manual tests, such as +unit, Web, and generic tests, and then run them simultaneously by using +virtual users. Running these tests under load generates test results, +including performance and other counters, in tables and in graphs. + +Generic test: A generic test is an existing program wrapped to function as a +test in Visual Studio. The following are examples of tests or programs that +you can turn into generic tests: + - An existing test that uses process exit codes to communicate whether the + test passed or failed. 0 indicates passing and any other value indicates + a failure. + - A general program to obtain specific functionality during a test scenario. + - A test or program that uses a special XML file (called a “summary results + file”), to communicate detailed results. + +Manual test: The manual test type is used when the test tasks are to be +completed by a test engineer as opposed to an automated script. + +Ordered test: Use an ordered test to execute a set of tests in an order you +specify. + +------------------------------------------------------------------------------- + + diff --git a/sources/Test/OpenMcdf.Test/CFSStreamTest.cs b/sources/Test/OpenMcdf.Test/CFSStreamTest.cs index db833719..5e95bf8c 100644 --- a/sources/Test/OpenMcdf.Test/CFSStreamTest.cs +++ b/sources/Test/OpenMcdf.Test/CFSStreamTest.cs @@ -1,1086 +1,1086 @@ -using System; -using System.Text; -using System.Collections.Generic; -using System.Linq; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using OpenMcdf; -using System.IO; - -namespace OpenMcdf.Test -{ - /// - /// Summary description for UnitTest1 - /// - [TestClass] - public class CFSStreamTest - { - - //const String TestContext.TestDir = "C:\\TestOutputFiles\\"; - - public CFSStreamTest() - { - - } - - private TestContext testContextInstance; - - /// - ///Gets or sets the test context which provides - ///information about and functionality for the current test run. - /// - public TestContext TestContext - { - get - { - return testContextInstance; - } - set - { - testContextInstance = value; - } - } - - #region Additional test attributes - // - // You can use the following additional attributes as you write your tests: - // - // Use ClassInitialize to run code before running the first test in the class - // [ClassInitialize()] - // public static void MyClassInitialize(TestContext testContext) { } - // - // Use ClassCleanup to run code after all tests in a class have run - // [ClassCleanup()] - // public static void MyClassCleanup() { } - // - // Use TestInitialize to run code before running each test - // [TestInitialize()] - // public void MyTestInitialize() { } - // - // Use TestCleanup to run code after each test has run - // [TestCleanup()] - // public void MyTestCleanup() { } - // - #endregion - - [TestMethod] - public void Test_READ_STREAM() - { - String filename = "report.xls"; - - CompoundFile cf = new CompoundFile(filename); - CFStream foundStream = cf.RootStorage.GetStream("Workbook"); - - byte[] temp = foundStream.GetData(); - - Assert.IsNotNull(temp); - Assert.IsTrue(temp.Length > 0); - - cf.Close(); - } - - [TestMethod] - public void Test_WRITE_STREAM() - { - const int BUFFER_LENGTH = 10000; - - byte[] b = Helpers.GetBuffer(BUFFER_LENGTH); - - CompoundFile cf = new CompoundFile(); - CFStream myStream = cf.RootStorage.AddStream("MyStream"); - - Assert.IsNotNull(myStream); - Assert.IsTrue(myStream.Size == 0); - - myStream.SetData(b); - - Assert.IsTrue(myStream.Size == BUFFER_LENGTH, "Stream size differs from buffer size"); - - cf.Close(); - } - - [TestMethod] - public void Test_WRITE_MINI_STREAM() - { - const int BUFFER_LENGTH = 1023; // < 4096 - - byte[] b = Helpers.GetBuffer(BUFFER_LENGTH); - - CompoundFile cf = new CompoundFile(); - CFStream myStream = cf.RootStorage.AddStream("MyMiniStream"); - - Assert.IsNotNull(myStream); - Assert.IsTrue(myStream.Size == 0); - - myStream.SetData(b); - - Assert.IsTrue(myStream.Size == BUFFER_LENGTH, "Mini Stream size differs from buffer size"); - - cf.Close(); - } - - [TestMethod] - public void Test_ZERO_LENGTH_WRITE_STREAM() - { - byte[] b = new byte[0]; - - CompoundFile cf = new CompoundFile(); - CFStream myStream = cf.RootStorage.AddStream("MyStream"); - - Assert.IsNotNull(myStream); - - try - { - myStream.SetData(b); cf.Save("ZERO_LENGTH_STREAM.cfs"); - } - catch - { - Assert.Fail("Failed setting zero length stream"); - } - finally - { - if (cf != null) - cf.Close(); - } - - if (File.Exists("ZERO_LENGTH_STREAM.cfs")) - File.Delete("ZERO_LENGTH_STREAM.cfs"); - - } - - [TestMethod] - public void Test_ZERO_LENGTH_RE_WRITE_STREAM() - { - byte[] b = new byte[0]; - - CompoundFile cf = new CompoundFile(); - CFStream myStream = cf.RootStorage.AddStream("MyStream"); - - Assert.IsNotNull(myStream); - - try - { - myStream.SetData(b); - } - catch - { - Assert.Fail("Failed setting zero length stream"); - } - - cf.Save("ZERO_LENGTH_STREAM_RE.cfs"); - cf.Close(); - - CompoundFile cfo = new CompoundFile("ZERO_LENGTH_STREAM_RE.cfs"); - CFStream oStream = cfo.RootStorage.GetStream("MyStream"); - - Assert.IsNotNull(oStream); - Assert.IsTrue(oStream.Size == 0); - - try - { - oStream.SetData(Helpers.GetBuffer(30)); - cfo.Save("ZERO_LENGTH_STREAM_RE2.cfs"); - } - catch - { - Assert.Fail("Failed re-writing zero length stream"); - } - finally - { - cfo.Close(); - } - - if (File.Exists("ZERO_LENGTH_STREAM_RE.cfs")) - File.Delete("ZERO_LENGTH_STREAM_RE.cfs"); - - if (File.Exists("ZERO_LENGTH_STREAM_RE2.cfs")) - File.Delete("ZERO_LENGTH_STREAM_RE2.cfs"); - - } - - - [TestMethod] - public void Test_WRITE_STREAM_WITH_DIFAT() - { - //const int SIZE = 15388609; //Incredible condition of 'resonance' between FAT and DIFAT sec number - const int SIZE = 15345665; // 64 -> 65 NOT working (in the past ;-) ) - byte[] b = Helpers.GetBuffer(SIZE, 0); - - CompoundFile cf = new CompoundFile(); - CFStream myStream = cf.RootStorage.AddStream("MyStream"); - Assert.IsNotNull(myStream); - myStream.SetData(b); - - cf.Save("WRITE_STREAM_WITH_DIFAT.cfs"); - cf.Close(); - - - CompoundFile cf2 = new CompoundFile("WRITE_STREAM_WITH_DIFAT.cfs"); - CFStream st = cf2.RootStorage.GetStream("MyStream"); - - Assert.IsNotNull(cf2); - Assert.IsTrue(st.Size == SIZE); - - Assert.IsTrue(Helpers.CompareBuffer(b, st.GetData())); - - cf2.Close(); - - if (File.Exists("WRITE_STREAM_WITH_DIFAT.cfs")) - File.Delete("WRITE_STREAM_WITH_DIFAT.cfs"); - - } - - - [TestMethod] - public void Test_WRITE_MINISTREAM_READ_REWRITE_STREAM() - { - const int BIGGER_SIZE = 350; - //const int SMALLER_SIZE = 290; - const int MEGA_SIZE = 18000000; - - byte[] ba1 = Helpers.GetBuffer(BIGGER_SIZE, 1); - byte[] ba2 = Helpers.GetBuffer(BIGGER_SIZE, 2); - byte[] ba3 = Helpers.GetBuffer(BIGGER_SIZE, 3); - byte[] ba4 = Helpers.GetBuffer(BIGGER_SIZE, 4); - byte[] ba5 = Helpers.GetBuffer(BIGGER_SIZE, 5); - - //WRITE 5 (mini)streams in a compound file -- - - CompoundFile cfa = new CompoundFile(); - - CFStream myStream = cfa.RootStorage.AddStream("MyFirstStream"); - Assert.IsNotNull(myStream); - - myStream.SetData(ba1); - Assert.IsTrue(myStream.Size == BIGGER_SIZE); - - CFStream myStream2 = cfa.RootStorage.AddStream("MySecondStream"); - Assert.IsNotNull(myStream2); - - myStream2.SetData(ba2); - Assert.IsTrue(myStream2.Size == BIGGER_SIZE); - - CFStream myStream3 = cfa.RootStorage.AddStream("MyThirdStream"); - Assert.IsNotNull(myStream3); - - myStream3.SetData(ba3); - Assert.IsTrue(myStream3.Size == BIGGER_SIZE); - - CFStream myStream4 = cfa.RootStorage.AddStream("MyFourthStream"); - Assert.IsNotNull(myStream4); - - myStream4.SetData(ba4); - Assert.IsTrue(myStream4.Size == BIGGER_SIZE); - - CFStream myStream5 = cfa.RootStorage.AddStream("MyFifthStream"); - Assert.IsNotNull(myStream5); - - myStream5.SetData(ba5); - Assert.IsTrue(myStream5.Size == BIGGER_SIZE); - - cfa.Save("WRITE_MINISTREAM_READ_REWRITE_STREAM.cfs"); - - cfa.Close(); - - // Now get the second stream and rewrite it smaller - byte[] bb = Helpers.GetBuffer(MEGA_SIZE); - CompoundFile cfb = new CompoundFile("WRITE_MINISTREAM_READ_REWRITE_STREAM.cfs"); - CFStream myStreamB = cfb.RootStorage.GetStream("MySecondStream"); - Assert.IsNotNull(myStreamB); - myStreamB.SetData(bb); - Assert.IsTrue(myStreamB.Size == MEGA_SIZE); - - byte[] bufferB = myStreamB.GetData(); - cfb.Save("WRITE_MINISTREAM_READ_REWRITE_STREAM_2ND.cfs"); - cfb.Close(); - - CompoundFile cfc = new CompoundFile("WRITE_MINISTREAM_READ_REWRITE_STREAM_2ND.cfs"); - CFStream myStreamC = cfc.RootStorage.GetStream("MySecondStream"); - Assert.IsTrue(myStreamC.Size == MEGA_SIZE, "DATA SIZE FAILED"); - - byte[] bufferC = myStreamC.GetData(); - Assert.IsTrue(Helpers.CompareBuffer(bufferB, bufferC), "DATA INTEGRITY FAILED"); - - cfc.Close(); - - if (File.Exists("WRITE_MINISTREAM_READ_REWRITE_STREAM.cfs")) - File.Delete("WRITE_MINISTREAM_READ_REWRITE_STREAM.cfs"); - - - if (File.Exists("WRITE_MINISTREAM_READ_REWRITE_STREAM_2ND.cfs")) - File.Delete("WRITE_MINISTREAM_READ_REWRITE_STREAM_2ND.cfs"); - - } - - [TestMethod] - public void Test_RE_WRITE_SMALLER_STREAM() - { - const int BUFFER_LENGTH = 8000; - - String filename = "report.xls"; - - byte[] b = Helpers.GetBuffer(BUFFER_LENGTH); - - CompoundFile cf = new CompoundFile(filename); - CFStream foundStream = cf.RootStorage.GetStream("Workbook"); - foundStream.SetData(b); - cf.Save("reportRW_SMALL.xls"); - cf.Close(); - - cf = new CompoundFile("reportRW_SMALL.xls"); - byte[] c = cf.RootStorage.GetStream("Workbook").GetData(); - Assert.IsTrue(c.Length == BUFFER_LENGTH); - cf.Close(); - - if (File.Exists("reportRW_SMALL.xls")) - File.Delete("reportRW_SMALL.xls"); - - } - - [TestMethod] - public void Test_RE_WRITE_SMALLER_MINI_STREAM() - { - String filename = "report.xls"; - - CompoundFile cf = new CompoundFile(filename); - CFStream foundStream = cf.RootStorage.GetStream("\x05SummaryInformation"); - int TEST_LENGTH = (int)foundStream.Size - 20; - byte[] b = Helpers.GetBuffer(TEST_LENGTH); - foundStream.SetData(b); - - cf.Save("RE_WRITE_SMALLER_MINI_STREAM.xls"); - cf.Close(); - - cf = new CompoundFile("RE_WRITE_SMALLER_MINI_STREAM.xls"); - byte[] c = cf.RootStorage.GetStream("\x05SummaryInformation").GetData(); - Assert.IsTrue(c.Length == TEST_LENGTH); - Assert.IsTrue(Helpers.CompareBuffer(c, b)); - cf.Close(); - - if (File.Exists("RE_WRITE_SMALLER_MINI_STREAM.xls")) - File.Delete("RE_WRITE_SMALLER_MINI_STREAM.xls"); - - } - - [TestMethod] - public void Test_TRANSACTED_ADD_STREAM_TO_EXISTING_FILE() - { - String srcFilename = "report.xls"; - String dstFilename = "reportOverwrite.xls"; - - File.Copy(srcFilename, dstFilename, true); - - CompoundFile cf = new CompoundFile(dstFilename, CFSUpdateMode.Update, CFSConfiguration.Default); - - byte[] buffer = Helpers.GetBuffer(5000); - - CFStream addedStream = cf.RootStorage.AddStream("MyNewStream"); - addedStream.SetData(buffer); - - cf.Commit(); - cf.Close(); - - - if (File.Exists("reportOverwrite.xls")) - File.Delete("reportOverwrite.xls"); - - } - - [TestMethod] - public void Test_TRANSACTED_ADD_REMOVE_MULTIPLE_STREAM_TO_EXISTING_FILE() - { - String srcFilename = "report.xls"; - String dstFilename = "reportOverwriteMultiple.xls"; - - File.Copy(srcFilename, dstFilename, true); - - CompoundFile cf = new CompoundFile(dstFilename, CFSUpdateMode.ReadOnly, CFSConfiguration.SectorRecycle); - - //CompoundFile cf = new CompoundFile(); - - Random r = new Random(); - - for (int i = 0; i < 254; i++) - { - //byte[] buffer = Helpers.GetBuffer(r.Next(100, 3500), (byte)i); - byte[] buffer = Helpers.GetBuffer(1995, 1); - - //if (i > 0) - //{ - // if (r.Next(0, 100) > 50) - // { - // cf.RootStorage.Delete("MyNewStream" + (i - 1).ToString()); - // } - //} - - CFStream addedStream = cf.RootStorage.AddStream("MyNewStream" + i.ToString()); - Assert.IsNotNull(addedStream, "Stream not found"); - addedStream.SetData(buffer); - - Assert.IsTrue(Helpers.CompareBuffer(addedStream.GetData(), buffer), "Data buffer corrupted"); - - // Random commit, not on single addition - //if (r.Next(0, 100) > 50) - // cf.UpdateFile(); - - } - - cf.Save(dstFilename + "PP"); - cf.Close(); - - if (File.Exists("reportOverwriteMultiple.xls")) - File.Delete("reportOverwriteMultiple.xls"); - - if (File.Exists("reportOverwriteMultiple.xlsPP")) - File.Delete("reportOverwriteMultiple.xlsPP"); - - - } - - [TestMethod] - public void Test_TRANSACTED_ADD_MINISTREAM_TO_EXISTING_FILE() - { - String srcFilename = "report.xls"; - String dstFilename = "reportOverwriteMultiple.xls"; - - File.Copy(srcFilename, dstFilename, true); - - CompoundFile cf = new CompoundFile(dstFilename, CFSUpdateMode.Update, CFSConfiguration.SectorRecycle | CFSConfiguration.EraseFreeSectors); - - Random r = new Random(); - - byte[] buffer = Helpers.GetBuffer(31, 0x0A); - - cf.RootStorage.AddStream("MyStream").SetData(buffer); - cf.Commit(); - cf.Close(); - FileStream larger = new FileStream(dstFilename, FileMode.Open); - FileStream smaller = new FileStream(srcFilename, FileMode.Open); - - // Equal condition if minisector can be "allocated" - // within the existing standard sector border - Assert.IsTrue(larger.Length >= smaller.Length); - - larger.Close(); - smaller.Close(); - - if (File.Exists("reportOverwriteMultiple.xlsPP")) - File.Delete("reportOverwriteMultiple.xlsPP"); - - - } - - [TestMethod] - public void Test_TRANSACTED_REMOVE_MINI_STREAM_ADD_MINISTREAM_TO_EXISTING_FILE() - { - String srcFilename = "report.xls"; - String dstFilename = "reportOverwrite2.xls"; - - File.Copy(srcFilename, dstFilename, true); - - CompoundFile cf = new CompoundFile(dstFilename, CFSUpdateMode.Update, CFSConfiguration.SectorRecycle | CFSConfiguration.EraseFreeSectors); - - cf.RootStorage.Delete("\x05SummaryInformation"); - - byte[] buffer = Helpers.GetBuffer(2000); - - CFStream addedStream = cf.RootStorage.AddStream("MyNewStream"); - addedStream.SetData(buffer); - - cf.Commit(); - cf.Close(); - - if (File.Exists("reportOverwrite2.xlsPP")) - File.Delete("reportOverwrite2.xlsPP"); - - - } - - - - [TestMethod] - public void Test_DELETE_STREAM_1() - { - String filename = "MultipleStorage.cfs"; - - CompoundFile cf = new CompoundFile(filename); - CFStorage cfs = cf.RootStorage.GetStorage("MyStorage"); - cfs.Delete("MySecondStream"); - - cf.Save(TestContext.TestDir + "MultipleStorage_REMOVED_STREAM_1.cfs"); - cf.Close(); - } - - [TestMethod] - public void Test_DELETE_STREAM_2() - { - String filename = "MultipleStorage.cfs"; - - CompoundFile cf = new CompoundFile(filename); - CFStorage cfs = cf.RootStorage.GetStorage("MyStorage").GetStorage("AnotherStorage"); - - cfs.Delete("AnotherStream"); - - cf.Save(TestContext.TestDir + "MultipleStorage_REMOVED_STREAM_2.cfs"); - - cf.Close(); - } - - - [TestMethod] - public void Test_WRITE_AND_READ_CFS() - { - String filename = "WRITE_AND_READ_CFS.cfs"; - - CompoundFile cf = new CompoundFile(); - - CFStorage st = cf.RootStorage.AddStorage("MyStorage"); - CFStream sm = st.AddStream("MyStream"); - byte[] b = Helpers.GetBuffer(220, 0x0A); - sm.SetData(b); - - cf.Save(filename); - cf.Close(); - - CompoundFile cf2 = new CompoundFile(filename); - CFStorage st2 = cf2.RootStorage.GetStorage("MyStorage"); - CFStream sm2 = st2.GetStream("MyStream"); - cf2.Close(); - - Assert.IsNotNull(sm2); - Assert.IsTrue(sm2.Size == 220); - - - if (File.Exists(filename)) - File.Delete(filename); - - - } - - [TestMethod] - public void Test_INCREMENTAL_SIZE_MULTIPLE_WRITE_AND_READ_CFS() - { - - Random r = new Random(); - - for (int i = r.Next(1, 100); i < 1024 * 1024 * 70; i = i << 1) - { - SingleWriteReadMatching(i + r.Next(0, 3)); - } - - } - - - [TestMethod] - public void Test_INCREMENTAL_SIZE_MULTIPLE_WRITE_AND_READ_CFS_STREAM() - { - - Random r = new Random(); - - for (int i = r.Next(1, 100); i < 1024 * 1024 * 70; i = i << 1) - { - SingleWriteReadMatchingSTREAMED(i + r.Next(0, 3)); - } - - } - - [TestMethod] - public void Test_DELETE_ZERO_LENGTH_STREAM() - { - byte[] b = new byte[0]; - - CompoundFile cf = new CompoundFile(); - - string zeroLengthName = "MyZeroStream"; - CFStream myStream = cf.RootStorage.AddStream(zeroLengthName); - - Assert.IsNotNull(myStream); - - try - { - myStream.SetData(b); - } - catch - { - Assert.Fail("Failed setting zero length stream"); - } - - string filename = "DeleteZeroLengthStream.cfs"; - cf.Save(filename); - cf.Close(); - - CompoundFile cf2 = new CompoundFile(filename); - - // Execption in next line! - cf2.RootStorage.Delete(zeroLengthName); - - CFStream zeroStream2 = null; - - try - { - zeroStream2 = cf2.RootStorage.GetStream(zeroLengthName); - } - catch (Exception ex) - { - Assert.IsNull(zeroStream2); - Assert.IsInstanceOfType(ex, typeof(CFItemNotFound)); - } - - cf2.Save("MultipleDeleteMiniStream.cfs"); - cf2.Close(); - } - - //[TestMethod] - //public void Test_INCREMENTAL_TRANSACTED_CHANGE_CFS() - //{ - - // Random r = new Random(); - - // for (int i = r.Next(1, 100); i < 1024 * 1024 * 70; i = i << 1) - // { - // SingleTransactedChange(i + r.Next(0, 3)); - // } - - //} - - private void SingleTransactedChange(int size) - { - - String filename = "INCREMENTAL_SIZE_MULTIPLE_WRITE_AND_READ_CFS.cfs"; - - if (File.Exists(filename)) - File.Delete(filename); - - CompoundFile cf = new CompoundFile(); - CFStorage st = cf.RootStorage.AddStorage("MyStorage"); - CFStream sm = st.AddStream("MyStream"); - - byte[] b = Helpers.GetBuffer(size); - - sm.SetData(b); - cf.Save(filename); - cf.Close(); - - CompoundFile cf2 = new CompoundFile(filename); - CFStorage st2 = cf2.RootStorage.GetStorage("MyStorage"); - CFStream sm2 = st2.GetStream("MyStream"); - - Assert.IsNotNull(sm2); - Assert.IsTrue(sm2.Size == size); - Assert.IsTrue(Helpers.CompareBuffer(sm2.GetData(), b)); - - cf2.Close(); - } - - private void SingleWriteReadMatching(int size) - { - - String filename = "INCREMENTAL_SIZE_MULTIPLE_WRITE_AND_READ_CFS.cfs"; - - if (File.Exists(filename)) - File.Delete(filename); - - CompoundFile cf = new CompoundFile(); - CFStorage st = cf.RootStorage.AddStorage("MyStorage"); - CFStream sm = st.AddStream("MyStream"); - - byte[] b = Helpers.GetBuffer(size); - - sm.SetData(b); - cf.Save(filename); - cf.Close(); - - CompoundFile cf2 = new CompoundFile(filename); - CFStorage st2 = cf2.RootStorage.GetStorage("MyStorage"); - CFStream sm2 = st2.GetStream("MyStream"); - - Assert.IsNotNull(sm2); - Assert.IsTrue(sm2.Size == size); - Assert.IsTrue(Helpers.CompareBuffer(sm2.GetData(), b)); - - cf2.Close(); - } - - private void SingleWriteReadMatchingSTREAMED(int size) - { - MemoryStream ms = new MemoryStream(size); - - CompoundFile cf = new CompoundFile(); - CFStorage st = cf.RootStorage.AddStorage("MyStorage"); - CFStream sm = st.AddStream("MyStream"); - - byte[] b = Helpers.GetBuffer(size); - - sm.SetData(b); - cf.Save(ms); - cf.Close(); - - CompoundFile cf2 = new CompoundFile(ms); - CFStorage st2 = cf2.RootStorage.GetStorage("MyStorage"); - CFStream sm2 = st2.GetStream("MyStream"); - - Assert.IsNotNull(sm2); - Assert.IsTrue(sm2.Size == size); - Assert.IsTrue(Helpers.CompareBuffer(sm2.GetData(), b)); - - cf2.Close(); - } - - - [TestMethod] - public void Test_APPEND_DATA_TO_STREAM() - { - MemoryStream ms = new MemoryStream(); - - byte[] b = new byte[] { 0x0, 0x1, 0x2, 0x3 }; - byte[] b2 = new byte[] { 0x4, 0x5, 0x6, 0x7 }; - - CompoundFile cf = new CompoundFile(); - CFStream st = cf.RootStorage.AddStream("MyMiniStream"); - st.SetData(b); - st.Append(b2); - - cf.Save(ms); - cf.Close(); - - byte[] cmp = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }; - cf = new CompoundFile(ms); - byte[] data = cf.RootStorage.GetStream("MyMiniStream").GetData(); - Assert.IsTrue(Helpers.CompareBuffer(cmp, data)); - - } - - [TestMethod] - public void Test_COPY_FROM_STREAM() - { - byte[] b = Helpers.GetBuffer(100); - MemoryStream ms = new MemoryStream(b); - - CompoundFile cf = new CompoundFile(); - CFStream st = cf.RootStorage.AddStream("MyImportedStream"); - st.CopyFrom(ms); - ms.Close(); - cf.Save("COPY_FROM_STREAM.cfs"); - cf.Close(); - - cf = new CompoundFile("COPY_FROM_STREAM.cfs"); - byte[] data = cf.RootStorage.GetStream("MyImportedStream").GetData(); - - Assert.IsTrue(Helpers.CompareBuffer(b, data)); - - } - - -#if LARGETEST - - [TestMethod] - public void Test_APPEND_DATA_TO_CREATE_LARGE_STREAM() - { - byte[] b = Helpers.GetBuffer(1024 * 1024 * 50); //2GB buffer - byte[] cmp = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }; - - CompoundFile cf = new CompoundFile(CFSVersion.Ver_4, false, false); - CFStream st = cf.RootStorage.AddStream("MySuperLargeStream"); - cf.Save("MEGALARGESSIMUSFILE.cfs"); - cf.Close(); - - - cf = new CompoundFile("MEGALARGESSIMUSFILE.cfs", UpdateMode.Update, false, false); - CFStream cfst = cf.RootStorage.GetStream("MySuperLargeStream"); - for (int i = 0; i < 42; i++) - { - cfst.AppendData(b); - cf.Commit(true); - } - - cfst.AppendData(cmp); - cf.Commit(true); - - cf.Close(); - - - cf = new CompoundFile("MEGALARGESSIMUSFILE.cfs"); - int count = 8; - byte[] data = cf.RootStorage.GetStream("MySuperLargeStream").GetData((long)b.Length * 42L, ref count); - Assert.IsTrue(Helpers.CompareBuffer(cmp, data)); - cf.Close(); - - } -#endif - [TestMethod] - public void Test_RESIZE_STREAM_NO_TRANSITION() - { - CompoundFile cf = null; - //CFStream st = null; - byte[] b = Helpers.GetBuffer(1024 * 1024 * 2); //2MB buffer - - cf = new CompoundFile(CFSVersion.Ver_3, CFSConfiguration.Default); - cf.RootStorage.AddStream("AStream").SetData(b); - cf.Save("$Test_RESIZE_STREAM.cfs"); - cf.Close(); - - cf = new CompoundFile("$Test_RESIZE_STREAM.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); - CFStream item = cf.RootStorage.GetStream("AStream"); - item.Resize(item.Size / 2); - //cf.RootStorage.AddStream("BStream").SetData(b); - cf.Commit(true); - cf.Close(); - } - - [TestMethod] - public void Test_RESIZE_STREAM_TRANSITION_TO_MINI() - { - String FILE_NAME = "$Test_RESIZE_STREAM_TRANSITION_TO_MINI.cfs"; - CompoundFile cf = null; - - byte[] b = Helpers.GetBuffer(1024 * 1024 * 2); //2MB buffer - byte[] b100 = new byte[100]; - - for (int i = 0; i < 100; i++) - { - b100[i] = b[i]; - } - - cf = new CompoundFile(CFSVersion.Ver_3, CFSConfiguration.Default); - cf.RootStorage.AddStream("AStream").SetData(b); - cf.Save(FILE_NAME); - cf.Close(); - - cf = new CompoundFile(FILE_NAME, CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); - CFStream item = cf.RootStorage.GetStream("AStream"); - item.Resize(100); - cf.Commit(); - cf.Close(); - - cf = new CompoundFile(FILE_NAME, CFSUpdateMode.ReadOnly, CFSConfiguration.Default); - Assert.IsTrue(Helpers.CompareBuffer(cf.RootStorage.GetStream("AStream").GetData(), b100)); - cf.Close(); - - if (File.Exists(FILE_NAME)) - File.Delete(FILE_NAME); - } - - [TestMethod] - public void Test_RESIZE_STREAM_TRANSITION_TO_NORMAL() - { - CompoundFile cf = null; - byte[] b = Helpers.GetBuffer(1024 * 2, 0xAA); //2MB buffer - - cf = new CompoundFile(CFSVersion.Ver_3, CFSConfiguration.Default); - cf.RootStorage.AddStream("AStream").SetData(b); - cf.Save("$Test_RESIZE_STREAM_TRANSITION_TO_NORMAL.cfs"); - cf.Save("$Test_RESIZE_STREAM_TRANSITION_TO_NORMAL2.cfs"); - cf.Close(); - - cf = new CompoundFile("$Test_RESIZE_STREAM_TRANSITION_TO_NORMAL.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle | CFSConfiguration.EraseFreeSectors); - CFStream item = cf.RootStorage.GetStream("AStream"); - item.Resize(5000); - cf.Commit(); - cf.Close(); - - cf = new CompoundFile("$Test_RESIZE_STREAM_TRANSITION_TO_NORMAL.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.Default); - item = cf.RootStorage.GetStream("AStream"); - Assert.IsTrue(item != null); - Assert.IsTrue(item.Size == 5000); - - byte[] buffer = new byte[2048]; - item.Read(buffer, 0, 2048); - Assert.IsTrue(Helpers.CompareBuffer(b, buffer)); - - } - - [TestMethod] - public void Test_RESIZE_MINISTREAM_NO_TRANSITION() - { - CompoundFile cf = null; - - byte[] b = Helpers.GetBuffer(1024 * 2); - - cf = new CompoundFile(CFSVersion.Ver_3, CFSConfiguration.Default); - cf.RootStorage.AddStream("MiniStream").SetData(b); - cf.Save("$Test_RESIZE_MINISTREAM.cfs"); - cf.Close(); - - cf = new CompoundFile("$Test_RESIZE_MINISTREAM.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle | CFSConfiguration.EraseFreeSectors); - CFStream item = cf.RootStorage.GetStream("MiniStream"); - item.Resize(item.Size / 2); - - cf.Commit(); - cf.Close(); - - cf = new CompoundFile("$Test_RESIZE_MINISTREAM.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.Default); - CFStream st = cf.RootStorage.GetStream("MiniStream"); - - Assert.IsNotNull(st); - Assert.IsTrue(st.Size == 1024); - - byte[] buffer = new byte[1024]; - st.Read(buffer, 0, 1024); - - Assert.IsTrue(Helpers.CompareBuffer(b, buffer, 1024)); - - cf.Close(); - } - - [TestMethod] - public void Test_RESIZE_MINISTREAM_SECTOR_RECYCLE() - { - CompoundFile cf = null; - - byte[] b = Helpers.GetBuffer(1024 * 2); - - cf = new CompoundFile(CFSVersion.Ver_3, CFSConfiguration.Default); - cf.RootStorage.AddStream("MiniStream").SetData(b); - cf.Save("$Test_RESIZE_MINISTREAM_RECYCLE.cfs"); - cf.Close(); - - cf = new CompoundFile("$Test_RESIZE_MINISTREAM_RECYCLE.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle | CFSConfiguration.EraseFreeSectors); - CFStream item = cf.RootStorage.GetStream("MiniStream"); - item.Resize(item.Size / 2); - - cf.Commit(); - cf.Close(); - - cf = new CompoundFile("$Test_RESIZE_MINISTREAM_RECYCLE.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.SectorRecycle | CFSConfiguration.EraseFreeSectors); - CFStream st = cf.RootStorage.AddStream("ANewStream"); - st.SetData(Helpers.GetBuffer(400)); - cf.Save("$Test_RESIZE_MINISTREAM_RECYCLE2.cfs"); - cf.Close(); - - Assert.IsTrue( - new FileInfo("$Test_RESIZE_MINISTREAM_RECYCLE.cfs").Length - == new FileInfo("$Test_RESIZE_MINISTREAM_RECYCLE2.cfs").Length); - - } - - [TestMethod] - public void Test_DELETE_STREAM_SECTOR_REUSE() - { - CompoundFile cf = null; - CFStream st = null; - - byte[] b = Helpers.GetBuffer(1024 * 1024 * 2); //2MB buffer - byte[] cmp = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }; - - cf = new CompoundFile(CFSVersion.Ver_4, CFSConfiguration.Default); - st = cf.RootStorage.AddStream("AStream"); - st.Append(b); - cf.Save("SectorRecycle.cfs"); - cf.Close(); - - - cf = new CompoundFile("SectorRecycle.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); - cf.RootStorage.Delete("AStream"); - cf.Commit(true); - cf.Close(); - - cf = new CompoundFile("SectorRecycle.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.Default); //No sector recycle - st = cf.RootStorage.AddStream("BStream"); - st.Append(Helpers.GetBuffer(1024 * 1024 * 1)); - cf.Save("SectorRecycleLarger.cfs"); - cf.Close(); - - Assert.IsFalse((new FileInfo("SectorRecycle.cfs").Length) >= (new FileInfo("SectorRecycleLarger.cfs").Length)); - - cf = new CompoundFile("SectorRecycle.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.SectorRecycle); - st = cf.RootStorage.AddStream("BStream"); - st.Append(Helpers.GetBuffer(1024 * 1024 * 1)); - cf.Save("SectorRecycleSmaller.cfs"); - cf.Close(); - long larger = (new FileInfo("SectorRecycle.cfs").Length); - long smaller = (new FileInfo("SectorRecycleSmaller.cfs").Length); - - Assert.IsTrue(larger >= smaller, "Larger size:" + larger.ToString() + " - Smaller size:" + smaller.ToString()); - - } - - - - [TestMethod] - public void TEST_STREAM_VIEW() - { - Stream a = null; - List temp = new List(); - Sector s = new Sector(512); - Buffer.BlockCopy(BitConverter.GetBytes((int)1), 0, s.GetData(), 0, 4); - temp.Add(s); - - StreamView sv = new StreamView(temp, 512, 0, a); - BinaryReader br = new BinaryReader(sv); - Int32 t = br.ReadInt32(); - - Assert.IsTrue(t == 1); - } - - - [TestMethod] - public void Test_STREAM_VIEW_2() - { - Stream b = null; - List temp = new List(); - - StreamView sv = new StreamView(temp, 512, b); - sv.Write(BitConverter.GetBytes(1), 0, 4); - sv.Seek(0, SeekOrigin.Begin); - BinaryReader br = new BinaryReader(sv); - Int32 t = br.ReadInt32(); - - Assert.IsTrue(t == 1); - } - - - /// - /// Write a sequence of Int32 greater than sector size, - /// read and compare. - /// - [TestMethod] - public void Test_STREAM_VIEW_3() - { - Stream b = null; - List temp = new List(); - - StreamView sv = new StreamView(temp, 512, b); - - for (int i = 0; i < 200; i++) - { - sv.Write(BitConverter.GetBytes(i), 0, 4); - } - - sv.Seek(0, SeekOrigin.Begin); - BinaryReader br = new BinaryReader(sv); - - for (int i = 0; i < 200; i++) - { - Assert.IsTrue(i == br.ReadInt32(), "Failed with " + i.ToString()); - } - } - - /// - /// Write a sequence of Int32 greater than sector size, - /// read and compare. - /// - [TestMethod] - public void Test_STREAM_VIEW_LARGE_DATA() - { - Stream b = null; - List temp = new List(); - - StreamView sv = new StreamView(temp, 512, b); - - for (int i = 0; i < 200; i++) - { - sv.Write(BitConverter.GetBytes(i), 0, 4); - } - - sv.Seek(0, SeekOrigin.Begin); - BinaryReader br = new BinaryReader(sv); - - for (int i = 0; i < 200; i++) - { - Assert.IsTrue(i == br.ReadInt32(), "Failed with " + i.ToString()); - } - } - - - - } -} +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenMcdf; +using System.IO; + +namespace OpenMcdf.Test +{ + /// + /// Summary description for UnitTest1 + /// + [TestClass] + public class CFSStreamTest + { + + //const String TestContext.TestDir = "C:\\TestOutputFiles\\"; + + public CFSStreamTest() + { + + } + + private TestContext testContextInstance; + + /// + ///Gets or sets the test context which provides + ///information about and functionality for the current test run. + /// + public TestContext TestContext + { + get + { + return testContextInstance; + } + set + { + testContextInstance = value; + } + } + + #region Additional test attributes + // + // You can use the following additional attributes as you write your tests: + // + // Use ClassInitialize to run code before running the first test in the class + // [ClassInitialize()] + // public static void MyClassInitialize(TestContext testContext) { } + // + // Use ClassCleanup to run code after all tests in a class have run + // [ClassCleanup()] + // public static void MyClassCleanup() { } + // + // Use TestInitialize to run code before running each test + // [TestInitialize()] + // public void MyTestInitialize() { } + // + // Use TestCleanup to run code after each test has run + // [TestCleanup()] + // public void MyTestCleanup() { } + // + #endregion + + [TestMethod] + public void Test_READ_STREAM() + { + String filename = "report.xls"; + + CompoundFile cf = new CompoundFile(filename); + CFStream foundStream = cf.RootStorage.GetStream("Workbook"); + + byte[] temp = foundStream.GetData(); + + Assert.IsNotNull(temp); + Assert.IsTrue(temp.Length > 0); + + cf.Close(); + } + + [TestMethod] + public void Test_WRITE_STREAM() + { + const int BUFFER_LENGTH = 10000; + + byte[] b = Helpers.GetBuffer(BUFFER_LENGTH); + + CompoundFile cf = new CompoundFile(); + CFStream myStream = cf.RootStorage.AddStream("MyStream"); + + Assert.IsNotNull(myStream); + Assert.IsTrue(myStream.Size == 0); + + myStream.SetData(b); + + Assert.IsTrue(myStream.Size == BUFFER_LENGTH, "Stream size differs from buffer size"); + + cf.Close(); + } + + [TestMethod] + public void Test_WRITE_MINI_STREAM() + { + const int BUFFER_LENGTH = 1023; // < 4096 + + byte[] b = Helpers.GetBuffer(BUFFER_LENGTH); + + CompoundFile cf = new CompoundFile(); + CFStream myStream = cf.RootStorage.AddStream("MyMiniStream"); + + Assert.IsNotNull(myStream); + Assert.IsTrue(myStream.Size == 0); + + myStream.SetData(b); + + Assert.IsTrue(myStream.Size == BUFFER_LENGTH, "Mini Stream size differs from buffer size"); + + cf.Close(); + } + + [TestMethod] + public void Test_ZERO_LENGTH_WRITE_STREAM() + { + byte[] b = new byte[0]; + + CompoundFile cf = new CompoundFile(); + CFStream myStream = cf.RootStorage.AddStream("MyStream"); + + Assert.IsNotNull(myStream); + + try + { + myStream.SetData(b); cf.Save("ZERO_LENGTH_STREAM.cfs"); + } + catch + { + Assert.Fail("Failed setting zero length stream"); + } + finally + { + if (cf != null) + cf.Close(); + } + + if (File.Exists("ZERO_LENGTH_STREAM.cfs")) + File.Delete("ZERO_LENGTH_STREAM.cfs"); + + } + + [TestMethod] + public void Test_ZERO_LENGTH_RE_WRITE_STREAM() + { + byte[] b = new byte[0]; + + CompoundFile cf = new CompoundFile(); + CFStream myStream = cf.RootStorage.AddStream("MyStream"); + + Assert.IsNotNull(myStream); + + try + { + myStream.SetData(b); + } + catch + { + Assert.Fail("Failed setting zero length stream"); + } + + cf.Save("ZERO_LENGTH_STREAM_RE.cfs"); + cf.Close(); + + CompoundFile cfo = new CompoundFile("ZERO_LENGTH_STREAM_RE.cfs"); + CFStream oStream = cfo.RootStorage.GetStream("MyStream"); + + Assert.IsNotNull(oStream); + Assert.IsTrue(oStream.Size == 0); + + try + { + oStream.SetData(Helpers.GetBuffer(30)); + cfo.Save("ZERO_LENGTH_STREAM_RE2.cfs"); + } + catch + { + Assert.Fail("Failed re-writing zero length stream"); + } + finally + { + cfo.Close(); + } + + if (File.Exists("ZERO_LENGTH_STREAM_RE.cfs")) + File.Delete("ZERO_LENGTH_STREAM_RE.cfs"); + + if (File.Exists("ZERO_LENGTH_STREAM_RE2.cfs")) + File.Delete("ZERO_LENGTH_STREAM_RE2.cfs"); + + } + + + [TestMethod] + public void Test_WRITE_STREAM_WITH_DIFAT() + { + //const int SIZE = 15388609; //Incredible condition of 'resonance' between FAT and DIFAT sec number + const int SIZE = 15345665; // 64 -> 65 NOT working (in the past ;-) ) + byte[] b = Helpers.GetBuffer(SIZE, 0); + + CompoundFile cf = new CompoundFile(); + CFStream myStream = cf.RootStorage.AddStream("MyStream"); + Assert.IsNotNull(myStream); + myStream.SetData(b); + + cf.Save("WRITE_STREAM_WITH_DIFAT.cfs"); + cf.Close(); + + + CompoundFile cf2 = new CompoundFile("WRITE_STREAM_WITH_DIFAT.cfs"); + CFStream st = cf2.RootStorage.GetStream("MyStream"); + + Assert.IsNotNull(cf2); + Assert.IsTrue(st.Size == SIZE); + + Assert.IsTrue(Helpers.CompareBuffer(b, st.GetData())); + + cf2.Close(); + + if (File.Exists("WRITE_STREAM_WITH_DIFAT.cfs")) + File.Delete("WRITE_STREAM_WITH_DIFAT.cfs"); + + } + + + [TestMethod] + public void Test_WRITE_MINISTREAM_READ_REWRITE_STREAM() + { + const int BIGGER_SIZE = 350; + //const int SMALLER_SIZE = 290; + const int MEGA_SIZE = 18000000; + + byte[] ba1 = Helpers.GetBuffer(BIGGER_SIZE, 1); + byte[] ba2 = Helpers.GetBuffer(BIGGER_SIZE, 2); + byte[] ba3 = Helpers.GetBuffer(BIGGER_SIZE, 3); + byte[] ba4 = Helpers.GetBuffer(BIGGER_SIZE, 4); + byte[] ba5 = Helpers.GetBuffer(BIGGER_SIZE, 5); + + //WRITE 5 (mini)streams in a compound file -- + + CompoundFile cfa = new CompoundFile(); + + CFStream myStream = cfa.RootStorage.AddStream("MyFirstStream"); + Assert.IsNotNull(myStream); + + myStream.SetData(ba1); + Assert.IsTrue(myStream.Size == BIGGER_SIZE); + + CFStream myStream2 = cfa.RootStorage.AddStream("MySecondStream"); + Assert.IsNotNull(myStream2); + + myStream2.SetData(ba2); + Assert.IsTrue(myStream2.Size == BIGGER_SIZE); + + CFStream myStream3 = cfa.RootStorage.AddStream("MyThirdStream"); + Assert.IsNotNull(myStream3); + + myStream3.SetData(ba3); + Assert.IsTrue(myStream3.Size == BIGGER_SIZE); + + CFStream myStream4 = cfa.RootStorage.AddStream("MyFourthStream"); + Assert.IsNotNull(myStream4); + + myStream4.SetData(ba4); + Assert.IsTrue(myStream4.Size == BIGGER_SIZE); + + CFStream myStream5 = cfa.RootStorage.AddStream("MyFifthStream"); + Assert.IsNotNull(myStream5); + + myStream5.SetData(ba5); + Assert.IsTrue(myStream5.Size == BIGGER_SIZE); + + cfa.Save("WRITE_MINISTREAM_READ_REWRITE_STREAM.cfs"); + + cfa.Close(); + + // Now get the second stream and rewrite it smaller + byte[] bb = Helpers.GetBuffer(MEGA_SIZE); + CompoundFile cfb = new CompoundFile("WRITE_MINISTREAM_READ_REWRITE_STREAM.cfs"); + CFStream myStreamB = cfb.RootStorage.GetStream("MySecondStream"); + Assert.IsNotNull(myStreamB); + myStreamB.SetData(bb); + Assert.IsTrue(myStreamB.Size == MEGA_SIZE); + + byte[] bufferB = myStreamB.GetData(); + cfb.Save("WRITE_MINISTREAM_READ_REWRITE_STREAM_2ND.cfs"); + cfb.Close(); + + CompoundFile cfc = new CompoundFile("WRITE_MINISTREAM_READ_REWRITE_STREAM_2ND.cfs"); + CFStream myStreamC = cfc.RootStorage.GetStream("MySecondStream"); + Assert.IsTrue(myStreamC.Size == MEGA_SIZE, "DATA SIZE FAILED"); + + byte[] bufferC = myStreamC.GetData(); + Assert.IsTrue(Helpers.CompareBuffer(bufferB, bufferC), "DATA INTEGRITY FAILED"); + + cfc.Close(); + + if (File.Exists("WRITE_MINISTREAM_READ_REWRITE_STREAM.cfs")) + File.Delete("WRITE_MINISTREAM_READ_REWRITE_STREAM.cfs"); + + + if (File.Exists("WRITE_MINISTREAM_READ_REWRITE_STREAM_2ND.cfs")) + File.Delete("WRITE_MINISTREAM_READ_REWRITE_STREAM_2ND.cfs"); + + } + + [TestMethod] + public void Test_RE_WRITE_SMALLER_STREAM() + { + const int BUFFER_LENGTH = 8000; + + String filename = "report.xls"; + + byte[] b = Helpers.GetBuffer(BUFFER_LENGTH); + + CompoundFile cf = new CompoundFile(filename); + CFStream foundStream = cf.RootStorage.GetStream("Workbook"); + foundStream.SetData(b); + cf.Save("reportRW_SMALL.xls"); + cf.Close(); + + cf = new CompoundFile("reportRW_SMALL.xls"); + byte[] c = cf.RootStorage.GetStream("Workbook").GetData(); + Assert.IsTrue(c.Length == BUFFER_LENGTH); + cf.Close(); + + if (File.Exists("reportRW_SMALL.xls")) + File.Delete("reportRW_SMALL.xls"); + + } + + [TestMethod] + public void Test_RE_WRITE_SMALLER_MINI_STREAM() + { + String filename = "report.xls"; + + CompoundFile cf = new CompoundFile(filename); + CFStream foundStream = cf.RootStorage.GetStream("\x05SummaryInformation"); + int TEST_LENGTH = (int)foundStream.Size - 20; + byte[] b = Helpers.GetBuffer(TEST_LENGTH); + foundStream.SetData(b); + + cf.Save("RE_WRITE_SMALLER_MINI_STREAM.xls"); + cf.Close(); + + cf = new CompoundFile("RE_WRITE_SMALLER_MINI_STREAM.xls"); + byte[] c = cf.RootStorage.GetStream("\x05SummaryInformation").GetData(); + Assert.IsTrue(c.Length == TEST_LENGTH); + Assert.IsTrue(Helpers.CompareBuffer(c, b)); + cf.Close(); + + if (File.Exists("RE_WRITE_SMALLER_MINI_STREAM.xls")) + File.Delete("RE_WRITE_SMALLER_MINI_STREAM.xls"); + + } + + [TestMethod] + public void Test_TRANSACTED_ADD_STREAM_TO_EXISTING_FILE() + { + String srcFilename = "report.xls"; + String dstFilename = "reportOverwrite.xls"; + + File.Copy(srcFilename, dstFilename, true); + + CompoundFile cf = new CompoundFile(dstFilename, CFSUpdateMode.Update, CFSConfiguration.Default); + + byte[] buffer = Helpers.GetBuffer(5000); + + CFStream addedStream = cf.RootStorage.AddStream("MyNewStream"); + addedStream.SetData(buffer); + + cf.Commit(); + cf.Close(); + + + if (File.Exists("reportOverwrite.xls")) + File.Delete("reportOverwrite.xls"); + + } + + [TestMethod] + public void Test_TRANSACTED_ADD_REMOVE_MULTIPLE_STREAM_TO_EXISTING_FILE() + { + String srcFilename = "report.xls"; + String dstFilename = "reportOverwriteMultiple.xls"; + + File.Copy(srcFilename, dstFilename, true); + + CompoundFile cf = new CompoundFile(dstFilename, CFSUpdateMode.ReadOnly, CFSConfiguration.SectorRecycle); + + //CompoundFile cf = new CompoundFile(); + + Random r = new Random(); + + for (int i = 0; i < 254; i++) + { + //byte[] buffer = Helpers.GetBuffer(r.Next(100, 3500), (byte)i); + byte[] buffer = Helpers.GetBuffer(1995, 1); + + //if (i > 0) + //{ + // if (r.Next(0, 100) > 50) + // { + // cf.RootStorage.Delete("MyNewStream" + (i - 1).ToString()); + // } + //} + + CFStream addedStream = cf.RootStorage.AddStream("MyNewStream" + i.ToString()); + Assert.IsNotNull(addedStream, "Stream not found"); + addedStream.SetData(buffer); + + Assert.IsTrue(Helpers.CompareBuffer(addedStream.GetData(), buffer), "Data buffer corrupted"); + + // Random commit, not on single addition + //if (r.Next(0, 100) > 50) + // cf.UpdateFile(); + + } + + cf.Save(dstFilename + "PP"); + cf.Close(); + + if (File.Exists("reportOverwriteMultiple.xls")) + File.Delete("reportOverwriteMultiple.xls"); + + if (File.Exists("reportOverwriteMultiple.xlsPP")) + File.Delete("reportOverwriteMultiple.xlsPP"); + + + } + + [TestMethod] + public void Test_TRANSACTED_ADD_MINISTREAM_TO_EXISTING_FILE() + { + String srcFilename = "report.xls"; + String dstFilename = "reportOverwriteMultiple.xls"; + + File.Copy(srcFilename, dstFilename, true); + + CompoundFile cf = new CompoundFile(dstFilename, CFSUpdateMode.Update, CFSConfiguration.SectorRecycle | CFSConfiguration.EraseFreeSectors); + + Random r = new Random(); + + byte[] buffer = Helpers.GetBuffer(31, 0x0A); + + cf.RootStorage.AddStream("MyStream").SetData(buffer); + cf.Commit(); + cf.Close(); + FileStream larger = new FileStream(dstFilename, FileMode.Open); + FileStream smaller = new FileStream(srcFilename, FileMode.Open); + + // Equal condition if minisector can be "allocated" + // within the existing standard sector border + Assert.IsTrue(larger.Length >= smaller.Length); + + larger.Close(); + smaller.Close(); + + if (File.Exists("reportOverwriteMultiple.xlsPP")) + File.Delete("reportOverwriteMultiple.xlsPP"); + + + } + + [TestMethod] + public void Test_TRANSACTED_REMOVE_MINI_STREAM_ADD_MINISTREAM_TO_EXISTING_FILE() + { + String srcFilename = "report.xls"; + String dstFilename = "reportOverwrite2.xls"; + + File.Copy(srcFilename, dstFilename, true); + + CompoundFile cf = new CompoundFile(dstFilename, CFSUpdateMode.Update, CFSConfiguration.SectorRecycle | CFSConfiguration.EraseFreeSectors); + + cf.RootStorage.Delete("\x05SummaryInformation"); + + byte[] buffer = Helpers.GetBuffer(2000); + + CFStream addedStream = cf.RootStorage.AddStream("MyNewStream"); + addedStream.SetData(buffer); + + cf.Commit(); + cf.Close(); + + if (File.Exists("reportOverwrite2.xlsPP")) + File.Delete("reportOverwrite2.xlsPP"); + + + } + + + + [TestMethod] + public void Test_DELETE_STREAM_1() + { + String filename = "MultipleStorage.cfs"; + + CompoundFile cf = new CompoundFile(filename); + CFStorage cfs = cf.RootStorage.GetStorage("MyStorage"); + cfs.Delete("MySecondStream"); + + cf.Save(TestContext.TestDir + "MultipleStorage_REMOVED_STREAM_1.cfs"); + cf.Close(); + } + + [TestMethod] + public void Test_DELETE_STREAM_2() + { + String filename = "MultipleStorage.cfs"; + + CompoundFile cf = new CompoundFile(filename); + CFStorage cfs = cf.RootStorage.GetStorage("MyStorage").GetStorage("AnotherStorage"); + + cfs.Delete("AnotherStream"); + + cf.Save(TestContext.TestDir + "MultipleStorage_REMOVED_STREAM_2.cfs"); + + cf.Close(); + } + + + [TestMethod] + public void Test_WRITE_AND_READ_CFS() + { + String filename = "WRITE_AND_READ_CFS.cfs"; + + CompoundFile cf = new CompoundFile(); + + CFStorage st = cf.RootStorage.AddStorage("MyStorage"); + CFStream sm = st.AddStream("MyStream"); + byte[] b = Helpers.GetBuffer(220, 0x0A); + sm.SetData(b); + + cf.Save(filename); + cf.Close(); + + CompoundFile cf2 = new CompoundFile(filename); + CFStorage st2 = cf2.RootStorage.GetStorage("MyStorage"); + CFStream sm2 = st2.GetStream("MyStream"); + cf2.Close(); + + Assert.IsNotNull(sm2); + Assert.IsTrue(sm2.Size == 220); + + + if (File.Exists(filename)) + File.Delete(filename); + + + } + + [TestMethod] + public void Test_INCREMENTAL_SIZE_MULTIPLE_WRITE_AND_READ_CFS() + { + + Random r = new Random(); + + for (int i = r.Next(1, 100); i < 1024 * 1024 * 70; i = i << 1) + { + SingleWriteReadMatching(i + r.Next(0, 3)); + } + + } + + + [TestMethod] + public void Test_INCREMENTAL_SIZE_MULTIPLE_WRITE_AND_READ_CFS_STREAM() + { + + Random r = new Random(); + + for (int i = r.Next(1, 100); i < 1024 * 1024 * 70; i = i << 1) + { + SingleWriteReadMatchingSTREAMED(i + r.Next(0, 3)); + } + + } + + [TestMethod] + public void Test_DELETE_ZERO_LENGTH_STREAM() + { + byte[] b = new byte[0]; + + CompoundFile cf = new CompoundFile(); + + string zeroLengthName = "MyZeroStream"; + CFStream myStream = cf.RootStorage.AddStream(zeroLengthName); + + Assert.IsNotNull(myStream); + + try + { + myStream.SetData(b); + } + catch + { + Assert.Fail("Failed setting zero length stream"); + } + + string filename = "DeleteZeroLengthStream.cfs"; + cf.Save(filename); + cf.Close(); + + CompoundFile cf2 = new CompoundFile(filename); + + // Execption in next line! + cf2.RootStorage.Delete(zeroLengthName); + + CFStream zeroStream2 = null; + + try + { + zeroStream2 = cf2.RootStorage.GetStream(zeroLengthName); + } + catch (Exception ex) + { + Assert.IsNull(zeroStream2); + Assert.IsInstanceOfType(ex, typeof(CFItemNotFound)); + } + + cf2.Save("MultipleDeleteMiniStream.cfs"); + cf2.Close(); + } + + //[TestMethod] + //public void Test_INCREMENTAL_TRANSACTED_CHANGE_CFS() + //{ + + // Random r = new Random(); + + // for (int i = r.Next(1, 100); i < 1024 * 1024 * 70; i = i << 1) + // { + // SingleTransactedChange(i + r.Next(0, 3)); + // } + + //} + + private void SingleTransactedChange(int size) + { + + String filename = "INCREMENTAL_SIZE_MULTIPLE_WRITE_AND_READ_CFS.cfs"; + + if (File.Exists(filename)) + File.Delete(filename); + + CompoundFile cf = new CompoundFile(); + CFStorage st = cf.RootStorage.AddStorage("MyStorage"); + CFStream sm = st.AddStream("MyStream"); + + byte[] b = Helpers.GetBuffer(size); + + sm.SetData(b); + cf.Save(filename); + cf.Close(); + + CompoundFile cf2 = new CompoundFile(filename); + CFStorage st2 = cf2.RootStorage.GetStorage("MyStorage"); + CFStream sm2 = st2.GetStream("MyStream"); + + Assert.IsNotNull(sm2); + Assert.IsTrue(sm2.Size == size); + Assert.IsTrue(Helpers.CompareBuffer(sm2.GetData(), b)); + + cf2.Close(); + } + + private void SingleWriteReadMatching(int size) + { + + String filename = "INCREMENTAL_SIZE_MULTIPLE_WRITE_AND_READ_CFS.cfs"; + + if (File.Exists(filename)) + File.Delete(filename); + + CompoundFile cf = new CompoundFile(); + CFStorage st = cf.RootStorage.AddStorage("MyStorage"); + CFStream sm = st.AddStream("MyStream"); + + byte[] b = Helpers.GetBuffer(size); + + sm.SetData(b); + cf.Save(filename); + cf.Close(); + + CompoundFile cf2 = new CompoundFile(filename); + CFStorage st2 = cf2.RootStorage.GetStorage("MyStorage"); + CFStream sm2 = st2.GetStream("MyStream"); + + Assert.IsNotNull(sm2); + Assert.IsTrue(sm2.Size == size); + Assert.IsTrue(Helpers.CompareBuffer(sm2.GetData(), b)); + + cf2.Close(); + } + + private void SingleWriteReadMatchingSTREAMED(int size) + { + MemoryStream ms = new MemoryStream(size); + + CompoundFile cf = new CompoundFile(); + CFStorage st = cf.RootStorage.AddStorage("MyStorage"); + CFStream sm = st.AddStream("MyStream"); + + byte[] b = Helpers.GetBuffer(size); + + sm.SetData(b); + cf.Save(ms); + cf.Close(); + + CompoundFile cf2 = new CompoundFile(ms); + CFStorage st2 = cf2.RootStorage.GetStorage("MyStorage"); + CFStream sm2 = st2.GetStream("MyStream"); + + Assert.IsNotNull(sm2); + Assert.IsTrue(sm2.Size == size); + Assert.IsTrue(Helpers.CompareBuffer(sm2.GetData(), b)); + + cf2.Close(); + } + + + [TestMethod] + public void Test_APPEND_DATA_TO_STREAM() + { + MemoryStream ms = new MemoryStream(); + + byte[] b = new byte[] { 0x0, 0x1, 0x2, 0x3 }; + byte[] b2 = new byte[] { 0x4, 0x5, 0x6, 0x7 }; + + CompoundFile cf = new CompoundFile(); + CFStream st = cf.RootStorage.AddStream("MyMiniStream"); + st.SetData(b); + st.Append(b2); + + cf.Save(ms); + cf.Close(); + + byte[] cmp = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }; + cf = new CompoundFile(ms); + byte[] data = cf.RootStorage.GetStream("MyMiniStream").GetData(); + Assert.IsTrue(Helpers.CompareBuffer(cmp, data)); + + } + + [TestMethod] + public void Test_COPY_FROM_STREAM() + { + byte[] b = Helpers.GetBuffer(100); + MemoryStream ms = new MemoryStream(b); + + CompoundFile cf = new CompoundFile(); + CFStream st = cf.RootStorage.AddStream("MyImportedStream"); + st.CopyFrom(ms); + ms.Close(); + cf.Save("COPY_FROM_STREAM.cfs"); + cf.Close(); + + cf = new CompoundFile("COPY_FROM_STREAM.cfs"); + byte[] data = cf.RootStorage.GetStream("MyImportedStream").GetData(); + + Assert.IsTrue(Helpers.CompareBuffer(b, data)); + + } + + +#if LARGETEST + + [TestMethod] + public void Test_APPEND_DATA_TO_CREATE_LARGE_STREAM() + { + byte[] b = Helpers.GetBuffer(1024 * 1024 * 50); //2GB buffer + byte[] cmp = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }; + + CompoundFile cf = new CompoundFile(CFSVersion.Ver_4, false, false); + CFStream st = cf.RootStorage.AddStream("MySuperLargeStream"); + cf.Save("MEGALARGESSIMUSFILE.cfs"); + cf.Close(); + + + cf = new CompoundFile("MEGALARGESSIMUSFILE.cfs", UpdateMode.Update, false, false); + CFStream cfst = cf.RootStorage.GetStream("MySuperLargeStream"); + for (int i = 0; i < 42; i++) + { + cfst.AppendData(b); + cf.Commit(true); + } + + cfst.AppendData(cmp); + cf.Commit(true); + + cf.Close(); + + + cf = new CompoundFile("MEGALARGESSIMUSFILE.cfs"); + int count = 8; + byte[] data = cf.RootStorage.GetStream("MySuperLargeStream").GetData((long)b.Length * 42L, ref count); + Assert.IsTrue(Helpers.CompareBuffer(cmp, data)); + cf.Close(); + + } +#endif + [TestMethod] + public void Test_RESIZE_STREAM_NO_TRANSITION() + { + CompoundFile cf = null; + //CFStream st = null; + byte[] b = Helpers.GetBuffer(1024 * 1024 * 2); //2MB buffer + + cf = new CompoundFile(CFSVersion.Ver_3, CFSConfiguration.Default); + cf.RootStorage.AddStream("AStream").SetData(b); + cf.Save("$Test_RESIZE_STREAM.cfs"); + cf.Close(); + + cf = new CompoundFile("$Test_RESIZE_STREAM.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); + CFStream item = cf.RootStorage.GetStream("AStream"); + item.Resize(item.Size / 2); + //cf.RootStorage.AddStream("BStream").SetData(b); + cf.Commit(true); + cf.Close(); + } + + [TestMethod] + public void Test_RESIZE_STREAM_TRANSITION_TO_MINI() + { + String FILE_NAME = "$Test_RESIZE_STREAM_TRANSITION_TO_MINI.cfs"; + CompoundFile cf = null; + + byte[] b = Helpers.GetBuffer(1024 * 1024 * 2); //2MB buffer + byte[] b100 = new byte[100]; + + for (int i = 0; i < 100; i++) + { + b100[i] = b[i]; + } + + cf = new CompoundFile(CFSVersion.Ver_3, CFSConfiguration.Default); + cf.RootStorage.AddStream("AStream").SetData(b); + cf.Save(FILE_NAME); + cf.Close(); + + cf = new CompoundFile(FILE_NAME, CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); + CFStream item = cf.RootStorage.GetStream("AStream"); + item.Resize(100); + cf.Commit(); + cf.Close(); + + cf = new CompoundFile(FILE_NAME, CFSUpdateMode.ReadOnly, CFSConfiguration.Default); + Assert.IsTrue(Helpers.CompareBuffer(cf.RootStorage.GetStream("AStream").GetData(), b100)); + cf.Close(); + + if (File.Exists(FILE_NAME)) + File.Delete(FILE_NAME); + } + + [TestMethod] + public void Test_RESIZE_STREAM_TRANSITION_TO_NORMAL() + { + CompoundFile cf = null; + byte[] b = Helpers.GetBuffer(1024 * 2, 0xAA); //2MB buffer + + cf = new CompoundFile(CFSVersion.Ver_3, CFSConfiguration.Default); + cf.RootStorage.AddStream("AStream").SetData(b); + cf.Save("$Test_RESIZE_STREAM_TRANSITION_TO_NORMAL.cfs"); + cf.Save("$Test_RESIZE_STREAM_TRANSITION_TO_NORMAL2.cfs"); + cf.Close(); + + cf = new CompoundFile("$Test_RESIZE_STREAM_TRANSITION_TO_NORMAL.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle | CFSConfiguration.EraseFreeSectors); + CFStream item = cf.RootStorage.GetStream("AStream"); + item.Resize(5000); + cf.Commit(); + cf.Close(); + + cf = new CompoundFile("$Test_RESIZE_STREAM_TRANSITION_TO_NORMAL.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.Default); + item = cf.RootStorage.GetStream("AStream"); + Assert.IsTrue(item != null); + Assert.IsTrue(item.Size == 5000); + + byte[] buffer = new byte[2048]; + item.Read(buffer, 0, 2048); + Assert.IsTrue(Helpers.CompareBuffer(b, buffer)); + + } + + [TestMethod] + public void Test_RESIZE_MINISTREAM_NO_TRANSITION() + { + CompoundFile cf = null; + + byte[] b = Helpers.GetBuffer(1024 * 2); + + cf = new CompoundFile(CFSVersion.Ver_3, CFSConfiguration.Default); + cf.RootStorage.AddStream("MiniStream").SetData(b); + cf.Save("$Test_RESIZE_MINISTREAM.cfs"); + cf.Close(); + + cf = new CompoundFile("$Test_RESIZE_MINISTREAM.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle | CFSConfiguration.EraseFreeSectors); + CFStream item = cf.RootStorage.GetStream("MiniStream"); + item.Resize(item.Size / 2); + + cf.Commit(); + cf.Close(); + + cf = new CompoundFile("$Test_RESIZE_MINISTREAM.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.Default); + CFStream st = cf.RootStorage.GetStream("MiniStream"); + + Assert.IsNotNull(st); + Assert.IsTrue(st.Size == 1024); + + byte[] buffer = new byte[1024]; + st.Read(buffer, 0, 1024); + + Assert.IsTrue(Helpers.CompareBuffer(b, buffer, 1024)); + + cf.Close(); + } + + [TestMethod] + public void Test_RESIZE_MINISTREAM_SECTOR_RECYCLE() + { + CompoundFile cf = null; + + byte[] b = Helpers.GetBuffer(1024 * 2); + + cf = new CompoundFile(CFSVersion.Ver_3, CFSConfiguration.Default); + cf.RootStorage.AddStream("MiniStream").SetData(b); + cf.Save("$Test_RESIZE_MINISTREAM_RECYCLE.cfs"); + cf.Close(); + + cf = new CompoundFile("$Test_RESIZE_MINISTREAM_RECYCLE.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle | CFSConfiguration.EraseFreeSectors); + CFStream item = cf.RootStorage.GetStream("MiniStream"); + item.Resize(item.Size / 2); + + cf.Commit(); + cf.Close(); + + cf = new CompoundFile("$Test_RESIZE_MINISTREAM_RECYCLE.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.SectorRecycle | CFSConfiguration.EraseFreeSectors); + CFStream st = cf.RootStorage.AddStream("ANewStream"); + st.SetData(Helpers.GetBuffer(400)); + cf.Save("$Test_RESIZE_MINISTREAM_RECYCLE2.cfs"); + cf.Close(); + + Assert.IsTrue( + new FileInfo("$Test_RESIZE_MINISTREAM_RECYCLE.cfs").Length + == new FileInfo("$Test_RESIZE_MINISTREAM_RECYCLE2.cfs").Length); + + } + + [TestMethod] + public void Test_DELETE_STREAM_SECTOR_REUSE() + { + CompoundFile cf = null; + CFStream st = null; + + byte[] b = Helpers.GetBuffer(1024 * 1024 * 2); //2MB buffer + byte[] cmp = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }; + + cf = new CompoundFile(CFSVersion.Ver_4, CFSConfiguration.Default); + st = cf.RootStorage.AddStream("AStream"); + st.Append(b); + cf.Save("SectorRecycle.cfs"); + cf.Close(); + + + cf = new CompoundFile("SectorRecycle.cfs", CFSUpdateMode.Update, CFSConfiguration.SectorRecycle); + cf.RootStorage.Delete("AStream"); + cf.Commit(true); + cf.Close(); + + cf = new CompoundFile("SectorRecycle.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.Default); //No sector recycle + st = cf.RootStorage.AddStream("BStream"); + st.Append(Helpers.GetBuffer(1024 * 1024 * 1)); + cf.Save("SectorRecycleLarger.cfs"); + cf.Close(); + + Assert.IsFalse((new FileInfo("SectorRecycle.cfs").Length) >= (new FileInfo("SectorRecycleLarger.cfs").Length)); + + cf = new CompoundFile("SectorRecycle.cfs", CFSUpdateMode.ReadOnly, CFSConfiguration.SectorRecycle); + st = cf.RootStorage.AddStream("BStream"); + st.Append(Helpers.GetBuffer(1024 * 1024 * 1)); + cf.Save("SectorRecycleSmaller.cfs"); + cf.Close(); + long larger = (new FileInfo("SectorRecycle.cfs").Length); + long smaller = (new FileInfo("SectorRecycleSmaller.cfs").Length); + + Assert.IsTrue(larger >= smaller, "Larger size:" + larger.ToString() + " - Smaller size:" + smaller.ToString()); + + } + + + + [TestMethod] + public void TEST_STREAM_VIEW() + { + Stream a = null; + List temp = new List(); + Sector s = new Sector(512); + Buffer.BlockCopy(BitConverter.GetBytes((int)1), 0, s.GetData(), 0, 4); + temp.Add(s); + + StreamView sv = new StreamView(temp, 512, 0,null, a); + BinaryReader br = new BinaryReader(sv); + Int32 t = br.ReadInt32(); + + Assert.IsTrue(t == 1); + } + + + [TestMethod] + public void Test_STREAM_VIEW_2() + { + Stream b = null; + List temp = new List(); + + StreamView sv = new StreamView(temp, 512, b); + sv.Write(BitConverter.GetBytes(1), 0, 4); + sv.Seek(0, SeekOrigin.Begin); + BinaryReader br = new BinaryReader(sv); + Int32 t = br.ReadInt32(); + + Assert.IsTrue(t == 1); + } + + + /// + /// Write a sequence of Int32 greater than sector size, + /// read and compare. + /// + [TestMethod] + public void Test_STREAM_VIEW_3() + { + Stream b = null; + List temp = new List(); + + StreamView sv = new StreamView(temp, 512, b); + + for (int i = 0; i < 200; i++) + { + sv.Write(BitConverter.GetBytes(i), 0, 4); + } + + sv.Seek(0, SeekOrigin.Begin); + BinaryReader br = new BinaryReader(sv); + + for (int i = 0; i < 200; i++) + { + Assert.IsTrue(i == br.ReadInt32(), "Failed with " + i.ToString()); + } + } + + /// + /// Write a sequence of Int32 greater than sector size, + /// read and compare. + /// + [TestMethod] + public void Test_STREAM_VIEW_LARGE_DATA() + { + Stream b = null; + List temp = new List(); + + StreamView sv = new StreamView(temp, 512, b); + + for (int i = 0; i < 200; i++) + { + sv.Write(BitConverter.GetBytes(i), 0, 4); + } + + sv.Seek(0, SeekOrigin.Begin); + BinaryReader br = new BinaryReader(sv); + + for (int i = 0; i < 200; i++) + { + Assert.IsTrue(i == br.ReadInt32(), "Failed with " + i.ToString()); + } + } + + + + } +} diff --git a/sources/Test/OpenMcdf.Test/CFSTorageTest.cs b/sources/Test/OpenMcdf.Test/CFSTorageTest.cs index d8f4bbb0..599d7a4a 100644 --- a/sources/Test/OpenMcdf.Test/CFSTorageTest.cs +++ b/sources/Test/OpenMcdf.Test/CFSTorageTest.cs @@ -1,429 +1,429 @@ -using System; -using System.Collections.Generic; -using System.IO; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using OpenMcdf; - -namespace OpenMcdf.Test -{ - /// - /// Summary description for CFTorageTest - /// - [TestClass] - public class CFSTorageTest - { - //const String OUTPUT_DIR = "C:\\TestOutputFiles\\"; - - public CFSTorageTest() - { - - } - - private TestContext testContextInstance; - - /// - ///Gets or sets the test context which provides - ///information about and functionality for the current test run. - /// - public TestContext TestContext - { - get - { - return testContextInstance; - } - set - { - testContextInstance = value; - } - } - - #region Additional test attributes - // - // You can use the following additional attributes as you write your tests: - // - // Use ClassInitialize to run code before running the first test in the class - // [ClassInitialize()] - //public static void MyClassInitialize(TestContext testContext) - - // - // Use ClassCleanup to run code after all tests in a class have run - // [ClassCleanup()] - // public static void MyClassCleanup() { } - // - // Use TestInitialize to run code before running each test - // [TestInitialize()] - // public void MyTestInitialize() { } - // - // Use TestCleanup to run code after each test has run - // [TestCleanup()] - // public void MyTestCleanup() { } - // - #endregion - - [TestMethod] - public void Test_CREATE_STORAGE() - { - const String STORAGE_NAME = "NewStorage"; - CompoundFile cf = new CompoundFile(); - - CFStorage st = cf.RootStorage.AddStorage(STORAGE_NAME); - - Assert.IsNotNull(st); - Assert.AreEqual(STORAGE_NAME, st.Name, false); - } - - [TestMethod] - public void Test_CREATE_STORAGE_WITH_CREATION_DATE() - { - const String STORAGE_NAME = "NewStorage1"; - CompoundFile cf = new CompoundFile(); - - CFStorage st = cf.RootStorage.AddStorage(STORAGE_NAME); - st.CreationDate = DateTime.Now; - - Assert.IsNotNull(st); - Assert.AreEqual(STORAGE_NAME, st.Name, false); - - cf.Save("ProvaData.cfs"); - cf.Close(); - } - - [TestMethod] - public void Test_VISIT_ENTRIES() - { - const String STORAGE_NAME = "report.xls"; - CompoundFile cf = new CompoundFile(STORAGE_NAME); - - FileStream output = new FileStream("LogEntries.txt", FileMode.Create); - TextWriter tw = new StreamWriter(output); - - Action va = delegate (CFItem item) - { - tw.WriteLine(item.Name); - }; - - cf.RootStorage.VisitEntries(va, true); - - tw.Close(); - - } - - - [TestMethod] - public void Test_TRY_GET_STREAM_STORAGE() - { - String FILENAME = "MultipleStorage.cfs"; - CompoundFile cf = new CompoundFile(FILENAME); - - CFStorage st = cf.RootStorage.TryGetStorage("MyStorage"); - Assert.IsNotNull(st); - - try - { - CFStorage nf = cf.RootStorage.TryGetStorage("IDONTEXIST"); - Assert.IsNull(nf); - } - catch (Exception) - { - Assert.Fail("Exception raised for try_get method"); - } - - try - { - CFStream s = st.TryGetStream("MyStream"); - Assert.IsNotNull(s); - CFStream ns = st.TryGetStream("IDONTEXIST2"); - Assert.IsNull(ns); - } - catch (Exception) - { - Assert.Fail("Exception raised for try_get method"); - } - } - - [TestMethod] - public void Test_VISIT_ENTRIES_CORRUPTED_FILE_VALIDATION_ON() - { - CompoundFile f = null; - - try - { - f = new CompoundFile("CorruptedDoc_bug3547815.doc", CFSUpdateMode.ReadOnly, CFSConfiguration.NoValidationException); - } - catch - { - Assert.Fail("No exception has to be fired on creation due to lazy loading"); - } - - FileStream output = null; - - try - { - output = new FileStream("LogEntriesCorrupted_1.txt", FileMode.Create); - - using (TextWriter tw = new StreamWriter(output)) - { - - Action va = delegate (CFItem item) - { - tw.WriteLine(item.Name); - }; - - f.RootStorage.VisitEntries(va, true); - tw.Flush(); - } - } - catch (Exception ex) - { - Assert.IsTrue(ex is CFCorruptedFileException); - Assert.IsTrue(f != null && f.IsClosed); - - } - finally - { - if (output != null) - output.Close(); - - - - } - } - - [TestMethod] - public void Test_VISIT_ENTRIES_CORRUPTED_FILE_VALIDATION_OFF_BUT_CAN_LOAD() - { - CompoundFile f = null; - - try - { - //Corrupted file has invalid children item sid reference - f = new CompoundFile("CorruptedDoc_bug3547815_B.doc", CFSUpdateMode.ReadOnly, CFSConfiguration.NoValidationException); - } - catch - { - Assert.Fail("No exception has to be fired on creation due to lazy loading"); - } - - FileStream output = null; - - try - { - output = new FileStream("LogEntriesCorrupted_2.txt", FileMode.Create); - - - using (TextWriter tw = new StreamWriter(output)) - { - - Action va = delegate (CFItem item) - { - tw.WriteLine(item.Name); - }; - - f.RootStorage.VisitEntries(va, true); - tw.Flush(); - } - } - catch - { - Assert.Fail("Fail is corrupted but it has to be loaded anyway by test design"); - } - finally - { - if (output != null) - output.Close(); - - - } - } - - - [TestMethod] - public void Test_VISIT_STORAGE() - { - String FILENAME = "testVisiting.xls"; - - // Remove... - if (File.Exists(FILENAME)) - File.Delete(FILENAME); - - //Create... - - CompoundFile ncf = new CompoundFile(); - - CFStorage l1 = ncf.RootStorage.AddStorage("Storage Level 1"); - l1.AddStream("l1ns1"); - l1.AddStream("l1ns2"); - l1.AddStream("l1ns3"); - - CFStorage l2 = l1.AddStorage("Storage Level 2"); - l2.AddStream("l2ns1"); - l2.AddStream("l2ns2"); - - ncf.Save(FILENAME); - ncf.Close(); - - - // Read... - - CompoundFile cf = new CompoundFile(FILENAME); - - FileStream output = new FileStream("reportVisit.txt", FileMode.Create); - TextWriter sw = new StreamWriter(output); - - Console.SetOut(sw); - - Action va = delegate (CFItem target) - { - sw.WriteLine(target.Name); - }; - - cf.RootStorage.VisitEntries(va, true); - - cf.Close(); - sw.Close(); - } - - [TestMethod] - public void Test_DELETE_DIRECTORY() - { - String FILENAME = "MultipleStorage2.cfs"; - CompoundFile cf = new CompoundFile(FILENAME, CFSUpdateMode.ReadOnly, CFSConfiguration.Default); - - CFStorage st = cf.RootStorage.GetStorage("MyStorage"); - - Assert.IsNotNull(st); - - st.Delete("AnotherStorage"); - - cf.Save("MultipleStorage_Delete.cfs"); - - cf.Close(); - } - - [TestMethod] - public void Test_DELETE_MINISTREAM_STREAM() - { - String FILENAME = "MultipleStorage2.cfs"; - CompoundFile cf = new CompoundFile(FILENAME); - - CFStorage found = null; - Action action = delegate (CFItem item) { if (item.Name == "AnotherStorage") found = item as CFStorage; }; - cf.RootStorage.VisitEntries(action, true); - - Assert.IsNotNull(found); - - found.Delete("AnotherStream"); - - cf.Save("MultipleDeleteMiniStream"); - cf.Close(); - } - - [TestMethod] - public void Test_DELETE_STREAM() - { - String FILENAME = "MultipleStorage3.cfs"; - CompoundFile cf = new CompoundFile(FILENAME); - - CFStorage found = null; - Action action = delegate (CFItem item) - { - if (item.Name == "AnotherStorage") - found = item as CFStorage; - }; - - cf.RootStorage.VisitEntries(action, true); - - Assert.IsNotNull(found); - - found.Delete("Another2Stream"); - - cf.Save("MultipleDeleteStream"); - cf.Close(); - } - - [TestMethod] - public void Test_CHECK_DISPOSED_() - { - const String FILENAME = "MultipleStorage.cfs"; - CompoundFile cf = new CompoundFile(FILENAME); - - CFStorage st = cf.RootStorage.GetStorage("MyStorage"); - cf.Close(); - - try - { - byte[] temp = st.GetStream("MyStream").GetData(); - Assert.Fail("Stream without media"); - } - catch (Exception ex) - { - Assert.IsTrue(ex is CFDisposedException); - } - } - - [TestMethod] - public void Test_LAZY_LOAD_CHILDREN_() - { - CompoundFile cf = new CompoundFile(); - cf.RootStorage.AddStorage("Level_1") - .AddStorage("Level_2") - .AddStream("Level2Stream") - .SetData(Helpers.GetBuffer(100)); - - cf.Save("$Hel1"); - - cf.Close(); - - cf = new CompoundFile("$Hel1"); - IList i = cf.GetAllNamedEntries("Level2Stream"); - Assert.IsNotNull(i[0]); - Assert.IsTrue(i[0] is CFStream); - Assert.IsTrue((i[0] as CFStream).GetData().Length == 100); - cf.Save("$Hel2"); - cf.Close(); - - if (File.Exists("$Hel1")) - { - File.Delete("$Hel1"); - } - if (File.Exists("$Hel2")) - { - File.Delete("$Hel2"); - } - } - - [TestMethod] - public void Test_FIX_BUG_31() - { - CompoundFile cf = new CompoundFile(); - cf.RootStorage.AddStorage("Level_1") - - .AddStream("Level2Stream") - .SetData(Helpers.GetBuffer(100)); - - cf.Save("$Hel1"); - - cf.Close(); - - CompoundFile cf1 = new CompoundFile("$Hel1"); - try - { - CFStream cs = cf1.RootStorage.GetStorage("Level_1").AddStream("Level2Stream"); - } - catch (Exception ex) - { - Assert.IsTrue(ex.GetType() == typeof(CFDuplicatedItemException)); - } - - } - - [TestMethod] - [ExpectedException(typeof(OpenMcdf.CFCorruptedFileException))] - public void Test_CORRUPTEDDOC_BUG36_SHOULD_THROW_CORRUPTED_FILE_EXCEPTION() - { - using (CompoundFile file = new CompoundFile("CorruptedDoc_bug36.doc", CFSUpdateMode.ReadOnly, CFSConfiguration.NoValidationException) ) { - //Many thanks to theseus for bug reporting - } - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenMcdf; + +namespace OpenMcdf.Test +{ + /// + /// Summary description for CFTorageTest + /// + [TestClass] + public class CFSTorageTest + { + //const String OUTPUT_DIR = "C:\\TestOutputFiles\\"; + + public CFSTorageTest() + { + + } + + private TestContext testContextInstance; + + /// + ///Gets or sets the test context which provides + ///information about and functionality for the current test run. + /// + public TestContext TestContext + { + get + { + return testContextInstance; + } + set + { + testContextInstance = value; + } + } + + #region Additional test attributes + // + // You can use the following additional attributes as you write your tests: + // + // Use ClassInitialize to run code before running the first test in the class + // [ClassInitialize()] + //public static void MyClassInitialize(TestContext testContext) + + // + // Use ClassCleanup to run code after all tests in a class have run + // [ClassCleanup()] + // public static void MyClassCleanup() { } + // + // Use TestInitialize to run code before running each test + // [TestInitialize()] + // public void MyTestInitialize() { } + // + // Use TestCleanup to run code after each test has run + // [TestCleanup()] + // public void MyTestCleanup() { } + // + #endregion + + [TestMethod] + public void Test_CREATE_STORAGE() + { + const String STORAGE_NAME = "NewStorage"; + CompoundFile cf = new CompoundFile(); + + CFStorage st = cf.RootStorage.AddStorage(STORAGE_NAME); + + Assert.IsNotNull(st); + Assert.AreEqual(STORAGE_NAME, st.Name, false); + } + + [TestMethod] + public void Test_CREATE_STORAGE_WITH_CREATION_DATE() + { + const String STORAGE_NAME = "NewStorage1"; + CompoundFile cf = new CompoundFile(); + + CFStorage st = cf.RootStorage.AddStorage(STORAGE_NAME); + st.CreationDate = DateTime.Now; + + Assert.IsNotNull(st); + Assert.AreEqual(STORAGE_NAME, st.Name, false); + + cf.Save("ProvaData.cfs"); + cf.Close(); + } + + [TestMethod] + public void Test_VISIT_ENTRIES() + { + const String STORAGE_NAME = "report.xls"; + CompoundFile cf = new CompoundFile(STORAGE_NAME); + + FileStream output = new FileStream("LogEntries.txt", FileMode.Create); + TextWriter tw = new StreamWriter(output); + + Action va = delegate (CFItem item) + { + tw.WriteLine(item.Name); + }; + + cf.RootStorage.VisitEntries(va, true); + + tw.Close(); + + } + + + [TestMethod] + public void Test_TRY_GET_STREAM_STORAGE() + { + String FILENAME = "MultipleStorage.cfs"; + CompoundFile cf = new CompoundFile(FILENAME); + + CFStorage st = cf.RootStorage.TryGetStorage("MyStorage"); + Assert.IsNotNull(st); + + try + { + CFStorage nf = cf.RootStorage.TryGetStorage("IDONTEXIST"); + Assert.IsNull(nf); + } + catch (Exception) + { + Assert.Fail("Exception raised for try_get method"); + } + + try + { + CFStream s = st.TryGetStream("MyStream"); + Assert.IsNotNull(s); + CFStream ns = st.TryGetStream("IDONTEXIST2"); + Assert.IsNull(ns); + } + catch (Exception) + { + Assert.Fail("Exception raised for try_get method"); + } + } + + [TestMethod] + public void Test_VISIT_ENTRIES_CORRUPTED_FILE_VALIDATION_ON() + { + CompoundFile f = null; + + try + { + f = new CompoundFile("CorruptedDoc_bug3547815.doc", CFSUpdateMode.ReadOnly, CFSConfiguration.NoValidationException); + } + catch + { + Assert.Fail("No exception has to be fired on creation due to lazy loading"); + } + + FileStream output = null; + + try + { + output = new FileStream("LogEntriesCorrupted_1.txt", FileMode.Create); + + using (TextWriter tw = new StreamWriter(output)) + { + + Action va = delegate (CFItem item) + { + tw.WriteLine(item.Name); + }; + + f.RootStorage.VisitEntries(va, true); + tw.Flush(); + } + } + catch (Exception ex) + { + Assert.IsTrue(ex is CFCorruptedFileException); + Assert.IsTrue(f != null && f.IsClosed); + + } + finally + { + if (output != null) + output.Close(); + + + + } + } + + [TestMethod] + public void Test_VISIT_ENTRIES_CORRUPTED_FILE_VALIDATION_OFF_BUT_CAN_LOAD() + { + CompoundFile f = null; + + try + { + //Corrupted file has invalid children item sid reference + f = new CompoundFile("CorruptedDoc_bug3547815_B.doc", CFSUpdateMode.ReadOnly, CFSConfiguration.NoValidationException); + } + catch + { + Assert.Fail("No exception has to be fired on creation due to lazy loading"); + } + + FileStream output = null; + + try + { + output = new FileStream("LogEntriesCorrupted_2.txt", FileMode.Create); + + + using (TextWriter tw = new StreamWriter(output)) + { + + Action va = delegate (CFItem item) + { + tw.WriteLine(item.Name); + }; + + f.RootStorage.VisitEntries(va, true); + tw.Flush(); + } + } + catch + { + Assert.Fail("Fail is corrupted but it has to be loaded anyway by test design"); + } + finally + { + if (output != null) + output.Close(); + + + } + } + + + [TestMethod] + public void Test_VISIT_STORAGE() + { + String FILENAME = "testVisiting.xls"; + + // Remove... + if (File.Exists(FILENAME)) + File.Delete(FILENAME); + + //Create... + + CompoundFile ncf = new CompoundFile(); + + CFStorage l1 = ncf.RootStorage.AddStorage("Storage Level 1"); + l1.AddStream("l1ns1"); + l1.AddStream("l1ns2"); + l1.AddStream("l1ns3"); + + CFStorage l2 = l1.AddStorage("Storage Level 2"); + l2.AddStream("l2ns1"); + l2.AddStream("l2ns2"); + + ncf.Save(FILENAME); + ncf.Close(); + + + // Read... + + CompoundFile cf = new CompoundFile(FILENAME); + + FileStream output = new FileStream("reportVisit.txt", FileMode.Create); + TextWriter sw = new StreamWriter(output); + + Console.SetOut(sw); + + Action va = delegate (CFItem target) + { + sw.WriteLine(target.Name); + }; + + cf.RootStorage.VisitEntries(va, true); + + cf.Close(); + sw.Close(); + } + + [TestMethod] + public void Test_DELETE_DIRECTORY() + { + String FILENAME = "MultipleStorage2.cfs"; + CompoundFile cf = new CompoundFile(FILENAME, CFSUpdateMode.ReadOnly, CFSConfiguration.Default); + + CFStorage st = cf.RootStorage.GetStorage("MyStorage"); + + Assert.IsNotNull(st); + + st.Delete("AnotherStorage"); + + cf.Save("MultipleStorage_Delete.cfs"); + + cf.Close(); + } + + [TestMethod] + public void Test_DELETE_MINISTREAM_STREAM() + { + String FILENAME = "MultipleStorage2.cfs"; + CompoundFile cf = new CompoundFile(FILENAME); + + CFStorage found = null; + Action action = delegate (CFItem item) { if (item.Name == "AnotherStorage") found = item as CFStorage; }; + cf.RootStorage.VisitEntries(action, true); + + Assert.IsNotNull(found); + + found.Delete("AnotherStream"); + + cf.Save("MultipleDeleteMiniStream"); + cf.Close(); + } + + [TestMethod] + public void Test_DELETE_STREAM() + { + String FILENAME = "MultipleStorage3.cfs"; + CompoundFile cf = new CompoundFile(FILENAME); + + CFStorage found = null; + Action action = delegate (CFItem item) + { + if (item.Name == "AnotherStorage") + found = item as CFStorage; + }; + + cf.RootStorage.VisitEntries(action, true); + + Assert.IsNotNull(found); + + found.Delete("Another2Stream"); + + cf.Save("MultipleDeleteStream"); + cf.Close(); + } + + [TestMethod] + public void Test_CHECK_DISPOSED_() + { + const String FILENAME = "MultipleStorage.cfs"; + CompoundFile cf = new CompoundFile(FILENAME); + + CFStorage st = cf.RootStorage.GetStorage("MyStorage"); + cf.Close(); + + try + { + byte[] temp = st.GetStream("MyStream").GetData(); + Assert.Fail("Stream without media"); + } + catch (Exception ex) + { + Assert.IsTrue(ex is CFDisposedException); + } + } + + [TestMethod] + public void Test_LAZY_LOAD_CHILDREN_() + { + CompoundFile cf = new CompoundFile(); + cf.RootStorage.AddStorage("Level_1") + .AddStorage("Level_2") + .AddStream("Level2Stream") + .SetData(Helpers.GetBuffer(100)); + + cf.Save("$Hel1"); + + cf.Close(); + + cf = new CompoundFile("$Hel1"); + IList i = cf.GetAllNamedEntries("Level2Stream"); + Assert.IsNotNull(i[0]); + Assert.IsTrue(i[0] is CFStream); + Assert.IsTrue((i[0] as CFStream).GetData().Length == 100); + cf.Save("$Hel2"); + cf.Close(); + + if (File.Exists("$Hel1")) + { + File.Delete("$Hel1"); + } + if (File.Exists("$Hel2")) + { + File.Delete("$Hel2"); + } + } + + [TestMethod] + public void Test_FIX_BUG_31() + { + CompoundFile cf = new CompoundFile(); + cf.RootStorage.AddStorage("Level_1") + + .AddStream("Level2Stream") + .SetData(Helpers.GetBuffer(100)); + + cf.Save("$Hel1"); + + cf.Close(); + + CompoundFile cf1 = new CompoundFile("$Hel1"); + try + { + CFStream cs = cf1.RootStorage.GetStorage("Level_1").AddStream("Level2Stream"); + } + catch (Exception ex) + { + Assert.IsTrue(ex.GetType() == typeof(CFDuplicatedItemException)); + } + + } + + [TestMethod] + [ExpectedException(typeof(OpenMcdf.CFCorruptedFileException))] + public void Test_CORRUPTEDDOC_BUG36_SHOULD_THROW_CORRUPTED_FILE_EXCEPTION() + { + using (CompoundFile file = new CompoundFile("CorruptedDoc_bug36.doc", CFSUpdateMode.ReadOnly, CFSConfiguration.NoValidationException) ) { + //Many thanks to theseus for bug reporting + } + } + } +} diff --git a/sources/Test/OpenMcdf.Test/CompoundFileTest.cs b/sources/Test/OpenMcdf.Test/CompoundFileTest.cs index bbe35da2..fd63af88 100644 --- a/sources/Test/OpenMcdf.Test/CompoundFileTest.cs +++ b/sources/Test/OpenMcdf.Test/CompoundFileTest.cs @@ -447,7 +447,7 @@ public void Test_FUNCTIONAL_BEHAVIOUR() Assert.IsTrue(new FileInfo("6_Streams_Shrinked.cfs").Length < new FileInfo("6_Streams.cfs").Length); cfTest = new CompoundFile("6_Streams_Shrinked.cfs"); - Action va = delegate(CFItem item) + Action va = delegate (CFItem item) { if (item.IsStream) { @@ -765,6 +765,24 @@ public void Test_FIX_BUG_28_CompoundFile_Delete_ChildElementMaintainsFiles() } } + [TestMethod] + public void Test_CORRUPTEDDOC_BUG36_SHOULD_THROW_CORRUPTED_FILE_EXCEPTION() + { + FileStream fs = null; + try + { + fs = new FileStream("CorruptedDoc_bug36.doc", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); + CompoundFile file = new CompoundFile(fs, CFSUpdateMode.ReadOnly, CFSConfiguration.LeaveOpen); + + } + catch (Exception ex) + { + Assert.IsTrue(fs.CanRead && fs.CanSeek && fs.CanWrite); + } + + + } + //[TestMethod] //public void Test_CORRUPTED_CYCLIC_DIFAT_VALIDATION_CHECK() //{ diff --git a/sources/Test/OpenMcdf.Test/Helpers.cs b/sources/Test/OpenMcdf.Test/Helpers.cs index ec83efb2..58fbfb38 100644 --- a/sources/Test/OpenMcdf.Test/Helpers.cs +++ b/sources/Test/OpenMcdf.Test/Helpers.cs @@ -1,56 +1,56 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace OpenMcdf.Test -{ - public static class Helpers - { - public static byte[] GetBuffer(int count) - { - Random r = new Random(); - byte[] b = new byte[count]; - r.NextBytes(b); - return b; - } - - public static byte[] GetBuffer(int count, byte c) - { - byte[] b = new byte[count]; - for (int i = 0; i < b.Length; i++) - { - b[i] = c; - } - - return b; - } - - public static bool CompareBuffer(byte[] b, byte[] p) - { - bool res = CompareBuffer(b, p, b.Length); - return res && (b.Length == p.Length); - } - - public static bool CompareBuffer(byte[] b, byte[] p, int count) - { - if (b == null && p == null) - throw new Exception("Null buffers"); - - if (b == null && p != null) - return false; - - if (b != null && p == null) - return false; - - - for (int i = 0; i < count; i++) - { - if (b[i] != p[i]) - return false; - } - - return true; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenMcdf.Test +{ + public static class Helpers + { + public static byte[] GetBuffer(int count) + { + Random r = new Random(); + byte[] b = new byte[count]; + r.NextBytes(b); + return b; + } + + public static byte[] GetBuffer(int count, byte c) + { + byte[] b = new byte[count]; + for (int i = 0; i < b.Length; i++) + { + b[i] = c; + } + + return b; + } + + public static bool CompareBuffer(byte[] b, byte[] p) + { + bool res = CompareBuffer(b, p, b.Length); + return res && (b.Length == p.Length); + } + + public static bool CompareBuffer(byte[] b, byte[] p, int count) + { + if (b == null && p == null) + throw new Exception("Null buffers"); + + if (b == null && p != null) + return false; + + if (b != null && p == null) + return false; + + + for (int i = 0; i < count; i++) + { + if (b[i] != p[i]) + return false; + } + + return true; + } + } +} diff --git a/sources/Test/OpenMcdf.Test/OpenMcdf.Test.csproj b/sources/Test/OpenMcdf.Test/OpenMcdf.Test.csproj index c69cd944..55b48849 100644 --- a/sources/Test/OpenMcdf.Test/OpenMcdf.Test.csproj +++ b/sources/Test/OpenMcdf.Test/OpenMcdf.Test.csproj @@ -1,120 +1,120 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {FD339266-8842-40B4-9230-F8E84FC42AC2} - Library - Properties - OpenMcdf.Test - OpenMcdf.Test - v4.0 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - - - 3.5 - - http://localhost/OpenMcdfTest/ - true - Web - true - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - true - false - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - false - - - - - - - - - - 3.5 - - - - - - - - - - - - - - - - - - - - False - Microsoft .NET Framework 4 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - False - Windows Installer 3.1 - true - - - - - {56e15d4a-8a37-4c7c-bb44-fd59aff220c1} - OpenMcdf - - - - + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {FD339266-8842-40B4-9230-F8E84FC42AC2} + Library + Properties + OpenMcdf.Test + OpenMcdf.Test + v4.0 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + 3.5 + + http://localhost/OpenMcdfTest/ + true + Web + true + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + true + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + false + + + + + + + + + + 3.5 + + + + + + + + + + + + + + + + + + + + False + Microsoft .NET Framework 4 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + False + Windows Installer 3.1 + true + + + + + {56e15d4a-8a37-4c7c-bb44-fd59aff220c1} + OpenMcdf + + + + \ No newline at end of file diff --git a/sources/Test/OpenMcdf.Test/Properties/AssemblyInfo.cs b/sources/Test/OpenMcdf.Test/Properties/AssemblyInfo.cs index e7bf1361..995ba9af 100644 --- a/sources/Test/OpenMcdf.Test/Properties/AssemblyInfo.cs +++ b/sources/Test/OpenMcdf.Test/Properties/AssemblyInfo.cs @@ -1,34 +1,34 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenMcdfTest")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("-")] -[assembly: AssemblyProduct("OpenMcdfTest")] -[assembly: AssemblyCopyright("Copyright © 2010-2011, Federico Blaseotto")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM componenets. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("7b918910-a8be-4e22-85d6-d927eae56003")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.5.1.*")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenMcdfTest")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("-")] +[assembly: AssemblyProduct("OpenMcdfTest")] +[assembly: AssemblyCopyright("Copyright © 2010-2011, Federico Blaseotto")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM componenets. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7b918910-a8be-4e22-85d6-d927eae56003")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.5.1.*")] diff --git a/sources/Test/OpenMcdf.Test/RBTreeTest.cs b/sources/Test/OpenMcdf.Test/RBTreeTest.cs index a2efef12..a6d7fc26 100644 --- a/sources/Test/OpenMcdf.Test/RBTreeTest.cs +++ b/sources/Test/OpenMcdf.Test/RBTreeTest.cs @@ -1,233 +1,233 @@ -using System; -using System.Text; -using System.Collections.Generic; -using System.Linq; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using OpenMcdf; -using RedBlackTree; - -namespace OpenMcdf.Test -{ - /// - /// Summary description for RBTreeTest - /// - [TestClass] - public class RBTreeTest - { - public RBTreeTest() - { - - } - - private TestContext testContextInstance; - - /// - ///Gets or sets the test context which provides - ///information about and functionality for the current test run. - /// - public TestContext TestContext - { - get - { - return testContextInstance; - } - set - { - testContextInstance = value; - } - } - - #region Additional test attributes - // - // You can use the following additional attributes as you write your tests: - // - // Use ClassInitialize to run code before running the first test in the class - // [ClassInitialize()] - // public static void MyClassInitialize(TestContext testContext) { } - // - // Use ClassCleanup to run code after all tests in a class have run - // [ClassCleanup()] - // public static void MyClassCleanup() { } - // - // Use TestInitialize to run code before running each test - // [TestInitialize()] - // public void MyTestInitialize() { } - // - // Use TestCleanup to run code after each test has run - // [TestCleanup()] - // public void MyTestCleanup() { } - // - #endregion - - internal IList GetDirectoryRepository(int count) - { - List repo = new List(); - for (int i = 0; i < count; i++) - { - IDirectoryEntry de = DirectoryEntry.New(i.ToString(), StgType.StgInvalid, repo); - } - - return repo; - } - - [TestMethod] - public void Test_RBTREE_INSERT() - { - RBTree rbTree = new RBTree(); - System.Collections.Generic.IList repo = GetDirectoryRepository(25); - - foreach (var item in repo) - { - rbTree.Insert(item); - } - - for (int i = 0; i < repo.Count; i++) - { - IRBNode c; - rbTree.TryLookup(DirectoryEntry.Mock(i.ToString(), StgType.StgInvalid), out c); - Assert.IsTrue(c is IDirectoryEntry); - Assert.IsTrue(((IDirectoryEntry)c).Name == i.ToString()); - //Assert.IsTrue(c.IsStream); - } - } - - - [TestMethod] - public void Test_RBTREE_DELETE() - { - RBTree rbTree = new RBTree(); - System.Collections.Generic.IList repo = GetDirectoryRepository(25); - - - foreach (var item in repo) - { - rbTree.Insert(item); - } - - try - { - IRBNode n; - rbTree.Delete(DirectoryEntry.Mock("5", StgType.StgInvalid),out n); - rbTree.Delete(DirectoryEntry.Mock("24", StgType.StgInvalid), out n); - rbTree.Delete(DirectoryEntry.Mock("7", StgType.StgInvalid), out n); - } - catch (Exception ex) - { - Assert.Fail("Item removal failed: " + ex.Message); - } - - - - // CFItem c; - // bool s = rbTree.TryLookup(new CFMock("7", StgType.StgStream), out c); - - - // Assert.IsFalse(s); - - // c = null; - - // Assert.IsTrue(rbTree.TryLookup(new CFMock("6", StgType.StgStream), out c)); - // Assert.IsTrue(c.IsStream); - // Assert.IsTrue(rbTree.TryLookup(new CFMock("12", StgType.StgStream), out c)); - // Assert.IsTrue(c.Name == "12"); - - - //} - - - } - - private static void VerifyProperties(RBTree t) - { - VerifyProperty1(t.Root); - VerifyProperty2(t.Root); - // Property 3 is implicit - VerifyProperty4(t.Root); - VerifyProperty5(t.Root); - } - - private static Color NodeColor(IRBNode n) - { - return n == null ? Color.BLACK : n.Color; - } - - private static void VerifyProperty1(IRBNode n) - { - - Assert.IsTrue(NodeColor(n) == Color.RED || NodeColor(n) == Color.BLACK); - - if (n == null) return; - VerifyProperty1(n.Left); - VerifyProperty1(n.Right); - } - - private static void VerifyProperty2(IRBNode root) - { - Assert.IsTrue(NodeColor(root) == Color.BLACK); - } - - private static void VerifyProperty4(IRBNode n) - { - - if (NodeColor(n) == Color.RED) - { - Assert.IsTrue((NodeColor(n.Left) == Color.BLACK)); - Assert.IsTrue((NodeColor(n.Right) == Color.BLACK)); - Assert.IsTrue((NodeColor(n.Parent) == Color.BLACK)); - } - - if (n == null) return; - VerifyProperty4(n.Left); - VerifyProperty4(n.Right); - } - - private static void VerifyProperty5(IRBNode root) - { - VerifyProperty5Helper(root, 0, -1); - } - - private static int VerifyProperty5Helper(IRBNode n, int blackCount, int pathBlackCount) - { - if (NodeColor(n) == Color.BLACK) - { - blackCount++; - } - if (n == null) - { - if (pathBlackCount == -1) - { - pathBlackCount = blackCount; - } - else - { - - Assert.IsTrue(blackCount == pathBlackCount); - - } - return pathBlackCount; - } - - pathBlackCount = VerifyProperty5Helper(n.Left, blackCount, pathBlackCount); - pathBlackCount = VerifyProperty5Helper(n.Right, blackCount, pathBlackCount); - - return pathBlackCount; - } - - - - [TestMethod] - public void Test_RBTREE_ENUMERATE() - { - RBTree rbTree = new RBTree(); - System.Collections.Generic.IList repo = GetDirectoryRepository(10000); - - foreach (var item in repo) - { - rbTree.Insert(item); - } - - VerifyProperties(rbTree); - //rbTree.Print(); - } - } -} +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenMcdf; +using RedBlackTree; + +namespace OpenMcdf.Test +{ + /// + /// Summary description for RBTreeTest + /// + [TestClass] + public class RBTreeTest + { + public RBTreeTest() + { + + } + + private TestContext testContextInstance; + + /// + ///Gets or sets the test context which provides + ///information about and functionality for the current test run. + /// + public TestContext TestContext + { + get + { + return testContextInstance; + } + set + { + testContextInstance = value; + } + } + + #region Additional test attributes + // + // You can use the following additional attributes as you write your tests: + // + // Use ClassInitialize to run code before running the first test in the class + // [ClassInitialize()] + // public static void MyClassInitialize(TestContext testContext) { } + // + // Use ClassCleanup to run code after all tests in a class have run + // [ClassCleanup()] + // public static void MyClassCleanup() { } + // + // Use TestInitialize to run code before running each test + // [TestInitialize()] + // public void MyTestInitialize() { } + // + // Use TestCleanup to run code after each test has run + // [TestCleanup()] + // public void MyTestCleanup() { } + // + #endregion + + internal IList GetDirectoryRepository(int count) + { + List repo = new List(); + for (int i = 0; i < count; i++) + { + IDirectoryEntry de = DirectoryEntry.New(i.ToString(), StgType.StgInvalid, repo); + } + + return repo; + } + + [TestMethod] + public void Test_RBTREE_INSERT() + { + RBTree rbTree = new RBTree(); + System.Collections.Generic.IList repo = GetDirectoryRepository(25); + + foreach (var item in repo) + { + rbTree.Insert(item); + } + + for (int i = 0; i < repo.Count; i++) + { + IRBNode c; + rbTree.TryLookup(DirectoryEntry.Mock(i.ToString(), StgType.StgInvalid), out c); + Assert.IsTrue(c is IDirectoryEntry); + Assert.IsTrue(((IDirectoryEntry)c).Name == i.ToString()); + //Assert.IsTrue(c.IsStream); + } + } + + + [TestMethod] + public void Test_RBTREE_DELETE() + { + RBTree rbTree = new RBTree(); + System.Collections.Generic.IList repo = GetDirectoryRepository(25); + + + foreach (var item in repo) + { + rbTree.Insert(item); + } + + try + { + IRBNode n; + rbTree.Delete(DirectoryEntry.Mock("5", StgType.StgInvalid),out n); + rbTree.Delete(DirectoryEntry.Mock("24", StgType.StgInvalid), out n); + rbTree.Delete(DirectoryEntry.Mock("7", StgType.StgInvalid), out n); + } + catch (Exception ex) + { + Assert.Fail("Item removal failed: " + ex.Message); + } + + + + // CFItem c; + // bool s = rbTree.TryLookup(new CFMock("7", StgType.StgStream), out c); + + + // Assert.IsFalse(s); + + // c = null; + + // Assert.IsTrue(rbTree.TryLookup(new CFMock("6", StgType.StgStream), out c)); + // Assert.IsTrue(c.IsStream); + // Assert.IsTrue(rbTree.TryLookup(new CFMock("12", StgType.StgStream), out c)); + // Assert.IsTrue(c.Name == "12"); + + + //} + + + } + + private static void VerifyProperties(RBTree t) + { + VerifyProperty1(t.Root); + VerifyProperty2(t.Root); + // Property 3 is implicit + VerifyProperty4(t.Root); + VerifyProperty5(t.Root); + } + + private static Color NodeColor(IRBNode n) + { + return n == null ? Color.BLACK : n.Color; + } + + private static void VerifyProperty1(IRBNode n) + { + + Assert.IsTrue(NodeColor(n) == Color.RED || NodeColor(n) == Color.BLACK); + + if (n == null) return; + VerifyProperty1(n.Left); + VerifyProperty1(n.Right); + } + + private static void VerifyProperty2(IRBNode root) + { + Assert.IsTrue(NodeColor(root) == Color.BLACK); + } + + private static void VerifyProperty4(IRBNode n) + { + + if (NodeColor(n) == Color.RED) + { + Assert.IsTrue((NodeColor(n.Left) == Color.BLACK)); + Assert.IsTrue((NodeColor(n.Right) == Color.BLACK)); + Assert.IsTrue((NodeColor(n.Parent) == Color.BLACK)); + } + + if (n == null) return; + VerifyProperty4(n.Left); + VerifyProperty4(n.Right); + } + + private static void VerifyProperty5(IRBNode root) + { + VerifyProperty5Helper(root, 0, -1); + } + + private static int VerifyProperty5Helper(IRBNode n, int blackCount, int pathBlackCount) + { + if (NodeColor(n) == Color.BLACK) + { + blackCount++; + } + if (n == null) + { + if (pathBlackCount == -1) + { + pathBlackCount = blackCount; + } + else + { + + Assert.IsTrue(blackCount == pathBlackCount); + + } + return pathBlackCount; + } + + pathBlackCount = VerifyProperty5Helper(n.Left, blackCount, pathBlackCount); + pathBlackCount = VerifyProperty5Helper(n.Right, blackCount, pathBlackCount); + + return pathBlackCount; + } + + + + [TestMethod] + public void Test_RBTREE_ENUMERATE() + { + RBTree rbTree = new RBTree(); + System.Collections.Generic.IList repo = GetDirectoryRepository(10000); + + foreach (var item in repo) + { + rbTree.Insert(item); + } + + VerifyProperties(rbTree); + //rbTree.Print(); + } + } +} diff --git a/sources/Test/OpenMcdf.Test/SectorCollectionTest.cs b/sources/Test/OpenMcdf.Test/SectorCollectionTest.cs index f1defed7..a64fcaca 100644 --- a/sources/Test/OpenMcdf.Test/SectorCollectionTest.cs +++ b/sources/Test/OpenMcdf.Test/SectorCollectionTest.cs @@ -1,198 +1,198 @@ -using OpenMcdf; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Collections.Generic; -using System; - -namespace OpenMcdf.Test -{ - - - /// - ///This is a test class for SectorCollectionTest and is intended - ///to contain all SectorCollectionTest Unit Tests - /// - [TestClass()] - public class SectorCollectionTest - { - - - private TestContext testContextInstance; - - /// - ///Gets or sets the test context which provides - ///information about and functionality for the current test run. - /// - public TestContext TestContext - { - get - { - return testContextInstance; - } - set - { - testContextInstance = value; - } - } - - #region Additional test attributes - // - //You can use the following additional attributes as you write your tests: - // - //Use ClassInitialize to run code before running the first test in the class - //[ClassInitialize()] - //public static void MyClassInitialize(TestContext testContext) - //{ - //} - // - //Use ClassCleanup to run code after all tests in a class have run - //[ClassCleanup()] - //public static void MyClassCleanup() - //{ - //} - // - //Use TestInitialize to run code before running each test - //[TestInitialize()] - //public void MyTestInitialize() - //{ - //} - // - //Use TestCleanup to run code after each test has run - //[TestCleanup()] - //public void MyTestCleanup() - //{ - //} - // - #endregion - - - /// - ///A test for Count - /// - [TestMethod()] - public void CountTest() - { - - int count = 0; - - SectorCollection target = new SectorCollection(); // TODO: Initialize to an appropriate value - int actual; - actual = target.Count; - - Assert.IsTrue(actual == count); - Sector s = new Sector(4096); - - target.Add(s); - Assert.IsTrue(target.Count == actual + 1); - - - for (int i = 0; i < 5000; i++) - target.Add(s); - - Assert.IsTrue(target.Count == actual + 1 + 5000); - } - - /// - ///A test for Item - /// - [TestMethod()] - public void ItemTest() - { - int count = 37; - - SectorCollection target = new SectorCollection(); - int index = 0; - - Sector expected = new Sector(4096); - target.Add(null); - - Sector actual; - target[index] = expected; - actual = target[index]; - - Assert.AreEqual(expected, actual); - Assert.IsNotNull(actual); - Assert.IsTrue(actual.Id == expected.Id); - - actual = null; - - try - { - actual = target[count + 100]; - } - catch (Exception ex) - { - Assert.IsTrue(ex is ArgumentOutOfRangeException); - } - - try - { - actual = target[-1]; - } - catch (Exception ex) - { - Assert.IsTrue(ex is ArgumentOutOfRangeException); - } - } - - /// - ///A test for SectorCollection Constructor - /// - [TestMethod()] - public void SectorCollectionConstructorTest() - { - - SectorCollection target = new SectorCollection(); - - Assert.IsNotNull(target); - Assert.IsTrue(target.Count == 0); - - Sector s = new Sector(4096); - target.Add(s); - Assert.IsTrue(target.Count == 1); - } - - /// - ///A test for Add - /// - [TestMethod()] - public void AddTest() - { - SectorCollection target = new SectorCollection(); - for (int i = 0; i < 579; i++) - { - target.Add(null); - } - - - Sector item = new Sector(4096); - target.Add(item); - Assert.IsTrue(target.Count == 580); - } - - /// - ///A test for GetEnumerator - /// - [TestMethod()] - public void GetEnumeratorTest() - { - SectorCollection target = new SectorCollection(); - for (int i = 0; i < 579; i++) - { - target.Add(null); - } - - - Sector item = new Sector(4096); - target.Add(item); - Assert.IsTrue(target.Count == 580); - - int cnt = 0; - foreach (Sector s in target) - { - cnt++; - } - - Assert.IsTrue(cnt == target.Count); - } - } -} +using OpenMcdf; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Collections.Generic; +using System; + +namespace OpenMcdf.Test +{ + + + /// + ///This is a test class for SectorCollectionTest and is intended + ///to contain all SectorCollectionTest Unit Tests + /// + [TestClass()] + public class SectorCollectionTest + { + + + private TestContext testContextInstance; + + /// + ///Gets or sets the test context which provides + ///information about and functionality for the current test run. + /// + public TestContext TestContext + { + get + { + return testContextInstance; + } + set + { + testContextInstance = value; + } + } + + #region Additional test attributes + // + //You can use the following additional attributes as you write your tests: + // + //Use ClassInitialize to run code before running the first test in the class + //[ClassInitialize()] + //public static void MyClassInitialize(TestContext testContext) + //{ + //} + // + //Use ClassCleanup to run code after all tests in a class have run + //[ClassCleanup()] + //public static void MyClassCleanup() + //{ + //} + // + //Use TestInitialize to run code before running each test + //[TestInitialize()] + //public void MyTestInitialize() + //{ + //} + // + //Use TestCleanup to run code after each test has run + //[TestCleanup()] + //public void MyTestCleanup() + //{ + //} + // + #endregion + + + /// + ///A test for Count + /// + [TestMethod()] + public void CountTest() + { + + int count = 0; + + SectorCollection target = new SectorCollection(); // TODO: Initialize to an appropriate value + int actual; + actual = target.Count; + + Assert.IsTrue(actual == count); + Sector s = new Sector(4096); + + target.Add(s); + Assert.IsTrue(target.Count == actual + 1); + + + for (int i = 0; i < 5000; i++) + target.Add(s); + + Assert.IsTrue(target.Count == actual + 1 + 5000); + } + + /// + ///A test for Item + /// + [TestMethod()] + public void ItemTest() + { + int count = 37; + + SectorCollection target = new SectorCollection(); + int index = 0; + + Sector expected = new Sector(4096); + target.Add(null); + + Sector actual; + target[index] = expected; + actual = target[index]; + + Assert.AreEqual(expected, actual); + Assert.IsNotNull(actual); + Assert.IsTrue(actual.Id == expected.Id); + + actual = null; + + try + { + actual = target[count + 100]; + } + catch (Exception ex) + { + Assert.IsTrue(ex is ArgumentOutOfRangeException); + } + + try + { + actual = target[-1]; + } + catch (Exception ex) + { + Assert.IsTrue(ex is ArgumentOutOfRangeException); + } + } + + /// + ///A test for SectorCollection Constructor + /// + [TestMethod()] + public void SectorCollectionConstructorTest() + { + + SectorCollection target = new SectorCollection(); + + Assert.IsNotNull(target); + Assert.IsTrue(target.Count == 0); + + Sector s = new Sector(4096); + target.Add(s); + Assert.IsTrue(target.Count == 1); + } + + /// + ///A test for Add + /// + [TestMethod()] + public void AddTest() + { + SectorCollection target = new SectorCollection(); + for (int i = 0; i < 579; i++) + { + target.Add(null); + } + + + Sector item = new Sector(4096); + target.Add(item); + Assert.IsTrue(target.Count == 580); + } + + /// + ///A test for GetEnumerator + /// + [TestMethod()] + public void GetEnumeratorTest() + { + SectorCollection target = new SectorCollection(); + for (int i = 0; i < 579; i++) + { + target.Add(null); + } + + + Sector item = new Sector(4096); + target.Add(item); + Assert.IsTrue(target.Count == 580); + + int cnt = 0; + foreach (Sector s in target) + { + cnt++; + } + + Assert.IsTrue(cnt == target.Count); + } + } +} diff --git a/sources/Test/OpenMcdf.Test/StreamRWTest.cs b/sources/Test/OpenMcdf.Test/StreamRWTest.cs index c8555a60..6d3ac7b2 100644 --- a/sources/Test/OpenMcdf.Test/StreamRWTest.cs +++ b/sources/Test/OpenMcdf.Test/StreamRWTest.cs @@ -1,52 +1,52 @@ -using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.IO; - -namespace OpenMcdf.Test -{ - [TestClass] - public class StreamRWTest - { - [TestMethod] - public void ReadInt64_MaxSizeRead() - { - Int64 input = Int64.MaxValue; - byte[] bytes = BitConverter.GetBytes(input); - long actual = 0; - using (MemoryStream memStream = new MemoryStream(bytes)) - { - OpenMcdf.StreamRW reader = new OpenMcdf.StreamRW(memStream); - actual = reader.ReadInt64(); - } - Assert.AreEqual((long)input, actual); - } - - [TestMethod] - public void ReadInt64_SmallNumber() - { - Int64 input = 1234; - byte[] bytes = BitConverter.GetBytes(input); - long actual = 0; - using (MemoryStream memStream = new MemoryStream(bytes)) - { - OpenMcdf.StreamRW reader = new OpenMcdf.StreamRW(memStream); - actual = reader.ReadInt64(); - } - Assert.AreEqual((long)input, actual); - } - - [TestMethod] - public void ReadInt64_Int32MaxPlusTen() - { - Int64 input = (Int64)Int32.MaxValue + 10; - byte[] bytes = BitConverter.GetBytes(input); - long actual = 0; - using (MemoryStream memStream = new MemoryStream(bytes)) - { - OpenMcdf.StreamRW reader = new OpenMcdf.StreamRW(memStream); - actual = reader.ReadInt64(); - } - Assert.AreEqual((long)input, actual); - } - } -} +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.IO; + +namespace OpenMcdf.Test +{ + [TestClass] + public class StreamRWTest + { + [TestMethod] + public void ReadInt64_MaxSizeRead() + { + Int64 input = Int64.MaxValue; + byte[] bytes = BitConverter.GetBytes(input); + long actual = 0; + using (MemoryStream memStream = new MemoryStream(bytes)) + { + OpenMcdf.StreamRW reader = new OpenMcdf.StreamRW(memStream); + actual = reader.ReadInt64(); + } + Assert.AreEqual((long)input, actual); + } + + [TestMethod] + public void ReadInt64_SmallNumber() + { + Int64 input = 1234; + byte[] bytes = BitConverter.GetBytes(input); + long actual = 0; + using (MemoryStream memStream = new MemoryStream(bytes)) + { + OpenMcdf.StreamRW reader = new OpenMcdf.StreamRW(memStream); + actual = reader.ReadInt64(); + } + Assert.AreEqual((long)input, actual); + } + + [TestMethod] + public void ReadInt64_Int32MaxPlusTen() + { + Int64 input = (Int64)Int32.MaxValue + 10; + byte[] bytes = BitConverter.GetBytes(input); + long actual = 0; + using (MemoryStream memStream = new MemoryStream(bytes)) + { + OpenMcdf.StreamRW reader = new OpenMcdf.StreamRW(memStream); + actual = reader.ReadInt64(); + } + Assert.AreEqual((long)input, actual); + } + } +} diff --git a/sources/Test/TestFiles/BUG_16_.xls b/sources/Test/TestFiles/BUG_16_.xls index 0c606904c9d388d5f6bf3309944d1a205c5a21c0..be2553a7c187d0d4c94de4ab33f56ec542fdb5b7 100644 GIT binary patch delta 22 dcmZqp!r1VIaYGIZJ43#DPIvgF&BZLer2uGf2=o8| delta 22 ecmZqp!r1VIaYGIZyTLvdw)02NZ!Tu(Ed>B>F$tLf From 2b97cfa32fb847567e81a842eb8236d7d6a41b20 Mon Sep 17 00:00:00 2001 From: Federico Date: Fri, 30 Dec 2016 16:01:58 +0100 Subject: [PATCH 18/18] v2.1.0.33051 - bug fixing --- .gitignore | 25 ++ .../Properties/Resources.Designer.cs | 256 ++++++++-------- .../Properties/Resources.resx | 279 +++++++++--------- .../StructuredStorageExplorer.csproj | 1 - 4 files changed, 286 insertions(+), 275 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a9cd27ca --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +################################################################################ +# This .gitignore file was automatically created by Microsoft(R) Visual Studio. +################################################################################ + +/.vs/OpenMcdf/v14 +/bin/Debug +/sources/OpenMcdf/obj/Debug +/Performance Test/obj/Debug +/OpenMcdfExtensionsTest/obj/Debug +/OpenMcdf.Extensions/obj/Debug +/Memory Test/obj/Debug +/sources/OpenMcdf.Extensions/obj/Debug +/sources/Structured Storage Explorer/obj/Debug +/Unit Test/obj/Debug +/TestResults +/Structured Storage Explorer/obj/Debug +/src/obj/Debug +/sources/Test/OpenMcdf.Test/obj/Debug +/sources/Test/OpenMcdf.Test/bin/Debug +/sources/Test/OpenMcdf.PerfTest/obj/Debug +/sources/Test/OpenMcdf.PerfTest/bin/Debug +/sources/Test/OpenMcdf.MemTest/obj/Debug +/sources/Test/OpenMcdf.MemTest/bin/Debug +/sources/Test/OpenMcdf.Extensions.Test/obj/Debug +/sources/Test/OpenMcdf.Extensions.Test/bin/Debug diff --git a/sources/Structured Storage Explorer/Properties/Resources.Designer.cs b/sources/Structured Storage Explorer/Properties/Resources.Designer.cs index dd55a353..fe5e034f 100644 --- a/sources/Structured Storage Explorer/Properties/Resources.Designer.cs +++ b/sources/Structured Storage Explorer/Properties/Resources.Designer.cs @@ -1,133 +1,123 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace StructuredStorageExplorer.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("StructuredStorageExplorer.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap disk { - get { - object obj = ResourceManager.GetObject("disk", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap door_out { - get { - object obj = ResourceManager.GetObject("door_out", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap folder { - get { - object obj = ResourceManager.GetObject("folder", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap oleprops { - get { - object obj = ResourceManager.GetObject("oleprops", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap page_white { - get { - object obj = ResourceManager.GetObject("page_white", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap storage { - get { - object obj = ResourceManager.GetObject("storage", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap stream { - get { - object obj = ResourceManager.GetObject("stream", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace StructuredStorageExplorer.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("StructuredStorageExplorer.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap disk { + get { + object obj = ResourceManager.GetObject("disk", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap door_out { + get { + object obj = ResourceManager.GetObject("door_out", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap folder { + get { + object obj = ResourceManager.GetObject("folder", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap page_white { + get { + object obj = ResourceManager.GetObject("page_white", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap storage { + get { + object obj = ResourceManager.GetObject("storage", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap stream { + get { + object obj = ResourceManager.GetObject("stream", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/sources/Structured Storage Explorer/Properties/Resources.resx b/sources/Structured Storage Explorer/Properties/Resources.resx index df7f48ea..4dccc070 100644 --- a/sources/Structured Storage Explorer/Properties/Resources.resx +++ b/sources/Structured Storage Explorer/Properties/Resources.resx @@ -1,142 +1,139 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - ..\img\disk.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\img\door_out.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\img\folder.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\img\application_view_detail.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\img\page_white.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\img\storage.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\img\stream.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\img\disk.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\img\door_out.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\img\folder.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\img\page_white.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\img\storage.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\img\stream.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/sources/Structured Storage Explorer/StructuredStorageExplorer.csproj b/sources/Structured Storage Explorer/StructuredStorageExplorer.csproj index 43ce1295..92afc911 100644 --- a/sources/Structured Storage Explorer/StructuredStorageExplorer.csproj +++ b/sources/Structured Storage Explorer/StructuredStorageExplorer.csproj @@ -110,7 +110,6 @@ -