Browse Source

移除过时的API

懒得勤快 2 năm trước cách đây
mục cha
commit
1ddaf1f08f
100 tập tin đã thay đổi với 2241 bổ sung2859 xóa
  1. 2117 2117
      Masuit.Tools.Abstractions/Files/FileDetector/AbstractCompoundFileDetailDetector.cs
  2. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/AbstractFullRegexDetector.cs
  3. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/AbstractISOBaseMediaFileDetailDetector.cs
  4. 2 2
      Masuit.Tools.Abstractions/Files/FileDetector/AbstractRegexSignatureDetector.cs
  5. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/AbstractSignatureDetector.cs
  6. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/AbstractZipDetailDetector.cs
  7. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/ApkDetector.cs
  8. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/AudioVideoInterleaveDetector.cs
  9. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/BashShellScriptDetector.cs
  10. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/BinaryPropertyListDetector.cs
  11. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/BitmapDetector.cs
  12. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/Bzip2Detector.cs
  13. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/CabDetector.cs
  14. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/CertDetector.cs
  15. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/CompoundHWPDetector.cs
  16. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/ConfigurationDetector.cs
  17. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/CursorDetector.cs
  18. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/DLLDetector.cs
  19. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/DMGDetector.cs
  20. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/DOCXDetector.cs
  21. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/DirectDrawSurfaceFormatDetector.cs
  22. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/EXEDetector.cs
  23. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/EpubDetector.cs
  24. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/FLVDetector.cs
  25. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/FlacDetector.cs
  26. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/GifDetector.cs
  27. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/GzDetector.cs
  28. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/HWPDetector.cs
  29. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/ISODetector.cs
  30. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/IconDetector.cs
  31. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/InitializationDetector.cs
  32. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/JavaClassDetector.cs
  33. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/Jpeg2000Detector.cs
  34. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/JpegDetector.cs
  35. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/JpegXRDetector.cs
  36. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/KTXDetector.cs
  37. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/LzhDetector.cs
  38. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/M4ADetector.cs
  39. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/M4VDetector.cs
  40. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/MP3Detector.cs
  41. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/MP4Detector.cs
  42. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/MicrosoftExcelXLSDetector.cs
  43. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/MicrosoftInstallerDetector.cs
  44. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/MicrosoftPowerPointPPTDetector.cs
  45. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/MicrosoftWordDocDetector.cs
  46. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/MidiDetector.cs
  47. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/MikeOBrienPackDetector.cs
  48. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/OggDetector.cs
  49. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/OpenDocumentFormulaDetector.cs
  50. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/OpenDocumentGraphicsDetector.cs
  51. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/OpenDocumentPresentationDetector.cs
  52. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/OpenDocumentSpreadSheetDetector.cs
  53. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/OpenDocumentTextDetector.cs
  54. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PAKArchiveDetector.cs
  55. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PDBDetector.cs
  56. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PFXDetector.cs
  57. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PKMDetector.cs
  58. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PPSXDetector.cs
  59. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PPTXDetector.cs
  60. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PdfDetector.cs
  61. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PngDetector.cs
  62. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PrePOSIXtarDetector.cs
  63. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PsdDetector.cs
  64. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/QuakeArchiveDetector.cs
  65. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/QuickTimeDetector.cs
  66. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/REGDetector.cs
  67. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/RarDetector.cs
  68. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/RedhatPackageManagerPackageDetector.cs
  69. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/RichTextFormatDetector.cs
  70. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/SQLiteDetector.cs
  71. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/SRTDetector.cs
  72. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/ShockwaveFlashDetector.cs
  73. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/TextDetector.cs
  74. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/TgaDetector.cs
  75. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/ThumbsDBDetector.cs
  76. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/TiffDetector.cs
  77. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/UStarFormatTarDetector.cs
  78. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/VisualStudioSolutionDetector.cs
  79. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/WaveDetector.cs
  80. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/WebMDetector.cs
  81. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/WebPDetector.cs
  82. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/WindowsMemoryDumpDetector.cs
  83. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/WindowsShortcutDetector.cs
  84. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/XLSXDetector.cs
  85. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/XMLDetector.cs
  86. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/XarDetector.cs
  87. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/ZDetector.cs
  88. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/ZipDetector.cs
  89. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/_3GPDetector.cs
  90. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/Detectors/_7zDetector.cs
  91. 1 1
      Masuit.Tools.Abstractions/Files/FileDetector/InstantDetector.cs
  92. 4 2
      Masuit.Tools.Abstractions/Mime/ContentType.cs
  93. 16 16
      Masuit.Tools.Abstractions/Mime/DefaultMimeItems.cs
  94. 2 2
      Masuit.Tools.Abstractions/Mime/IMimeMapper.cs
  95. 4 4
      Masuit.Tools.Abstractions/Mime/MimeMapper.cs
  96. 3 3
      Masuit.Tools.Abstractions/Mime/MimeMappingItem.cs
  97. 0 604
      Masuit.Tools.Abstractions/Net/FtpClient.cs
  98. 3 2
      Masuit.Tools.AspNetCore/AspNetCore/Extensions/ControllerExtensions.cs
  99. 1 0
      Masuit.Tools.AspNetCore/Masuit.Tools.AspNetCore.csproj
  100. 0 18
      Masuit.Tools.Net45/Masuit.Tools.Net45.csproj

+ 2117 - 2117
Masuit.Tools.Abstractions/Files/FileDetector/AbstractCompoundFileDetailDetector.cs

@@ -1,331 +1,331 @@
-using Masuit.Tools.AspNetCore.Mime;
-using System;
+using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector;
 
 public abstract class AbstractCompoundFileDetailDetector : AbstractSignatureDetector
 {
-	private static readonly SignatureInformation[] CfSignatureInfo = {
-		new() { Position = 0, Signature = new byte [] { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 } },
-	};
-
-	/// <inheritdoc />
-	protected override SignatureInformation[] SignatureInformations => CfSignatureInfo;
-
-	public abstract IEnumerable<string> Chunks { get; }
-
-	public override string MimeType => new MimeMapper().GetMimeFromExtension("." + Extension);
-
-	public override List<FormatCategory> FormatCategories => GetType().GetCustomAttributes<FormatCategoryAttribute>().Select(a => a.Category).ToList();
-
-	protected abstract bool IsValidChunk(string chunkName, byte[] chunkData);
-
-	public override bool Detect(Stream stream)
-	{
-		if (!base.Detect(stream))
-		{
-			return false;
-		}
-
-		stream.Position = 0;
-		try
-		{
-			using var cf = new CompoundFile(stream, CFSConfiguration.LeaveOpen | CFSConfiguration.Default);
-			foreach (var chunk in Chunks)
-			{
-				var compoundFileStream = cf.RootStorage.GetStream(chunk);
-				if (compoundFileStream == null || !IsValidChunk(chunk, compoundFileStream.GetData()))
-				{
-					return false;
-				}
-			}
-
-			return true;
-		}
-		catch
-		{
-			return false;
-		}
-	}
-
-	#region Modified OpenMCDF
-
-	// -------------------------------------------------------------
-	// 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.                        |
-	// -------------------------------------------------------------
-	internal enum Color
-	{ RED = 0, BLACK = 1 }
-
-	internal enum NodeOp
-	{
-		LAssigned, RAssigned, CAssigned, PAssigned, VAssigned
-	}
-
-	internal interface IRBNode : IComparable
-	{
-		IRBNode Left { get; set; }
-
-		IRBNode Right { get; set; }
-
-		Color Color { get; set; }
-
-		IRBNode Parent { get; set; }
-
-		IRBNode Grandparent();
-
-		IRBNode Sibling();
-
-		IRBNode Uncle();
-	}
-
-	internal sealed class RBTree
-	{
-		public IRBNode Root { get; set; }
-
-		private static Color NodeColor(IRBNode n) => n == null ? Color.BLACK : n.Color;
-
-		public RBTree()
-		{ }
-
-		public RBTree(IRBNode root)
-		{ Root = root; }
-
-		private IRBNode Lookup(IRBNode template)
-		{
-			IRBNode n = Root;
-			while (n != null)
-			{
-				int compResult = template.CompareTo(n);
-				if (compResult == 0) return n;
-				n = compResult < 0 ? n.Left : n.Right;
-			}
-			return n;
-		}
-
-		public bool TryLookup(IRBNode template, out IRBNode val)
-		{
-			val = Lookup(template);
-			return val != null;
-		}
-
-		private void Replace(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 RotateL(IRBNode n)
-		{
-			IRBNode r = n.Right;
-			Replace(n, r);
-			n.Right = r.Left;
-			if (r.Left != null) r.Left.Parent = n;
-			r.Left = n;
-			n.Parent = r;
-		}
-
-		private void RotateR(IRBNode n)
-		{
-			IRBNode l = n.Left;
-			Replace(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 Exception($"RBNode {newNode} already present in tree");
-					if (compResult < 0)
-					{
-						if (n.Left == null)
-						{
-							n.Left = insertedNode;
-							break;
-						}
-
-						n = n.Left;
-					}
-					else
-					{
-						if (n.Right == null)
-						{
-							n.Right = insertedNode;
-							break;
-						}
-						n = n.Right;
-					}
-				}
-				insertedNode.Parent = n;
-			}
-
-			Insert1(insertedNode);
-			NodeInserted?.Invoke(insertedNode);
-		}
-
-		private void Insert1(IRBNode n)
-		{
-			if (n.Parent == null) n.Color = Color.BLACK;
-			else Insert2(n);
-		}
-
-		private void Insert2(IRBNode n)
-		{
-			if (NodeColor(n.Parent) == Color.BLACK) return;
-			Insert3(n);
-		}
-
-		private void Insert3(IRBNode n)
-		{
-			if (NodeColor(n.Uncle()) == Color.RED)
-			{
-				n.Parent.Color = Color.BLACK;
-				n.Uncle().Color = Color.BLACK;
-				n.Grandparent().Color = Color.RED;
-				Insert1(n.Grandparent());
-			}
-			else Insert4(n);
-		}
-
-		private void Insert4(IRBNode n)
-		{
-			if (n == n.Parent.Right && n.Parent == n.Grandparent().Left)
-			{
-				RotateL(n.Parent);
-				n = n.Left;
-			}
-			else if (n == n.Parent.Left && n.Parent == n.Grandparent().Right)
-			{
-				RotateR(n.Parent);
-				n = n.Right;
-			}
-			Insert5(n);
-		}
-
-		private void Insert5(IRBNode n)
-		{
-			n.Parent.Color = Color.BLACK;
-			n.Grandparent().Color = Color.RED;
-			if (n == n.Parent.Left && n.Parent == n.Grandparent().Left)
-				RotateR(n.Grandparent());
-			else RotateL(n.Grandparent());
-		}
-
-		private static IRBNode MaximumNode(IRBNode n)
-		{
-			while (n.Right != null)
-				n = n.Right;
-			return n;
-		}
-
-		public void VisitTree(Action<IRBNode> action)
-		{
-			IRBNode walker = Root;
-			if (walker != null)
-				DoVisitTree(action, walker);
-		}
-
-		private void DoVisitTree(Action<IRBNode> action, IRBNode walker)
-		{
-			if (walker.Left != null)
-			{
-				DoVisitTree(action, walker.Left);
-			}
-
-			action?.Invoke(walker);
-			if (walker.Right != null)
-			{
-				DoVisitTree(action, walker.Right);
-			}
-		}
-
-		internal void VisitTreeNodes(Action<IRBNode> action)
-		{
-			IRBNode walker = Root;
-			if (walker != null)
-			{
-				DoVisitTreeNodes(action, walker);
-			}
-		}
-
-		private void DoVisitTreeNodes(Action<IRBNode> action, IRBNode walker)
-		{
-			if (walker.Left != null)
-			{
-				DoVisitTreeNodes(action, walker.Left);
-			}
-
-			action?.Invoke(walker);
-			if (walker.Right != null)
-			{
-				DoVisitTreeNodes(action, walker.Right);
-			}
-		}
-
-		public class RBTreeEnumerator : IEnumerator<IRBNode>
-		{
-			private int position = -1;
-			private Queue<IRBNode> heap = new();
-
-			internal RBTreeEnumerator(RBTree tree)
-			{ tree.VisitTreeNodes(item => heap.Enqueue(item)); }
-
-			public IRBNode Current => heap.ElementAt(position);
-
-			public void Dispose()
-			{ }
-
-			object System.Collections.IEnumerator.Current => heap.ElementAt(position);
-
-			public bool MoveNext() => (++position < heap.Count);
-
-			public void Reset()
-			{ position = -1; }
-		}
-
-		public RBTreeEnumerator GetEnumerator() => new RBTreeEnumerator(this);
-
-		internal void FireNodeOperation(IRBNode node, NodeOp operation)
-		{
-			NodeOperation?.Invoke(node, operation);
-		}
-
-		internal event Action<IRBNode> NodeInserted;
-
-		internal event Action<IRBNode, NodeOp> NodeOperation;
-	}
-
-	/* This Source Code Form is subject to the terms of the Mozilla Public
+    private static readonly SignatureInformation[] CfSignatureInfo = {
+        new() { Position = 0, Signature = new byte [] { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 } },
+    };
+
+    /// <inheritdoc />
+    protected override SignatureInformation[] SignatureInformations => CfSignatureInfo;
+
+    public abstract IEnumerable<string> Chunks { get; }
+
+    public override string MimeType => new MimeMapper().GetMimeFromExtension("." + Extension);
+
+    public override List<FormatCategory> FormatCategories => GetType().GetCustomAttributes<FormatCategoryAttribute>().Select(a => a.Category).ToList();
+
+    protected abstract bool IsValidChunk(string chunkName, byte[] chunkData);
+
+    public override bool Detect(Stream stream)
+    {
+        if (!base.Detect(stream))
+        {
+            return false;
+        }
+
+        stream.Position = 0;
+        try
+        {
+            using var cf = new CompoundFile(stream, CFSConfiguration.LeaveOpen | CFSConfiguration.Default);
+            foreach (var chunk in Chunks)
+            {
+                var compoundFileStream = cf.RootStorage.GetStream(chunk);
+                if (compoundFileStream == null || !IsValidChunk(chunk, compoundFileStream.GetData()))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+        catch
+        {
+            return false;
+        }
+    }
+
+    #region Modified OpenMCDF
+
+    // -------------------------------------------------------------
+    // 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.                        |
+    // -------------------------------------------------------------
+    internal enum Color
+    { RED = 0, BLACK = 1 }
+
+    internal enum NodeOp
+    {
+        LAssigned, RAssigned, CAssigned, PAssigned, VAssigned
+    }
+
+    internal interface IRBNode : IComparable
+    {
+        IRBNode Left { get; set; }
+
+        IRBNode Right { get; set; }
+
+        Color Color { get; set; }
+
+        IRBNode Parent { get; set; }
+
+        IRBNode Grandparent();
+
+        IRBNode Sibling();
+
+        IRBNode Uncle();
+    }
+
+    internal sealed class RBTree
+    {
+        public IRBNode Root { get; set; }
+
+        private static Color NodeColor(IRBNode n) => n == null ? Color.BLACK : n.Color;
+
+        public RBTree()
+        { }
+
+        public RBTree(IRBNode root)
+        { Root = root; }
+
+        private IRBNode Lookup(IRBNode template)
+        {
+            IRBNode n = Root;
+            while (n != null)
+            {
+                int compResult = template.CompareTo(n);
+                if (compResult == 0) return n;
+                n = compResult < 0 ? n.Left : n.Right;
+            }
+            return n;
+        }
+
+        public bool TryLookup(IRBNode template, out IRBNode val)
+        {
+            val = Lookup(template);
+            return val != null;
+        }
+
+        private void Replace(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 RotateL(IRBNode n)
+        {
+            IRBNode r = n.Right;
+            Replace(n, r);
+            n.Right = r.Left;
+            if (r.Left != null) r.Left.Parent = n;
+            r.Left = n;
+            n.Parent = r;
+        }
+
+        private void RotateR(IRBNode n)
+        {
+            IRBNode l = n.Left;
+            Replace(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 Exception($"RBNode {newNode} already present in tree");
+                    if (compResult < 0)
+                    {
+                        if (n.Left == null)
+                        {
+                            n.Left = insertedNode;
+                            break;
+                        }
+
+                        n = n.Left;
+                    }
+                    else
+                    {
+                        if (n.Right == null)
+                        {
+                            n.Right = insertedNode;
+                            break;
+                        }
+                        n = n.Right;
+                    }
+                }
+                insertedNode.Parent = n;
+            }
+
+            Insert1(insertedNode);
+            NodeInserted?.Invoke(insertedNode);
+        }
+
+        private void Insert1(IRBNode n)
+        {
+            if (n.Parent == null) n.Color = Color.BLACK;
+            else Insert2(n);
+        }
+
+        private void Insert2(IRBNode n)
+        {
+            if (NodeColor(n.Parent) == Color.BLACK) return;
+            Insert3(n);
+        }
+
+        private void Insert3(IRBNode n)
+        {
+            if (NodeColor(n.Uncle()) == Color.RED)
+            {
+                n.Parent.Color = Color.BLACK;
+                n.Uncle().Color = Color.BLACK;
+                n.Grandparent().Color = Color.RED;
+                Insert1(n.Grandparent());
+            }
+            else Insert4(n);
+        }
+
+        private void Insert4(IRBNode n)
+        {
+            if (n == n.Parent.Right && n.Parent == n.Grandparent().Left)
+            {
+                RotateL(n.Parent);
+                n = n.Left;
+            }
+            else if (n == n.Parent.Left && n.Parent == n.Grandparent().Right)
+            {
+                RotateR(n.Parent);
+                n = n.Right;
+            }
+            Insert5(n);
+        }
+
+        private void Insert5(IRBNode n)
+        {
+            n.Parent.Color = Color.BLACK;
+            n.Grandparent().Color = Color.RED;
+            if (n == n.Parent.Left && n.Parent == n.Grandparent().Left)
+                RotateR(n.Grandparent());
+            else RotateL(n.Grandparent());
+        }
+
+        private static IRBNode MaximumNode(IRBNode n)
+        {
+            while (n.Right != null)
+                n = n.Right;
+            return n;
+        }
+
+        public void VisitTree(Action<IRBNode> action)
+        {
+            IRBNode walker = Root;
+            if (walker != null)
+                DoVisitTree(action, walker);
+        }
+
+        private void DoVisitTree(Action<IRBNode> action, IRBNode walker)
+        {
+            if (walker.Left != null)
+            {
+                DoVisitTree(action, walker.Left);
+            }
+
+            action?.Invoke(walker);
+            if (walker.Right != null)
+            {
+                DoVisitTree(action, walker.Right);
+            }
+        }
+
+        internal void VisitTreeNodes(Action<IRBNode> action)
+        {
+            IRBNode walker = Root;
+            if (walker != null)
+            {
+                DoVisitTreeNodes(action, walker);
+            }
+        }
+
+        private void DoVisitTreeNodes(Action<IRBNode> action, IRBNode walker)
+        {
+            if (walker.Left != null)
+            {
+                DoVisitTreeNodes(action, walker.Left);
+            }
+
+            action?.Invoke(walker);
+            if (walker.Right != null)
+            {
+                DoVisitTreeNodes(action, walker.Right);
+            }
+        }
+
+        public class RBTreeEnumerator : IEnumerator<IRBNode>
+        {
+            private int position = -1;
+            private Queue<IRBNode> heap = new();
+
+            internal RBTreeEnumerator(RBTree tree)
+            { tree.VisitTreeNodes(item => heap.Enqueue(item)); }
+
+            public IRBNode Current => heap.ElementAt(position);
+
+            public void Dispose()
+            { }
+
+            object System.Collections.IEnumerator.Current => heap.ElementAt(position);
+
+            public bool MoveNext() => (++position < heap.Count);
+
+            public void Reset()
+            { position = -1; }
+        }
+
+        public RBTreeEnumerator GetEnumerator() => new RBTreeEnumerator(this);
+
+        internal void FireNodeOperation(IRBNode node, NodeOp operation)
+        {
+            NodeOperation?.Invoke(node, operation);
+        }
+
+        internal event Action<IRBNode> NodeInserted;
+
+        internal event Action<IRBNode, NodeOp> NodeOperation;
+    }
+
+    /* 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/.
      *
@@ -333,1837 +333,1837 @@ public abstract class AbstractCompoundFileDetailDetector : AbstractSignatureDete
      *
      * The Initial Developer of the Original Code is Federico Blaseotto.*/
 
-	internal enum SectorType
-	{
-		Normal, Mini, FAT, DIFAT, RangeLockSector, Directory
-	}
-
-	internal sealed class Sector : IDisposable
-	{
-		public static int MinisectorSize = 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);
-
-		public bool DirtyFlag { get; set; }
-
-		public bool IsStreamed => _stream != null && Size != MinisectorSize && Id * Size + Size < _stream.Length;
-
-		private readonly 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;
-		}
-
-		internal SectorType Type { get; set; }
-
-		public int Id { get; set; } = -1;
-
-		public int Size { get; private set; } = 0;
-
-		private byte[] _data;
-
-		public byte[] GetData()
-		{
-			if (_data == null)
-			{
-				_data = new byte[Size];
-
-				if (IsStreamed)
-				{
-					_stream.Seek(Size + Id * Size, SeekOrigin.Begin);
-					_stream.Read(_data, 0, Size);
-				}
-			}
-
-			return _data;
-		}
-
-		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 readonly object _lockObject = new Object();
-
-		#region IDisposable Members
-
-		private bool _disposed;
-
-		void IDisposable.Dispose()
-		{
-			try
-			{
-				if (!_disposed)
-				{
-					lock (_lockObject)
-					{
-						this._data = null;
-						this.DirtyFlag = false;
-						this.Id = Sector.Endofchain;
-						this.Size = 0;
-					}
-				}
-			}
-			finally { _disposed = true; }
-			GC.SuppressFinalize(this);
-		}
+    internal enum SectorType
+    {
+        Normal, Mini, FAT, DIFAT, RangeLockSector, Directory
+    }
+
+    internal sealed class Sector : IDisposable
+    {
+        public static int MinisectorSize = 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);
+
+        public bool DirtyFlag { get; set; }
+
+        public bool IsStreamed => _stream != null && Size != MinisectorSize && Id * Size + Size < _stream.Length;
+
+        private readonly 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;
+        }
+
+        internal SectorType Type { get; set; }
+
+        public int Id { get; set; } = -1;
+
+        public int Size { get; private set; } = 0;
+
+        private byte[] _data;
+
+        public byte[] GetData()
+        {
+            if (_data == null)
+            {
+                _data = new byte[Size];
+
+                if (IsStreamed)
+                {
+                    _stream.Seek(Size + Id * Size, SeekOrigin.Begin);
+                    _stream.Read(_data, 0, Size);
+                }
+            }
+
+            return _data;
+        }
+
+        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 readonly object _lockObject = new Object();
+
+        #region IDisposable Members
+
+        private bool _disposed;
+
+        void IDisposable.Dispose()
+        {
+            try
+            {
+                if (!_disposed)
+                {
+                    lock (_lockObject)
+                    {
+                        this._data = null;
+                        this.DirtyFlag = false;
+                        this.Id = Sector.Endofchain;
+                        this.Size = 0;
+                    }
+                }
+            }
+            finally { _disposed = true; }
+            GC.SuppressFinalize(this);
+        }
 
