diff --git a/SharpFileSystem.Tests/NetZipArchive/NetZipArchiveFileSystemTest.cs b/SharpFileSystem.Tests/NetZipArchive/NetZipArchiveFileSystemTest.cs new file mode 100644 index 0000000..3af08d5 --- /dev/null +++ b/SharpFileSystem.Tests/NetZipArchive/NetZipArchiveFileSystemTest.cs @@ -0,0 +1,132 @@ +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using ICSharpCode.SharpZipLib.Zip; +using NUnit.Framework; +using SharpFileSystem.IO; +using SharpFileSystem.SharpZipArchive; + +namespace SharpFileSystem.Tests.NetZipArchive +{ + [TestFixture] + public class NetZipArchiveFileSystemTest + { + private Stream zipStream; + private NetZipArchiveFileSystem fileSystem; + private string fileContentString = "this is a file"; + [OneTimeSetUp] + public void Initialize() + { + var memoryStream = new MemoryStream(); + zipStream = memoryStream; + var zipOutput = new ZipOutputStream(zipStream); + + + var fileContentBytes = Encoding.ASCII.GetBytes(fileContentString); + zipOutput.PutNextEntry(new ZipEntry("textfileA.txt") + { + Size = fileContentBytes.Length + }); + zipOutput.Write(fileContentBytes); + zipOutput.PutNextEntry(new ZipEntry("directory/fileInDirectory.txt")); + zipOutput.PutNextEntry(new ZipEntry("scratchdirectory/scratch")); + zipOutput.Finish(); + + memoryStream.Position = 0; + fileSystem = NetZipArchiveFileSystem.Open(zipStream); + } + + [OneTimeTearDown] + public void Cleanup() + { + fileSystem.Dispose(); + zipStream.Dispose(); + } + + private readonly FileSystemPath directoryPath = FileSystemPath.Parse("/directory/"); + private readonly FileSystemPath textfileAPath = FileSystemPath.Parse("/textfileA.txt"); + private readonly FileSystemPath fileInDirectoryPath = FileSystemPath.Parse("/directory/fileInDirectory.txt"); + private readonly FileSystemPath scratchDirectoryPath = FileSystemPath.Parse("/scratchdirectory/"); + + [Test] + public void GetEntitiesOfRootTest() + { + CollectionAssert.AreEquivalent(new[] + { + textfileAPath, + directoryPath, + scratchDirectoryPath + }, fileSystem.GetEntities(FileSystemPath.Root).ToArray()); + } + + [Test] + public void GetEntitiesOfDirectoryTest() + { + CollectionAssert.AreEquivalent(new[] + { + fileInDirectoryPath + }, fileSystem.GetEntities(directoryPath).ToArray()); + } + + [Test] + public void ExistsTest() + { + Assert.IsTrue(fileSystem.Exists(FileSystemPath.Root)); + Assert.IsTrue(fileSystem.Exists(textfileAPath)); + Assert.IsTrue(fileSystem.Exists(directoryPath)); + Assert.IsTrue(fileSystem.Exists(fileInDirectoryPath)); + Assert.IsFalse(fileSystem.Exists(FileSystemPath.Parse("/nonExistingFile"))); + Assert.IsFalse(fileSystem.Exists(FileSystemPath.Parse("/nonExistingDirectory/"))); + Assert.IsFalse(fileSystem.Exists(FileSystemPath.Parse("/directory/nonExistingFileInDirectory"))); + } + + [Test] + public void CanReadFile() + { + var file = fileSystem.OpenFile(textfileAPath, FileAccess.ReadWrite); + var text = file.ReadAllText(); + Assert.IsTrue(string.Equals(text, fileContentString)); + } + + [Test] + public void CanWriteFile() + { + var file = fileSystem.OpenFile(textfileAPath, FileAccess.ReadWrite); + var textBytes = Encoding.ASCII.GetBytes(fileContentString + " and a new string"); + file.Write(textBytes); + file.Close(); + + + file = fileSystem.OpenFile(textfileAPath, FileAccess.ReadWrite); + var text = file.ReadAllText(); + Assert.IsTrue(string.Equals(text, fileContentString + " and a new string")); + } + + [Test] + public void CanAddFile() + { + var fsp = FileSystemPath.Parse("/scratchdirectory/recentlyadded.txt"); + var file = fileSystem.CreateFile(fsp); + var textBytes = Encoding.ASCII.GetBytes("recently added"); + file.Write(textBytes); + file.Close(); + + Assert.IsTrue(fileSystem.Exists(fsp)); + + file = fileSystem.OpenFile(fsp, FileAccess.ReadWrite); + var text = file.ReadAllText(); + Assert.IsTrue(string.Equals(text, "recently added")); + } + + [Test] + public void CanAddDirectory() + { + var fsp = FileSystemPath.Parse("/scratchdirectory/newdir/"); + fileSystem.CreateDirectory(fsp); + + Assert.IsTrue(fileSystem.Exists(fsp)); + } + } +} diff --git a/SharpFileSystem.Tests/SharpFileSystem.Tests.csproj b/SharpFileSystem.Tests/SharpFileSystem.Tests.csproj index 606a39c..ad9b564 100644 --- a/SharpFileSystem.Tests/SharpFileSystem.Tests.csproj +++ b/SharpFileSystem.Tests/SharpFileSystem.Tests.csproj @@ -1,4 +1,4 @@ - + Debug @@ -43,12 +43,17 @@ + + + {8d44f07f-a1f8-4544-8eef-b2fd99d0fba2} + SharpFileSystem.NetZipArchive + {3C4D07BA-23B5-4A63-92CF-F3BF892B7329} SharpFileSystem @@ -72,4 +77,4 @@ - + \ No newline at end of file diff --git a/SharpFileSystem.ZipArchive/NetZipArchiveFileSystem.cs b/SharpFileSystem.ZipArchive/NetZipArchiveFileSystem.cs new file mode 100644 index 0000000..139611b --- /dev/null +++ b/SharpFileSystem.ZipArchive/NetZipArchiveFileSystem.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO.Compression; + +namespace SharpFileSystem.SharpZipArchive +{ + public class NetZipArchiveFileSystem : IFileSystem + { + public ZipArchive ZipArchive { get; private set; } + + public static NetZipArchiveFileSystem Open(Stream s) + { + return new NetZipArchiveFileSystem(new ZipArchive(s,ZipArchiveMode.Update,true)); + } + + public static NetZipArchiveFileSystem Create(Stream s) + { + return new NetZipArchiveFileSystem(new ZipArchive(s, ZipArchiveMode.Create, true)); + } + + private NetZipArchiveFileSystem(ZipArchive archive) + { + ZipArchive = archive; + } + public void Dispose() + { + ZipArchive.Dispose(); + } + + protected IEnumerable GetZipEntries() + { + return ZipArchive.Entries; + } + protected FileSystemPath ToPath(ZipArchiveEntry entry) + { + return FileSystemPath.Parse(FileSystemPath.DirectorySeparator + entry.FullName); + } + protected string ToEntryPath(FileSystemPath path) + { + // Remove heading '/' from path. + return path.Path.TrimStart(FileSystemPath.DirectorySeparator); + } + + protected ZipArchiveEntry ToEntry(FileSystemPath path) + { + return ZipArchive.GetEntry(ToEntryPath(path)); + } + public ICollection GetEntities(FileSystemPath path) + { + return GetZipEntries().Select(ToPath).Where(path.IsParentOf) + .Select(entryPath => entryPath.ParentPath == path + ? entryPath + : path.AppendDirectory(entryPath.RemoveParent(path).GetDirectorySegments()[0]) + ) + .Distinct() + .ToList(); + } + + public bool Exists(FileSystemPath path) + { + if (path.IsFile) + return ToEntry(path) != null; + return GetZipEntries() + .Select(ToPath) + .Any(entryPath => entryPath.IsChildOf(path)); + + //foreach (var zipArchiveEntry in GetZipEntries()) + //{ + // var p = ToPath(zipArchiveEntry); + // if(p.IsChildOf(path) ) + // return true; + //} + //return false; + } + + public Stream CreateFile(FileSystemPath path) + { + var zae = ZipArchive.CreateEntry(ToEntryPath(path)); + return zae.Open(); + } + + public Stream OpenFile(FileSystemPath path, FileAccess access) + { + var zae = ZipArchive.GetEntry(ToEntryPath(path)); + return zae.Open(); + } + + public void CreateDirectory(FileSystemPath path) + { + ZipArchive.CreateEntry(ToEntryPath(path)); + } + + public void Delete(FileSystemPath path) + { + var zae = ZipArchive.GetEntry(ToEntryPath(path)); + zae.Delete(); + } + } +} diff --git a/SharpFileSystem.ZipArchive/Properties/AssemblyInfo.cs b/SharpFileSystem.ZipArchive/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..58a4df8 --- /dev/null +++ b/SharpFileSystem.ZipArchive/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SharpFileSystem.ZipArchive")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SharpFileSystem.ZipArchive")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8d44f07f-a1f8-4544-8eef-b2fd99d0fba2")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SharpFileSystem.ZipArchive/SharpFileSystem.NetZipArchive.csproj b/SharpFileSystem.ZipArchive/SharpFileSystem.NetZipArchive.csproj new file mode 100644 index 0000000..3fd8173 --- /dev/null +++ b/SharpFileSystem.ZipArchive/SharpFileSystem.NetZipArchive.csproj @@ -0,0 +1,56 @@ + + + + + Debug + AnyCPU + {8D44F07F-A1F8-4544-8EEF-B2FD99D0FBA2} + Library + Properties + SharpFileSystem.SharpZipArchive + SharpFileSystem.SharpZipArchive + v4.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + {3C4D07BA-23B5-4A63-92CF-F3BF892B7329} + SharpFileSystem + + + + \ No newline at end of file diff --git a/SharpFileSystem.sln b/SharpFileSystem.sln index aca9579..9df2031 100644 --- a/SharpFileSystem.sln +++ b/SharpFileSystem.sln @@ -1,7 +1,6 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -VisualStudioVersion = 14.0.23107.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.26228.12 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0F7EEFA8-7215-406A-9353-849DF790CAA0}" EndProject @@ -15,38 +14,45 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpFileSystem.SharpZipLib EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpFileSystem.Tests", "SharpFileSystem.Tests\SharpFileSystem.Tests.csproj", "{5B828500-C591-4B35-AFB2-D38026A7ECBC}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpFileSystem.NetZipArchive", "SharpFileSystem.ZipArchive\SharpFileSystem.NetZipArchive.csproj", "{8D44F07F-A1F8-4544-8EEF-B2FD99D0FBA2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {34CA60AC-D3A0-4A58-BCE1-3CEA55844715}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {34CA60AC-D3A0-4A58-BCE1-3CEA55844715}.Debug|Any CPU.Build.0 = Debug|Any CPU - {34CA60AC-D3A0-4A58-BCE1-3CEA55844715}.Release|Any CPU.ActiveCfg = Release|Any CPU - {34CA60AC-D3A0-4A58-BCE1-3CEA55844715}.Release|Any CPU.Build.0 = Release|Any CPU {3C4D07BA-23B5-4A63-92CF-F3BF892B7329}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3C4D07BA-23B5-4A63-92CF-F3BF892B7329}.Debug|Any CPU.Build.0 = Debug|Any CPU {3C4D07BA-23B5-4A63-92CF-F3BF892B7329}.Release|Any CPU.ActiveCfg = Release|Any CPU {3C4D07BA-23B5-4A63-92CF-F3BF892B7329}.Release|Any CPU.Build.0 = Release|Any CPU - {5B828500-C591-4B35-AFB2-D38026A7ECBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5B828500-C591-4B35-AFB2-D38026A7ECBC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5B828500-C591-4B35-AFB2-D38026A7ECBC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5B828500-C591-4B35-AFB2-D38026A7ECBC}.Release|Any CPU.Build.0 = Release|Any CPU - {E0BAC37A-07E5-4192-8BD9-51C7CA66C165}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E0BAC37A-07E5-4192-8BD9-51C7CA66C165}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E0BAC37A-07E5-4192-8BD9-51C7CA66C165}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E0BAC37A-07E5-4192-8BD9-51C7CA66C165}.Release|Any CPU.Build.0 = Release|Any CPU {EA7CBA29-CFA8-4945-BB64-CCF25078190E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EA7CBA29-CFA8-4945-BB64-CCF25078190E}.Debug|Any CPU.Build.0 = Debug|Any CPU {EA7CBA29-CFA8-4945-BB64-CCF25078190E}.Release|Any CPU.ActiveCfg = Release|Any CPU {EA7CBA29-CFA8-4945-BB64-CCF25078190E}.Release|Any CPU.Build.0 = Release|Any CPU + {34CA60AC-D3A0-4A58-BCE1-3CEA55844715}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {34CA60AC-D3A0-4A58-BCE1-3CEA55844715}.Debug|Any CPU.Build.0 = Debug|Any CPU + {34CA60AC-D3A0-4A58-BCE1-3CEA55844715}.Release|Any CPU.ActiveCfg = Release|Any CPU + {34CA60AC-D3A0-4A58-BCE1-3CEA55844715}.Release|Any CPU.Build.0 = Release|Any CPU + {E0BAC37A-07E5-4192-8BD9-51C7CA66C165}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0BAC37A-07E5-4192-8BD9-51C7CA66C165}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0BAC37A-07E5-4192-8BD9-51C7CA66C165}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0BAC37A-07E5-4192-8BD9-51C7CA66C165}.Release|Any CPU.Build.0 = Release|Any CPU + {5B828500-C591-4B35-AFB2-D38026A7ECBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B828500-C591-4B35-AFB2-D38026A7ECBC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B828500-C591-4B35-AFB2-D38026A7ECBC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B828500-C591-4B35-AFB2-D38026A7ECBC}.Release|Any CPU.Build.0 = Release|Any CPU + {8D44F07F-A1F8-4544-8EEF-B2FD99D0FBA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8D44F07F-A1F8-4544-8EEF-B2FD99D0FBA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D44F07F-A1F8-4544-8EEF-B2FD99D0FBA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8D44F07F-A1F8-4544-8EEF-B2FD99D0FBA2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection - GlobalSection(NestedProjects) = preSolution + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution Policies = $0 - $0.TextStylePolicy = $1 + $0.TextStylePolicy = $6 $1.inheritsSet = null $1.scope = text/x-csharp $0.CSharpFormattingPolicy = $2 @@ -77,27 +83,20 @@ Global $2.inheritsSet = Mono $2.inheritsScope = text/x-csharp $2.scope = text/x-csharp - $0.TextStylePolicy = $3 $3.NoTabsAfterNonTabs = True $3.EolMarker = Windows $3.inheritsSet = VisualStudio $3.inheritsScope = text/plain $3.scope = text/plain - $0.TextStylePolicy = $4 $4.inheritsSet = null $4.scope = application/config+xml - $0.XmlFormattingPolicy = $5 + $0.XmlFormattingPolicy = $7 $5.inheritsSet = null $5.scope = application/config+xml - $0.TextStylePolicy = $6 $6.inheritsSet = null $6.scope = application/xml - $0.XmlFormattingPolicy = $7 $7.inheritsSet = Mono $7.inheritsScope = application/xml $7.scope = application/xml EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection EndGlobal diff --git a/SharpFileSystem/FileSystemPath.cs b/SharpFileSystem/FileSystemPath.cs index d5aeb2c..4c189f1 100644 --- a/SharpFileSystem/FileSystemPath.cs +++ b/SharpFileSystem/FileSystemPath.cs @@ -139,7 +139,7 @@ public bool IsParentOf(FileSystemPath path) [Pure] public bool IsChildOf(FileSystemPath path) { - return path.IsParentOf(this); + return path.IsParentOf(this) || path.Equals(this); } [Pure]