diff --git a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs index f60105a5..f89ba345 100644 --- a/src/SharpCompress/Archives/IArchiveEntryExtensions.cs +++ b/src/SharpCompress/Archives/IArchiveEntryExtensions.cs @@ -106,8 +106,7 @@ public static class IArchiveEntryExtensions string destinationDirectory, ExtractionOptions? options = null ) => - ExtractionMethods.WriteEntryToDirectory( - entry, + entry.WriteEntryToDirectory( destinationDirectory, options, (path) => entry.WriteToFile(path, options) @@ -121,9 +120,8 @@ public static class IArchiveEntryExtensions ExtractionOptions? options = null, CancellationToken cancellationToken = default ) => - await ExtractionMethods + await entry .WriteEntryToDirectoryAsync( - entry, destinationDirectory, options, async (path, ct) => @@ -136,8 +134,7 @@ public static class IArchiveEntryExtensions /// Extract to specific file /// public void WriteToFile(string destinationFileName, ExtractionOptions? options = null) => - ExtractionMethods.WriteEntryToFile( - entry, + entry.WriteEntryToFile( destinationFileName, options, (x, fm) => @@ -155,9 +152,8 @@ public static class IArchiveEntryExtensions ExtractionOptions? options = null, CancellationToken cancellationToken = default ) => - await ExtractionMethods + await entry .WriteEntryToFileAsync( - entry, destinationFileName, options, async (x, fm, ct) => diff --git a/src/SharpCompress/Archives/IArchiveExtensions.cs b/src/SharpCompress/Archives/IArchiveExtensions.cs index 0417cdd7..2ae6e4ab 100644 --- a/src/SharpCompress/Archives/IArchiveExtensions.cs +++ b/src/SharpCompress/Archives/IArchiveExtensions.cs @@ -49,8 +49,7 @@ public static class IArchiveExtensions { if (entry.IsDirectory) { - ExtractionMethods.WriteEntryToDirectoryCore( - entry, + entry.WriteEntryToDirectoryCore( fullDestinationDirectoryPath, options, _ => { } @@ -58,8 +57,7 @@ public static class IArchiveExtensions continue; } - ExtractionMethods.WriteEntryToDirectoryCore( - entry, + entry.WriteEntryToDirectoryCore( fullDestinationDirectoryPath, options, path => entry.WriteToFile(path, options) diff --git a/src/SharpCompress/Archives/IAsyncArchiveExtensions.cs b/src/SharpCompress/Archives/IAsyncArchiveExtensions.cs index 3d9db3f2..a3e9948e 100644 --- a/src/SharpCompress/Archives/IAsyncArchiveExtensions.cs +++ b/src/SharpCompress/Archives/IAsyncArchiveExtensions.cs @@ -70,9 +70,8 @@ public static class IAsyncArchiveExtensions if (entry.IsDirectory) { - await ExtractionMethods + await entry .WriteEntryToDirectoryAsyncCore( - entry, fullDestinationDirectoryPath, options, (_, _) => new ValueTask(), @@ -82,9 +81,8 @@ public static class IAsyncArchiveExtensions continue; } - await ExtractionMethods + await entry .WriteEntryToDirectoryAsyncCore( - entry, fullDestinationDirectoryPath, options, async (path, ct) => diff --git a/src/SharpCompress/Common/DirectoryManagement.cs b/src/SharpCompress/Common/DirectoryManagement.cs index b4574018..4bd4585d 100644 --- a/src/SharpCompress/Common/DirectoryManagement.cs +++ b/src/SharpCompress/Common/DirectoryManagement.cs @@ -4,7 +4,6 @@ namespace SharpCompress.Common; internal static class DirectoryManagement { - internal const string CreateDirectoryOutsideDestinationMessage = "Entry is trying to create a directory outside of the destination directory."; internal const string WriteFileOutsideDestinationMessage = @@ -59,8 +58,6 @@ internal static class DirectoryManagement throw new ExtractionException(exceptionMessage); } - - private static bool IsDirectorySeparator(char value) => value == Path.DirectorySeparatorChar || value == Path.AltDirectorySeparatorChar; @@ -77,5 +74,4 @@ internal static class DirectoryManagement return end == path.Length ? path : path.Substring(0, end); } - } diff --git a/src/SharpCompress/Common/ExtractionMethods.Async.cs b/src/SharpCompress/Common/ExtractionMethods.Async.cs deleted file mode 100644 index b9c913cd..00000000 --- a/src/SharpCompress/Common/ExtractionMethods.Async.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace SharpCompress.Common; - -internal static partial class ExtractionMethods -{ - public static async ValueTask WriteEntryToDirectoryAsync( - IEntry entry, - string destinationDirectory, - ExtractionOptions? options, - Func writeAsync, - CancellationToken cancellationToken = default - ) - { - options ??= new ExtractionOptions(); - var fullDestinationDirectoryPath = DirectoryManagement.GetFullDestinationDirectoryPath(destinationDirectory); - - await WriteEntryToDirectoryAsyncCore( - entry, - fullDestinationDirectoryPath, - options, - writeAsync, - cancellationToken - ) - .ConfigureAwait(false); - } - - internal static async ValueTask WriteEntryToDirectoryAsyncCore( - IEntry entry, - string fullDestinationDirectoryPath, - ExtractionOptions options, - Func writeAsync, - CancellationToken cancellationToken = default - ) - { - var destinationFileName = GetEntryDestinationFileName( - entry, - fullDestinationDirectoryPath, - options - ); - - if (!entry.IsDirectory) - { - destinationFileName = Path.GetFullPath(destinationFileName); - - DirectoryManagement.EnsurePathInDestinationDirectory( - destinationFileName, - fullDestinationDirectoryPath, - DirectoryManagement.WriteFileOutsideDestinationMessage - ); - - await writeAsync(destinationFileName, cancellationToken).ConfigureAwait(false); - } - else if (options.ExtractFullPath) - { - destinationFileName = Path.GetFullPath(destinationFileName); - - DirectoryManagement.EnsurePathInDestinationDirectory( - destinationFileName, - fullDestinationDirectoryPath, - DirectoryManagement.CreateDirectoryOutsideDestinationMessage - ); - - if (!Directory.Exists(destinationFileName)) - { - Directory.CreateDirectory(destinationFileName); - } - } - } - - public static async ValueTask WriteEntryToFileAsync( - IEntry entry, - string destinationFileName, - ExtractionOptions? options, - Func openAndWriteAsync, - CancellationToken cancellationToken = default - ) - { - options ??= new ExtractionOptions(); - if (entry.LinkTarget != null) - { - if (options.SymbolicLinkHandler is not null) - { - options.SymbolicLinkHandler(destinationFileName, entry.LinkTarget); - } - else - { - ExtractionOptions.DefaultSymbolicLinkHandler(destinationFileName, entry.LinkTarget); - } - return; - } - else - { - var fm = FileMode.Create; - - if (!options.Overwrite) - { - fm = FileMode.CreateNew; - } - - await openAndWriteAsync(destinationFileName, fm, cancellationToken) - .ConfigureAwait(false); - entry.PreserveExtractionOptions(destinationFileName, options); - } - } -} diff --git a/src/SharpCompress/Common/ExtractionMethods.cs b/src/SharpCompress/Common/ExtractionMethods.cs deleted file mode 100644 index 66172b36..00000000 --- a/src/SharpCompress/Common/ExtractionMethods.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System; -using System.IO; - -namespace SharpCompress.Common; - -internal static partial class ExtractionMethods -{ - /// - /// Extract to specific directory, retaining filename - /// - public static void WriteEntryToDirectory( - IEntry entry, - string destinationDirectory, - ExtractionOptions? options, - Action write - ) - { - options ??= new ExtractionOptions(); - var fullDestinationDirectoryPath = DirectoryManagement.GetFullDestinationDirectoryPath(destinationDirectory); - - WriteEntryToDirectoryCore(entry, fullDestinationDirectoryPath, options, write); - } - - internal static void WriteEntryToDirectoryCore( - IEntry entry, - string fullDestinationDirectoryPath, - ExtractionOptions options, - Action write - ) - { - var destinationFileName = GetEntryDestinationFileName( - entry, - fullDestinationDirectoryPath, - options - ); - - if (!entry.IsDirectory) - { - destinationFileName = Path.GetFullPath(destinationFileName); - - DirectoryManagement.EnsurePathInDestinationDirectory( - destinationFileName, - fullDestinationDirectoryPath, - DirectoryManagement.WriteFileOutsideDestinationMessage - ); - - write(destinationFileName); - } - else if (options.ExtractFullPath) - { - destinationFileName = Path.GetFullPath(destinationFileName); - - DirectoryManagement.EnsurePathInDestinationDirectory( - destinationFileName, - fullDestinationDirectoryPath, - DirectoryManagement.CreateDirectoryOutsideDestinationMessage - ); - - if (!Directory.Exists(destinationFileName)) - { - Directory.CreateDirectory(destinationFileName); - } - } - } - - private static string GetEntryDestinationFileName( - IEntry entry, - string fullDestinationDirectoryPath, - ExtractionOptions options - ) - { - var file = Path.GetFileName(entry.Key.NotNull("Entry Key is null")).NotNull("File is null"); - file = Utility.ReplaceInvalidFileNameChars(file); - - if (options.ExtractFullPath) - { - var folder = Path.GetDirectoryName(entry.Key.NotNull("Entry Key is null")) - .NotNull("Directory is null"); - var destdir = Path.GetFullPath(Path.Combine(fullDestinationDirectoryPath, folder)); - - DirectoryManagement.EnsurePathInDestinationDirectory( - destdir, - fullDestinationDirectoryPath, - entry.IsDirectory - ? DirectoryManagement.CreateDirectoryOutsideDestinationMessage - : DirectoryManagement.WriteFileOutsideDestinationMessage - ); - - if (!Directory.Exists(destdir)) - { - Directory.CreateDirectory(destdir); - } - - return Path.Combine(destdir, file); - } - - return Path.Combine(fullDestinationDirectoryPath, file); - } - public static void WriteEntryToFile( - IEntry entry, - string destinationFileName, - ExtractionOptions? options, - Action openAndWrite - ) - { - options ??= new ExtractionOptions(); - if (entry.LinkTarget != null) - { - if (options.SymbolicLinkHandler is not null) - { - options.SymbolicLinkHandler(destinationFileName, entry.LinkTarget); - } - else - { - ExtractionOptions.DefaultSymbolicLinkHandler(destinationFileName, entry.LinkTarget); - } - return; - } - else - { - var fm = FileMode.Create; - - if (!options.Overwrite) - { - fm = FileMode.CreateNew; - } - - openAndWrite(destinationFileName, fm); - entry.PreserveExtractionOptions(destinationFileName, options); - } - } -} diff --git a/src/SharpCompress/Common/IEntryExtensions.Async.cs b/src/SharpCompress/Common/IEntryExtensions.Async.cs new file mode 100644 index 00000000..234a1d3c --- /dev/null +++ b/src/SharpCompress/Common/IEntryExtensions.Async.cs @@ -0,0 +1,114 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace SharpCompress.Common; + +internal static partial class IEntryExtensions +{ + extension(IEntry entry) + { + public async ValueTask WriteEntryToDirectoryAsync( + string destinationDirectory, + ExtractionOptions? options, + Func writeAsync, + CancellationToken cancellationToken = default + ) + { + options ??= new ExtractionOptions(); + var fullDestinationDirectoryPath = DirectoryManagement.GetFullDestinationDirectoryPath( + destinationDirectory + ); + + await WriteEntryToDirectoryAsyncCore( + entry, + fullDestinationDirectoryPath, + options, + writeAsync, + cancellationToken + ) + .ConfigureAwait(false); + } + + internal async ValueTask WriteEntryToDirectoryAsyncCore( + string fullDestinationDirectoryPath, + ExtractionOptions options, + Func writeAsync, + CancellationToken cancellationToken = default + ) + { + var destinationFileName = GetEntryDestinationFileName( + entry, + fullDestinationDirectoryPath, + options + ); + + if (!entry.IsDirectory) + { + destinationFileName = Path.GetFullPath(destinationFileName); + + DirectoryManagement.EnsurePathInDestinationDirectory( + destinationFileName, + fullDestinationDirectoryPath, + DirectoryManagement.WriteFileOutsideDestinationMessage + ); + + await writeAsync(destinationFileName, cancellationToken).ConfigureAwait(false); + } + else if (options.ExtractFullPath) + { + destinationFileName = Path.GetFullPath(destinationFileName); + + DirectoryManagement.EnsurePathInDestinationDirectory( + destinationFileName, + fullDestinationDirectoryPath, + DirectoryManagement.CreateDirectoryOutsideDestinationMessage + ); + + if (!Directory.Exists(destinationFileName)) + { + Directory.CreateDirectory(destinationFileName); + } + } + } + + public async ValueTask WriteEntryToFileAsync( + string destinationFileName, + ExtractionOptions? options, + Func openAndWriteAsync, + CancellationToken cancellationToken = default + ) + { + options ??= new ExtractionOptions(); + if (entry.LinkTarget != null) + { + if (options.SymbolicLinkHandler is not null) + { + options.SymbolicLinkHandler(destinationFileName, entry.LinkTarget); + } + else + { + ExtractionOptions.DefaultSymbolicLinkHandler( + destinationFileName, + entry.LinkTarget + ); + } + return; + } + else + { + var fm = FileMode.Create; + + if (!options.Overwrite) + { + fm = FileMode.CreateNew; + } + + await openAndWriteAsync(destinationFileName, fm, cancellationToken) + .ConfigureAwait(false); + entry.PreserveExtractionOptions(destinationFileName, options); + } + } + } +} diff --git a/src/SharpCompress/Common/IEntryExtensions.cs b/src/SharpCompress/Common/IEntryExtensions.cs new file mode 100644 index 00000000..a0b0d5bc --- /dev/null +++ b/src/SharpCompress/Common/IEntryExtensions.cs @@ -0,0 +1,139 @@ +using System; +using System.IO; + +namespace SharpCompress.Common; + +internal static partial class IEntryExtensions +{ + extension(IEntry entry) + { + /// + /// Extract to specific directory, retaining filename + /// + public void WriteEntryToDirectory( + string destinationDirectory, + ExtractionOptions? options, + Action write + ) + { + options ??= new ExtractionOptions(); + var fullDestinationDirectoryPath = DirectoryManagement.GetFullDestinationDirectoryPath( + destinationDirectory + ); + + WriteEntryToDirectoryCore(entry, fullDestinationDirectoryPath, options, write); + } + + internal void WriteEntryToDirectoryCore( + string fullDestinationDirectoryPath, + ExtractionOptions options, + Action write + ) + { + var destinationFileName = GetEntryDestinationFileName( + entry, + fullDestinationDirectoryPath, + options + ); + + if (!entry.IsDirectory) + { + destinationFileName = Path.GetFullPath(destinationFileName); + + DirectoryManagement.EnsurePathInDestinationDirectory( + destinationFileName, + fullDestinationDirectoryPath, + DirectoryManagement.WriteFileOutsideDestinationMessage + ); + + write(destinationFileName); + } + else if (options.ExtractFullPath) + { + destinationFileName = Path.GetFullPath(destinationFileName); + + DirectoryManagement.EnsurePathInDestinationDirectory( + destinationFileName, + fullDestinationDirectoryPath, + DirectoryManagement.CreateDirectoryOutsideDestinationMessage + ); + + if (!Directory.Exists(destinationFileName)) + { + Directory.CreateDirectory(destinationFileName); + } + } + } + + private string GetEntryDestinationFileName( + string fullDestinationDirectoryPath, + ExtractionOptions options + ) + { + var file = Path.GetFileName(entry.Key.NotNull("Entry Key is null")) + .NotNull("File is null"); + file = Utility.ReplaceInvalidFileNameChars(file); + + if (options.ExtractFullPath) + { + var folder = Path.GetDirectoryName(entry.Key.NotNull("Entry Key is null")) + .NotNull("Directory is null"); + var destdir = Path.GetFullPath(Path.Combine(fullDestinationDirectoryPath, folder)); + + DirectoryManagement.EnsurePathInDestinationDirectory( + destdir, + fullDestinationDirectoryPath, + entry.IsDirectory + ? DirectoryManagement.CreateDirectoryOutsideDestinationMessage + : DirectoryManagement.WriteFileOutsideDestinationMessage + ); + + if (!Directory.Exists(destdir)) + { + Directory.CreateDirectory(destdir); + } + + return Path.Combine(destdir, file); + } + + return Path.Combine(fullDestinationDirectoryPath, file); + } + + public void WriteEntryToFile( + string destinationFileName, + ExtractionOptions? options, + Action openAndWrite + ) + { + options ??= new ExtractionOptions(); + if (entry.LinkTarget != null) + { + if (options.SymbolicLinkHandler is not null) + { + options.SymbolicLinkHandler(destinationFileName, entry.LinkTarget); + } + else + { + ExtractionOptions.DefaultSymbolicLinkHandler( + destinationFileName, + entry.LinkTarget + ); + } + + return; + } + else + { + var fm = FileMode.Create; + + if (!options.Overwrite) + { + fm = FileMode.CreateNew; + } + + openAndWrite(destinationFileName, fm); + entry.PreserveExtractionOptions(destinationFileName, options); + } + } + } +} diff --git a/src/SharpCompress/Readers/IAsyncReaderExtensions.cs b/src/SharpCompress/Readers/IAsyncReaderExtensions.cs index 120e2f69..a2c01e52 100644 --- a/src/SharpCompress/Readers/IAsyncReaderExtensions.cs +++ b/src/SharpCompress/Readers/IAsyncReaderExtensions.cs @@ -17,9 +17,8 @@ public static class IAsyncReaderExtensions ExtractionOptions? options = null, CancellationToken cancellationToken = default ) => - await ExtractionMethods - .WriteEntryToDirectoryAsync( - reader.Entry, + await reader + .Entry.WriteEntryToDirectoryAsync( destinationDirectory, options, async (path, ct) => @@ -36,9 +35,8 @@ public static class IAsyncReaderExtensions ExtractionOptions? options = null, CancellationToken cancellationToken = default ) => - await ExtractionMethods - .WriteEntryToFileAsync( - reader.Entry, + await reader + .Entry.WriteEntryToFileAsync( destinationFileName, options, async (x, fm, ct) => @@ -72,9 +70,8 @@ public static class IAsyncReaderExtensions ExtractionOptions? options = null, CancellationToken cancellationToken = default ) => - await ExtractionMethods - .WriteEntryToFileAsync( - reader.Entry, + await reader + .Entry.WriteEntryToFileAsync( destinationFileName, options, async (x, fm, ct) => diff --git a/src/SharpCompress/Readers/IReaderExtensions.cs b/src/SharpCompress/Readers/IReaderExtensions.cs index 54dfa14f..74c708a5 100644 --- a/src/SharpCompress/Readers/IReaderExtensions.cs +++ b/src/SharpCompress/Readers/IReaderExtensions.cs @@ -40,8 +40,7 @@ public static class IReaderExtensions string destinationDirectory, ExtractionOptions? options = null ) => - ExtractionMethods.WriteEntryToDirectory( - reader.Entry, + reader.Entry.WriteEntryToDirectory( destinationDirectory, options, (path) => reader.WriteEntryToFile(path, options) @@ -54,8 +53,7 @@ public static class IReaderExtensions string destinationFileName, ExtractionOptions? options = null ) => - ExtractionMethods.WriteEntryToFile( - reader.Entry, + reader.Entry.WriteEntryToFile( destinationFileName, options, (x, fm) =>