-		#endregion IDisposable Members
-	}
+        #endregion IDisposable Members
+    }
 
-	internal enum StgType : int
-	{
-		StgInvalid = 0,
-		StgStorage = 1,
-		StgStream = 2,
-		StgLockbytes = 3,
-		StgProperty = 4,
-		StgRoot = 5
-	}
+    internal enum StgType : int
+    {
+        StgInvalid = 0,
+        StgStorage = 1,
+        StgStream = 2,
+        StgLockbytes = 3,
+        StgProperty = 4,
+        StgRoot = 5
+    }
 
-	internal sealed class DirectoryEntry : IRBNode
-	{
-		internal const int THIS_IS_GREATER = 1;
-		internal const int OTHER_IS_GREATER = -1;
-		private IList<DirectoryEntry> dirRepository;
+    internal sealed class DirectoryEntry : IRBNode
+    {
+        internal const int THIS_IS_GREATER = 1;
+        internal const int OTHER_IS_GREATER = -1;
+        private IList<DirectoryEntry> dirRepository;
 
-		public int SID { get; set; } = -1;
+        public int SID { get; set; } = -1;
 
-		internal const Int32 NOSTREAM = unchecked((int)0xFFFFFFFF);
+        internal const Int32 NOSTREAM = unchecked((int)0xFFFFFFFF);
 
-		private DirectoryEntry(String name, StgType stgType, IList<DirectoryEntry> dirRepository)
-		{
-			this.dirRepository = dirRepository;
+        private DirectoryEntry(String name, StgType stgType, IList<DirectoryEntry> dirRepository)
+        {
+            this.dirRepository = dirRepository;
 
-			this.StgType = stgType;
+            this.StgType = stgType;
 
-			switch (stgType)
-			{
-				case StgType.StgStream:
+            switch (stgType)
+            {
+                case StgType.StgStream:
 
-					StorageCLSID = new Guid(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
-					CreationDate = new byte[8];
-					ModifyDate = new byte[8];
-					break;
+                    StorageCLSID = new Guid(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                    CreationDate = new byte[8];
+                    ModifyDate = new byte[8];
+                    break;
 
-				case StgType.StgStorage:
-					CreationDate = BitConverter.GetBytes((DateTime.Now.ToFileTime()));
-					break;
-
-				case StgType.StgRoot:
-					CreationDate = new byte[8];
-					ModifyDate = new byte[8];
-					break;
-			}
+                case StgType.StgStorage:
+                    CreationDate = BitConverter.GetBytes((DateTime.Now.ToFileTime()));
+                    break;
+
+                case StgType.StgRoot:
+                    CreationDate = new byte[8];
+                    ModifyDate = new byte[8];
+                    break;
+            }
 
-			this.SetEntryName(name);
-		}
+            this.SetEntryName(name);
+        }
 
-		public byte[] EntryName { get; private set; } = new byte[64];
+        public byte[] EntryName { get; private set; } = new byte[64];
 
-		public String GetEntryName()
-		{
-			if (EntryName != null && EntryName.Length > 0)
-				return Encoding.Unicode.GetString(EntryName).Remove((NameLength - 1) / 2);
-			else return String.Empty;
-		}
+        public String GetEntryName()
+        {
+            if (EntryName != null && EntryName.Length > 0)
+                return Encoding.Unicode.GetString(EntryName).Remove((NameLength - 1) / 2);
+            else return String.Empty;
+        }
 
-		public void SetEntryName(String entryName)
-		{
-			if (entryName.Contains(@"\") || entryName.Contains(@"/") ||
-				entryName.Contains(@":") || entryName.Contains(@"!"))
-				throw new Exception("Invalid character in entry: the characters '\\', '/', ':','!' cannot be used in entry name");
-
-			if (entryName.Length > 31)
-				throw new Exception("Entry name MUST be smaller than 31 characters");
-
-			byte[] newName = null;
-			byte[] temp = Encoding.Unicode.GetBytes(entryName);
-			newName = new byte[64];
-			Buffer.BlockCopy(temp, 0, newName, 0, temp.Length);
-			newName[temp.Length] = 0x00;
-			newName[temp.Length + 1] = 0x00;
-
-			EntryName = newName;
-			NameLength = (ushort)(temp.Length + 2);
-		}
-
-		public ushort NameLength { get; private set; }
-
-		public StgType StgType { get; set; } = StgType.StgInvalid;
-
-		public Color Color { get; set; } = Color.BLACK;
-
-		public Int32 LeftSibling { get; set; } = NOSTREAM;
-
-		public Int32 RightSibling { get; set; } = NOSTREAM;
-
-		public Int32 Child { get; set; } = NOSTREAM;
-
-		public Guid StorageCLSID { get; set; } = Guid.NewGuid();
-
-		public Int32 StateBits { get; set; }
-
-		public byte[] CreationDate { get; set; } = new byte[8] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-		public byte[] ModifyDate { get; set; } = new byte[8] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-		public Int32 StartSetc { get; set; } = Sector.Endofchain;
-
-		public long Size { get; set; }
-
-		public int CompareTo(object obj)
-		{
-			DirectoryEntry otherDir = obj as DirectoryEntry;
-
-			if (otherDir == null)
-				throw new Exception("Invalid casting: compared object does not implement IDirectorEntry interface");
-
-			if (this.NameLength > otherDir.NameLength)
-				return THIS_IS_GREATER;
-			else if (this.NameLength < otherDir.NameLength)
-				return OTHER_IS_GREATER;
-			else
-			{
-				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++)
-				{
-					char thisChar = char.ToUpperInvariant(thisName[z]);
-					char otherChar = char.ToUpperInvariant(otherName[z]);
-
-					if (thisChar > otherChar)
-						return THIS_IS_GREATER;
-					else if (thisChar < otherChar)
-						return OTHER_IS_GREATER;
-				}
-
-				return 0;
-			}
-		}
-
-		public override bool Equals(object obj)
-		{
-			return CompareTo(obj) == 0;
-		}
-
-		private static ulong Fnv_hash(byte[] buffer)
-		{
-			ulong h = 2166136261;
-			int i;
-
-			for (i = 0; i < buffer.Length; i++)
-				h = (h * 16777619) ^ buffer[i];
-
-			return h;
-		}
-
-		public override int GetHashCode()
-		{
-			return (int)Fnv_hash(EntryName);
-		}
-
-		public void Read(Stream stream, int ver = 3)
-		{
-			using (BinaryReader rw = new BinaryReader(stream, Encoding.UTF8, true))
-			{
-				EntryName = rw.ReadBytes(64);
-				NameLength = rw.ReadUInt16();
-				StgType = (StgType)rw.ReadByte();
-				Color = (Color)rw.ReadByte();
-				LeftSibling = rw.ReadInt32();
-				RightSibling = rw.ReadInt32();
-				Child = rw.ReadInt32();
-
-				if (StgType == StgType.StgInvalid)
-				{
-					LeftSibling = NOSTREAM;
-					RightSibling = NOSTREAM;
-					Child = NOSTREAM;
-				}
-
-				StorageCLSID = new Guid(rw.ReadBytes(16));
-				StateBits = rw.ReadInt32();
-				CreationDate = rw.ReadBytes(8);
-				ModifyDate = rw.ReadBytes(8);
-				StartSetc = rw.ReadInt32();
-
-				if (ver == 3)
-				{
-					Size = rw.ReadInt32();
-					rw.ReadBytes(4);
-				}
-				else
-					Size = rw.ReadInt64();
-			}
-		}
-
-		public string Name => GetEntryName();
-
-		public IRBNode Left
-		{
-			get
-			{
-				if (LeftSibling == NOSTREAM)
-					return null;
-				return dirRepository[LeftSibling];
-			}
-
-			set
-			{
-				LeftSibling = value != null ? (value as DirectoryEntry).SID : NOSTREAM;
-				if (LeftSibling != NOSTREAM)
-					dirRepository[LeftSibling].Parent = this;
-			}
-		}
-
-		public IRBNode Right
-		{
-			get
-			{
-				if (RightSibling == NOSTREAM)
-					return null;
-				return dirRepository[RightSibling];
-			}
-
-			set
-			{
-				RightSibling = value != null ? ((DirectoryEntry)value).SID : NOSTREAM;
-				if (RightSibling != NOSTREAM)
-					dirRepository[RightSibling].Parent = this;
-			}
-		}
-
-		public IRBNode Parent { get; set; }
-
-		public IRBNode Grandparent() => Parent?.Parent;
-
-		public IRBNode Sibling() => (this == Parent.Left) ? Parent.Right : Parent.Left;
-
-		public IRBNode Uncle() => Parent?.Sibling();
-
-		internal static DirectoryEntry New(String name, StgType stgType, IList<DirectoryEntry> dirRepository)
-		{
-			DirectoryEntry de = null;
-			if (dirRepository != null)
-			{
-				de = new DirectoryEntry(name, stgType, dirRepository);
-				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 DirectoryEntry Mock(String name, StgType stgType) => new DirectoryEntry(name, stgType, null);
-
-		internal static DirectoryEntry TryNew(String name, StgType stgType, IList<DirectoryEntry> dirRepository)
-		{
-			DirectoryEntry de = new DirectoryEntry(name, stgType, dirRepository);
-
-			if (de != null)
-			{
-				for (int i = 0; i < dirRepository.Count; i++)
-				{
-					if (dirRepository[i].StgType == StgType.StgInvalid)
-					{
-						dirRepository[i] = de;
-						de.SID = i;
-						return de;
-					}
-				}
-			}
-
-			dirRepository.Add(de);
-			de.SID = dirRepository.Count - 1;
-
-			return de;
-		}
-
-		public override string ToString() => $"{Name} [{SID}]{(StgType == StgType.StgStream ? "Stream" : "Storage")}";
-
-		public void AssignValueTo(IRBNode other)
-		{
-			DirectoryEntry d = other as DirectoryEntry;
-
-			d.SetEntryName(GetEntryName());
-
-			d.CreationDate = new byte[CreationDate.Length];
-			CreationDate.CopyTo(d.CreationDate, 0);
-
-			d.ModifyDate = new byte[ModifyDate.Length];
-			ModifyDate.CopyTo(d.ModifyDate, 0);
-
-			d.Size = Size;
-			d.StartSetc = StartSetc;
-			d.StateBits = StateBits;
-			d.StgType = StgType;
-			d.StorageCLSID = new Guid(StorageCLSID.ToByteArray());
-			d.Child = Child;
-		}
-	}
-
-	internal abstract class CFItem : IComparable<CFItem>
-	{
-		private CompoundFile compoundFile;
-
-		protected CompoundFile CompoundFile => compoundFile;
-
-		protected void CheckDisposed()
-		{
-			if (compoundFile.IsClosed)
-				throw new ObjectDisposedException("Owner Compound file has been closed and owned items have been invalidated");
-		}
-
-		protected CFItem()
-		{ }
-
-		protected CFItem(CompoundFile compoundFile)
-		{ this.compoundFile = compoundFile; }
-
-		internal DirectoryEntry DirEntry { get; set; }
-
-		internal int CompareTo(CFItem other) => DirEntry.CompareTo(other.DirEntry);
-
-		public int CompareTo(object obj) => DirEntry.CompareTo((obj as CFItem).DirEntry);
-
-		public static bool operator ==(CFItem leftItem, CFItem rightItem)
-		{
-			if (System.Object.ReferenceEquals(leftItem, rightItem))
-				return true;
-			if (((object)leftItem == null) || ((object)rightItem == null))
-				return false;
-			return leftItem.CompareTo(rightItem) == 0;
-		}
-
-		public static bool operator !=(CFItem leftItem, CFItem rightItem) => !(leftItem == rightItem);
-
-		public override bool Equals(object obj) => CompareTo(obj) == 0;
-
-		public override int GetHashCode() => DirEntry.GetEntryName().GetHashCode();
-
-		public string Name
-		{
-			get
-			{
-				var n = DirEntry.GetEntryName();
-				return (n != null && n.Length > 0) ? n.TrimEnd('\0') : string.Empty;
-			}
-		}
-
-		public long Size => DirEntry.Size;
-
-		public bool IsStorage => DirEntry.StgType == StgType.StgStorage;
-
-		public bool IsStream => DirEntry.StgType == StgType.StgStream;
-
-		public bool IsRoot => DirEntry.StgType == StgType.StgRoot;
-
-		public DateTime CreationDate
-		{
-			get => DateTime.FromFileTime(BitConverter.ToInt64(DirEntry.CreationDate, 0));
-
-			set
-			{
-				if (DirEntry.StgType != StgType.StgStream && DirEntry.StgType != StgType.StgRoot)
-					DirEntry.CreationDate = BitConverter.GetBytes((value.ToFileTime()));
-				else
-					throw new Exception("Creation Date can only be set on storage entries");
-			}
-		}
-
-		public DateTime ModifyDate
-		{
-			get => DateTime.FromFileTime(BitConverter.ToInt64(DirEntry.ModifyDate, 0));
-
-			set
-			{
-				if (DirEntry.StgType != StgType.StgStream && DirEntry.StgType != StgType.StgRoot)
-					DirEntry.ModifyDate = BitConverter.GetBytes((value.ToFileTime()));
-				else
-					throw new Exception("Modify Date can only be set on storage entries");
-			}
-		}
-
-		public Guid CLSID
-		{
-			get => DirEntry.StorageCLSID;
-
-			set
-			{
-				if (DirEntry.StgType != StgType.StgStream)
-					DirEntry.StorageCLSID = value;
-				else
-					throw new Exception("Object class GUID can only be set on Root and Storage entries");
-			}
-		}
-
-		int IComparable<CFItem>.CompareTo(CFItem other) => DirEntry.CompareTo(other.DirEntry);
-
-		public override string ToString()
-		{
-			return (DirEntry != null)
-				? $"[{DirEntry.LeftSibling},{DirEntry.SID},{DirEntry.RightSibling}] {DirEntry.GetEntryName()}"
-				: string.Empty;
-		}
-	}
-
-	internal sealed class CFStream : CFItem
-	{
-		internal CFStream(CompoundFile compoundFile, DirectoryEntry dirEntry)
-			: base(compoundFile)
-		{
-			if (dirEntry == null || dirEntry.SID < 0)
-				throw new Exception("Attempting to add a CFStream using an unitialized directory");
-			this.DirEntry = dirEntry;
-		}
-
-		public Byte[] GetData()
-		{
-			CheckDisposed();
-			return this.CompoundFile.GetData(this);
-		}
-
-		public int Read(byte[] buffer, long position, int count)
-		{
-			CheckDisposed();
-			return this.CompoundFile.ReadData(this, position, buffer, 0, count);
-		}
-
-		internal int Read(byte[] buffer, long position, int offset, int count)
-		{
-			CheckDisposed();
-			return this.CompoundFile.ReadData(this, position, buffer, offset, count);
-		}
-	}
-
-	internal sealed class CFStorage : CFItem
-	{
-		private RBTree children;
-
-		internal RBTree Children
-		{
-			get
-			{
-				if (children == null)
-					children = LoadChildren(this.DirEntry.SID) ?? this.CompoundFile.CreateNewTree();
-				return children;
-			}
-		}
-
-		internal CFStorage(CompoundFile compFile, DirectoryEntry dirEntry)
-			: base(compFile)
-		{
-			if (dirEntry == null || dirEntry.SID < 0)
-				throw new Exception("Attempting to create a CFStorage using an unitialized directory");
-			this.DirEntry = dirEntry;
-		}
-
-		private RBTree LoadChildren(int SID)
-		{
-			RBTree childrenTree = this.CompoundFile.GetChildrenTree(SID);
-
-			if (childrenTree.Root != null)
-				this.DirEntry.Child = (childrenTree.Root as DirectoryEntry).SID;
-			else
-				this.DirEntry.Child = DirectoryEntry.NOSTREAM;
-
-			return childrenTree;
-		}
-
-		public CFStream GetStream(String streamName)
-		{
-			CheckDisposed();
-
-			DirectoryEntry tmp = DirectoryEntry.Mock(streamName, StgType.StgStream);
-
-			if (Children.TryLookup(tmp, out IRBNode outDe) && (((DirectoryEntry)outDe).StgType == StgType.StgStream))
-				return new CFStream(this.CompoundFile, (DirectoryEntry)outDe);
-			else
-				throw new KeyNotFoundException("Cannot find item [" + streamName + "] within the current storage");
-		}
-
-		public CFStream TryGetStream(String streamName)
-		{
-			CheckDisposed();
-
-			DirectoryEntry tmp = DirectoryEntry.Mock(streamName, StgType.StgStream);
+        public void SetEntryName(String entryName)
+        {
+            if (entryName.Contains(@"\") || entryName.Contains(@"/") ||
+                entryName.Contains(@":") || entryName.Contains(@"!"))
+                throw new Exception("Invalid character in entry: the characters '\\', '/', ':','!' cannot be used in entry name");
+
+            if (entryName.Length > 31)
+                throw new Exception("Entry name MUST be smaller than 31 characters");
+
+            byte[] newName = null;
+            byte[] temp = Encoding.Unicode.GetBytes(entryName);
+            newName = new byte[64];
+            Buffer.BlockCopy(temp, 0, newName, 0, temp.Length);
+            newName[temp.Length] = 0x00;
+            newName[temp.Length + 1] = 0x00;
+
+            EntryName = newName;
+            NameLength = (ushort)(temp.Length + 2);
+        }
+
+        public ushort NameLength { get; private set; }
+
+        public StgType StgType { get; set; } = StgType.StgInvalid;
+
+        public Color Color { get; set; } = Color.BLACK;
+
+        public Int32 LeftSibling { get; set; } = NOSTREAM;
+
+        public Int32 RightSibling { get; set; } = NOSTREAM;
+
+        public Int32 Child { get; set; } = NOSTREAM;
+
+        public Guid StorageCLSID { get; set; } = Guid.NewGuid();
+
+        public Int32 StateBits { get; set; }
+
+        public byte[] CreationDate { get; set; } = new byte[8] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+        public byte[] ModifyDate { get; set; } = new byte[8] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+        public Int32 StartSetc { get; set; } = Sector.Endofchain;
+
+        public long Size { get; set; }
+
+        public int CompareTo(object obj)
+        {
+            DirectoryEntry otherDir = obj as DirectoryEntry;
+
+            if (otherDir == null)
+                throw new Exception("Invalid casting: compared object does not implement IDirectorEntry interface");
+
+            if (this.NameLength > otherDir.NameLength)
+                return THIS_IS_GREATER;
+            else if (this.NameLength < otherDir.NameLength)
+                return OTHER_IS_GREATER;
+            else
+            {
+                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++)
+                {
+                    char thisChar = char.ToUpperInvariant(thisName[z]);
+                    char otherChar = char.ToUpperInvariant(otherName[z]);
+
+                    if (thisChar > otherChar)
+                        return THIS_IS_GREATER;
+                    else if (thisChar < otherChar)
+                        return OTHER_IS_GREATER;
+                }
+
+                return 0;
+            }
+        }
+
+        public override bool Equals(object obj)
+        {
+            return CompareTo(obj) == 0;
+        }
+
+        private static ulong Fnv_hash(byte[] buffer)
+        {
+            ulong h = 2166136261;
+            int i;
+
+            for (i = 0; i < buffer.Length; i++)
+                h = (h * 16777619) ^ buffer[i];
+
+            return h;
+        }
+
+        public override int GetHashCode()
+        {
+            return (int)Fnv_hash(EntryName);
+        }
+
+        public void Read(Stream stream, int ver = 3)
+        {
+            using (BinaryReader rw = new BinaryReader(stream, Encoding.UTF8, true))
+            {
+                EntryName = rw.ReadBytes(64);
+                NameLength = rw.ReadUInt16();
+                StgType = (StgType)rw.ReadByte();
+                Color = (Color)rw.ReadByte();
+                LeftSibling = rw.ReadInt32();
+                RightSibling = rw.ReadInt32();
+                Child = rw.ReadInt32();
+
+                if (StgType == StgType.StgInvalid)
+                {
+                    LeftSibling = NOSTREAM;
+                    RightSibling = NOSTREAM;
+                    Child = NOSTREAM;
+                }
+
+                StorageCLSID = new Guid(rw.ReadBytes(16));
+                StateBits = rw.ReadInt32();
+                CreationDate = rw.ReadBytes(8);
+                ModifyDate = rw.ReadBytes(8);
+                StartSetc = rw.ReadInt32();
+
+                if (ver == 3)
+                {
+                    Size = rw.ReadInt32();
+                    rw.ReadBytes(4);
+                }
+                else
+                    Size = rw.ReadInt64();
+            }
+        }
+
+        public string Name => GetEntryName();
+
+        public IRBNode Left
+        {
+            get
+            {
+                if (LeftSibling == NOSTREAM)
+                    return null;
+                return dirRepository[LeftSibling];
+            }
+
+            set
+            {
+                LeftSibling = value != null ? (value as DirectoryEntry).SID : NOSTREAM;
+                if (LeftSibling != NOSTREAM)
+                    dirRepository[LeftSibling].Parent = this;
+            }
+        }
+
+        public IRBNode Right
+        {
+            get
+            {
+                if (RightSibling == NOSTREAM)
+                    return null;
+                return dirRepository[RightSibling];
+            }
+
+            set
+            {
+                RightSibling = value != null ? ((DirectoryEntry)value).SID : NOSTREAM;
+                if (RightSibling != NOSTREAM)
+                    dirRepository[RightSibling].Parent = this;
+            }
+        }
+
+        public IRBNode Parent { get; set; }
+
+        public IRBNode Grandparent() => Parent?.Parent;
+
+        public IRBNode Sibling() => (this == Parent.Left) ? Parent.Right : Parent.Left;
+
+        public IRBNode Uncle() => Parent?.Sibling();
+
+        internal static DirectoryEntry New(String name, StgType stgType, IList<DirectoryEntry> dirRepository)
+        {
+            DirectoryEntry de = null;
+            if (dirRepository != null)
+            {
+                de = new DirectoryEntry(name, stgType, dirRepository);
+                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 DirectoryEntry Mock(String name, StgType stgType) => new DirectoryEntry(name, stgType, null);
+
+        internal static DirectoryEntry TryNew(String name, StgType stgType, IList<DirectoryEntry> dirRepository)
+        {
+            DirectoryEntry de = new DirectoryEntry(name, stgType, dirRepository);
+
+            if (de != null)
+            {
+                for (int i = 0; i < dirRepository.Count; i++)
+                {
+                    if (dirRepository[i].StgType == StgType.StgInvalid)
+                    {
+                        dirRepository[i] = de;
+                        de.SID = i;
+                        return de;
+                    }
+                }
+            }
+
+            dirRepository.Add(de);
+            de.SID = dirRepository.Count - 1;
+
+            return de;
+        }
+
+        public override string ToString() => $"{Name} [{SID}]{(StgType == StgType.StgStream ? "Stream" : "Storage")}";
+
+        public void AssignValueTo(IRBNode other)
+        {
+            DirectoryEntry d = other as DirectoryEntry;
+
+            d.SetEntryName(GetEntryName());
+
+            d.CreationDate = new byte[CreationDate.Length];
+            CreationDate.CopyTo(d.CreationDate, 0);
+
+            d.ModifyDate = new byte[ModifyDate.Length];
+            ModifyDate.CopyTo(d.ModifyDate, 0);
+
+            d.Size = Size;
+            d.StartSetc = StartSetc;
+            d.StateBits = StateBits;
+            d.StgType = StgType;
+            d.StorageCLSID = new Guid(StorageCLSID.ToByteArray());
+            d.Child = Child;
+        }
+    }
+
+    internal abstract class CFItem : IComparable<CFItem>
+    {
+        private CompoundFile compoundFile;
+
+        protected CompoundFile CompoundFile => compoundFile;
+
+        protected void CheckDisposed()
+        {
+            if (compoundFile.IsClosed)
+                throw new ObjectDisposedException("Owner Compound file has been closed and owned items have been invalidated");
+        }
+
+        protected CFItem()
+        { }
+
+        protected CFItem(CompoundFile compoundFile)
+        { this.compoundFile = compoundFile; }
+
+        internal DirectoryEntry DirEntry { get; set; }
+
+        internal int CompareTo(CFItem other) => DirEntry.CompareTo(other.DirEntry);
+
+        public int CompareTo(object obj) => DirEntry.CompareTo((obj as CFItem).DirEntry);
+
+        public static bool operator ==(CFItem leftItem, CFItem rightItem)
+        {
+            if (System.Object.ReferenceEquals(leftItem, rightItem))
+                return true;
+            if (((object)leftItem == null) || ((object)rightItem == null))
+                return false;
+            return leftItem.CompareTo(rightItem) == 0;
+        }
+
+        public static bool operator !=(CFItem leftItem, CFItem rightItem) => !(leftItem == rightItem);
+
+        public override bool Equals(object obj) => CompareTo(obj) == 0;
+
+        public override int GetHashCode() => DirEntry.GetEntryName().GetHashCode();
+
+        public string Name
+        {
+            get
+            {
+                var n = DirEntry.GetEntryName();
+                return (n != null && n.Length > 0) ? n.TrimEnd('\0') : string.Empty;
+            }
+        }
+
+        public long Size => DirEntry.Size;
+
+        public bool IsStorage => DirEntry.StgType == StgType.StgStorage;
+
+        public bool IsStream => DirEntry.StgType == StgType.StgStream;
+
+        public bool IsRoot => DirEntry.StgType == StgType.StgRoot;
+
+        public DateTime CreationDate
+        {
+            get => DateTime.FromFileTime(BitConverter.ToInt64(DirEntry.CreationDate, 0));
+
+            set
+            {
+                if (DirEntry.StgType != StgType.StgStream && DirEntry.StgType != StgType.StgRoot)
+                    DirEntry.CreationDate = BitConverter.GetBytes((value.ToFileTime()));
+                else
+                    throw new Exception("Creation Date can only be set on storage entries");
+            }
+        }
+
+        public DateTime ModifyDate
+        {
+            get => DateTime.FromFileTime(BitConverter.ToInt64(DirEntry.ModifyDate, 0));
+
+            set
+            {
+                if (DirEntry.StgType != StgType.StgStream && DirEntry.StgType != StgType.StgRoot)
+                    DirEntry.ModifyDate = BitConverter.GetBytes((value.ToFileTime()));
+                else
+                    throw new Exception("Modify Date can only be set on storage entries");
+            }
+        }
+
+        public Guid CLSID
+        {
+            get => DirEntry.StorageCLSID;
+
+            set
+            {
+                if (DirEntry.StgType != StgType.StgStream)
+                    DirEntry.StorageCLSID = value;
+                else
+                    throw new Exception("Object class GUID can only be set on Root and Storage entries");
+            }
+        }
+
+        int IComparable<CFItem>.CompareTo(CFItem other) => DirEntry.CompareTo(other.DirEntry);
+
+        public override string ToString()
+        {
+            return (DirEntry != null)
+                ? $"[{DirEntry.LeftSibling},{DirEntry.SID},{DirEntry.RightSibling}] {DirEntry.GetEntryName()}"
+                : string.Empty;
+        }
+    }
+
+    internal sealed class CFStream : CFItem
+    {
+        internal CFStream(CompoundFile compoundFile, DirectoryEntry dirEntry)
+            : base(compoundFile)
+        {
+            if (dirEntry == null || dirEntry.SID < 0)
+                throw new Exception("Attempting to add a CFStream using an unitialized directory");
+            this.DirEntry = dirEntry;
+        }
+
+        public Byte[] GetData()
+        {
+            CheckDisposed();
+            return this.CompoundFile.GetData(this);
+        }
+
+        public int Read(byte[] buffer, long position, int count)
+        {
+            CheckDisposed();
+            return this.CompoundFile.ReadData(this, position, buffer, 0, count);
+        }
+
+        internal int Read(byte[] buffer, long position, int offset, int count)
+        {
+            CheckDisposed();
+            return this.CompoundFile.ReadData(this, position, buffer, offset, count);
+        }
+    }
+
+    internal sealed class CFStorage : CFItem
+    {
+        private RBTree children;
+
+        internal RBTree Children
+        {
+            get
+            {
+                if (children == null)
+                    children = LoadChildren(this.DirEntry.SID) ?? this.CompoundFile.CreateNewTree();
+                return children;
+            }
+        }
+
+        internal CFStorage(CompoundFile compFile, DirectoryEntry dirEntry)
+            : base(compFile)
+        {
+            if (dirEntry == null || dirEntry.SID < 0)
+                throw new Exception("Attempting to create a CFStorage using an unitialized directory");
+            this.DirEntry = dirEntry;
+        }
+
+        private RBTree LoadChildren(int SID)
+        {
+            RBTree childrenTree = this.CompoundFile.GetChildrenTree(SID);
+
+            if (childrenTree.Root != null)
+                this.DirEntry.Child = (childrenTree.Root as DirectoryEntry).SID;
+            else
+                this.DirEntry.Child = DirectoryEntry.NOSTREAM;
+
+            return childrenTree;
+        }
+
+        public CFStream GetStream(String streamName)
+        {
+            CheckDisposed();
+
+            DirectoryEntry tmp = DirectoryEntry.Mock(streamName, StgType.StgStream);
+
+            if (Children.TryLookup(tmp, out IRBNode outDe) && (((DirectoryEntry)outDe).StgType == StgType.StgStream))
+                return new CFStream(this.CompoundFile, (DirectoryEntry)outDe);
+            else
+                throw new KeyNotFoundException("Cannot find item [" + streamName + "] within the current storage");
+        }
+
+        public CFStream TryGetStream(String streamName)
+        {
+            CheckDisposed();
+
+            DirectoryEntry tmp = DirectoryEntry.Mock(streamName, StgType.StgStream);
 
-			if (Children.TryLookup(tmp, out IRBNode outDe) && ((outDe as DirectoryEntry).StgType == StgType.StgStream))
-				return new CFStream(this.CompoundFile, (DirectoryEntry)outDe);
-			else
-				return null;
-		}
+            if (Children.TryLookup(tmp, out IRBNode outDe) && ((outDe as DirectoryEntry).StgType == StgType.StgStream))
+                return new CFStream(this.CompoundFile, (DirectoryEntry)outDe);
+            else
+                return null;
+        }
 
-		public CFStorage GetStorage(String storageName)
-		{
-			CheckDisposed();
-
-			DirectoryEntry template = DirectoryEntry.Mock(storageName, StgType.StgInvalid);
-
-			if (Children.TryLookup(template, out IRBNode outDe) && (outDe as DirectoryEntry).StgType == StgType.StgStorage)
-				return new CFStorage(this.CompoundFile, outDe as DirectoryEntry);
-			else
-				throw new KeyNotFoundException("Cannot find item [" + storageName + "] within the current storage");
-		}
+        public CFStorage GetStorage(String storageName)
+        {
+            CheckDisposed();
+
+            DirectoryEntry template = DirectoryEntry.Mock(storageName, StgType.StgInvalid);
+
+            if (Children.TryLookup(template, out IRBNode outDe) && (outDe as DirectoryEntry).StgType == StgType.StgStorage)
+                return new CFStorage(this.CompoundFile, outDe as DirectoryEntry);
+            else
+                throw new KeyNotFoundException("Cannot find item [" + storageName + "] within the current storage");
+        }
 
-		public CFStorage TryGetStorage(String storageName)
-		{
-			CheckDisposed();
+        public CFStorage TryGetStorage(String storageName)
+        {
+            CheckDisposed();
 
-			DirectoryEntry template = DirectoryEntry.Mock(storageName, StgType.StgInvalid);
+            DirectoryEntry template = DirectoryEntry.Mock(storageName, StgType.StgInvalid);
 
-			if (Children.TryLookup(template, out IRBNode outDe) && ((DirectoryEntry)outDe).StgType == StgType.StgStorage)
-				return new CFStorage(this.CompoundFile, outDe as DirectoryEntry);
-			else
-				return null;
-		}
+            if (Children.TryLookup(template, out IRBNode outDe) && ((DirectoryEntry)outDe).StgType == StgType.StgStorage)
+                return new CFStorage(this.CompoundFile, outDe as DirectoryEntry);
+            else
+                return null;
+        }
 
-		public void VisitEntries(Action<CFItem> action, bool recursive)
-		{
-			CheckDisposed();
+        public void VisitEntries(Action<CFItem> action, bool recursive)
+        {
+            CheckDisposed();
 
-			if (action != null)
-			{
-				List<IRBNode> subStorages = new List<IRBNode>();
-
-				void internalAction(IRBNode targetNode)
-				{
-					DirectoryEntry d = targetNode as DirectoryEntry;
-					if (d.StgType == StgType.StgStream)
-						action(new CFStream(this.CompoundFile, d));
-					else
-						action(new CFStorage(this.CompoundFile, d));
-
-					if (d.Child != DirectoryEntry.NOSTREAM)
-						subStorages.Add(targetNode);
-
-					return;
-				}
-
-				this.Children.VisitTreeNodes(internalAction);
-
-				if (recursive && subStorages.Count > 0)
-					foreach (IRBNode n in subStorages)
-						(new CFStorage(this.CompoundFile, n as DirectoryEntry)).VisitEntries(action, recursive);
-			}
-		}
-	}
-
-	internal class CFItemComparer : IComparer<CFItem>
-	{
-		public int Compare(CFItem x, CFItem y) => (x.DirEntry.CompareTo(y.DirEntry));
-	}
-
-	internal sealed class Header
-	{
-		public byte[] HeaderSignature { get; private set; } = new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 };
-
-		public byte[] CLSID { get; set; } = new byte[16];
-
-		public ushort MinorVersion { get; private set; } = 0x003E;
-
-		public ushort MajorVersion { get; private set; } = 0x0003;
-
-		public ushort ByteOrder { get; private set; } = 0xFFFE;
-
-		public ushort SectorShift { get; private set; } = 9;
-
-		public ushort MiniSectorShift { get; private set; } = 6;
-
-		public int DirectorySectorsNumber { get; set; }
-
-		public int FATSectorsNumber { get; set; }
-
-		public int FirstDirectorySectorID { get; set; } = Sector.Endofchain;
-
-		public uint MinSizeStandardStream { get; set; } = 4096;
-
-		public int FirstMiniFATSectorID { get; set; } = unchecked((int)0xFFFFFFFE);
-
-		public uint MiniFATSectorsNumber { get; set; }
-
-		public int FirstDIFATSectorID { get; set; } = Sector.Endofchain;
-
-		public uint DIFATSectorsNumber { get; set; }
-
-		public int[] DIFAT { get; private set; } = new int[109];
-
-		public Header() : this(3)
-		{
-		}
-
-		public Header(ushort version)
-		{
-			switch (version)
-			{
-				case 3:
-					MajorVersion = 3;
-					SectorShift = 0x0009;
-					break;
+            if (action != null)
+            {
+                List<IRBNode> subStorages = new List<IRBNode>();
+
+                void internalAction(IRBNode targetNode)
+                {
+                    DirectoryEntry d = targetNode as DirectoryEntry;
+                    if (d.StgType == StgType.StgStream)
+                        action(new CFStream(this.CompoundFile, d));
+                    else
+                        action(new CFStorage(this.CompoundFile, d));
+
+                    if (d.Child != DirectoryEntry.NOSTREAM)
+                        subStorages.Add(targetNode);
+
+                    return;
+                }
+
+                this.Children.VisitTreeNodes(internalAction);
+
+                if (recursive && subStorages.Count > 0)
+                    foreach (IRBNode n in subStorages)
+                        (new CFStorage(this.CompoundFile, n as DirectoryEntry)).VisitEntries(action, recursive);
+            }
+        }
+    }
+
+    internal class CFItemComparer : IComparer<CFItem>
+    {
+        public int Compare(CFItem x, CFItem y) => (x.DirEntry.CompareTo(y.DirEntry));
+    }
+
+    internal sealed class Header
+    {
+        public byte[] HeaderSignature { get; private set; } = new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 };
+
+        public byte[] CLSID { get; set; } = new byte[16];
+
+        public ushort MinorVersion { get; private set; } = 0x003E;
+
+        public ushort MajorVersion { get; private set; } = 0x0003;
+
+        public ushort ByteOrder { get; private set; } = 0xFFFE;
+
+        public ushort SectorShift { get; private set; } = 9;
+
+        public ushort MiniSectorShift { get; private set; } = 6;
+
+        public int DirectorySectorsNumber { get; set; }
+
+        public int FATSectorsNumber { get; set; }
+
+        public int FirstDirectorySectorID { get; set; } = Sector.Endofchain;
+
+        public uint MinSizeStandardStream { get; set; } = 4096;
+
+        public int FirstMiniFATSectorID { get; set; } = unchecked((int)0xFFFFFFFE);
+
+        public uint MiniFATSectorsNumber { get; set; }
+
+        public int FirstDIFATSectorID { get; set; } = Sector.Endofchain;
+
+        public uint DIFATSectorsNumber { get; set; }
+
+        public int[] DIFAT { get; private set; } = new int[109];
+
+        public Header() : this(3)
+        {
+        }
+
+        public Header(ushort version)
+        {
+            switch (version)
+            {
+                case 3:
+                    MajorVersion = 3;
+                    SectorShift = 0x0009;
+                    break;
 
-				case 4:
-					MajorVersion = 4;
-					SectorShift = 0x000C;
-					break;
+                case 4:
+                    MajorVersion = 4;
+                    SectorShift = 0x000C;
+                    break;
 
-				default:
-					throw new Exception("Invalid Compound File Format version");
-			}
+                default:
+                    throw new Exception("Invalid Compound File Format version");
+            }
 
-			for (int i = 0; i < 109; i++)
-				DIFAT[i] = Sector.Freesect;
-		}
-
-		public void Read(Stream stream)
-		{
-			using (BinaryReader rw = new BinaryReader(stream, Encoding.UTF8, true))
-			{
-				HeaderSignature = rw.ReadBytes(8);
-				CheckSignature();
-				CLSID = rw.ReadBytes(16);
-				MinorVersion = rw.ReadUInt16();
-				MajorVersion = rw.ReadUInt16();
-				CheckVersion();
-				ByteOrder = rw.ReadUInt16();
-				SectorShift = rw.ReadUInt16();
-				MiniSectorShift = rw.ReadUInt16();
-				rw.ReadBytes(6);
-				DirectorySectorsNumber = rw.ReadInt32();
-				FATSectorsNumber = rw.ReadInt32();
-				FirstDirectorySectorID = rw.ReadInt32();
-				rw.ReadUInt32();
-				MinSizeStandardStream = rw.ReadUInt32();
-				FirstMiniFATSectorID = rw.ReadInt32();
-				MiniFATSectorsNumber = rw.ReadUInt32();
-				FirstDIFATSectorID = rw.ReadInt32();
-				DIFATSectorsNumber = rw.ReadUInt32();
+            for (int i = 0; i < 109; i++)
+                DIFAT[i] = Sector.Freesect;
+        }
+
+        public void Read(Stream stream)
+        {
+            using (BinaryReader rw = new BinaryReader(stream, Encoding.UTF8, true))
+            {
+                HeaderSignature = rw.ReadBytes(8);
+                CheckSignature();
+                CLSID = rw.ReadBytes(16);
+                MinorVersion = rw.ReadUInt16();
+                MajorVersion = rw.ReadUInt16();
+                CheckVersion();
+                ByteOrder = rw.ReadUInt16();
+                SectorShift = rw.ReadUInt16();
+                MiniSectorShift = rw.ReadUInt16();
+                rw.ReadBytes(6);
+                DirectorySectorsNumber = rw.ReadInt32();
+                FATSectorsNumber = rw.ReadInt32();
+                FirstDirectorySectorID = rw.ReadInt32();
+                rw.ReadUInt32();
+                MinSizeStandardStream = rw.ReadUInt32();
+                FirstMiniFATSectorID = rw.ReadInt32();
+                MiniFATSectorsNumber = rw.ReadUInt32();
+                FirstDIFATSectorID = rw.ReadInt32();
+                DIFATSectorsNumber = rw.ReadUInt32();
 
-				for (int i = 0; i < 109; i++)
-					DIFAT[i] = rw.ReadInt32();
-			}
-		}
+                for (int i = 0; i < 109; i++)
+                    DIFAT[i] = rw.ReadInt32();
+            }
+        }
 
-		private void CheckVersion()
-		{
-			if (MajorVersion != 3 && MajorVersion != 4)
-				throw new InvalidDataException("Unsupported Binary File Format version: OpenMcdf only supports Compound Files with major version equal to 3 or 4 ");
-		}
+        private void CheckVersion()
+        {
+            if (MajorVersion != 3 && MajorVersion != 4)
+                throw new InvalidDataException("Unsupported Binary File Format version: OpenMcdf only supports Compound Files with major version equal to 3 or 4 ");
+        }
 
-		private byte[] OLE_CFS_SIGNATURE = new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 };
+        private byte[] OLE_CFS_SIGNATURE = new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 };
 
-		private void CheckSignature()
-		{
-			for (int i = 0; i < HeaderSignature.Length; i++)
-				if (HeaderSignature[i] != OLE_CFS_SIGNATURE[i])
-					throw new InvalidDataException("Invalid OLE structured storage file");
-		}
-	}
+        private void CheckSignature()
+        {
+            for (int i = 0; i < HeaderSignature.Length; i++)
+                if (HeaderSignature[i] != OLE_CFS_SIGNATURE[i])
+                    throw new InvalidDataException("Invalid OLE structured storage file");
+        }
+    }
 
-	internal sealed class StreamView : Stream
-	{
-		private readonly int _sectorSize;
-		private long _position;
-
-		private readonly List<Sector> _sectorChain;
-		private readonly Stream _stream;
-		private readonly bool _isFatStream = false;
-		private readonly List<Sector> _freeSectors = new List<Sector>();
-
-		public IEnumerable<Sector> FreeSectors => _freeSectors;
-
-		public StreamView(List<Sector> sectorChain, int sectorSize, Stream stream)
-		{
-			if (sectorSize <= 0)
-				throw new Exception("Sector size must be greater than zero");
-
-			this._sectorChain = sectorChain ?? throw new Exception("Sector Chain cannot be null");
-			this._sectorSize = sectorSize;
-			this._stream = stream;
-		}
-
-		public StreamView(List<Sector> sectorChain, int sectorSize, long length, Queue<Sector> availableSectors, Stream stream, bool isFatStream = false)
-			: this(sectorChain, sectorSize, stream)
-		{
-			this._isFatStream = isFatStream;
-			AdjustLength(length, availableSectors);
-		}
-
-		public List<Sector> BaseSectorChain => _sectorChain;
-
-		public override bool CanRead => true;
-
-		public override bool CanSeek => true;
-
-		public override bool CanWrite => true;
-
-		public override void Flush()
-		{ }
-
-		private long _length;
-
-		public override long Length => _length;
-
-		public override long Position
-		{
-			get => _position;
-
-			set
-			{
-				if (_position > _length - 1)
-					throw new ArgumentOutOfRangeException("value");
-				_position = value;
-			}
-		}
-
-		private byte[] buf = new byte[4];
-
-		public int ReadInt32()
-		{
-			this.Read(buf, 0, 4);
-			return (((buf[0] | (buf[1] << 8)) | (buf[2] << 16)) | (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 / _sectorSize);
-
-				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, Queue<Sector> availableSectors = null)
-		{
-			this._length = value;
-			long delta = value - (_sectorChain.Count * (long)_sectorSize);
-
-			if (delta > 0)
-			{
-				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.MinisectorSize)
-							t.Type = SectorType.Mini;
-					}
-					else
-						t = availableSectors.Dequeue();
-
-					if (_isFatStream)
-						t.InitFATData();
-					_sectorChain.Add(t);
-					nSec--;
-				}
-			}
-		}
-
-		public override void SetLength(long value) => AdjustLength(value);
-
-		public override void Write(byte[] buffer, int offset, int count) => throw new NotImplementedException();
-	}
-
-	[Flags]
-	internal enum CFSConfiguration
-	{
-		Default = 1,
-		LeaveOpen = 16,
-	}
-
-	internal sealed class CompoundFile : IDisposable
-	{
-		public CFSConfiguration Configuration { get; private set; } = CFSConfiguration.Default;
-
-		internal int GetSectorSize() => 2 << (header.SectorShift - 1);
-
-		private const int HEADER_DIFAT_ENTRIES_COUNT = 109;
-		private readonly int DIFAT_SECTOR_FAT_ENTRIES_COUNT = 127;
-		private readonly int FAT_SECTOR_ENTRIES_COUNT = 128;
-		private const int SIZE_OF_SID = 4;
-		private const int FLUSHING_QUEUE_SIZE = 6000;
-		private const int FLUSHING_BUFFER_MAX_SIZE = 1024 * 1024 * 16;
-
-		private List<Sector> sectors = new List<Sector>();
-
-		private Header header;
-
-		internal Stream sourceStream = null;
-
-		public CompoundFile(Stream stream, CFSConfiguration configParameters)
-		{
-			this.closeStream = !configParameters.HasFlag(CFSConfiguration.LeaveOpen);
-
-			LoadStream(stream);
-
-			DIFAT_SECTOR_FAT_ENTRIES_COUNT = (GetSectorSize() / 4) - 1;
-			FAT_SECTOR_ENTRIES_COUNT = (GetSectorSize() / 4);
-		}
-
-		private string fileName = string.Empty;
-
-		private void Load(Stream stream)
-		{
-			try
-			{
-				this.header = new Header();
-				this.directoryEntries = new List<DirectoryEntry>();
-
-				this.sourceStream = stream;
-
-				header.Read(stream);
-
-				int n_sector = Ceiling(((stream.Length - GetSectorSize()) / (double)GetSectorSize()));
-
-				if (stream.Length > 0x7FFFFF0)
-					this._transactionLockAllocated = true;
-
-				sectors = new List<Sector>();
-				for (int i = 0; i < n_sector; i++)
-					sectors.Add(null);
-
-				LoadDirectories();
-
-				this.RootStorage = new CFStorage(this, directoryEntries[0]);
-			}
-			catch (Exception)
-			{
-				if (stream != null && closeStream)
-					stream.Dispose();
-				throw;
-			}
-		}
-
-		private void LoadFile(String fileName)
-		{
-			this.fileName = fileName;
-			FileStream fs = null;
-
-			try
-			{
-				fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
-				Load(fs);
-			}
-			catch
-			{
-				if (fs != null)
-					fs.Dispose();
-				throw;
-			}
-		}
-
-		private void LoadStream(Stream stream)
-		{
-			if (stream == null)
-				throw new Exception("Stream parameter cannot be null");
-			if (!stream.CanSeek)
-				throw new Exception("Cannot load a non-seekable Stream");
-			stream.Seek(0, SeekOrigin.Begin);
-			Load(stream);
-		}
-
-		public bool HasSourceStream => sourceStream != null;
-
-		private void PersistMiniStreamToStream(List<Sector> miniSectorChain)
-		{
-			List<Sector> miniStream = GetSectorChain(RootEntry.StartSetc, SectorType.Normal);
-
-			StreamView miniStreamView = new StreamView(miniStream, GetSectorSize(), this.RootStorage.Size, null, sourceStream);
-
-			for (int i = 0; i < miniSectorChain.Count; i++)
-			{
-				Sector s = miniSectorChain[i];
-
-				if (s.Id == -1)
-					throw new Exception("Invalid minisector index");
-
-				miniStreamView.Seek(Sector.MinisectorSize * s.Id, SeekOrigin.Begin);
-				miniStreamView.Write(s.GetData(), 0, Sector.MinisectorSize);
-			}
-		}
-
-		private void AllocateMiniSectorChain(List<Sector> sectorChain)
-		{
-			List<Sector> miniFAT = GetSectorChain(header.FirstMiniFATSectorID, SectorType.Normal);
-			List<Sector> miniStream = GetSectorChain(RootEntry.StartSetc, SectorType.Normal);
-
-			StreamView miniFATView = new StreamView(miniFAT, GetSectorSize(),
-				header.MiniFATSectorsNumber * Sector.MinisectorSize,
-				null, this.sourceStream, true);
-
-			StreamView miniStreamView = new StreamView(miniStream, GetSectorSize(),
-				this.RootStorage.Size, null, sourceStream);
-
-			for (int i = 0; i < sectorChain.Count; i++)
-			{
-				Sector s = sectorChain[i];
-
-				if (s.Id == -1)
-				{
-					miniStreamView.Seek(this.RootStorage.Size + Sector.MinisectorSize, SeekOrigin.Begin);
-					s.Id = (int)(miniStreamView.Position - Sector.MinisectorSize) / Sector.MinisectorSize;
-
-					this.RootStorage.DirEntry.Size = miniStreamView.Length;
-				}
-			}
-
-			for (int i = 0; i < sectorChain.Count - 1; i++)
-			{
-				Int32 currentId = sectorChain[i].Id;
-				Int32 nextId = sectorChain[i + 1].Id;
-
-				miniFATView.Seek(currentId * 4, SeekOrigin.Begin);
-				miniFATView.Write(BitConverter.GetBytes(nextId), 0, 4);
-			}
-
-			miniFATView.Seek(sectorChain[sectorChain.Count - 1].Id * SIZE_OF_SID, SeekOrigin.Begin);
-			miniFATView.Write(BitConverter.GetBytes(Sector.Endofchain), 0, 4);
-
-			AllocateSectorChain(miniStreamView.BaseSectorChain);
-			AllocateSectorChain(miniFATView.BaseSectorChain);
-
-			if (miniFAT.Count > 0)
-			{
-				this.RootStorage.DirEntry.StartSetc = miniStream[0].Id;
-				header.MiniFATSectorsNumber = (uint)miniFAT.Count;
-				header.FirstMiniFATSectorID = miniFAT[0].Id;
-			}
-		}
-
-		private void SetSectorChain(List<Sector> sectorChain)
-		{
-			if (sectorChain == null || sectorChain.Count == 0)
-				return;
-
-			SectorType _st = sectorChain[0].Type;
-
-			if (_st == SectorType.Normal)
-				AllocateSectorChain(sectorChain);
-			else if (_st == SectorType.Mini)
-				AllocateMiniSectorChain(sectorChain);
-		}
-
-		private void AllocateSectorChain(List<Sector> sectorChain)
-		{
-			foreach (Sector s in sectorChain)
-			{
-				if (s.Id == -1)
-				{
-					sectors.Add(s);
-					s.Id = sectors.Count - 1;
-				}
-			}
-
-			AllocateFATSectorChain(sectorChain);
-		}
-
-		internal bool _transactionLockAdded = false;
-		internal int _lockSectorId = -1;
-		internal bool _transactionLockAllocated = false;
-
-		private void CheckForLockSector()
-		{
-			if (_transactionLockAdded && !_transactionLockAllocated)
-			{
-				StreamView fatStream = new StreamView(GetFatSectorChain(), GetSectorSize(), sourceStream);
-
-				fatStream.Seek(_lockSectorId * 4, SeekOrigin.Begin);
-				fatStream.Write(BitConverter.GetBytes(Sector.Endofchain), 0, 4);
-
-				_transactionLockAllocated = true;
-			}
-		}
-
-		private void AllocateFATSectorChain(List<Sector> sectorChain)
-		{
-			List<Sector> fatSectors = GetSectorChain(-1, SectorType.FAT);
-
-			StreamView fatStream = new StreamView(fatSectors, GetSectorSize(),
-				header.FATSectorsNumber * GetSectorSize(), null,
-				sourceStream, true);
-
-			for (int i = 0; i < sectorChain.Count - 1; i++)
-			{
-				Sector sN = sectorChain[i + 1];
-				Sector sC = sectorChain[i];
-
-				fatStream.Seek(sC.Id * 4, SeekOrigin.Begin);
-				fatStream.Write(BitConverter.GetBytes(sN.Id), 0, 4);
-			}
-
-			fatStream.Seek(sectorChain[sectorChain.Count - 1].Id * 4, SeekOrigin.Begin);
-			fatStream.Write(BitConverter.GetBytes(Sector.Endofchain), 0, 4);
-
-			AllocateDIFATSectorChain(fatStream.BaseSectorChain);
-		}
-
-		private void AllocateDIFATSectorChain(List<Sector> FATsectorChain)
-		{
-			header.FATSectorsNumber = FATsectorChain.Count;
-
-			foreach (Sector s in FATsectorChain)
-			{
-				if (s.Id == -1)
-				{
-					sectors.Add(s);
-					s.Id = sectors.Count - 1;
-					s.Type = SectorType.FAT;
-				}
-			}
-
-			int nCurrentSectors = sectors.Count;
-
-			int nDIFATSectors = (int)header.DIFATSectorsNumber;
-
-			if (FATsectorChain.Count > HEADER_DIFAT_ENTRIES_COUNT)
-			{
-				nDIFATSectors = Ceiling((double)(FATsectorChain.Count - HEADER_DIFAT_ENTRIES_COUNT) / DIFAT_SECTOR_FAT_ENTRIES_COUNT);
-				nDIFATSectors = LowSaturation(nDIFATSectors - (int)header.DIFATSectorsNumber); //required DIFAT
-			}
-
-			nCurrentSectors += nDIFATSectors;
-
-			while (header.FATSectorsNumber * FAT_SECTOR_ENTRIES_COUNT < nCurrentSectors)
-			{
-				Sector extraFATSector = new Sector(GetSectorSize(), sourceStream);
-				sectors.Add(extraFATSector);
-
-				extraFATSector.Id = sectors.Count - 1;
-				extraFATSector.Type = SectorType.FAT;
-
-				FATsectorChain.Add(extraFATSector);
-
-				header.FATSectorsNumber++;
-				nCurrentSectors++;
-
-				if (nDIFATSectors * DIFAT_SECTOR_FAT_ENTRIES_COUNT <
-					(header.FATSectorsNumber > HEADER_DIFAT_ENTRIES_COUNT ?
-						header.FATSectorsNumber - HEADER_DIFAT_ENTRIES_COUNT :
-						0))
-				{
-					nDIFATSectors++;
-					nCurrentSectors++;
-				}
-			}
-
-			List<Sector> difatSectors = GetSectorChain(-1, SectorType.DIFAT);
-			StreamView difatStream = new StreamView(difatSectors, GetSectorSize(), sourceStream);
-
-			for (int i = 0; i < FATsectorChain.Count; i++)
-			{
-				if (i < HEADER_DIFAT_ENTRIES_COUNT)
-					header.DIFAT[i] = FATsectorChain[i].Id;
-				else
-				{
-					if (i != HEADER_DIFAT_ENTRIES_COUNT && (i - HEADER_DIFAT_ENTRIES_COUNT) % DIFAT_SECTOR_FAT_ENTRIES_COUNT == 0)
-					{
-						difatStream.Write(new byte[sizeof(int)], 0, sizeof(int));
-					}
-
-					difatStream.Write(BitConverter.GetBytes(FATsectorChain[i].Id), 0, sizeof(int));
-				}
-			}
-
-			for (int i = 0; i < difatStream.BaseSectorChain.Count; i++)
-			{
-				if (difatStream.BaseSectorChain[i].Id == -1)
-				{
-					sectors.Add(difatStream.BaseSectorChain[i]);
-					difatStream.BaseSectorChain[i].Id = sectors.Count - 1;
-					difatStream.BaseSectorChain[i].Type = SectorType.DIFAT;
-				}
-			}
-
-			header.DIFATSectorsNumber = (uint)nDIFATSectors;
-
-			if (difatStream.BaseSectorChain != null && difatStream.BaseSectorChain.Count > 0)
-			{
-				header.FirstDIFATSectorID = difatStream.BaseSectorChain[0].Id;
-				header.DIFATSectorsNumber = (uint)difatStream.BaseSectorChain.Count;
-
-				for (int i = 0; i < difatStream.BaseSectorChain.Count - 1; i++)
-					Buffer.BlockCopy(BitConverter.GetBytes(difatStream.BaseSectorChain[i + 1].Id),
-						0, difatStream.BaseSectorChain[i].GetData(),
-						GetSectorSize() - sizeof(int), 4);
-
-				Buffer.BlockCopy(BitConverter.GetBytes(Sector.Endofchain), 0,
-					difatStream.BaseSectorChain[difatStream.BaseSectorChain.Count - 1].GetData(),
-					GetSectorSize() - sizeof(int), sizeof(int));
-			}
-			else header.FirstDIFATSectorID = Sector.Endofchain;
-
-			StreamView fatSv = new StreamView(FATsectorChain, GetSectorSize(), header.FATSectorsNumber * GetSectorSize(), null, sourceStream);
-
-			for (int i = 0; i < header.DIFATSectorsNumber; i++)
-			{
-				fatSv.Seek(difatStream.BaseSectorChain[i].Id * 4, SeekOrigin.Begin);
-				fatSv.Write(BitConverter.GetBytes(Sector.Difsect), 0, 4);
-			}
-
-			for (int i = 0; i < header.FATSectorsNumber; i++)
-			{
-				fatSv.Seek(fatSv.BaseSectorChain[i].Id * 4, SeekOrigin.Begin);
-				fatSv.Write(BitConverter.GetBytes(Sector.Fatsect), 0, 4);
-			}
-
-			header.FATSectorsNumber = fatSv.BaseSectorChain.Count;
-		}
-
-		private List<Sector> GetDifatSectorChain()
-		{
-			int validationCount = 0;
-
-			List<Sector> result = new List<Sector>();
-
-			int nextSecID
-				= Sector.Endofchain;
-
-			if (header.DIFATSectorsNumber != 0)
-			{
-				validationCount = (int)header.DIFATSectorsNumber;
-
-				Sector s = sectors[header.FirstDIFATSectorID];
-
-				if (s == null)
-				{
-					sectors[header.FirstDIFATSectorID] = s = new Sector(GetSectorSize(), sourceStream)
-					{
-						Type = SectorType.DIFAT,
-						Id = header.FirstDIFATSectorID
-					};
-				}
-
-				result.Add(s);
-
-				while (true && validationCount >= 0)
-				{
-					nextSecID = BitConverter.ToInt32(s.GetData(), GetSectorSize() - 4);
-
-					if (nextSecID == Sector.Freesect || nextSecID == Sector.Endofchain) break;
-
-					validationCount--;
-
-					if (validationCount < 0)
-					{
-						Dispose();
-						throw new InvalidDataException("DIFAT sectors count mismatched. Corrupted compound file");
-					}
-
-					s = sectors[nextSecID];
-
-					if (s == null)
-						sectors[nextSecID] = s = new Sector(GetSectorSize(), sourceStream) { Id = nextSecID };
-
-					result.Add(s);
-				}
-			}
-
-			return result;
-		}
-
-		private List<Sector> GetFatSectorChain()
-		{
-			int N_HEADER_FAT_ENTRY = 109;
-
-			List<Sector> result = new List<Sector>();
-			int nextSecID = Sector.Endofchain;
-			List<Sector> difatSectors = GetDifatSectorChain();
-
-			int idx = 0;
-			while (idx < header.FATSectorsNumber && idx < N_HEADER_FAT_ENTRY)
-			{
-				nextSecID = header.DIFAT[idx];
-				Sector s = sectors[nextSecID];
-
-				if (s == null)
-				{
-					sectors[nextSecID] = s = new Sector(GetSectorSize(), sourceStream)
-					{
-						Id = nextSecID,
-						Type = SectorType.FAT
-					};
-				}
-
-				result.Add(s);
-				++idx;
-			}
-
-			if (difatSectors.Count > 0)
-			{
-				var difatStream = new StreamView(difatSectors, GetSectorSize(),
-					header.FATSectorsNumber > N_HEADER_FAT_ENTRY ? (header.FATSectorsNumber - N_HEADER_FAT_ENTRY) * 4 : 0,
-					null, sourceStream);
-
-				byte[] nextDIFATSectorBuffer = new byte[4];
-				difatStream.Read(nextDIFATSectorBuffer, 0, 4);
-				nextSecID = BitConverter.ToInt32(nextDIFATSectorBuffer, 0);
-
-				int i = 0;
-				int nFat = N_HEADER_FAT_ENTRY;
-
-				while (nFat < header.FATSectorsNumber)
-				{
-					if (difatStream.Position == ((GetSectorSize() - 4) + i * GetSectorSize()))
-					{
-						difatStream.Seek(4, SeekOrigin.Current);
-						++i;
-						continue;
-					}
+    internal sealed class StreamView : Stream
+    {
+        private readonly int _sectorSize;
+        private long _position;
+
+        private readonly List<Sector> _sectorChain;
+        private readonly Stream _stream;
+        private readonly bool _isFatStream = false;
+        private readonly List<Sector> _freeSectors = new List<Sector>();
+
+        public IEnumerable<Sector> FreeSectors => _freeSectors;
+
+        public StreamView(List<Sector> sectorChain, int sectorSize, Stream stream)
+        {
+            if (sectorSize <= 0)
+                throw new Exception("Sector size must be greater than zero");
+
+            this._sectorChain = sectorChain ?? throw new Exception("Sector Chain cannot be null");
+            this._sectorSize = sectorSize;
+            this._stream = stream;
+        }
+
+        public StreamView(List<Sector> sectorChain, int sectorSize, long length, Queue<Sector> availableSectors, Stream stream, bool isFatStream = false)
+            : this(sectorChain, sectorSize, stream)
+        {
+            this._isFatStream = isFatStream;
+            AdjustLength(length, availableSectors);
+        }
+
+        public List<Sector> BaseSectorChain => _sectorChain;
+
+        public override bool CanRead => true;
+
+        public override bool CanSeek => true;
+
+        public override bool CanWrite => true;
+
+        public override void Flush()
+        { }
+
+        private long _length;
+
+        public override long Length => _length;
+
+        public override long Position
+        {
+            get => _position;
+
+            set
+            {
+                if (_position > _length - 1)
+                    throw new ArgumentOutOfRangeException("value");
+                _position = value;
+            }
+        }
+
+        private byte[] buf = new byte[4];
+
+        public int ReadInt32()
+        {
+            this.Read(buf, 0, 4);
+            return (((buf[0] | (buf[1] << 8)) | (buf[2] << 16)) | (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 / _sectorSize);
+
+                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, Queue<Sector> availableSectors = null)
+        {
+            this._length = value;
+            long delta = value - (_sectorChain.Count * (long)_sectorSize);
+
+            if (delta > 0)
+            {
+                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.MinisectorSize)
+                            t.Type = SectorType.Mini;
+                    }
+                    else
+                        t = availableSectors.Dequeue();
+
+                    if (_isFatStream)
+                        t.InitFATData();
+                    _sectorChain.Add(t);
+                    nSec--;
+                }
+            }
+        }
+
+        public override void SetLength(long value) => AdjustLength(value);
+
+        public override void Write(byte[] buffer, int offset, int count) => throw new NotImplementedException();
+    }
+
+    [Flags]
+    internal enum CFSConfiguration
+    {
+        Default = 1,
+        LeaveOpen = 16,
+    }
+
+    internal sealed class CompoundFile : IDisposable
+    {
+        public CFSConfiguration Configuration { get; private set; } = CFSConfiguration.Default;
+
+        internal int GetSectorSize() => 2 << (header.SectorShift - 1);
+
+        private const int HEADER_DIFAT_ENTRIES_COUNT = 109;
+        private readonly int DIFAT_SECTOR_FAT_ENTRIES_COUNT = 127;
+        private readonly int FAT_SECTOR_ENTRIES_COUNT = 128;
+        private const int SIZE_OF_SID = 4;
+        private const int FLUSHING_QUEUE_SIZE = 6000;
+        private const int FLUSHING_BUFFER_MAX_SIZE = 1024 * 1024 * 16;
+
+        private List<Sector> sectors = new List<Sector>();
+
+        private Header header;
+
+        internal Stream sourceStream = null;
+
+        public CompoundFile(Stream stream, CFSConfiguration configParameters)
+        {
+            this.closeStream = !configParameters.HasFlag(CFSConfiguration.LeaveOpen);
+
+            LoadStream(stream);
+
+            DIFAT_SECTOR_FAT_ENTRIES_COUNT = (GetSectorSize() / 4) - 1;
+            FAT_SECTOR_ENTRIES_COUNT = (GetSectorSize() / 4);
+        }
+
+        private string fileName = string.Empty;
+
+        private void Load(Stream stream)
+        {
+            try
+            {
+                this.header = new Header();
+                this.directoryEntries = new List<DirectoryEntry>();
+
+                this.sourceStream = stream;
+
+                header.Read(stream);
+
+                int n_sector = Ceiling(((stream.Length - GetSectorSize()) / (double)GetSectorSize()));
+
+                if (stream.Length > 0x7FFFFF0)
+                    this._transactionLockAllocated = true;
+
+                sectors = new List<Sector>();
+                for (int i = 0; i < n_sector; i++)
+                    sectors.Add(null);
+
+                LoadDirectories();
+
+                this.RootStorage = new CFStorage(this, directoryEntries[0]);
+            }
+            catch (Exception)
+            {
+                if (stream != null && closeStream)
+                    stream.Dispose();
+                throw;
+            }
+        }
+
+        private void LoadFile(String fileName)
+        {
+            this.fileName = fileName;
+            FileStream fs = null;
+
+            try
+            {
+                fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+                Load(fs);
+            }
+            catch
+            {
+                if (fs != null)
+                    fs.Dispose();
+                throw;
+            }
+        }
+
+        private void LoadStream(Stream stream)
+        {
+            if (stream == null)
+                throw new Exception("Stream parameter cannot be null");
+            if (!stream.CanSeek)
+                throw new Exception("Cannot load a non-seekable Stream");
+            stream.Seek(0, SeekOrigin.Begin);
+            Load(stream);
+        }
+
+        public bool HasSourceStream => sourceStream != null;
+
+        private void PersistMiniStreamToStream(List<Sector> miniSectorChain)
+        {
+            List<Sector> miniStream = GetSectorChain(RootEntry.StartSetc, SectorType.Normal);
+
+            StreamView miniStreamView = new StreamView(miniStream, GetSectorSize(), this.RootStorage.Size, null, sourceStream);
+
+            for (int i = 0; i < miniSectorChain.Count; i++)
+            {
+                Sector s = miniSectorChain[i];
+
+                if (s.Id == -1)
+                    throw new Exception("Invalid minisector index");
+
+                miniStreamView.Seek(Sector.MinisectorSize * s.Id, SeekOrigin.Begin);
+                miniStreamView.Write(s.GetData(), 0, Sector.MinisectorSize);
+            }
+        }
+
+        private void AllocateMiniSectorChain(List<Sector> sectorChain)
+        {
+            List<Sector> miniFAT = GetSectorChain(header.FirstMiniFATSectorID, SectorType.Normal);
+            List<Sector> miniStream = GetSectorChain(RootEntry.StartSetc, SectorType.Normal);
+
+            StreamView miniFATView = new StreamView(miniFAT, GetSectorSize(),
+                header.MiniFATSectorsNumber * Sector.MinisectorSize,
+                null, this.sourceStream, true);
+
+            StreamView miniStreamView = new StreamView(miniStream, GetSectorSize(),
+                this.RootStorage.Size, null, sourceStream);
+
+            for (int i = 0; i < sectorChain.Count; i++)
+            {
+                Sector s = sectorChain[i];
+
+                if (s.Id == -1)
+                {
+                    miniStreamView.Seek(this.RootStorage.Size + Sector.MinisectorSize, SeekOrigin.Begin);
+                    s.Id = (int)(miniStreamView.Position - Sector.MinisectorSize) / Sector.MinisectorSize;
+
+                    this.RootStorage.DirEntry.Size = miniStreamView.Length;
+                }
+            }
+
+            for (int i = 0; i < sectorChain.Count - 1; i++)
+            {
+                Int32 currentId = sectorChain[i].Id;
+                Int32 nextId = sectorChain[i + 1].Id;
+
+                miniFATView.Seek(currentId * 4, SeekOrigin.Begin);
+                miniFATView.Write(BitConverter.GetBytes(nextId), 0, 4);
+            }
+
+            miniFATView.Seek(sectorChain[sectorChain.Count - 1].Id * SIZE_OF_SID, SeekOrigin.Begin);
+            miniFATView.Write(BitConverter.GetBytes(Sector.Endofchain), 0, 4);
+
+            AllocateSectorChain(miniStreamView.BaseSectorChain);
+            AllocateSectorChain(miniFATView.BaseSectorChain);
+
+            if (miniFAT.Count > 0)
+            {
+                this.RootStorage.DirEntry.StartSetc = miniStream[0].Id;
+                header.MiniFATSectorsNumber = (uint)miniFAT.Count;
+                header.FirstMiniFATSectorID = miniFAT[0].Id;
+            }
+        }
+
+        private void SetSectorChain(List<Sector> sectorChain)
+        {
+            if (sectorChain == null || sectorChain.Count == 0)
+                return;
+
+            SectorType _st = sectorChain[0].Type;
+
+            if (_st == SectorType.Normal)
+                AllocateSectorChain(sectorChain);
+            else if (_st == SectorType.Mini)
+                AllocateMiniSectorChain(sectorChain);
+        }
+
+        private void AllocateSectorChain(List<Sector> sectorChain)
+        {
+            foreach (Sector s in sectorChain)
+            {
+                if (s.Id == -1)
+                {
+                    sectors.Add(s);
+                    s.Id = sectors.Count - 1;
+                }
+            }
+
+            AllocateFATSectorChain(sectorChain);
+        }
+
+        internal bool _transactionLockAdded = false;
+        internal int _lockSectorId = -1;
+        internal bool _transactionLockAllocated = false;
+
+        private void CheckForLockSector()
+        {
+            if (_transactionLockAdded && !_transactionLockAllocated)
+            {
+                StreamView fatStream = new StreamView(GetFatSectorChain(), GetSectorSize(), sourceStream);
+
+                fatStream.Seek(_lockSectorId * 4, SeekOrigin.Begin);
+                fatStream.Write(BitConverter.GetBytes(Sector.Endofchain), 0, 4);
+
+                _transactionLockAllocated = true;
+            }
+        }
+
+        private void AllocateFATSectorChain(List<Sector> sectorChain)
+        {
+            List<Sector> fatSectors = GetSectorChain(-1, SectorType.FAT);
+
+            StreamView fatStream = new StreamView(fatSectors, GetSectorSize(),
+                header.FATSectorsNumber * GetSectorSize(), null,
+                sourceStream, true);
+
+            for (int i = 0; i < sectorChain.Count - 1; i++)
+            {
+                Sector sN = sectorChain[i + 1];
+                Sector sC = sectorChain[i];
+
+                fatStream.Seek(sC.Id * 4, SeekOrigin.Begin);
+                fatStream.Write(BitConverter.GetBytes(sN.Id), 0, 4);
+            }
+
+            fatStream.Seek(sectorChain[sectorChain.Count - 1].Id * 4, SeekOrigin.Begin);
+            fatStream.Write(BitConverter.GetBytes(Sector.Endofchain), 0, 4);
+
+            AllocateDIFATSectorChain(fatStream.BaseSectorChain);
+        }
+
+        private void AllocateDIFATSectorChain(List<Sector> FATsectorChain)
+        {
+            header.FATSectorsNumber = FATsectorChain.Count;
+
+            foreach (Sector s in FATsectorChain)
+            {
+                if (s.Id == -1)
+                {
+                    sectors.Add(s);
+                    s.Id = sectors.Count - 1;
+                    s.Type = SectorType.FAT;
+                }
+            }
+
+            int nCurrentSectors = sectors.Count;
+
+            int nDIFATSectors = (int)header.DIFATSectorsNumber;
+
+            if (FATsectorChain.Count > HEADER_DIFAT_ENTRIES_COUNT)
+            {
+                nDIFATSectors = Ceiling((double)(FATsectorChain.Count - HEADER_DIFAT_ENTRIES_COUNT) / DIFAT_SECTOR_FAT_ENTRIES_COUNT);
+                nDIFATSectors = LowSaturation(nDIFATSectors - (int)header.DIFATSectorsNumber); //required DIFAT
+            }
+
+            nCurrentSectors += nDIFATSectors;
+
+            while (header.FATSectorsNumber * FAT_SECTOR_ENTRIES_COUNT < nCurrentSectors)
+            {
+                Sector extraFATSector = new Sector(GetSectorSize(), sourceStream);
+                sectors.Add(extraFATSector);
+
+                extraFATSector.Id = sectors.Count - 1;
+                extraFATSector.Type = SectorType.FAT;
+
+                FATsectorChain.Add(extraFATSector);
+
+                header.FATSectorsNumber++;
+                nCurrentSectors++;
+
+                if (nDIFATSectors * DIFAT_SECTOR_FAT_ENTRIES_COUNT <
+                    (header.FATSectorsNumber > HEADER_DIFAT_ENTRIES_COUNT ?
+                        header.FATSectorsNumber - HEADER_DIFAT_ENTRIES_COUNT :
+                        0))
+                {
+                    nDIFATSectors++;
+                    nCurrentSectors++;
+                }
+            }
+
+            List<Sector> difatSectors = GetSectorChain(-1, SectorType.DIFAT);
+            StreamView difatStream = new StreamView(difatSectors, GetSectorSize(), sourceStream);
+
+            for (int i = 0; i < FATsectorChain.Count; i++)
+            {
+                if (i < HEADER_DIFAT_ENTRIES_COUNT)
+                    header.DIFAT[i] = FATsectorChain[i].Id;
+                else
+                {
+                    if (i != HEADER_DIFAT_ENTRIES_COUNT && (i - HEADER_DIFAT_ENTRIES_COUNT) % DIFAT_SECTOR_FAT_ENTRIES_COUNT == 0)
+                    {
+                        difatStream.Write(new byte[sizeof(int)], 0, sizeof(int));
+                    }
+
+                    difatStream.Write(BitConverter.GetBytes(FATsectorChain[i].Id), 0, sizeof(int));
+                }
+            }
+
+            for (int i = 0; i < difatStream.BaseSectorChain.Count; i++)
+            {
+                if (difatStream.BaseSectorChain[i].Id == -1)
+                {
+                    sectors.Add(difatStream.BaseSectorChain[i]);
+                    difatStream.BaseSectorChain[i].Id = sectors.Count - 1;
+                    difatStream.BaseSectorChain[i].Type = SectorType.DIFAT;
+                }
+            }
+
+            header.DIFATSectorsNumber = (uint)nDIFATSectors;
+
+            if (difatStream.BaseSectorChain != null && difatStream.BaseSectorChain.Count > 0)
+            {
+                header.FirstDIFATSectorID = difatStream.BaseSectorChain[0].Id;
+                header.DIFATSectorsNumber = (uint)difatStream.BaseSectorChain.Count;
+
+                for (int i = 0; i < difatStream.BaseSectorChain.Count - 1; i++)
+                    Buffer.BlockCopy(BitConverter.GetBytes(difatStream.BaseSectorChain[i + 1].Id),
+                        0, difatStream.BaseSectorChain[i].GetData(),
+                        GetSectorSize() - sizeof(int), 4);
+
+                Buffer.BlockCopy(BitConverter.GetBytes(Sector.Endofchain), 0,
+                    difatStream.BaseSectorChain[difatStream.BaseSectorChain.Count - 1].GetData(),
+                    GetSectorSize() - sizeof(int), sizeof(int));
+            }
+            else header.FirstDIFATSectorID = Sector.Endofchain;
+
+            StreamView fatSv = new StreamView(FATsectorChain, GetSectorSize(), header.FATSectorsNumber * GetSectorSize(), null, sourceStream);
+
+            for (int i = 0; i < header.DIFATSectorsNumber; i++)
+            {
+                fatSv.Seek(difatStream.BaseSectorChain[i].Id * 4, SeekOrigin.Begin);
+                fatSv.Write(BitConverter.GetBytes(Sector.Difsect), 0, 4);
+            }
+
+            for (int i = 0; i < header.FATSectorsNumber; i++)
+            {
+                fatSv.Seek(fatSv.BaseSectorChain[i].Id * 4, SeekOrigin.Begin);
+                fatSv.Write(BitConverter.GetBytes(Sector.Fatsect), 0, 4);
+            }
+
+            header.FATSectorsNumber = fatSv.BaseSectorChain.Count;
+        }
+
+        private List<Sector> GetDifatSectorChain()
+        {
+            int validationCount = 0;
+
+            List<Sector> result = new List<Sector>();
+
+            int nextSecID
+                = Sector.Endofchain;
+
+            if (header.DIFATSectorsNumber != 0)
+            {
+                validationCount = (int)header.DIFATSectorsNumber;
+
+                Sector s = sectors[header.FirstDIFATSectorID];
+
+                if (s == null)
+                {
+                    sectors[header.FirstDIFATSectorID] = s = new Sector(GetSectorSize(), sourceStream)
+                    {
+                        Type = SectorType.DIFAT,
+                        Id = header.FirstDIFATSectorID
+                    };
+                }
+
+                result.Add(s);
+
+                while (true && validationCount >= 0)
+                {
+                    nextSecID = BitConverter.ToInt32(s.GetData(), GetSectorSize() - 4);
+
+                    if (nextSecID == Sector.Freesect || nextSecID == Sector.Endofchain) break;
+
+                    validationCount--;
+
+                    if (validationCount < 0)
+                    {
+                        Dispose();
+                        throw new InvalidDataException("DIFAT sectors count mismatched. Corrupted compound file");
+                    }
+
+                    s = sectors[nextSecID];
+
+                    if (s == null)
+                        sectors[nextSecID] = s = new Sector(GetSectorSize(), sourceStream) { Id = nextSecID };
+
+                    result.Add(s);
+                }
+            }
+
+            return result;
+        }
+
+        private List<Sector> GetFatSectorChain()
+        {
+            int N_HEADER_FAT_ENTRY = 109;
+
+            List<Sector> result = new List<Sector>();
+            int nextSecID = Sector.Endofchain;
+            List<Sector> difatSectors = GetDifatSectorChain();
+
+            int idx = 0;
+            while (idx < header.FATSectorsNumber && idx < N_HEADER_FAT_ENTRY)
+            {
+                nextSecID = header.DIFAT[idx];
+                Sector s = sectors[nextSecID];
+
+                if (s == null)
+                {
+                    sectors[nextSecID] = s = new Sector(GetSectorSize(), sourceStream)
+                    {
+                        Id = nextSecID,
+                        Type = SectorType.FAT
+                    };
+                }
+
+                result.Add(s);
+                ++idx;
+            }
+
+            if (difatSectors.Count > 0)
+            {
+                var difatStream = new StreamView(difatSectors, GetSectorSize(),
+                    header.FATSectorsNumber > N_HEADER_FAT_ENTRY ? (header.FATSectorsNumber - N_HEADER_FAT_ENTRY) * 4 : 0,
+                    null, sourceStream);
+
+                byte[] nextDIFATSectorBuffer = new byte[4];
+                difatStream.Read(nextDIFATSectorBuffer, 0, 4);
+                nextSecID = BitConverter.ToInt32(nextDIFATSectorBuffer, 0);
+
+                int i = 0;
+                int nFat = N_HEADER_FAT_ENTRY;
+
+                while (nFat < header.FATSectorsNumber)
+                {
+                    if (difatStream.Position == ((GetSectorSize() - 4) + i * GetSectorSize()))
+                    {
+                        difatStream.Seek(4, SeekOrigin.Current);
+                        ++i;
+                        continue;
+                    }
 
-					Sector s = sectors[nextSecID];
+                    Sector s = sectors[nextSecID];
 
-					if (s == null)
-					{
-						sectors[nextSecID] = s = new Sector(GetSectorSize(), sourceStream)
-						{
-							Type = SectorType.FAT,
-							Id = nextSecID
-						};
-					}
-
-					result.Add(s);
-
-					difatStream.Read(nextDIFATSectorBuffer, 0, 4);
-					nextSecID = BitConverter.ToInt32(nextDIFATSectorBuffer, 0);
-					nFat++;
-				}
-			}
-			return result;
-		}
+                    if (s == null)
+                    {
+                        sectors[nextSecID] = s = new Sector(GetSectorSize(), sourceStream)
+                        {
+                            Type = SectorType.FAT,
+                            Id = nextSecID
+                        };
+                    }
+
+                    result.Add(s);
+
+                    difatStream.Read(nextDIFATSectorBuffer, 0, 4);
+                    nextSecID = BitConverter.ToInt32(nextDIFATSectorBuffer, 0);
+                    nFat++;
+                }
+            }
+            return result;
+        }
 
