mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-22 23:15:20 +00:00
switch Task to ValueTask
This commit is contained in:
@@ -8,7 +8,7 @@ using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archives;
|
||||
|
||||
class AutoArchiveFactory : IArchiveFactory
|
||||
internal class AutoArchiveFactory : IArchiveFactory
|
||||
{
|
||||
public string Name => nameof(AutoArchiveFactory);
|
||||
|
||||
@@ -22,7 +22,7 @@ class AutoArchiveFactory : IArchiveFactory
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize
|
||||
) => throw new NotSupportedException();
|
||||
|
||||
public Task<bool> IsArchiveAsync(
|
||||
public ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize,
|
||||
@@ -34,18 +34,18 @@ class AutoArchiveFactory : IArchiveFactory
|
||||
public IArchive Open(Stream stream, ReaderOptions? readerOptions = null) =>
|
||||
ArchiveFactory.Open(stream, readerOptions);
|
||||
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public async ValueTask<IArchiveAsync> OpenAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) => ArchiveFactory.OpenAsync(stream, readerOptions, cancellationToken);
|
||||
) => await ArchiveFactory.OpenAsync(stream, readerOptions, cancellationToken);
|
||||
|
||||
public IArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null) =>
|
||||
ArchiveFactory.Open(fileInfo, readerOptions);
|
||||
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public async ValueTask<IArchiveAsync> OpenAsync(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) => ArchiveFactory.OpenAsync(fileInfo, readerOptions, cancellationToken);
|
||||
) => await ArchiveFactory.OpenAsync(fileInfo, readerOptions, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -108,14 +108,14 @@ public class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZipVolume>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(stream, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(stream, readerOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -124,14 +124,14 @@ public class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZipVolume>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(fileInfo, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(fileInfo, readerOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -140,14 +140,14 @@ public class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZipVolume>
|
||||
/// <param name="streams"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(streams, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(streams, readerOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -156,14 +156,14 @@ public class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZipVolume>
|
||||
/// <param name="fileInfos"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(fileInfos, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(fileInfos, readerOptions));
|
||||
}
|
||||
|
||||
public static GZipArchive Create() => new();
|
||||
@@ -231,7 +231,7 @@ public class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZipVolume>
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async Task<bool> IsGZipFileAsync(
|
||||
public static async ValueTask<bool> IsGZipFileAsync(
|
||||
Stream stream,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
|
||||
100
src/SharpCompress/Archives/IArchiveAsyncExtensions.cs
Normal file
100
src/SharpCompress/Archives/IArchiveAsyncExtensions.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archives;
|
||||
|
||||
public static class IArchiveAsyncExtensions
|
||||
{
|
||||
/// <param name="archive">The archive to extract.</param>
|
||||
extension(IArchiveAsync archive)
|
||||
{
|
||||
/// <summary>
|
||||
/// Extract to specific directory asynchronously with progress reporting and cancellation support
|
||||
/// </summary>
|
||||
/// <param name="destinationDirectory">The folder to extract into.</param>
|
||||
/// <param name="options">Extraction options.</param>
|
||||
/// <param name="progress">Optional progress reporter for tracking extraction progress.</param>
|
||||
/// <param name="cancellationToken">Optional cancellation token.</param>
|
||||
public async Task WriteToDirectoryAsync(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null,
|
||||
IProgress<ProgressReport>? progress = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
// For solid archives (Rar, 7Zip), use the optimized reader-based approach
|
||||
if (await archive.IsSolidAsync() || archive.Type == ArchiveType.SevenZip)
|
||||
{
|
||||
using var reader = await archive.ExtractAllEntriesAsync();
|
||||
await reader.WriteAllToDirectoryAsync(
|
||||
destinationDirectory,
|
||||
options,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// For non-solid archives, extract entries directly
|
||||
await archive.WriteToDirectoryAsyncInternal(
|
||||
destinationDirectory,
|
||||
options,
|
||||
progress,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task WriteToDirectoryAsyncInternal(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options,
|
||||
IProgress<ProgressReport>? progress,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
// Prepare for progress reporting
|
||||
var totalBytes = await archive.TotalUncompressSizeAsync();
|
||||
var bytesRead = 0L;
|
||||
|
||||
// Tracking for created directories.
|
||||
var seenDirectories = new HashSet<string>();
|
||||
|
||||
// Extract
|
||||
await foreach (var entry in archive.EntriesAsync.WithCancellation(cancellationToken))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (entry.IsDirectory)
|
||||
{
|
||||
var dirPath = Path.Combine(
|
||||
destinationDirectory,
|
||||
entry.Key.NotNull("Entry Key is null")
|
||||
);
|
||||
if (
|
||||
Path.GetDirectoryName(dirPath + "/") is { } parentDirectory
|
||||
&& seenDirectories.Add(dirPath)
|
||||
)
|
||||
{
|
||||
Directory.CreateDirectory(parentDirectory);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use the entry's WriteToDirectoryAsync method which respects ExtractionOptions
|
||||
await entry
|
||||
.WriteToDirectoryAsync(destinationDirectory, options, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// Update progress
|
||||
bytesRead += entry.Size;
|
||||
progress?.Report(
|
||||
new ProgressReport(entry.Key ?? string.Empty, bytesRead, totalBytes)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
@@ -80,89 +78,5 @@ public static class IArchiveExtensions
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract to specific directory asynchronously with progress reporting and cancellation support
|
||||
/// </summary>
|
||||
/// <param name="destinationDirectory">The folder to extract into.</param>
|
||||
/// <param name="options">Extraction options.</param>
|
||||
/// <param name="progress">Optional progress reporter for tracking extraction progress.</param>
|
||||
/// <param name="cancellationToken">Optional cancellation token.</param>
|
||||
public async Task WriteToDirectoryAsync(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null,
|
||||
IProgress<ProgressReport>? progress = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
// For solid archives (Rar, 7Zip), use the optimized reader-based approach
|
||||
if (archive.IsSolid || archive.Type == ArchiveType.SevenZip)
|
||||
{
|
||||
using var reader = archive.ExtractAllEntries();
|
||||
await reader.WriteAllToDirectoryAsync(
|
||||
destinationDirectory,
|
||||
options,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// For non-solid archives, extract entries directly
|
||||
await archive.WriteToDirectoryAsyncInternal(
|
||||
destinationDirectory,
|
||||
options,
|
||||
progress,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task WriteToDirectoryAsyncInternal(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options,
|
||||
IProgress<ProgressReport>? progress,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
// Prepare for progress reporting
|
||||
var totalBytes = archive.TotalUncompressSize;
|
||||
var bytesRead = 0L;
|
||||
|
||||
// Tracking for created directories.
|
||||
var seenDirectories = new HashSet<string>();
|
||||
|
||||
// Extract
|
||||
foreach (var entry in archive.Entries)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (entry.IsDirectory)
|
||||
{
|
||||
var dirPath = Path.Combine(
|
||||
destinationDirectory,
|
||||
entry.Key.NotNull("Entry Key is null")
|
||||
);
|
||||
if (
|
||||
Path.GetDirectoryName(dirPath + "/") is { } parentDirectory
|
||||
&& seenDirectories.Add(dirPath)
|
||||
)
|
||||
{
|
||||
Directory.CreateDirectory(parentDirectory);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use the entry's WriteToDirectoryAsync method which respects ExtractionOptions
|
||||
await entry
|
||||
.WriteToDirectoryAsync(destinationDirectory, options, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// Update progress
|
||||
bytesRead += entry.Size;
|
||||
progress?.Report(
|
||||
new ProgressReport(entry.Key ?? string.Empty, bytesRead, totalBytes)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public interface IArchiveFactory : IFactory
|
||||
/// <param name="stream">An open, readable and seekable stream.</param>
|
||||
/// <param name="readerOptions">reading options.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
Task<IArchiveAsync> OpenAsync(
|
||||
ValueTask<IArchiveAsync> OpenAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -53,7 +53,7 @@ public interface IArchiveFactory : IFactory
|
||||
/// <param name="fileInfo">the file to open.</param>
|
||||
/// <param name="readerOptions">reading options.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
Task<IArchiveAsync> OpenAsync(
|
||||
ValueTask<IArchiveAsync> OpenAsync(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
|
||||
@@ -35,7 +35,7 @@ public interface IMultiArchiveFactory : IFactory
|
||||
/// <param name="streams"></param>
|
||||
/// <param name="readerOptions">reading options.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
Task<IArchiveAsync> OpenAsync(
|
||||
ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -54,7 +54,7 @@ public interface IMultiArchiveFactory : IFactory
|
||||
/// <param name="fileInfos"></param>
|
||||
/// <param name="readerOptions">reading options.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
Task<IArchiveAsync> OpenAsync(
|
||||
ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
|
||||
@@ -189,14 +189,14 @@ public class RarArchive : AbstractArchive<RarArchiveEntry, RarVolume>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(stream, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(stream, readerOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -205,14 +205,14 @@ public class RarArchive : AbstractArchive<RarArchiveEntry, RarVolume>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(fileInfo, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(fileInfo, readerOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -221,14 +221,14 @@ public class RarArchive : AbstractArchive<RarArchiveEntry, RarVolume>
|
||||
/// <param name="streams"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(streams, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(streams, readerOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -237,14 +237,14 @@ public class RarArchive : AbstractArchive<RarArchiveEntry, RarVolume>
|
||||
/// <param name="fileInfos"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(fileInfos, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(fileInfos, readerOptions));
|
||||
}
|
||||
|
||||
public static bool IsRarFile(string filePath) => IsRarFile(new FileInfo(filePath));
|
||||
|
||||
@@ -111,14 +111,14 @@ public class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, SevenZipVol
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(stream, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(stream, readerOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -127,14 +127,14 @@ public class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, SevenZipVol
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(fileInfo, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(fileInfo, readerOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -143,14 +143,14 @@ public class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, SevenZipVol
|
||||
/// <param name="streams"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(streams, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(streams, readerOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -159,14 +159,14 @@ public class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, SevenZipVol
|
||||
/// <param name="fileInfos"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(fileInfos, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(fileInfos, readerOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -109,14 +109,14 @@ public class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(stream, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(stream, readerOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -125,14 +125,14 @@ public class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(fileInfo, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(fileInfo, readerOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -141,14 +141,14 @@ public class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
|
||||
/// <param name="streams"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(streams, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(streams, readerOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -157,14 +157,14 @@ public class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
|
||||
/// <param name="fileInfos"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(fileInfos, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(fileInfos, readerOptions));
|
||||
}
|
||||
|
||||
public static bool IsTarFile(string filePath) => IsTarFile(new FileInfo(filePath));
|
||||
|
||||
@@ -130,14 +130,14 @@ public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(stream, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(stream, readerOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -146,14 +146,14 @@ public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(fileInfo, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(fileInfo, readerOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -162,14 +162,14 @@ public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
|
||||
/// <param name="streams"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(streams, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(streams, readerOptions));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -178,14 +178,14 @@ public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
|
||||
/// <param name="fileInfos"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public static async Task<IArchiveAsync> OpenAsync(
|
||||
public static ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(fileInfos, readerOptions)).ConfigureAwait(false);
|
||||
return new(Open(fileInfos, readerOptions));
|
||||
}
|
||||
|
||||
public static bool IsZipFile(
|
||||
@@ -283,7 +283,7 @@ public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<bool> IsZipFileAsync(
|
||||
public static async ValueTask<bool> IsZipFileAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize,
|
||||
@@ -319,7 +319,7 @@ public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<bool> IsZipMultiAsync(
|
||||
public static async ValueTask<bool> IsZipMultiAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize,
|
||||
@@ -345,7 +345,8 @@ public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
|
||||
var z = new SeekableZipHeaderFactory(password, new ArchiveEncoding());
|
||||
ZipHeader? x = null;
|
||||
await foreach (
|
||||
var h in z.ReadSeekableHeader(stream).WithCancellation(cancellationToken)
|
||||
var h in z.ReadSeekableHeaderAsync(stream)
|
||||
.WithCancellation(cancellationToken)
|
||||
)
|
||||
{
|
||||
x = h;
|
||||
@@ -451,6 +452,59 @@ public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
|
||||
}
|
||||
}
|
||||
|
||||
protected override async IAsyncEnumerable<ZipArchiveEntry> LoadEntriesAsync(
|
||||
IAsyncEnumerable<ZipVolume> volumes
|
||||
)
|
||||
{
|
||||
var vols = await volumes.ToListAsync();
|
||||
var volsArray = vols.ToArray();
|
||||
|
||||
await foreach (
|
||||
var h in headerFactory.NotNull().ReadSeekableHeaderAsync(volsArray.Last().Stream)
|
||||
)
|
||||
{
|
||||
if (h != null)
|
||||
{
|
||||
switch (h.ZipHeaderType)
|
||||
{
|
||||
case ZipHeaderType.DirectoryEntry:
|
||||
{
|
||||
var deh = (DirectoryEntryHeader)h;
|
||||
Stream s;
|
||||
if (
|
||||
deh.RelativeOffsetOfEntryHeader + deh.CompressedSize
|
||||
> volsArray[deh.DiskNumberStart].Stream.Length
|
||||
)
|
||||
{
|
||||
var v = volsArray.Skip(deh.DiskNumberStart).ToArray();
|
||||
s = new SourceStream(
|
||||
v[0].Stream,
|
||||
i => i < v.Length ? v[i].Stream : null,
|
||||
new ReaderOptions() { LeaveStreamOpen = true }
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
s = volsArray[deh.DiskNumberStart].Stream;
|
||||
}
|
||||
|
||||
yield return new ZipArchiveEntry(
|
||||
this,
|
||||
new SeekableZipFilePart(headerFactory.NotNull(), deh, s)
|
||||
);
|
||||
}
|
||||
break;
|
||||
case ZipHeaderType.DirectoryEnd:
|
||||
{
|
||||
var bytes = ((DirectoryEndHeader)h).Comment ?? Array.Empty<byte>();
|
||||
volsArray.Last().Comment = ReaderOptions.ArchiveEncoding.Decode(bytes);
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveTo(Stream stream) => SaveTo(stream, new WriterOptions(CompressionType.Deflate));
|
||||
|
||||
protected override void SaveTo(
|
||||
|
||||
@@ -13,9 +13,17 @@ public class ZipArchiveEntry : ZipEntry, IArchiveEntry
|
||||
|
||||
public virtual Stream OpenEntryStream() => Parts.Single().GetCompressedStream().NotNull();
|
||||
|
||||
public virtual Task<Stream> OpenEntryStreamAsync(
|
||||
public virtual async Task<Stream> OpenEntryStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
) => Task.FromResult(OpenEntryStream());
|
||||
)
|
||||
{
|
||||
var part = Parts.Single();
|
||||
if (part is SeekableZipFilePart seekablePart)
|
||||
{
|
||||
return (await seekablePart.GetCompressedStreamAsync(cancellationToken)).NotNull();
|
||||
}
|
||||
return OpenEntryStream();
|
||||
}
|
||||
|
||||
#region IArchiveEntry Members
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common.Zip.Headers;
|
||||
|
||||
namespace SharpCompress.Common.Zip;
|
||||
@@ -25,9 +27,24 @@ internal class SeekableZipFilePart : ZipFilePart
|
||||
return base.GetCompressedStream();
|
||||
}
|
||||
|
||||
internal override async Task<Stream?> GetCompressedStreamAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (!_isLocalHeaderLoaded)
|
||||
{
|
||||
await LoadLocalHeaderAsync(cancellationToken);
|
||||
_isLocalHeaderLoaded = true;
|
||||
}
|
||||
return await base.GetCompressedStreamAsync(cancellationToken);
|
||||
}
|
||||
|
||||
private void LoadLocalHeader() =>
|
||||
Header = _headerFactory.GetLocalHeader(BaseStream, (DirectoryEntryHeader)Header);
|
||||
|
||||
private async ValueTask LoadLocalHeaderAsync(CancellationToken cancellationToken = default) =>
|
||||
Header = await _headerFactory.GetLocalHeaderAsync(BaseStream, (DirectoryEntryHeader)Header);
|
||||
|
||||
protected override Stream CreateBaseStream()
|
||||
{
|
||||
BaseStream.Position = Header.DataStartPosition.NotNull();
|
||||
|
||||
@@ -19,11 +19,11 @@ internal sealed class SeekableZipHeaderFactory : ZipHeaderFactory
|
||||
internal SeekableZipHeaderFactory(string? password, ArchiveEncoding archiveEncoding)
|
||||
: base(StreamingMode.Seekable, password, archiveEncoding) { }
|
||||
|
||||
internal async IAsyncEnumerable<ZipHeader> ReadSeekableHeader(Stream stream)
|
||||
internal async IAsyncEnumerable<ZipHeader> ReadSeekableHeaderAsync(Stream stream)
|
||||
{
|
||||
var reader = new AsyncBinaryReader(stream);
|
||||
|
||||
await SeekBackToHeader(stream, reader);
|
||||
await SeekBackToHeaderAsync(stream, reader);
|
||||
|
||||
var eocd_location = stream.Position;
|
||||
var entry = new DirectoryEndHeader();
|
||||
@@ -153,6 +153,73 @@ internal sealed class SeekableZipHeaderFactory : ZipHeaderFactory
|
||||
}
|
||||
}
|
||||
|
||||
internal async IAsyncEnumerable<ZipHeader> ReadSeekableHeaderAsync(Stream stream, bool useSync)
|
||||
{
|
||||
var reader = new AsyncBinaryReader(stream);
|
||||
|
||||
await SeekBackToHeaderAsync(stream, reader);
|
||||
|
||||
var eocd_location = stream.Position;
|
||||
var entry = new DirectoryEndHeader();
|
||||
await entry.Read(reader);
|
||||
|
||||
if (entry.IsZip64)
|
||||
{
|
||||
_zip64 = true;
|
||||
|
||||
// ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR should be before the EOCD
|
||||
stream.Seek(eocd_location - ZIP64_EOCD_LENGTH - 4, SeekOrigin.Begin);
|
||||
var zip64_locator = await reader.ReadUInt32Async();
|
||||
if (zip64_locator != ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR)
|
||||
{
|
||||
throw new ArchiveException("Failed to locate the Zip64 Directory Locator");
|
||||
}
|
||||
|
||||
var zip64Locator = new Zip64DirectoryEndLocatorHeader();
|
||||
await zip64Locator.Read(reader);
|
||||
|
||||
stream.Seek(zip64Locator.RelativeOffsetOfTheEndOfDirectoryRecord, SeekOrigin.Begin);
|
||||
var zip64Signature = await reader.ReadUInt32Async();
|
||||
if (zip64Signature != ZIP64_END_OF_CENTRAL_DIRECTORY)
|
||||
{
|
||||
throw new ArchiveException("Failed to locate the Zip64 Header");
|
||||
}
|
||||
|
||||
var zip64Entry = new Zip64DirectoryEndHeader();
|
||||
await zip64Entry.Read(reader);
|
||||
stream.Seek(zip64Entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin);
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.Seek(entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
var position = stream.Position;
|
||||
while (true)
|
||||
{
|
||||
stream.Position = position;
|
||||
var signature = await reader.ReadUInt32Async();
|
||||
var nextHeader = await ReadHeader(signature, reader, _zip64);
|
||||
position = stream.Position;
|
||||
|
||||
if (nextHeader is null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (nextHeader is DirectoryEntryHeader entryHeader)
|
||||
{
|
||||
//entry could be zero bytes so we need to know that.
|
||||
entryHeader.HasData = entryHeader.CompressedSize != 0;
|
||||
yield return entryHeader;
|
||||
}
|
||||
else if (nextHeader is DirectoryEndHeader endHeader)
|
||||
{
|
||||
yield return endHeader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsMatch(byte[] haystack, int position, byte[] needle)
|
||||
{
|
||||
for (var i = 0; i < needle.Length; i++)
|
||||
@@ -166,7 +233,7 @@ internal sealed class SeekableZipHeaderFactory : ZipHeaderFactory
|
||||
return true;
|
||||
}
|
||||
|
||||
private static async ValueTask SeekBackToHeader(Stream stream, AsyncBinaryReader reader)
|
||||
private static async ValueTask SeekBackToHeaderAsync(Stream stream, AsyncBinaryReader reader)
|
||||
{
|
||||
// Minimum EOCD length
|
||||
if (stream.Length < MINIMUM_EOCD_LENGTH)
|
||||
@@ -270,4 +337,31 @@ internal sealed class SeekableZipHeaderFactory : ZipHeaderFactory
|
||||
}
|
||||
return localEntryHeader;
|
||||
}
|
||||
|
||||
internal async ValueTask<LocalEntryHeader> GetLocalHeaderAsync(
|
||||
Stream stream,
|
||||
DirectoryEntryHeader directoryEntryHeader
|
||||
)
|
||||
{
|
||||
stream.Seek(directoryEntryHeader.RelativeOffsetOfEntryHeader, SeekOrigin.Begin);
|
||||
var reader = new AsyncBinaryReader(stream);
|
||||
var signature = await reader.ReadUInt32Async();
|
||||
if (await ReadHeader(signature, reader, _zip64) is not LocalEntryHeader localEntryHeader)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
// populate fields only known from the DirectoryEntryHeader
|
||||
localEntryHeader.HasData = directoryEntryHeader.HasData;
|
||||
localEntryHeader.ExternalFileAttributes = directoryEntryHeader.ExternalFileAttributes;
|
||||
localEntryHeader.Comment = directoryEntryHeader.Comment;
|
||||
|
||||
if (FlagUtility.HasFlag(localEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor))
|
||||
{
|
||||
localEntryHeader.Crc = directoryEntryHeader.Crc;
|
||||
localEntryHeader.CompressedSize = directoryEntryHeader.CompressedSize;
|
||||
localEntryHeader.UncompressedSize = directoryEntryHeader.UncompressedSize;
|
||||
}
|
||||
return localEntryHeader;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,10 +35,10 @@ namespace SharpCompress.Factories
|
||||
public IReader OpenReader(Stream stream, ReaderOptions? options) =>
|
||||
AceReader.Open(stream, options);
|
||||
|
||||
public Task<IReader> OpenReaderAsync(
|
||||
public ValueTask<IReader> OpenReaderAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
) => Task.FromResult(OpenReader(stream, options));
|
||||
) => new(OpenReader(stream, options));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,14 +44,14 @@ namespace SharpCompress.Factories
|
||||
public IReader OpenReader(Stream stream, ReaderOptions? options) =>
|
||||
ArcReader.Open(stream, options);
|
||||
|
||||
public async Task<IReader> OpenReaderAsync(
|
||||
public ValueTask<IReader> OpenReaderAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(OpenReader(stream, options)).ConfigureAwait(false);
|
||||
return new(OpenReader(stream, options));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,14 +35,14 @@ namespace SharpCompress.Factories
|
||||
public IReader OpenReader(Stream stream, ReaderOptions? options) =>
|
||||
ArjReader.Open(stream, options);
|
||||
|
||||
public async Task<IReader> OpenReaderAsync(
|
||||
public ValueTask<IReader> OpenReaderAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(OpenReader(stream, options)).ConfigureAwait(false);
|
||||
return new(OpenReader(stream, options));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public abstract class Factory : IFactory
|
||||
);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual Task<bool> IsArchiveAsync(
|
||||
public virtual ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize,
|
||||
@@ -68,7 +68,7 @@ public abstract class Factory : IFactory
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return Task.FromResult(IsArchive(stream, password, bufferSize));
|
||||
return new(IsArchive(stream, password, bufferSize));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -49,7 +49,7 @@ public class GZipFactory
|
||||
) => GZipArchive.IsGZipFile(stream);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task<bool> IsArchiveAsync(
|
||||
public override ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize,
|
||||
@@ -65,7 +65,7 @@ public class GZipFactory
|
||||
GZipArchive.Open(stream, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -76,7 +76,7 @@ public class GZipFactory
|
||||
GZipArchive.Open(fileInfo, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -91,7 +91,7 @@ public class GZipFactory
|
||||
GZipArchive.Open(streams, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -102,7 +102,7 @@ public class GZipFactory
|
||||
GZipArchive.Open(fileInfos, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -147,14 +147,14 @@ public class GZipFactory
|
||||
GZipReader.Open(stream, options);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IReader> OpenReaderAsync(
|
||||
public ValueTask<IReader> OpenReaderAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(OpenReader(stream, options)).ConfigureAwait(false);
|
||||
return new(OpenReader(stream, options));
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -172,14 +172,14 @@ public class GZipFactory
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IWriter> OpenAsync(
|
||||
public ValueTask<IWriter> OpenAsync(
|
||||
Stream stream,
|
||||
WriterOptions writerOptions,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(stream, writerOptions)).ConfigureAwait(false);
|
||||
return new(Open(stream, writerOptions));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -51,7 +51,7 @@ public interface IFactory
|
||||
/// <param name="password">optional password</param>
|
||||
/// <param name="bufferSize">buffer size for reading</param>
|
||||
/// <param name="cancellationToken">cancellation token</param>
|
||||
Task<bool> IsArchiveAsync(
|
||||
ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize,
|
||||
|
||||
@@ -50,7 +50,7 @@ public class RarFactory : Factory, IArchiveFactory, IMultiArchiveFactory, IReade
|
||||
RarArchive.Open(stream, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -61,7 +61,7 @@ public class RarFactory : Factory, IArchiveFactory, IMultiArchiveFactory, IReade
|
||||
RarArchive.Open(fileInfo, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -76,7 +76,7 @@ public class RarFactory : Factory, IArchiveFactory, IMultiArchiveFactory, IReade
|
||||
RarArchive.Open(streams, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -87,7 +87,7 @@ public class RarFactory : Factory, IArchiveFactory, IMultiArchiveFactory, IReade
|
||||
RarArchive.Open(fileInfos, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -102,14 +102,14 @@ public class RarFactory : Factory, IArchiveFactory, IMultiArchiveFactory, IReade
|
||||
RarReader.Open(stream, options);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IReader> OpenReaderAsync(
|
||||
public ValueTask<IReader> OpenReaderAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(OpenReader(stream, options)).ConfigureAwait(false);
|
||||
return new(OpenReader(stream, options));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -45,7 +45,7 @@ public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory
|
||||
SevenZipArchive.Open(stream, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -56,7 +56,7 @@ public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory
|
||||
SevenZipArchive.Open(fileInfo, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -71,7 +71,7 @@ public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory
|
||||
SevenZipArchive.Open(streams, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -82,7 +82,7 @@ public class SevenZipFactory : Factory, IArchiveFactory, IMultiArchiveFactory
|
||||
SevenZipArchive.Open(fileInfos, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
|
||||
@@ -70,7 +70,7 @@ public class TarFactory
|
||||
TarArchive.Open(stream, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -81,7 +81,7 @@ public class TarFactory
|
||||
TarArchive.Open(fileInfo, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -96,7 +96,7 @@ public class TarFactory
|
||||
TarArchive.Open(streams, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -107,7 +107,7 @@ public class TarFactory
|
||||
TarArchive.Open(fileInfos, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -265,14 +265,14 @@ public class TarFactory
|
||||
TarReader.Open(stream, options);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IReader> OpenReaderAsync(
|
||||
public ValueTask<IReader> OpenReaderAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(OpenReader(stream, options)).ConfigureAwait(false);
|
||||
return new(OpenReader(stream, options));
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -284,14 +284,14 @@ public class TarFactory
|
||||
new TarWriter(stream, new TarWriterOptions(writerOptions));
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IWriter> OpenAsync(
|
||||
public ValueTask<IWriter> OpenAsync(
|
||||
Stream stream,
|
||||
WriterOptions writerOptions,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(stream, writerOptions)).ConfigureAwait(false);
|
||||
return new(Open(stream, writerOptions));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -82,7 +82,7 @@ public class ZipFactory
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task<bool> IsArchiveAsync(
|
||||
public override async ValueTask<bool> IsArchiveAsync(
|
||||
Stream stream,
|
||||
string? password = null,
|
||||
int bufferSize = ReaderOptions.DefaultBufferSize,
|
||||
@@ -137,7 +137,7 @@ public class ZipFactory
|
||||
ZipArchive.Open(stream, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -148,7 +148,7 @@ public class ZipFactory
|
||||
ZipArchive.Open(fileInfo, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
FileInfo fileInfo,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -163,7 +163,7 @@ public class ZipFactory
|
||||
ZipArchive.Open(streams, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<Stream> streams,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -174,7 +174,7 @@ public class ZipFactory
|
||||
ZipArchive.Open(fileInfos, readerOptions);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<IArchiveAsync> OpenAsync(
|
||||
public ValueTask<IArchiveAsync> OpenAsync(
|
||||
IReadOnlyList<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null,
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -189,14 +189,14 @@ public class ZipFactory
|
||||
ZipReader.Open(stream, options);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IReader> OpenReaderAsync(
|
||||
public ValueTask<IReader> OpenReaderAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(OpenReader(stream, options)).ConfigureAwait(false);
|
||||
return new(OpenReader(stream, options));
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -208,14 +208,14 @@ public class ZipFactory
|
||||
new ZipWriter(stream, new ZipWriterOptions(writerOptions));
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IWriter> OpenAsync(
|
||||
public ValueTask<IWriter> OpenAsync(
|
||||
Stream stream,
|
||||
WriterOptions writerOptions,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
return await Task.FromResult(Open(stream, writerOptions)).ConfigureAwait(false);
|
||||
return new(Open(stream, writerOptions));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -21,7 +21,7 @@ public interface IReaderFactory : Factories.IFactory
|
||||
/// <param name="options"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<IReader> OpenReaderAsync(
|
||||
ValueTask<IReader> OpenReaderAsync(
|
||||
Stream stream,
|
||||
ReaderOptions? options,
|
||||
CancellationToken cancellationToken = default
|
||||
|
||||
@@ -9,7 +9,7 @@ public interface IWriterFactory : IFactory
|
||||
{
|
||||
IWriter Open(Stream stream, WriterOptions writerOptions);
|
||||
|
||||
Task<IWriter> OpenAsync(
|
||||
ValueTask<IWriter> OpenAsync(
|
||||
Stream stream,
|
||||
WriterOptions writerOptions,
|
||||
CancellationToken cancellationToken = default
|
||||
|
||||
@@ -23,7 +23,7 @@ public class ExtractAllTests : TestBase
|
||||
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, archivePath);
|
||||
var options = new ExtractionOptions() { ExtractFullPath = true, Overwrite = true };
|
||||
|
||||
using var archive = ArchiveFactory.Open(testArchive);
|
||||
await using var archive = await ArchiveFactory.OpenAsync(testArchive);
|
||||
await archive.WriteToDirectoryAsync(SCRATCH_FILES_PATH, options);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.Zip;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.Test.Mocks;
|
||||
using SharpCompress.Writers;
|
||||
using SharpCompress.Writers.Zip;
|
||||
using Xunit;
|
||||
@@ -118,7 +119,7 @@ public class ZipArchiveAsyncTests : ArchiveTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Zip_Random_Write_Remove_Async()
|
||||
public async Task Zip_Random_Write_Remove_Sync()
|
||||
{
|
||||
var scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip");
|
||||
var unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
|
||||
@@ -140,7 +141,7 @@ public class ZipArchiveAsyncTests : ArchiveTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Zip_Random_Write_Add_Async()
|
||||
public async Task Zip_Random_Write_Add_Sync()
|
||||
{
|
||||
var jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg");
|
||||
var scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip");
|
||||
@@ -182,9 +183,9 @@ public class ZipArchiveAsyncTests : ArchiveTests
|
||||
public async Task Zip_Deflate_Entry_Stream_Async()
|
||||
{
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.zip")))
|
||||
using (var archive = ZipArchive.Open(stream))
|
||||
await using (var archive = await ZipArchive.OpenAsync(new AsyncOnlyStream(stream)))
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
await foreach (var entry in archive.EntriesAsync.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
await entry.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
@@ -199,7 +200,7 @@ public class ZipArchiveAsyncTests : ArchiveTests
|
||||
public async Task Zip_Deflate_Archive_WriteToDirectoryAsync()
|
||||
{
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.zip")))
|
||||
using (var archive = ZipArchive.Open(stream))
|
||||
await using (var archive = await ZipArchive.OpenAsync(new AsyncOnlyStream(stream)))
|
||||
{
|
||||
await archive.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
@@ -216,7 +217,7 @@ public class ZipArchiveAsyncTests : ArchiveTests
|
||||
var progress = new Progress<ProgressReport>(report => progressReports.Add(report));
|
||||
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.zip")))
|
||||
using (var archive = ZipArchive.Open(stream))
|
||||
await using (var archive = await ZipArchive.OpenAsync(new AsyncOnlyStream(stream)))
|
||||
{
|
||||
await archive.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
|
||||
Reference in New Issue
Block a user