made methods extension methods for IEntry

This commit is contained in:
Adam Hathcock
2026-05-05 17:30:02 +01:00
parent bd0fa73cce
commit 2c35d2d242
10 changed files with 269 additions and 274 deletions

View File

@@ -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
/// </summary>
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) =>

View File

@@ -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)

View File

@@ -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) =>

View File

@@ -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);
}
}

View File

@@ -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<string, CancellationToken, ValueTask> 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<string, CancellationToken, ValueTask> 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<string, FileMode, CancellationToken, ValueTask> 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);
}
}
}

View File

@@ -1,132 +0,0 @@
using System;
using System.IO;
namespace SharpCompress.Common;
internal static partial class ExtractionMethods
{
/// <summary>
/// Extract to specific directory, retaining filename
/// </summary>
public static void WriteEntryToDirectory(
IEntry entry,
string destinationDirectory,
ExtractionOptions? options,
Action<string> 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<string> 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<string, FileMode> 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);
}
}
}

View File

@@ -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<string, CancellationToken, ValueTask> 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<string, CancellationToken, ValueTask> 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<string, FileMode, CancellationToken, ValueTask> 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);
}
}
}
}

View File

@@ -0,0 +1,139 @@
using System;
using System.IO;
namespace SharpCompress.Common;
internal static partial class IEntryExtensions
{
extension(IEntry entry)
{
/// <summary>
/// Extract to specific directory, retaining filename
/// </summary>
public void WriteEntryToDirectory(
string destinationDirectory,
ExtractionOptions? options,
Action<string> write
)
{
options ??= new ExtractionOptions();
var fullDestinationDirectoryPath = DirectoryManagement.GetFullDestinationDirectoryPath(
destinationDirectory
);
WriteEntryToDirectoryCore(entry, fullDestinationDirectoryPath, options, write);
}
internal void WriteEntryToDirectoryCore(
string fullDestinationDirectoryPath,
ExtractionOptions options,
Action<string> 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<string, FileMode> 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);
}
}
}
}

View File

@@ -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) =>

View File

@@ -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) =>