-		private List<Sector> GetNormalSectorChain(int secID)
-		{
-			List<Sector> result = new List<Sector>();
-
-			int nextSecID = secID;
-
-			List<Sector> fatSectors = GetFatSectorChain();
+        private List<Sector> GetNormalSectorChain(int secID)
+        {
+            List<Sector> result = new List<Sector>();
+
+            int nextSecID = secID;
+
+            List<Sector> fatSectors = GetFatSectorChain();
 
-			var fatStream = new StreamView(fatSectors, GetSectorSize(), fatSectors.Count * GetSectorSize(), null, sourceStream);
+            var fatStream = new StreamView(fatSectors, GetSectorSize(), fatSectors.Count * GetSectorSize(), null, sourceStream);
 
-			while (true)
-			{
-				if (nextSecID == Sector.Endofchain) break;
-
-				if (nextSecID < 0)
-					throw new InvalidDataException(String.Format("Next Sector ID reference is below zero. NextID : {0}", nextSecID));
-
-				if (nextSecID >= sectors.Count)
-					throw new InvalidDataException(String.Format("Next Sector ID reference an out of range sector. NextID : {0} while sector count {1}", nextSecID, sectors.Count));
-
-				Sector s = sectors[nextSecID];
-				if (s == null)
-				{
-					sectors[nextSecID] = s = new Sector(GetSectorSize(), sourceStream)
-					{
-						Id = nextSecID,
-						Type = SectorType.Normal
-					};
-				}
-
-				result.Add(s);
-
-				fatStream.Seek(nextSecID * 4, SeekOrigin.Begin);
-				int next = fatStream.ReadInt32();
-
-				if (next != nextSecID)
-					nextSecID = next;
-				else
-					throw new InvalidDataException("Cyclic sector chain found. File is corrupted");
-			}
-
-			return result;
-		}
-
-		private List<Sector> GetMiniSectorChain(int secID)
-		{
-			List<Sector> result = new List<Sector>();
-
-			if (secID != Sector.Endofchain)
-			{
-				int nextSecID = secID;
-
-				List<Sector> miniFAT = GetNormalSectorChain(header.FirstMiniFATSectorID);
-				List<Sector> miniStream = GetNormalSectorChain(RootEntry.StartSetc);
-
-				StreamView miniFATView = new StreamView(miniFAT, GetSectorSize(), header.MiniFATSectorsNumber * Sector.MinisectorSize, null, sourceStream);
-				StreamView miniStreamView = new StreamView(miniStream, GetSectorSize(), RootStorage.Size, null, sourceStream);
-				BinaryReader miniFATReader = new BinaryReader(miniFATView);
-
-				nextSecID = secID;
-
-				while (true)
-				{
-					if (nextSecID == Sector.Endofchain)
-						break;
-
-					Sector ms = new Sector(Sector.MinisectorSize, sourceStream);
-					byte[] temp = new byte[Sector.MinisectorSize];
-
-					ms.Id = nextSecID;
-					ms.Type = SectorType.Mini;
-
-					miniStreamView.Seek(nextSecID * Sector.MinisectorSize, SeekOrigin.Begin);
-					miniStreamView.Read(ms.GetData(), 0, Sector.MinisectorSize);
-
-					result.Add(ms);
-
-					miniFATView.Seek(nextSecID * 4, SeekOrigin.Begin);
-					nextSecID = miniFATReader.ReadInt32();
-				}
-			}
-			return result;
-		}
-
-		internal List<Sector> GetSectorChain(int secID, SectorType chainType)
-		{
-			switch (chainType)
-			{
-				case SectorType.DIFAT:
-					return GetDifatSectorChain();
-
-				case SectorType.FAT:
-					return GetFatSectorChain();
-
-				case SectorType.Normal:
-					return GetNormalSectorChain(secID);
-
-				case SectorType.Mini:
-					return GetMiniSectorChain(secID);
-
-				default:
-					throw new Exception("Unsupproted chain type");
-			}
-		}
-
-		public CFStorage RootStorage { get; private set; }
-
-		public int Version => this.header.MajorVersion;
-
-		internal RBTree CreateNewTree()
-		{
-			RBTree bst = new RBTree();
-			return bst;
-		}
-
-		internal RBTree GetChildrenTree(int sid)
-		{
-			RBTree bst = new RBTree();
-			DoLoadChildren(bst, directoryEntries[sid]);
-			return bst;
-		}
-
-		private RBTree DoLoadChildrenTrusted(DirectoryEntry de)
-		{
-			RBTree bst = null;
-			if (de.Child != DirectoryEntry.NOSTREAM)
-				bst = new RBTree(directoryEntries[de.Child]);
-			return bst;
-		}
-
-		private void DoLoadChildren(RBTree bst, DirectoryEntry de)
-		{
-			if (de.Child != DirectoryEntry.NOSTREAM)
-			{
-				if (directoryEntries[de.Child].StgType == StgType.StgInvalid) return;
-
-				LoadSiblings(bst, directoryEntries[de.Child]);
-				NullifyChildNodes(directoryEntries[de.Child]);
-				bst.Insert(directoryEntries[de.Child]);
-			}
-		}
-
-		private void NullifyChildNodes(DirectoryEntry de)
-		{
-			de.Parent = null;
-			de.Left = null;
-			de.Right = null;
-		}
-
-		private readonly List<int> _levelSiDs = new List<int>();
-
-		private void LoadSiblings(RBTree bst, DirectoryEntry de)
-		{
-			_levelSiDs.Clear();
-
-			if (de.LeftSibling != DirectoryEntry.NOSTREAM)
-				DoLoadSiblings(bst, directoryEntries[de.LeftSibling]);
-
-			if (de.RightSibling != DirectoryEntry.NOSTREAM)
-			{
-				_levelSiDs.Add(de.RightSibling);
-				DoLoadSiblings(bst, directoryEntries[de.RightSibling]);
-			}
-		}
-
-		private void DoLoadSiblings(RBTree bst, DirectoryEntry de)
-		{
-			if (ValidateSibling(de.LeftSibling))
-			{
-				_levelSiDs.Add(de.LeftSibling);
-				DoLoadSiblings(bst, directoryEntries[de.LeftSibling]);
-			}
-
-			if (ValidateSibling(de.RightSibling))
-			{
-				_levelSiDs.Add(de.RightSibling);
-				DoLoadSiblings(bst, directoryEntries[de.RightSibling]);
-			}
-
-			NullifyChildNodes(de);
-			bst.Insert(de);
-		}
-
-		private bool ValidateSibling(int sid)
-		{
-			if (sid != DirectoryEntry.NOSTREAM)
-			{
-				if (sid >= directoryEntries.Count)
-					return false;
-
-				if (directoryEntries[sid].StgType == StgType.StgInvalid)
-					return false;
-
-				if (!Enum.IsDefined(typeof(StgType), directoryEntries[sid].StgType))
-					return false;
-
-				if (_levelSiDs.Contains(sid))
-					throw new InvalidDataException("Cyclic reference of directory item");
-
-				return true;
-			}
-
-			return false;
-		}
-
-		private void LoadDirectories()
-		{
-			List<Sector> directoryChain = GetSectorChain(header.FirstDirectorySectorID, SectorType.Normal);
-
-			if (header.FirstDirectorySectorID == Sector.Endofchain)
-				header.FirstDirectorySectorID = directoryChain[0].Id;
-
-			StreamView dirReader = new StreamView(directoryChain, GetSectorSize(), directoryChain.Count * GetSectorSize(), null, sourceStream);
-
-			while (dirReader.Position < directoryChain.Count * GetSectorSize())
-			{
-				DirectoryEntry de = DirectoryEntry.New(String.Empty, StgType.StgInvalid, directoryEntries);
-				de.Read(dirReader, this.Version);
-			}
-		}
-
-		private void CheckFileLength() => throw new NotImplementedException();
-
-		internal int ReadData(CFStream cFStream, long position, byte[] buffer, int count)
-		{
-			if (count > buffer.Length)
-				throw new ArgumentException("count parameter exceeds buffer size");
-
-			DirectoryEntry de = cFStream.DirEntry;
-
-			count = (int)Math.Min(de.Size - position, count);
-
-			StreamView sView = null;
-			if (de.Size < header.MinSizeStandardStream)
-				sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Mini), Sector.MinisectorSize, de.Size, null, sourceStream);
-			else
-				sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Normal), GetSectorSize(), de.Size, null, sourceStream);
-
-			sView.Seek(position, SeekOrigin.Begin);
-			int result = sView.Read(buffer, 0, count);
-
-			return result;
-		}
-
-		internal int ReadData(CFStream cFStream, long position, byte[] buffer, int offset, int count)
-		{
-			DirectoryEntry de = cFStream.DirEntry;
-
-			count = (int)Math.Min(de.Size - offset, count);
-
-			StreamView sView = null;
-			if (de.Size < header.MinSizeStandardStream)
-				sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Mini), Sector.MinisectorSize, de.Size, null, sourceStream);
-			else
-				sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Normal), GetSectorSize(), de.Size, null, sourceStream);
-
-			sView.Seek(position, SeekOrigin.Begin);
-			int result = sView.Read(buffer, offset, count);
-
-			return result;
-		}
-
-		internal byte[] GetData(CFStream cFStream)
-		{
-			AssertDisposed();
-
-			byte[] result = null;
-
-			DirectoryEntry de = cFStream.DirEntry;
-
-			if (de.Size < header.MinSizeStandardStream)
-			{
-				var miniView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Mini), Sector.MinisectorSize, de.Size, null, sourceStream);
-
-				using (BinaryReader br = new BinaryReader(miniView))
-					result = br.ReadBytes((int)de.Size);
-			}
-			else
-			{
-				var sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Normal), GetSectorSize(), de.Size, null, sourceStream);
-				result = new byte[(int)de.Size];
-				sView.Read(result, 0, result.Length);
-			}
-
-			return result;
-		}
-
-		public byte[] GetDataBySID(int sid)
-		{
-			AssertDisposed();
-			if (sid < 0)
-				return null;
-			byte[] result = null;
-			try
-			{
-				DirectoryEntry de = directoryEntries[sid];
-				if (de.Size < header.MinSizeStandardStream)
-				{
-					var miniView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Mini), Sector.MinisectorSize, de.Size, null, sourceStream);
-					BinaryReader br = new BinaryReader(miniView);
-					result = br.ReadBytes((int)de.Size);
-					br.Dispose();
-				}
-				else
-				{
-					var sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Normal), GetSectorSize(), de.Size, null, sourceStream);
-					result = new byte[(int)de.Size];
-					sView.Read(result, 0, result.Length);
-				}
-			}
-			catch
-			{
-				throw new Exception("Cannot get data for SID");
-			}
-			return result;
-		}
-
-		public Guid GetGuidBySID(int sid)
-		{
-			AssertDisposed();
-			if (sid < 0)
-				throw new Exception("Invalid SID");
-			DirectoryEntry de = directoryEntries[sid];
-			return de.StorageCLSID;
-		}
-
-		public Guid GetGuidForStream(int sid)
-		{
-			AssertDisposed();
-			if (sid < 0)
-				throw new Exception("Invalid SID");
-			Guid g = new Guid("00000000000000000000000000000000");
-			for (int i = sid - 1; i >= 0; i--)
-			{
-				if (directoryEntries[i].StorageCLSID != g && directoryEntries[i].StgType == StgType.StgStorage)
-					return directoryEntries[i].StorageCLSID;
-			}
-			return g;
-		}
-
-		private static int Ceiling(double d) => (int)Math.Ceiling(d);
-
-		private static int LowSaturation(int i) => i > 0 ? i : 0;
-
-		private bool closeStream = true;
-
-		internal bool IsClosed => _disposed;
-
-		#region IDisposable Members
-
-		private bool _disposed;//false
-		private object lockObject = new Object();
-
-		public void Dispose()
-		{
-			try
-			{
-				if (!_disposed)
-				{
-					lock (lockObject)
-					{
-						if (sectors != null)
-						{
-							sectors.Clear();
-							sectors = null;
-						}
-
-						this.RootStorage = null;
-						this.header = null;
-						this.directoryEntries.Clear();
-						this.directoryEntries = null;
-						this.fileName = null;
-					}
-
-					if (this.sourceStream != null && closeStream && !Configuration.HasFlag(CFSConfiguration.LeaveOpen))
-						this.sourceStream.Dispose();
-				}
-			}
-			finally
-			{
-				_disposed = true;
-			}
-			GC.SuppressFinalize(this);
-		}
-
-		#endregion IDisposable Members
-
-		private List<DirectoryEntry> directoryEntries = new List<DirectoryEntry>();
-
-		internal IList<DirectoryEntry> GetDirectories() => directoryEntries;
-
-		internal DirectoryEntry RootEntry => directoryEntries[0];
-
-		private IList<DirectoryEntry> FindDirectoryEntries(String entryName)
-		{
-			List<DirectoryEntry> result = new List<DirectoryEntry>();
-
-			foreach (DirectoryEntry d in directoryEntries)
-				if (d.GetEntryName() == entryName && d.StgType != StgType.StgInvalid)
-					result.Add(d);
-
-			return result;
-		}
-
-		public IList<CFItem> GetAllNamedEntries(String entryName)
-		{
-			IList<DirectoryEntry> r = FindDirectoryEntries(entryName);
-			List<CFItem> result = new List<CFItem>();
-
-			foreach (DirectoryEntry id in r)
-				if (id.GetEntryName() == entryName && id.StgType != StgType.StgInvalid)
-					result.Add(id.StgType == StgType.StgStorage ? new CFStorage(this, id) : new CFStream(this, id));
-
-			return result;
-		}
-
-		public int GetNumDirectories()
-		{
-			AssertDisposed();
-			return directoryEntries.Count;
-		}
-
-		public string GetNameDirEntry(int id)
-		{
-			AssertDisposed();
-			if (id < 0)
-				throw new Exception("Invalid Storage ID");
-			return directoryEntries[id].Name;
-		}
-
-		public StgType GetStorageType(int id)
-		{
-			AssertDisposed();
-			if (id < 0)
-				throw new Exception("Invalid Storage ID");
-			return directoryEntries[id].StgType;
-		}
-
-		private void AssertDisposed()
-		{
-			if (_disposed)
-				throw new ObjectDisposedException("Compound File closed: cannot access data");
-		}
-	}
-
-	#endregion Modified OpenMCDF
+            while (true)
+            {
+                if (nextSecID == Sector.Endofchain) break;
+
+                if (nextSecID < 0)
+                    throw new InvalidDataException(String.Format("Next Sector ID reference is below zero. NextID : {0}", nextSecID));
+
+                if (nextSecID >= sectors.Count)
+                    throw new InvalidDataException(String.Format("Next Sector ID reference an out of range sector. NextID : {0} while sector count {1}", nextSecID, sectors.Count));
+
+                Sector s = sectors[nextSecID];
+                if (s == null)
+                {
+                    sectors[nextSecID] = s = new Sector(GetSectorSize(), sourceStream)
+                    {
+                        Id = nextSecID,
+                        Type = SectorType.Normal
+                    };
+                }
+
+                result.Add(s);
+
+                fatStream.Seek(nextSecID * 4, SeekOrigin.Begin);
+                int next = fatStream.ReadInt32();
+
+                if (next != nextSecID)
+                    nextSecID = next;
+                else
+                    throw new InvalidDataException("Cyclic sector chain found. File is corrupted");
+            }
+
+            return result;
+        }
+
+        private List<Sector> GetMiniSectorChain(int secID)
+        {
+            List<Sector> result = new List<Sector>();
+
+            if (secID != Sector.Endofchain)
+            {
+                int nextSecID = secID;
+
+                List<Sector> miniFAT = GetNormalSectorChain(header.FirstMiniFATSectorID);
+                List<Sector> miniStream = GetNormalSectorChain(RootEntry.StartSetc);
+
+                StreamView miniFATView = new StreamView(miniFAT, GetSectorSize(), header.MiniFATSectorsNumber * Sector.MinisectorSize, null, sourceStream);
+                StreamView miniStreamView = new StreamView(miniStream, GetSectorSize(), RootStorage.Size, null, sourceStream);
+                BinaryReader miniFATReader = new BinaryReader(miniFATView);
+
+                nextSecID = secID;
+
+                while (true)
+                {
+                    if (nextSecID == Sector.Endofchain)
+                        break;
+
+                    Sector ms = new Sector(Sector.MinisectorSize, sourceStream);
+                    byte[] temp = new byte[Sector.MinisectorSize];
+
+                    ms.Id = nextSecID;
+                    ms.Type = SectorType.Mini;
+
+                    miniStreamView.Seek(nextSecID * Sector.MinisectorSize, SeekOrigin.Begin);
+                    miniStreamView.Read(ms.GetData(), 0, Sector.MinisectorSize);
+
+                    result.Add(ms);
+
+                    miniFATView.Seek(nextSecID * 4, SeekOrigin.Begin);
+                    nextSecID = miniFATReader.ReadInt32();
+                }
+            }
+            return result;
+        }
+
+        internal List<Sector> GetSectorChain(int secID, SectorType chainType)
+        {
+            switch (chainType)
+            {
+                case SectorType.DIFAT:
+                    return GetDifatSectorChain();
+
+                case SectorType.FAT:
+                    return GetFatSectorChain();
+
+                case SectorType.Normal:
+                    return GetNormalSectorChain(secID);
+
+                case SectorType.Mini:
+                    return GetMiniSectorChain(secID);
+
+                default:
+                    throw new Exception("Unsupproted chain type");
+            }
+        }
+
+        public CFStorage RootStorage { get; private set; }
+
+        public int Version => this.header.MajorVersion;
+
+        internal RBTree CreateNewTree()
+        {
+            RBTree bst = new RBTree();
+            return bst;
+        }
+
+        internal RBTree GetChildrenTree(int sid)
+        {
+            RBTree bst = new RBTree();
+            DoLoadChildren(bst, directoryEntries[sid]);
+            return bst;
+        }
+
+        private RBTree DoLoadChildrenTrusted(DirectoryEntry de)
+        {
+            RBTree bst = null;
+            if (de.Child != DirectoryEntry.NOSTREAM)
+                bst = new RBTree(directoryEntries[de.Child]);
+            return bst;
+        }
+
+        private void DoLoadChildren(RBTree bst, DirectoryEntry de)
+        {
+            if (de.Child != DirectoryEntry.NOSTREAM)
+            {
+                if (directoryEntries[de.Child].StgType == StgType.StgInvalid) return;
+
+                LoadSiblings(bst, directoryEntries[de.Child]);
+                NullifyChildNodes(directoryEntries[de.Child]);
+                bst.Insert(directoryEntries[de.Child]);
+            }
+        }
+
+        private void NullifyChildNodes(DirectoryEntry de)
+        {
+            de.Parent = null;
+            de.Left = null;
+            de.Right = null;
+        }
+
+        private readonly List<int> _levelSiDs = new List<int>();
+
+        private void LoadSiblings(RBTree bst, DirectoryEntry de)
+        {
+            _levelSiDs.Clear();
+
+            if (de.LeftSibling != DirectoryEntry.NOSTREAM)
+                DoLoadSiblings(bst, directoryEntries[de.LeftSibling]);
+
+            if (de.RightSibling != DirectoryEntry.NOSTREAM)
+            {
+                _levelSiDs.Add(de.RightSibling);
+                DoLoadSiblings(bst, directoryEntries[de.RightSibling]);
+            }
+        }
+
+        private void DoLoadSiblings(RBTree bst, DirectoryEntry de)
+        {
+            if (ValidateSibling(de.LeftSibling))
+            {
+                _levelSiDs.Add(de.LeftSibling);
+                DoLoadSiblings(bst, directoryEntries[de.LeftSibling]);
+            }
+
+            if (ValidateSibling(de.RightSibling))
+            {
+                _levelSiDs.Add(de.RightSibling);
+                DoLoadSiblings(bst, directoryEntries[de.RightSibling]);
+            }
+
+            NullifyChildNodes(de);
+            bst.Insert(de);
+        }
+
+        private bool ValidateSibling(int sid)
+        {
+            if (sid != DirectoryEntry.NOSTREAM)
+            {
+                if (sid >= directoryEntries.Count)
+                    return false;
+
+                if (directoryEntries[sid].StgType == StgType.StgInvalid)
+                    return false;
+
+                if (!Enum.IsDefined(typeof(StgType), directoryEntries[sid].StgType))
+                    return false;
+
+                if (_levelSiDs.Contains(sid))
+                    throw new InvalidDataException("Cyclic reference of directory item");
+
+                return true;
+            }
+
+            return false;
+        }
+
+        private void LoadDirectories()
+        {
+            List<Sector> directoryChain = GetSectorChain(header.FirstDirectorySectorID, SectorType.Normal);
+
+            if (header.FirstDirectorySectorID == Sector.Endofchain)
+                header.FirstDirectorySectorID = directoryChain[0].Id;
+
+            StreamView dirReader = new StreamView(directoryChain, GetSectorSize(), directoryChain.Count * GetSectorSize(), null, sourceStream);
+
+            while (dirReader.Position < directoryChain.Count * GetSectorSize())
+            {
+                DirectoryEntry de = DirectoryEntry.New(String.Empty, StgType.StgInvalid, directoryEntries);
+                de.Read(dirReader, this.Version);
+            }
+        }
+
+        private void CheckFileLength() => throw new NotImplementedException();
+
+        internal int ReadData(CFStream cFStream, long position, byte[] buffer, int count)
+        {
+            if (count > buffer.Length)
+                throw new ArgumentException("count parameter exceeds buffer size");
+
+            DirectoryEntry de = cFStream.DirEntry;
+
+            count = (int)Math.Min(de.Size - position, count);
+
+            StreamView sView = null;
+            if (de.Size < header.MinSizeStandardStream)
+                sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Mini), Sector.MinisectorSize, de.Size, null, sourceStream);
+            else
+                sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Normal), GetSectorSize(), de.Size, null, sourceStream);
+
+            sView.Seek(position, SeekOrigin.Begin);
+            int result = sView.Read(buffer, 0, count);
+
+            return result;
+        }
+
+        internal int ReadData(CFStream cFStream, long position, byte[] buffer, int offset, int count)
+        {
+            DirectoryEntry de = cFStream.DirEntry;
+
+            count = (int)Math.Min(de.Size - offset, count);
+
+            StreamView sView = null;
+            if (de.Size < header.MinSizeStandardStream)
+                sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Mini), Sector.MinisectorSize, de.Size, null, sourceStream);
+            else
+                sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Normal), GetSectorSize(), de.Size, null, sourceStream);
+
+            sView.Seek(position, SeekOrigin.Begin);
+            int result = sView.Read(buffer, offset, count);
+
+            return result;
+        }
+
+        internal byte[] GetData(CFStream cFStream)
+        {
+            AssertDisposed();
+
+            byte[] result = null;
+
+            DirectoryEntry de = cFStream.DirEntry;
+
+            if (de.Size < header.MinSizeStandardStream)
+            {
+                var miniView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Mini), Sector.MinisectorSize, de.Size, null, sourceStream);
+
+                using (BinaryReader br = new BinaryReader(miniView))
+                    result = br.ReadBytes((int)de.Size);
+            }
+            else
+            {
+                var sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Normal), GetSectorSize(), de.Size, null, sourceStream);
+                result = new byte[(int)de.Size];
+                sView.Read(result, 0, result.Length);
+            }
+
+            return result;
+        }
+
+        public byte[] GetDataBySID(int sid)
+        {
+            AssertDisposed();
+            if (sid < 0)
+                return null;
+            byte[] result = null;
+            try
+            {
+                DirectoryEntry de = directoryEntries[sid];
+                if (de.Size < header.MinSizeStandardStream)
+                {
+                    var miniView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Mini), Sector.MinisectorSize, de.Size, null, sourceStream);
+                    BinaryReader br = new BinaryReader(miniView);
+                    result = br.ReadBytes((int)de.Size);
+                    br.Dispose();
+                }
+                else
+                {
+                    var sView = new StreamView(GetSectorChain(de.StartSetc, SectorType.Normal), GetSectorSize(), de.Size, null, sourceStream);
+                    result = new byte[(int)de.Size];
+                    sView.Read(result, 0, result.Length);
+                }
+            }
+            catch
+            {
+                throw new Exception("Cannot get data for SID");
+            }
+            return result;
+        }
+
+        public Guid GetGuidBySID(int sid)
+        {
+            AssertDisposed();
+            if (sid < 0)
+                throw new Exception("Invalid SID");
+            DirectoryEntry de = directoryEntries[sid];
+            return de.StorageCLSID;
+        }
+
+        public Guid GetGuidForStream(int sid)
+        {
+            AssertDisposed();
+            if (sid < 0)
+                throw new Exception("Invalid SID");
+            Guid g = new Guid("00000000000000000000000000000000");
+            for (int i = sid - 1; i >= 0; i--)
+            {
+                if (directoryEntries[i].StorageCLSID != g && directoryEntries[i].StgType == StgType.StgStorage)
+                    return directoryEntries[i].StorageCLSID;
+            }
+            return g;
+        }
+
+        private static int Ceiling(double d) => (int)Math.Ceiling(d);
+
+        private static int LowSaturation(int i) => i > 0 ? i : 0;
+
+        private bool closeStream = true;
+
+        internal bool IsClosed => _disposed;
+
+        #region IDisposable Members
+
+        private bool _disposed;//false
+        private object lockObject = new Object();
+
+        public void Dispose()
+        {
+            try
+            {
+                if (!_disposed)
+                {
+                    lock (lockObject)
+                    {
+                        if (sectors != null)
+                        {
+                            sectors.Clear();
+                            sectors = null;
+                        }
+
+                        this.RootStorage = null;
+                        this.header = null;
+                        this.directoryEntries.Clear();
+                        this.directoryEntries = null;
+                        this.fileName = null;
+                    }
+
+                    if (this.sourceStream != null && closeStream && !Configuration.HasFlag(CFSConfiguration.LeaveOpen))
+                        this.sourceStream.Dispose();
+                }
+            }
+            finally
+            {
+                _disposed = true;
+            }
+            GC.SuppressFinalize(this);
+        }
+
+        #endregion IDisposable Members
+
+        private List<DirectoryEntry> directoryEntries = new List<DirectoryEntry>();
+
+        internal IList<DirectoryEntry> GetDirectories() => directoryEntries;
+
+        internal DirectoryEntry RootEntry => directoryEntries[0];
+
+        private IList<DirectoryEntry> FindDirectoryEntries(String entryName)
+        {
+            List<DirectoryEntry> result = new List<DirectoryEntry>();
+
+            foreach (DirectoryEntry d in directoryEntries)
+                if (d.GetEntryName() == entryName && d.StgType != StgType.StgInvalid)
+                    result.Add(d);
+
+            return result;
+        }
+
+        public IList<CFItem> GetAllNamedEntries(String entryName)
+        {
+            IList<DirectoryEntry> r = FindDirectoryEntries(entryName);
+            List<CFItem> result = new List<CFItem>();
+
+            foreach (DirectoryEntry id in r)
+                if (id.GetEntryName() == entryName && id.StgType != StgType.StgInvalid)
+                    result.Add(id.StgType == StgType.StgStorage ? new CFStorage(this, id) : new CFStream(this, id));
+
+            return result;
+        }
+
+        public int GetNumDirectories()
+        {
+            AssertDisposed();
+            return directoryEntries.Count;
+        }
+
+        public string GetNameDirEntry(int id)
+        {
+            AssertDisposed();
+            if (id < 0)
+                throw new Exception("Invalid Storage ID");
+            return directoryEntries[id].Name;
+        }
+
+        public StgType GetStorageType(int id)
+        {
+            AssertDisposed();
+            if (id < 0)
+                throw new Exception("Invalid Storage ID");
+            return directoryEntries[id].StgType;
+        }
+
+        private void AssertDisposed()
+        {
+            if (_disposed)
+                throw new ObjectDisposedException("Compound File closed: cannot access data");
+        }
+    }
+
+    #endregion Modified OpenMCDF
 }

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/AbstractFullRegexDetector.cs

@@ -4,7 +4,7 @@ using System.Linq;
 using System.Reflection;
 using System.Text;
 using System.Text.RegularExpressions;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/AbstractISOBaseMediaFileDetailDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector;
 

+ 2 - 2
Masuit.Tools.Abstractions/Files/FileDetector/AbstractRegexSignatureDetector.cs

@@ -4,7 +4,7 @@ using System.Linq;
 using System.Reflection;
 using System.Text;
 using System.Text.RegularExpressions;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector;
 
@@ -46,4 +46,4 @@ public abstract class AbstractRegexSignatureDetector : IDetector
 
         return false;
     }
-}
+}

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/AbstractSignatureDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Runtime.InteropServices;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/AbstractZipDetailDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.IO.Compression;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/ApkDetector.cs

@@ -1,7 +1,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/AudioVideoInterleaveDetector.cs

@@ -1,7 +1,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/BashShellScriptDetector.cs

@@ -2,7 +2,7 @@
 using System.Linq;
 using System.Reflection;
 using System.Text.RegularExpressions;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/BinaryPropertyListDetector.cs

@@ -1,7 +1,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/BitmapDetector.cs

@@ -1,7 +1,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/Bzip2Detector.cs

@@ -1,7 +1,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/CabDetector.cs

@@ -1,7 +1,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/CertDetector.cs

@@ -2,7 +2,7 @@
 using System.Linq;
 using System.Reflection;
 using System.Text;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/CompoundHWPDetector.cs

@@ -2,7 +2,7 @@
 using System.Linq;
 using System.Reflection;
 using System.Text;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/ConfigurationDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Xml;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/CursorDetector.cs

@@ -1,7 +1,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/DLLDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/DMGDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/DOCXDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/DirectDrawSurfaceFormatDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/EXEDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/EpubDetector.cs

@@ -4,7 +4,7 @@ using System.Linq;
 using System.IO.Compression;
 using System.Reflection;
 using System.Text;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/FLVDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/FlacDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/GifDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/GzDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/HWPDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text.RegularExpressions;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/ISODetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/IconDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/InitializationDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text.RegularExpressions;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/JavaClassDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/Jpeg2000Detector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/JpegDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/JpegXRDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/KTXDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/LzhDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/M4ADetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/M4VDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/MP3Detector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/MP4Detector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/MicrosoftExcelXLSDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/MicrosoftInstallerDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/MicrosoftPowerPointPPTDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/MicrosoftWordDocDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/MidiDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/MikeOBrienPackDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/OggDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/OpenDocumentFormulaDetector.cs

@@ -4,7 +4,7 @@ using System.Linq;
 using System.IO.Compression;
 using System.Reflection;
 using System.Text;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/OpenDocumentGraphicsDetector.cs

@@ -4,7 +4,7 @@ using System.Linq;
 using System.IO.Compression;
 using System.Reflection;
 using System.Text;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/OpenDocumentPresentationDetector.cs

@@ -4,7 +4,7 @@ using System.Linq;
 using System.IO.Compression;
 using System.Reflection;
 using System.Text;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/OpenDocumentSpreadSheetDetector.cs

@@ -4,7 +4,7 @@ using System.Linq;
 using System.IO.Compression;
 using System.Reflection;
 using System.Text;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/OpenDocumentTextDetector.cs

@@ -4,7 +4,7 @@ using System.Linq;
 using System.IO.Compression;
 using System.Reflection;
 using System.Text;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PAKArchiveDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PDBDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text.RegularExpressions;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PFXDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PKMDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PPSXDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.IO.Compression;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PPTXDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.IO.Compression;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PdfDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text.RegularExpressions;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PngDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PrePOSIXtarDetector.cs

@@ -4,7 +4,7 @@ using System.Linq;
 using System.Reflection;
 using System.Text;
 using System.Text.RegularExpressions;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/PsdDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/QuakeArchiveDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/QuickTimeDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/REGDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text.RegularExpressions;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/RarDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/RedhatPackageManagerPackageDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/RichTextFormatDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/SQLiteDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/SRTDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text.RegularExpressions;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/ShockwaveFlashDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/TextDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/TgaDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/ThumbsDBDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/TiffDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/UStarFormatTarDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/VisualStudioSolutionDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text.RegularExpressions;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/WaveDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/WebMDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/WebPDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/WindowsMemoryDumpDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/WindowsShortcutDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/XLSXDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/XMLDetector.cs

@@ -3,7 +3,7 @@ using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text.RegularExpressions;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/XarDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/ZDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/ZipDetector.cs

@@ -2,7 +2,7 @@
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/_3GPDetector.cs

@@ -1,7 +1,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/Detectors/_7zDetector.cs

@@ -1,7 +1,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Reflection;
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 
 namespace Masuit.Tools.Files.FileDetector.Detectors;
 

+ 1 - 1
Masuit.Tools.Abstractions/Files/FileDetector/InstantDetector.cs

@@ -1,4 +1,4 @@
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 using System;
 using System.Collections.Generic;
 using System.IO;

+ 4 - 2
Masuit.Tools.Abstractions/Mime/ContentType.cs

@@ -1,6 +1,7 @@
-namespace Masuit.Tools.AspNetCore.Mime
+namespace Masuit.Tools.Mime
 {
 #pragma warning disable 1591
+
     /// <summary>
     /// 默认MIME映射器,可以根据文件扩展名获取标准内容类型。
     /// </summary>
@@ -182,5 +183,6 @@
         public const string z = "application/x-compress";
         public const string Zip = "application/zip";
     }
+
 #pragma warning restore 1591
-}
+}

+ 16 - 16
Masuit.Tools.Abstractions/Mime/DefaultMimeItems.cs

@@ -1,7 +1,7 @@
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 
-namespace Masuit.Tools.AspNetCore.Mime
+namespace Masuit.Tools.Mime
 {
     public static class DefaultMimeItems
     {
@@ -389,46 +389,46 @@ namespace Masuit.Tools.AspNetCore.Mime
             new MimeMappingItem{Extension = "ms", MimeType = "application/x-wais-source"},
             new MimeMappingItem{Extension = "nc", MimeType = "application/x-netcdf"},
             new MimeMappingItem{Extension = "oda", MimeType = "application/oda"},
-            
+
             //<!-- OpenDocument Database -->
             new MimeMappingItem{Extension = "odb", MimeType = "application/vnd.oasis.opendocument.database"},
-            
+
             //<!-- OpenDocument Chart -->
             new MimeMappingItem{Extension = "odc", MimeType = "application/vnd.oasis.opendocument.chart"},
-    
+
             //<!-- OpenDocument Formula -->
             new MimeMappingItem{Extension = "odf", MimeType = "application/vnd.oasis.opendocument.formula"},
-    
+
             //<!-- OpenDocument Drawing -->
             new MimeMappingItem{Extension = "odg", MimeType = "application/vnd.oasis.opendocument.graphics"},
-    
+
             //<!-- OpenDocument Image -->
             new MimeMappingItem{Extension = "odi", MimeType = "application/vnd.oasis.opendocument.image"},
-    
+
             //<!-- OpenDocument Master Document -->
             new MimeMappingItem{Extension = "odm", MimeType = "application/vnd.oasis.opendocument.text-master"},
-    
+
             //<!-- OpenDocument Presentation -->
             new MimeMappingItem{Extension = "odp", MimeType = "application/vnd.oasis.opendocument.presentation"},
-    
+
             //<!-- OpenDocument Spreadsheet -->
             new MimeMappingItem{Extension = "ods", MimeType = "application/vnd.oasis.opendocument.spreadsheet"},
-    
+
             //<!-- OpenDocument Text -->
             new MimeMappingItem{Extension = "odt", MimeType = "application/vnd.oasis.opendocument.text"},
-    
+
             //<!-- OpenDocument Drawing Template -->
             new MimeMappingItem{Extension = "otg ", MimeType = "application/vnd.oasis.opendocument.graphics-template"},
-    
+
             //<!-- HTML Document Template -->
             new MimeMappingItem{Extension = "oth", MimeType = "application/vnd.oasis.opendocument.text-web"},
-    
+
             //<!-- OpenDocument Presentation Template -->
             new MimeMappingItem{Extension = "otp", MimeType = "application/vnd.oasis.opendocument.presentation-template"},
-    
+
             //<!-- OpenDocument Spreadsheet Template -->
             new MimeMappingItem{Extension = "ots", MimeType = "application/vnd.oasis.opendocument.spreadsheet-template "},
-    
+
             //<!-- OpenDocument Text Template -->
             new MimeMappingItem{Extension = "ott", MimeType = "application/vnd.oasis.opendocument.text-template"},
             new MimeMappingItem{Extension = "pbm", MimeType = "image/x-portable-bitmap"},
@@ -498,7 +498,7 @@ namespace Masuit.Tools.AspNetCore.Mime
             new MimeMappingItem{Extension = "xwd", MimeType = "image/x-xwindowdump"},
             new MimeMappingItem{Extension = "vsd", MimeType = "application/x-visio"},
             new MimeMappingItem{Extension = "wav", MimeType = "audio/x-wav"},
-            
+
             //<!-- Wireless Bitmap -->
             new MimeMappingItem{Extension = "wbmp", MimeType = "image/vnd.wap.wbmp"},
 

+ 2 - 2
Masuit.Tools.Abstractions/Mime/IMimeMapper.cs

@@ -1,4 +1,4 @@
-namespace Masuit.Tools.AspNetCore.Mime
+namespace Masuit.Tools.Mime
 {
     /// <summary>
     /// Mime
@@ -26,4 +26,4 @@
         /// <returns></returns>
         string GetMimeFromPath(string filePath);
     }
-}
+}

+ 4 - 4
Masuit.Tools.Abstractions/Mime/MimeMapper.cs

@@ -1,7 +1,7 @@
 using System.Collections.Generic;
 using System.Text.RegularExpressions;
 
-namespace Masuit.Tools.AspNetCore.Mime
+namespace Masuit.Tools.Mime
 {
     /// <summary>
     /// 默认MIME映射器,可以根据文件扩展名获取标准内容类型。
@@ -38,14 +38,14 @@ namespace Masuit.Tools.AspNetCore.Mime
         }
 
         /// <summary>
-        /// 
+        ///
         /// </summary>
         public MimeMapper() : this(null)
         {
         }
 
         /// <summary>
-        /// 
+        ///
         /// </summary>
         /// <param name="extensions"></param>
         public MimeMapper(params MimeMappingItem[] extensions)
@@ -120,4 +120,4 @@ namespace Masuit.Tools.AspNetCore.Mime
             return null;
         }
     }
-}
+}

+ 3 - 3
Masuit.Tools.Abstractions/Mime/MimeMappingItem.cs

@@ -1,7 +1,7 @@
-namespace Masuit.Tools.AspNetCore.Mime
+namespace Masuit.Tools.Mime
 {
     /// <summary>
-    /// 
+    ///
     /// </summary>
     public class MimeMappingItem
     {
@@ -15,4 +15,4 @@
         /// </summary>
         public string MimeType { get; set; }
     }
-}
+}

+ 0 - 604
Masuit.Tools.Abstractions/Net/FtpClient.cs

@@ -1,604 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Text;
-
-namespace Masuit.Tools.Net
-{
-    /// <summary>
-    /// FTP客户端操作类
-    /// </summary>
-    public class FtpClient
-    {
-        #region 变量属性
-
-        /// <summary>
-        /// Ftp服务器ip
-        /// </summary>
-        private string FtpServer { get; set; }
-
-        /// <summary>
-        /// Ftp 指定用户名
-        /// </summary>
-        private string Username { get; set; }
-
-        /// <summary>
-        /// Ftp 指定用户密码
-        /// </summary>
-        private string Password { get; set; }
-
-        #endregion
-
-        /// <summary>
-        /// 获取一个匿名登录的ftp客户端
-        /// </summary>
-        /// <param name="serverIp">服务器IP地址</param>
-        /// <param name="matchInetAddress">是否验证IP地址</param>
-        /// <returns></returns>
-        public static FtpClient GetAnonymousClient(string serverIp,bool matchInetAddress=true)
-        {
-            if (!serverIp.MatchInetAddress()&&matchInetAddress)
-            {
-                throw new ArgumentException("IP地址格式不正确");
-            }
-
-            return new FtpClient
-            {
-                FtpServer = serverIp
-            };
-        }
-
-        /// <summary>
-        /// 获取一个匿名登录的ftp客户端
-        /// </summary>
-        /// <param name="serverIp">服务器ip</param>
-        /// <param name="username">用户名</param>
-        /// <param name="password">密码</param>
-        /// <param name="matchInetAddress">是否验证IP地址</param>
-        /// <returns></returns>
-        public static FtpClient GetClient(string serverIp, string username, string password,bool matchInetAddress=true)
-        {
-            if (!serverIp.MatchInetAddress()&&matchInetAddress)
-            {
-                throw new ArgumentException("IP地址格式不正确");
-            }
-
-            return new FtpClient
-            {
-                FtpServer = serverIp,
-                Username = username,
-                Password = password
-            };
-        }
-
-        #region 从FTP服务器下载文件,指定本地路径和本地文件名
-
-        /// <summary>
-        /// 从FTP服务器下载文件,指定本地路径和本地文件名
-        /// </summary>
-        /// <param name="remoteFileName">远程文件名</param>
-        /// <param name="localFileName">保存本地的文件名(包含路径)</param>
-        /// <param name="ifCredential">是否启用身份验证(false:表示允许用户匿名下载)</param>
-        /// <param name="updateProgress">报告进度的处理(第一个参数:总大小,第二个参数:当前进度)</param>
-        public void Download(string remoteFileName, string localFileName, bool ifCredential = false, Action<int, int> updateProgress = null)
-        {
-            using var outputStream = new FileStream(localFileName, FileMode.Create);
-            if (FtpServer == null || FtpServer.Trim().Length == 0)
-            {
-                throw new Exception("ftp下载目标服务器地址未设置!");
-            }
-
-            Uri uri = new Uri("ftp://" + FtpServer + "/" + remoteFileName);
-            var ftpsize = (FtpWebRequest)WebRequest.Create(uri);
-            ftpsize.UseBinary = true;
-            var reqFtp = (FtpWebRequest)WebRequest.Create(uri);
-            reqFtp.UseBinary = true;
-            reqFtp.KeepAlive = false;
-            if (ifCredential) //使用用户身份认证
-            {
-                ftpsize.Credentials = new NetworkCredential(Username, Password);
-                reqFtp.Credentials = new NetworkCredential(Username, Password);
-            }
-
-            ftpsize.Method = WebRequestMethods.Ftp.GetFileSize;
-            using var re = (FtpWebResponse)ftpsize.GetResponse();
-            long totalBytes = re.ContentLength;
-            reqFtp.Method = WebRequestMethods.Ftp.DownloadFile;
-            using var response = (FtpWebResponse)reqFtp.GetResponse();
-            using var ftpStream = response.GetResponseStream();
-            //更新进度 
-            updateProgress?.Invoke((int)totalBytes, 0); //更新进度条 
-            long totalDownloadedByte = 0;
-            int bufferSize = 1024 * 1024;
-            byte[] buffer = new byte[bufferSize];
-            if (ftpStream != null)
-            {
-                var readCount = ftpStream.Read(buffer, 0, bufferSize);
-                while (readCount > 0)
-                {
-                    totalDownloadedByte = readCount + totalDownloadedByte;
-                    outputStream.Write(buffer, 0, readCount);
-                    //更新进度 
-                    updateProgress?.Invoke((int)totalBytes, (int)totalDownloadedByte); //更新进度条 
-                    readCount = ftpStream.Read(buffer, 0, bufferSize);
-                }
-            }
-        }
-
-        /// <summary>
-        /// 从FTP服务器下载文件,指定本地路径和本地文件名(支持断点下载)
-        /// </summary>
-        /// <param name="remoteFileName">远程文件名</param>
-        /// <param name="localFileName">保存本地的文件名(包含路径)</param>
-        /// <param name="ifCredential">是否启用身份验证(false:表示允许用户匿名下载)</param>
-        /// <param name="size">已下载文件流大小</param>
-        /// <param name="updateProgress">报告进度的处理(第一个参数:总大小,第二个参数:当前进度)</param>
-        public void BrokenDownload(string remoteFileName, string localFileName, bool ifCredential, long size, Action<int, int> updateProgress = null)
-        {
-            using var outputStream = new FileStream(localFileName, FileMode.Append);
-            if (FtpServer == null || FtpServer.Trim().Length == 0)
-            {
-                throw new Exception("ftp下载目标服务器地址未设置!");
-            }
-
-            Uri uri = new Uri("ftp://" + FtpServer + "/" + remoteFileName);
-            var ftpsize = (FtpWebRequest)WebRequest.Create(uri);
-            ftpsize.UseBinary = true;
-            ftpsize.ContentOffset = size;
-            var reqFtp = (FtpWebRequest)WebRequest.Create(uri);
-            reqFtp.UseBinary = true;
-            reqFtp.KeepAlive = false;
-            reqFtp.ContentOffset = size;
-            if (ifCredential) //使用用户身份认证
-            {
-                ftpsize.Credentials = new NetworkCredential(Username, Password);
-                reqFtp.Credentials = new NetworkCredential(Username, Password);
-            }
-
-            ftpsize.Method = WebRequestMethods.Ftp.GetFileSize;
-            using var re = (FtpWebResponse)ftpsize.GetResponse();
-            var totalBytes = re.ContentLength;
-            reqFtp.Method = WebRequestMethods.Ftp.DownloadFile;
-            using var response = (FtpWebResponse)reqFtp.GetResponse();
-            using var ftpStream = response.GetResponseStream();
-            updateProgress?.Invoke((int)totalBytes, 0); //更新进度条 
-            long totalDownloadedByte = 0;
-            int bufferSize = 1024 * 1024;
-            byte[] buffer = new byte[bufferSize];
-            if (ftpStream != null)
-            {
-                var readCount = ftpStream.Read(buffer, 0, bufferSize);
-                while (readCount > 0)
-                {
-                    totalDownloadedByte = readCount + totalDownloadedByte;
-                    outputStream.Write(buffer, 0, readCount);
-                    //更新进度 
-                    updateProgress?.Invoke((int)totalBytes, (int)totalDownloadedByte); //更新进度条 
-                    readCount = ftpStream.Read(buffer, 0, bufferSize);
-                }
-            }
-        }
-
-        /// <summary>
-        /// 从FTP服务器下载文件,指定本地路径和本地文件名
-        /// </summary>
-        /// <param name="remoteFileName">远程文件名</param>
-        /// <param name="localFileName">保存本地的文件名(包含路径)</param>
-        /// <param name="ifCredential">是否启用身份验证(false:表示允许用户匿名下载)</param>
-        /// <param name="updateProgress">报告进度的处理(第一个参数:总大小,第二个参数:当前进度)</param>
-        /// <param name="brokenOpen">是否断点下载:true 会在localFileName 找是否存在已经下载的文件,并计算文件流大小</param>
-        public void Download(string remoteFileName, string localFileName, bool ifCredential, bool brokenOpen, Action<int, int> updateProgress = null)
-        {
-            if (brokenOpen)
-            {
-                long size = 0;
-                if (File.Exists(localFileName))
-                {
-                    using var outputStream = new FileStream(localFileName, FileMode.Open);
-                    size = outputStream.Length;
-                }
-
-                BrokenDownload(remoteFileName, localFileName, ifCredential, size, updateProgress);
-            }
-
-            Download(remoteFileName, localFileName, ifCredential, updateProgress);
-        }
-
-        #endregion
-
-        #region 上传文件到FTP服务器
-
-        /// <summary>
-        /// 上传文件到FTP服务器
-        /// </summary>
-        /// <param name="relativePath">相对目录</param>
-        /// <param name="localFullPathName">本地带有完整路径的文件名</param>
-        /// <param name="updateProgress">报告进度的处理(第一个参数:总大小,第二个参数:当前进度)</param>
-        public void UploadFile(string relativePath, string localFullPathName, Action<int, int> updateProgress = null)
-        {
-            var finfo = new FileInfo(localFullPathName);
-            if (FtpServer == null || FtpServer.Trim().Length == 0)
-            {
-                throw new Exception("ftp上传目标服务器地址未设置!");
-            }
-
-            Uri uri = new Uri("ftp://" + FtpServer + "/" + relativePath + "/" + finfo.Name);
-            var reqFtp = (FtpWebRequest)WebRequest.Create(uri);
-            reqFtp.KeepAlive = false;
-            reqFtp.UseBinary = true;
-            reqFtp.Credentials = new NetworkCredential(Username, Password); //用户,密码
-            reqFtp.Method = WebRequestMethods.Ftp.UploadFile; //向服务器发出下载请求命令
-            reqFtp.ContentLength = finfo.Length; //为request指定上传文件的大小
-            int buffLength = 1024 * 1024;
-            byte[] buff = new byte[buffLength];
-            using var fs = finfo.OpenRead();
-            using var stream = reqFtp.GetRequestStream();
-            var contentLen = fs.Read(buff, 0, buffLength);
-            int allbye = (int)finfo.Length;
-            //更新进度 
-            updateProgress?.Invoke(allbye, 0); //更新进度条 
-            int startbye = 0;
-            while (contentLen != 0)
-            {
-                startbye = contentLen + startbye;
-                stream.Write(buff, 0, contentLen);
-                //更新进度 
-                updateProgress?.Invoke(allbye, startbye); //更新进度条 
-                contentLen = fs.Read(buff, 0, buffLength);
-            }
-        }
-
-        /// <summary>
-        /// 上传文件到FTP服务器(断点续传)
-        /// </summary>
-        /// <param name="localFullPath">本地文件全路径名称:C:\Users\JianKunKing\Desktop\IronPython脚本测试工具</param>
-        /// <param name="remoteFilepath">远程文件所在文件夹路径</param>
-        /// <param name="updateProgress">报告进度的处理(第一个参数:总大小,第二个参数:当前进度)</param>
-        /// <returns></returns> 
-        public bool UploadBroken(string localFullPath, string remoteFilepath, Action<int, int> updateProgress = null)
-        {
-            if (remoteFilepath == null)
-            {
-                remoteFilepath = "";
-            }
-
-            string newFileName;
-            var fileInf = new FileInfo(localFullPath);
-            long allbye = fileInf.Length;
-            if (fileInf.Name.IndexOf("#", StringComparison.Ordinal) == -1)
-            {
-                newFileName = RemoveSpaces(fileInf.Name);
-            }
-            else
-            {
-                newFileName = fileInf.Name.Replace("#", "#");
-                newFileName = RemoveSpaces(newFileName);
-            }
-
-            long startfilesize = GetFileSize(newFileName, remoteFilepath);
-            if (startfilesize >= allbye)
-            {
-                return false;
-            }
-
-            long startbye = startfilesize;
-            //更新进度 
-            updateProgress?.Invoke((int)allbye, (int)startfilesize); //更新进度条 
-            string uri;
-            if (remoteFilepath.Length == 0)
-            {
-                uri = "ftp://" + FtpServer + "/" + newFileName;
-            }
-            else
-            {
-                uri = "ftp://" + FtpServer + "/" + remoteFilepath + "/" + newFileName;
-            }
-
-            // 根据uri创建FtpWebRequest对象 
-            var reqFtp = (FtpWebRequest)WebRequest.Create(new Uri(uri));
-            // ftp用户名和密码 
-            reqFtp.Credentials = new NetworkCredential(Username, Password);
-            // 默认为true,连接不会被关闭 
-            // 在一个命令之后被执行 
-            reqFtp.KeepAlive = false;
-            // 指定执行什么命令 
-            reqFtp.Method = WebRequestMethods.Ftp.AppendFile;
-            // 指定数据传输类型 
-            reqFtp.UseBinary = true;
-            // 上传文件时通知服务器文件的大小 
-            reqFtp.ContentLength = fileInf.Length;
-            int buffLength = 1024 * 1024; // 缓冲大小设置为2kb 
-            byte[] buff = new byte[buffLength];
-            // 打开一个文件流 (System.IO.FileStream) 去读上传的文件 
-            using FileStream fs = fileInf.OpenRead();
-            using var strm = reqFtp.GetRequestStream();
-            // 把上传的文件写入流 
-            fs.Seek(startfilesize, 0);
-            int contentLen = fs.Read(buff, 0, buffLength);
-            // 流内容没有结束 
-            while (contentLen != 0)
-            {
-                // 把内容从file stream 写入 upload stream 
-                strm.Write(buff, 0, contentLen);
-                contentLen = fs.Read(buff, 0, buffLength);
-                startbye += contentLen;
-                //更新进度 
-                updateProgress?.Invoke((int)allbye, (int)startbye); //更新进度条 
-            }
-
-            return true;
-        }
-
-        /// <summary>
-        /// 去除空格
-        /// </summary>
-        /// <param name="str"></param>
-        /// <returns></returns>
-        private string RemoveSpaces(string str)
-        {
-            string a = str.Where(c => Encoding.ASCII.GetBytes(c.ToString())[0] != 32).Aggregate("", (current, c) => current + c);
-            return a.Split('.')[a.Split('.').Length - 2] + "." + a.Split('.')[a.Split('.').Length - 1];
-        }
-
-        /// <summary>
-        /// 获取已上传文件大小
-        /// </summary>
-        /// <param name="filePath">文件名称</param>
-        /// <param name="remoteFilepath">服务器文件路径</param>
-        /// <returns></returns>
-        public long GetFileSize(string filePath, string remoteFilepath)
-        {
-            try
-            {
-                var fi = new FileInfo(filePath);
-                string uri;
-                if (remoteFilepath.Length == 0)
-                {
-                    uri = "ftp://" + FtpServer + "/" + fi.Name;
-                }
-                else
-                {
-                    uri = "ftp://" + FtpServer + "/" + remoteFilepath + "/" + fi.Name;
-                }
-
-                var reqFtp = (FtpWebRequest)WebRequest.Create(uri);
-                reqFtp.KeepAlive = false;
-                reqFtp.UseBinary = true;
-                reqFtp.Credentials = new NetworkCredential(Username, Password); //用户,密码
-                reqFtp.Method = WebRequestMethods.Ftp.GetFileSize;
-                var response = (FtpWebResponse)reqFtp.GetResponse();
-                var filesize = response.ContentLength;
-                return filesize;
-            }
-            catch
-            {
-                return 0;
-            }
-        }
-
-        #endregion
-
-        #region 获取当前目录下明细
-
-        /// <summary>
-        /// 获取当前目录下明细(包含文件和文件夹)
-        /// </summary>
-        /// <returns></returns>
-        public List<string> GetFilesDetails(string relativePath = "")
-        {
-            var result = new List<string>();
-            var ftp = (FtpWebRequest)WebRequest.Create(new Uri(Path.Combine("ftp://" + FtpServer, relativePath).Replace("\\", "/")));
-            ftp.Credentials = new NetworkCredential(Username, Password);
-            ftp.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
-            using var response = ftp.GetResponse();
-            using var reader = new StreamReader(response.GetResponseStream() ?? throw new InvalidOperationException(), Encoding.UTF8);
-            string line = reader.ReadLine();
-            while (line != null)
-            {
-                result.Add(line);
-                line = reader.ReadLine();
-            }
-
-            return result;
-        }
-
-        /// <summary>
-        /// 获取当前目录下文件列表(仅文件)
-        /// </summary>
-        /// <returns></returns>
-        public List<string> GetFiles(string relativePath = "", string mask = "*.*")
-        {
-            var result = new List<string>();
-            var reqFtp = (FtpWebRequest)WebRequest.Create(new Uri(Path.Combine("ftp://" + FtpServer, relativePath).Replace("\\", "/")));
-            reqFtp.UseBinary = true;
-            reqFtp.Credentials = new NetworkCredential(Username, Password);
-            reqFtp.Method = WebRequestMethods.Ftp.ListDirectory;
-            using var response = reqFtp.GetResponse();
-            using var reader = new StreamReader(response.GetResponseStream() ?? throw new InvalidOperationException(), Encoding.UTF8);
-            string line = reader.ReadLine();
-            while (line != null)
-            {
-                if (mask.Trim() != string.Empty && mask.Trim() != "*.*")
-                {
-                    string temp = mask.Substring(0, mask.IndexOf("*", StringComparison.Ordinal));
-                    if (line.Substring(0, temp.Length) == temp)
-                    {
-                        result.Add(line);
-                    }
-                }
-                else
-                {
-                    result.Add(line);
-                }
-
-                line = reader.ReadLine();
-            }
-
-            return result;
-        }
-
-        /// <summary>
-        /// 获取当前目录下所有的文件夹列表(仅文件夹)
-        /// </summary>
-        /// <returns></returns>
-        public string[] GetDirectories(string relativePath)
-        {
-            var drectory = GetFilesDetails(relativePath);
-            string m = string.Empty;
-            foreach (string str in drectory)
-            {
-                int dirPos = str.IndexOf("<DIR>", StringComparison.Ordinal);
-                if (dirPos > 0)
-                {
-                    /*判断 Windows 风格*/
-                    m += str.Substring(dirPos + 5).Trim() + "\n";
-                }
-                else if (str.Trim().StartsWith("d"))
-                {
-                    /*判断 Unix 风格*/
-                    string dir = str.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries)[8];
-                    if (dir != "." && dir != "..")
-                    {
-                        dir = str.Substring(str.IndexOf(dir, StringComparison.Ordinal));
-                        m += dir + "\n";
-                    }
-                }
-            }
-
-            char[] n =
-            {
-                '\n'
-            };
-            return m.Split(n);
-        }
-        #endregion
-
-        #region 删除文件及文件夹
-
-        /// <summary>
-        /// 删除文件
-        /// </summary>
-        /// <param name="filePath"></param>
-        public void Delete(string filePath)
-        {
-            string uri = Path.Combine("ftp://" + FtpServer, filePath).Replace("\\", "/");
-            var reqFtp = (FtpWebRequest)WebRequest.Create(new Uri(uri));
-            reqFtp.Credentials = new NetworkCredential(Username, Password);
-            reqFtp.KeepAlive = false;
-            reqFtp.Method = WebRequestMethods.Ftp.DeleteFile;
-            using FtpWebResponse response = (FtpWebResponse)reqFtp.GetResponse();
-            using Stream datastream = response.GetResponseStream();
-            using StreamReader sr = new StreamReader(datastream ?? throw new InvalidOperationException());
-            sr.ReadToEnd();
-        }
-
-        /// <summary>
-        /// 删除文件夹
-        /// </summary>
-        /// <param name="dirPath"></param>
-        public void RemoveDirectory(string dirPath)
-        {
-            string uri = Path.Combine("ftp://" + FtpServer, dirPath).Replace("\\", "/");
-            var reqFtp = (FtpWebRequest)WebRequest.Create(new Uri(uri));
-            reqFtp.Credentials = new NetworkCredential(Username, Password);
-            reqFtp.KeepAlive = false;
-            reqFtp.Method = WebRequestMethods.Ftp.RemoveDirectory;
-            using var response = (FtpWebResponse)reqFtp.GetResponse();
-            using var datastream = response.GetResponseStream();
-            using var sr = new StreamReader(datastream ?? throw new InvalidOperationException());
-            sr.ReadToEnd();
-        }
-
-        #endregion
-
-        #region 其他操作
-
-        /// <summary>
-        /// 获取指定文件大小
-        /// </summary>
-        /// <param name="filePath"></param>
-        /// <returns></returns>
-        public long GetFileSize(string filePath)
-        {
-            var reqFtp = (FtpWebRequest)WebRequest.Create(new Uri(Path.Combine("ftp://" + FtpServer, filePath).Replace("\\", "/")));
-            reqFtp.Method = WebRequestMethods.Ftp.GetFileSize;
-            reqFtp.UseBinary = true;
-            reqFtp.Credentials = new NetworkCredential(Username, Password);
-            using var response = (FtpWebResponse)reqFtp.GetResponse();
-            var fileSize = response.ContentLength;
-            return fileSize;
-        }
-
-        /// <summary>
-        /// 判断当前目录下指定的子目录是否存在
-        /// </summary>
-        /// <param name="remoteDirPath">指定的目录名</param>
-        public bool DirectoryExist(string remoteDirPath)
-        {
-            try
-            {
-                string[] dirList = GetDirectories(remoteDirPath);
-                return dirList.Any(str => str.Trim() == remoteDirPath.Trim());
-            }
-            catch
-            {
-                return false;
-            }
-        }
-
-        /// <summary>
-        /// 判断当前目录下指定的文件是否存在
-        /// </summary>
-        /// <param name="remoteFileName">远程文件名</param>
-        public bool FileExist(string remoteFileName)
-        {
-            return GetFiles("*.*").Any(str => str.Trim() == remoteFileName.Trim());
-        }
-
-        /// <summary>
-        /// 创建文件夹
-        /// </summary>
-        /// <param name="relativePath">路径</param>
-        /// <param name="newDir">新建文件夹</param>
-        public void MakeDir(string relativePath, string newDir)
-        {
-            var reqFtp = (FtpWebRequest)WebRequest.Create(new Uri(Path.Combine("ftp://" + FtpServer, relativePath, newDir).Replace("\\", "/")));
-            reqFtp.Method = WebRequestMethods.Ftp.MakeDirectory;
-            reqFtp.UseBinary = true;
-            reqFtp.Credentials = new NetworkCredential(Username, Password);
-            using var response = (FtpWebResponse)reqFtp.GetResponse();
-            using var _ = response.GetResponseStream();
-        }
-
-        /// <summary>
-        /// 改名
-        /// </summary>
-        /// <param name="relativePath">相对路径</param>
-        /// <param name="currentFilename"></param>
-        /// <param name="newFilename"></param>
-        public void Rename(string relativePath, string currentFilename, string newFilename)
-        {
-            var reqFtp = (FtpWebRequest)WebRequest.Create(new Uri(Path.Combine("ftp://" + FtpServer, relativePath, currentFilename).Replace("\\", "/")));
-            reqFtp.Method = WebRequestMethods.Ftp.Rename;
-            reqFtp.RenameTo = newFilename;
-            reqFtp.UseBinary = true;
-            reqFtp.Credentials = new NetworkCredential(Username, Password);
-            using var response = (FtpWebResponse)reqFtp.GetResponse();
-            using var _ = response.GetResponseStream();
-        }
-
-        /// <summary>
-        /// 移动文件
-        /// </summary>
-        /// <param name="relativePath">相对路径</param>
-        /// <param name="currentFilename"></param>
-        /// <param name="newDirectory"></param>
-        public void MoveFile(string relativePath, string currentFilename, string newDirectory)
-        {
-            Rename(relativePath, currentFilename, newDirectory);
-        }
-        #endregion
-    }
-}

+ 3 - 2
Masuit.Tools.AspNetCore/AspNetCore/Extensions/ControllerExtensions.cs

@@ -1,4 +1,4 @@
-using Masuit.Tools.AspNetCore.Mime;
+using Masuit.Tools.Mime;
 using Masuit.Tools.AspNetCore.ResumeFileResults.ResumeFileResult;
 using Microsoft.AspNetCore.Mvc;
 using System.IO;
@@ -11,6 +11,7 @@ namespace Masuit.Tools.AspNetCore.ResumeFileResults.Extensions
     public static class ControllerExtensions
     {
         private static readonly IMimeMapper _mimeMapper = new MimeMapper();
+
         /// <summary>
         /// 可断点续传和多线程下载的FileResult
         /// </summary>
@@ -179,4 +180,4 @@ namespace Masuit.Tools.AspNetCore.ResumeFileResults.Extensions
             };
         }
     }
-}
+}

+ 1 - 0
Masuit.Tools.AspNetCore/Masuit.Tools.AspNetCore.csproj

@@ -44,6 +44,7 @@
     </ItemGroup>
 
     <ItemGroup>
+      <PackageReference Include="FastExpressionCompiler" Version="3.3.4" />
       <PackageReference Include="System.Net.Http.Json" Version="7.0.1" />
     </ItemGroup>
 

+ 0 - 18
Masuit.Tools.Net45/Masuit.Tools.Net45.csproj

@@ -150,9 +150,6 @@
     <Compile Include="..\Masuit.Tools.Abstractions\Models\TreeExtensions.cs">
       <Link>Models\TreeExtensions.cs</Link>
     </Compile>
-    <Compile Include="..\Masuit.Tools.Abstractions\Net\FtpClient.cs">
-      <Link>Net\FtpClient.cs</Link>
-    </Compile>
     <Compile Include="..\Masuit.Tools.Abstractions\Net\MultiThreadDownloader.cs">
       <Link>Net\MultiThreadDownloader.cs</Link>
     </Compile>
@@ -252,21 +249,6 @@
     <Compile Include="..\Masuit.Tools\Mvc\Internal\ByteRange.cs">
       <Link>Mvc\Internal\ByteRange.cs</Link>
     </Compile>
-    <Compile Include="..\Masuit.Tools\Mvc\Mime\ContentType.cs">
-      <Link>Mvc\Mime\ContentType.cs</Link>
-    </Compile>
-    <Compile Include="..\Masuit.Tools\Mvc\Mime\DefaultMimeItems.cs">
-      <Link>Mvc\Mime\DefaultMimeItems.cs</Link>
-    </Compile>
-    <Compile Include="..\Masuit.Tools\Mvc\Mime\IMimeMapper.cs">
-      <Link>Mvc\Mime\IMimeMapper.cs</Link>
-    </Compile>
-    <Compile Include="..\Masuit.Tools\Mvc\Mime\MimeMapper.cs">
-      <Link>Mvc\Mime\MimeMapper.cs</Link>
-    </Compile>
-    <Compile Include="..\Masuit.Tools\Mvc\Mime\MimeMappingItem.cs">
-      <Link>Mvc\Mime\MimeMappingItem.cs</Link>
-    </Compile>
     <Compile Include="..\Masuit.Tools\Net\CacheHelper.cs">
       <Link>Net\CacheHelper.cs</Link>
     </Compile>

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác