Merge remote-tracking branch 'origin/master' into adam/add-alternate-compressions

# Conflicts:
#	src/SharpCompress/Archives/GZip/GZipArchive.Async.cs
#	src/SharpCompress/Archives/GZip/GZipArchive.cs
#	src/SharpCompress/Archives/Zip/ZipArchive.Async.cs
#	src/SharpCompress/Archives/Zip/ZipArchive.cs
#	src/SharpCompress/Common/GZip/GZipEntry.Async.cs
#	src/SharpCompress/Common/GZip/GZipEntry.cs
#	src/SharpCompress/Common/Options/IReaderOptions.cs
#	src/SharpCompress/Readers/ReaderOptions.cs
#	src/SharpCompress/Readers/Zip/ZipReader.Async.cs
#	src/SharpCompress/Readers/Zip/ZipReader.cs
#	src/SharpCompress/Writers/GZip/GZipWriterOptions.cs
This commit is contained in:
Adam Hathcock
2026-02-10 15:21:13 +00:00
219 changed files with 3874 additions and 1921 deletions

View File

@@ -21,7 +21,7 @@ public abstract partial class AbstractArchive<TEntry, TVolume>
IAsyncEnumerable<TVolume> volumes
)
{
foreach (var item in LoadEntries(await volumes.ToListAsync()))
foreach (var item in LoadEntries(await volumes.ToListAsync().ConfigureAwait(false)))
{
yield return item;
}
@@ -47,8 +47,8 @@ public abstract partial class AbstractArchive<TEntry, TVolume>
private async ValueTask EnsureEntriesLoadedAsync()
{
await _lazyEntriesAsync.EnsureFullyLoaded();
await _lazyVolumesAsync.EnsureFullyLoaded();
await _lazyEntriesAsync.EnsureFullyLoaded().ConfigureAwait(false);
await _lazyVolumesAsync.EnsureFullyLoaded().ConfigureAwait(false);
}
private async IAsyncEnumerable<IArchiveEntry> EntriesAsyncCast()
@@ -73,29 +73,31 @@ public abstract partial class AbstractArchive<TEntry, TVolume>
public async ValueTask<IAsyncReader> ExtractAllEntriesAsync()
{
if (!await IsSolidAsync() && Type != ArchiveType.SevenZip)
if (!await IsSolidAsync().ConfigureAwait(false) && Type != ArchiveType.SevenZip)
{
throw new SharpCompressException(
"ExtractAllEntries can only be used on solid archives or 7Zip archives (which require random access)."
);
}
await EnsureEntriesLoadedAsync();
return await CreateReaderForSolidExtractionAsync();
await EnsureEntriesLoadedAsync().ConfigureAwait(false);
return await CreateReaderForSolidExtractionAsync().ConfigureAwait(false);
}
public virtual ValueTask<bool> IsSolidAsync() => new(false);
public async ValueTask<bool> IsCompleteAsync()
{
await EnsureEntriesLoadedAsync();
return await EntriesAsync.AllAsync(x => x.IsComplete);
await EnsureEntriesLoadedAsync().ConfigureAwait(false);
return await EntriesAsync.AllAsync(x => x.IsComplete).ConfigureAwait(false);
}
public async ValueTask<long> TotalSizeAsync() =>
await EntriesAsync.AggregateAsync(0L, (total, cf) => total + cf.CompressedSize);
await EntriesAsync
.AggregateAsync(0L, (total, cf) => total + cf.CompressedSize)
.ConfigureAwait(false);
public async ValueTask<long> TotalUncompressedSizeAsync() =>
await EntriesAsync.AggregateAsync(0L, (total, cf) => total + cf.Size);
await EntriesAsync.AggregateAsync(0L, (total, cf) => total + cf.Size).ConfigureAwait(false);
public ValueTask<bool> IsEncryptedAsync() => new(IsEncrypted);

View File

@@ -20,7 +20,7 @@ public abstract partial class AbstractArchive<TEntry, TVolume> : IArchive, IAsyn
private readonly LazyAsyncReadOnlyCollection<TVolume> _lazyVolumesAsync;
private readonly LazyAsyncReadOnlyCollection<TEntry> _lazyEntriesAsync;
protected ReaderOptions ReaderOptions { get; }
public ReaderOptions ReaderOptions { get; protected set; }
internal AbstractArchive(ArchiveType type, SourceStream sourceStream)
{

View File

@@ -6,13 +6,13 @@ using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
using SharpCompress.Common.Options;
using SharpCompress.Writers;
namespace SharpCompress.Archives;
public abstract partial class AbstractWritableArchive<TEntry, TVolume>
public abstract partial class AbstractWritableArchive<TEntry, TVolume, TOptions>
where TEntry : IArchiveEntry
where TVolume : IVolume
where TOptions : IWriterOptions
{
// Async property moved from main file
private IAsyncEnumerable<TEntry> OldEntriesAsync =>
@@ -39,7 +39,7 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
if (!removedEntries.Contains(entry))
{
removedEntries.Add(entry);
await RebuildModifiedCollectionAsync();
await RebuildModifiedCollectionAsync().ConfigureAwait(false);
}
}
@@ -86,7 +86,7 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
}
var entry = CreateEntry(key, source, size, modified, closeStream);
newEntries.Add(entry);
await RebuildModifiedCollectionAsync();
await RebuildModifiedCollectionAsync().ConfigureAwait(false);
return entry;
}
@@ -106,13 +106,13 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
}
var entry = CreateDirectoryEntry(key, modified);
newEntries.Add(entry);
await RebuildModifiedCollectionAsync();
await RebuildModifiedCollectionAsync().ConfigureAwait(false);
return entry;
}
public async ValueTask SaveToAsync(
Stream stream,
IWriterOptions options,
TOptions options,
CancellationToken cancellationToken = default
)
{
@@ -121,4 +121,12 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
await SaveToAsync(stream, options, OldEntriesAsync, newEntries, cancellationToken)
.ConfigureAwait(false);
}
protected abstract ValueTask SaveToAsync(
Stream stream,
TOptions options,
IAsyncEnumerable<TEntry> oldEntries,
IEnumerable<TEntry> newEntries,
CancellationToken cancellationToken = default
);
}

View File

@@ -11,18 +11,19 @@ using SharpCompress.Writers;
namespace SharpCompress.Archives;
public abstract partial class AbstractWritableArchive<TEntry, TVolume>
public abstract partial class AbstractWritableArchive<TEntry, TVolume, TOptions>
: AbstractArchive<TEntry, TVolume>,
IWritableArchive,
IWritableAsyncArchive
IWritableArchive<TOptions>,
IWritableAsyncArchive<TOptions>
where TEntry : IArchiveEntry
where TVolume : IVolume
where TOptions : IWriterOptions
{
private class RebuildPauseDisposable : IDisposable
{
private readonly AbstractWritableArchive<TEntry, TVolume> archive;
private readonly AbstractWritableArchive<TEntry, TVolume, TOptions> archive;
public RebuildPauseDisposable(AbstractWritableArchive<TEntry, TVolume> archive)
public RebuildPauseDisposable(AbstractWritableArchive<TEntry, TVolume, TOptions> archive)
{
this.archive = archive;
archive.pauseRebuilding = true;
@@ -151,13 +152,15 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
long size,
DateTime? modified,
CancellationToken cancellationToken
) => await AddEntryAsync(key, source, closeStream, size, modified, cancellationToken);
) =>
await AddEntryAsync(key, source, closeStream, size, modified, cancellationToken)
.ConfigureAwait(false);
async ValueTask<IArchiveEntry> IWritableAsyncArchive.AddDirectoryEntryAsync(
string key,
DateTime? modified,
CancellationToken cancellationToken
) => await AddDirectoryEntryAsync(key, modified, cancellationToken);
) => await AddDirectoryEntryAsync(key, modified, cancellationToken).ConfigureAwait(false);
public TEntry AddDirectoryEntry(string key, DateTime? modified = null)
{
@@ -175,7 +178,7 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
return entry;
}
public void SaveTo(Stream stream, IWriterOptions options)
public void SaveTo(Stream stream, TOptions options)
{
//reset streams of new entries
newEntries.Cast<IWritableArchiveEntry>().ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin));
@@ -211,19 +214,11 @@ public abstract partial class AbstractWritableArchive<TEntry, TVolume>
protected abstract void SaveTo(
Stream stream,
IWriterOptions options,
TOptions options,
IEnumerable<TEntry> oldEntries,
IEnumerable<TEntry> newEntries
);
protected abstract ValueTask SaveToAsync(
Stream stream,
IWriterOptions options,
IAsyncEnumerable<TEntry> oldEntries,
IEnumerable<TEntry> newEntries,
CancellationToken cancellationToken = default
);
public override void Dispose()
{
base.Dispose();

View File

@@ -19,8 +19,9 @@ public static partial class ArchiveFactory
CancellationToken cancellationToken = default
)
{
readerOptions ??= new ReaderOptions();
var factory = await FindFactoryAsync<IArchiveFactory>(stream, cancellationToken);
readerOptions ??= ReaderOptions.ForExternalStream;
var factory = await FindFactoryAsync<IArchiveFactory>(stream, cancellationToken)
.ConfigureAwait(false);
return factory.OpenAsyncArchive(stream, readerOptions);
}
@@ -40,9 +41,10 @@ public static partial class ArchiveFactory
CancellationToken cancellationToken = default
)
{
options ??= new ReaderOptions { LeaveStreamOpen = false };
options ??= ReaderOptions.ForOwnedFile;
var factory = await FindFactoryAsync<IArchiveFactory>(fileInfo, cancellationToken);
var factory = await FindFactoryAsync<IArchiveFactory>(fileInfo, cancellationToken)
.ConfigureAwait(false);
return factory.OpenAsyncArchive(fileInfo, options);
}
@@ -62,14 +64,16 @@ public static partial class ArchiveFactory
var fileInfo = filesArray[0];
if (filesArray.Length == 1)
{
return await OpenAsyncArchive(fileInfo, options, cancellationToken);
return await OpenAsyncArchive(fileInfo, options, cancellationToken)
.ConfigureAwait(false);
}
fileInfo.NotNull(nameof(fileInfo));
options ??= new ReaderOptions { LeaveStreamOpen = false };
options ??= ReaderOptions.ForOwnedFile;
var factory = await FindFactoryAsync<IMultiArchiveFactory>(fileInfo, cancellationToken);
return factory.OpenAsyncArchive(filesArray, options, cancellationToken);
var factory = await FindFactoryAsync<IMultiArchiveFactory>(fileInfo, cancellationToken)
.ConfigureAwait(false);
return factory.OpenAsyncArchive(filesArray, options);
}
public static async ValueTask<IAsyncArchive> OpenAsyncArchive(
@@ -89,13 +93,15 @@ public static partial class ArchiveFactory
var firstStream = streamsArray[0];
if (streamsArray.Length == 1)
{
return await OpenAsyncArchive(firstStream, options, cancellationToken);
return await OpenAsyncArchive(firstStream, options, cancellationToken)
.ConfigureAwait(false);
}
firstStream.NotNull(nameof(firstStream));
options ??= new ReaderOptions();
options ??= ReaderOptions.ForExternalStream;
var factory = await FindFactoryAsync<IMultiArchiveFactory>(firstStream, cancellationToken);
var factory = await FindFactoryAsync<IMultiArchiveFactory>(firstStream, cancellationToken)
.ConfigureAwait(false);
return factory.OpenAsyncArchive(streamsArray, options);
}
@@ -117,7 +123,7 @@ public static partial class ArchiveFactory
{
finfo.NotNull(nameof(finfo));
using Stream stream = finfo.OpenRead();
return await FindFactoryAsync<T>(stream, cancellationToken);
return await FindFactoryAsync<T>(stream, cancellationToken).ConfigureAwait(false);
}
private static async ValueTask<T> FindFactoryAsync<T>(
@@ -140,7 +146,11 @@ public static partial class ArchiveFactory
{
stream.Seek(startPosition, SeekOrigin.Begin);
if (await factory.IsArchiveAsync(stream, cancellationToken: cancellationToken))
if (
await factory
.IsArchiveAsync(stream, cancellationToken: cancellationToken)
.ConfigureAwait(false)
)
{
stream.Seek(startPosition, SeekOrigin.Begin);

View File

@@ -5,6 +5,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
using SharpCompress.Common.Options;
using SharpCompress.Factories;
using SharpCompress.IO;
using SharpCompress.Readers;
@@ -15,22 +16,23 @@ public static partial class ArchiveFactory
{
public static IArchive OpenArchive(Stream stream, ReaderOptions? readerOptions = null)
{
readerOptions ??= new ReaderOptions();
readerOptions ??= ReaderOptions.ForExternalStream;
return FindFactory<IArchiveFactory>(stream).OpenArchive(stream, readerOptions);
}
public static IWritableArchive CreateArchive(ArchiveType type)
public static IWritableArchive<TOptions> CreateArchive<TOptions>()
where TOptions : IWriterOptions
{
var factory = Factory
.Factories.OfType<IWriteableArchiveFactory>()
.FirstOrDefault(item => item.KnownArchiveType == type);
.Factories.OfType<IWriteableArchiveFactory<TOptions>>()
.FirstOrDefault();
if (factory != null)
{
return factory.CreateArchive();
}
throw new NotSupportedException("Cannot create Archives of type: " + type);
throw new NotSupportedException("Cannot create Archives of type: " + typeof(TOptions));
}
public static IArchive OpenArchive(string filePath, ReaderOptions? options = null)
@@ -41,7 +43,7 @@ public static partial class ArchiveFactory
public static IArchive OpenArchive(FileInfo fileInfo, ReaderOptions? options = null)
{
options ??= new ReaderOptions { LeaveStreamOpen = false };
options ??= ReaderOptions.ForOwnedFile;
return FindFactory<IArchiveFactory>(fileInfo).OpenArchive(fileInfo, options);
}
@@ -65,7 +67,7 @@ public static partial class ArchiveFactory
}
fileInfo.NotNull(nameof(fileInfo));
options ??= new ReaderOptions { LeaveStreamOpen = false };
options ??= ReaderOptions.ForOwnedFile;
return FindFactory<IMultiArchiveFactory>(fileInfo).OpenArchive(filesArray, options);
}
@@ -86,7 +88,7 @@ public static partial class ArchiveFactory
}
firstStream.NotNull(nameof(firstStream));
options ??= new ReaderOptions();
options ??= ReaderOptions.ForExternalStream;
return FindFactory<IMultiArchiveFactory>(firstStream).OpenArchive(streamsArray, options);
}
@@ -94,11 +96,11 @@ public static partial class ArchiveFactory
public static void WriteToDirectory(
string sourceArchive,
string destinationDirectory,
ExtractionOptions? options = null
ReaderOptions? options = null
)
{
using var archive = OpenArchive(sourceArchive);
archive.WriteToDirectory(destinationDirectory, options);
using var archive = OpenArchive(sourceArchive, options);
archive.WriteToDirectory(destinationDirectory);
}
public static T FindFactory<T>(string path)

View File

@@ -6,7 +6,6 @@ using System.Threading.Tasks;
using SharpCompress.Common;
using SharpCompress.Common.GZip;
using SharpCompress.Common.Options;
using SharpCompress.IO;
using SharpCompress.Readers;
using SharpCompress.Readers.GZip;
using SharpCompress.Writers;
@@ -25,13 +24,13 @@ public partial class GZipArchive
)
{
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
await SaveToAsync(stream, new WriterOptions(CompressionType.GZip), cancellationToken)
await SaveToAsync(stream, new GZipWriterOptions(CompressionType.GZip), cancellationToken)
.ConfigureAwait(false);
}
protected override async ValueTask SaveToAsync(
Stream stream,
IWriterOptions options,
GZipWriterOptions options,
IAsyncEnumerable<GZipArchiveEntry> oldEntries,
IEnumerable<GZipArchiveEntry> newEntries,
CancellationToken cancellationToken = default
@@ -41,7 +40,7 @@ public partial class GZipArchive
{
throw new InvalidFormatException("Only one entry is allowed in a GZip Archive");
}
using var writer = new GZipWriter(
await using var writer = new GZipWriter(
stream,
options as GZipWriterOptions ?? new GZipWriterOptions(options)
);
@@ -51,7 +50,9 @@ public partial class GZipArchive
{
if (!entry.IsDirectory)
{
using var entryStream = entry.OpenEntryStream();
using var entryStream = await entry
.OpenEntryStreamAsync(cancellationToken)
.ConfigureAwait(false);
await writer
.WriteAsync(
entry.Key.NotNull("Entry Key is null"),
@@ -63,7 +64,9 @@ public partial class GZipArchive
}
foreach (var entry in newEntries.Where(x => !x.IsDirectory))
{
using var entryStream = entry.OpenEntryStream();
using var entryStream = await entry
.OpenEntryStreamAsync(cancellationToken)
.ConfigureAwait(false);
await writer
.WriteAsync(entry.Key.NotNull("Entry Key is null"), entryStream, cancellationToken)
.ConfigureAwait(false);
@@ -81,14 +84,13 @@ public partial class GZipArchive
IAsyncEnumerable<GZipVolume> volumes
)
{
var stream = (await volumes.SingleAsync()).Stream;
var stream = (await volumes.SingleAsync().ConfigureAwait(false)).Stream;
yield return new GZipArchiveEntry(
this,
await GZipFilePart.CreateAsync(
stream,
ReaderOptions.ArchiveEncoding,
ReaderOptions.CompressionProviders
)
await GZipFilePart
.CreateAsync(stream, ReaderOptions.ArchiveEncoding)
.ConfigureAwait(false),
ReaderOptions
);
}
}

View File

@@ -5,43 +5,41 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
using SharpCompress.Common.GZip;
using SharpCompress.IO;
using SharpCompress.Readers;
using SharpCompress.Readers.GZip;
using SharpCompress.Writers;
using SharpCompress.Writers.GZip;
namespace SharpCompress.Archives.GZip;
public partial class GZipArchive
#if NET8_0_OR_GREATER
: IWritableArchiveOpenable,
IMultiArchiveOpenable<IWritableArchive, IWritableAsyncArchive>
: IWritableArchiveOpenable<GZipWriterOptions>,
IMultiArchiveOpenable<
IWritableArchive<GZipWriterOptions>,
IWritableAsyncArchive<GZipWriterOptions>
>
#endif
{
public static IWritableAsyncArchive OpenAsyncArchive(
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
string path,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
ReaderOptions? readerOptions = null
)
{
cancellationToken.ThrowIfCancellationRequested();
path.NotNullOrEmpty(nameof(path));
return (IWritableAsyncArchive)OpenArchive(
new FileInfo(path),
readerOptions ?? new ReaderOptions()
);
return (IWritableAsyncArchive<GZipWriterOptions>)
OpenArchive(new FileInfo(path), readerOptions ?? new ReaderOptions());
}
public static IWritableArchive OpenArchive(string filePath, ReaderOptions? readerOptions = null)
public static IWritableArchive<GZipWriterOptions> OpenArchive(
string filePath,
ReaderOptions? readerOptions = null
)
{
filePath.NotNullOrEmpty(nameof(filePath));
return OpenArchive(new FileInfo(filePath), readerOptions ?? new ReaderOptions());
}
public static IWritableArchive OpenArchive(
public static IWritableArchive<GZipWriterOptions> OpenArchive(
FileInfo fileInfo,
ReaderOptions? readerOptions = null
)
@@ -56,7 +54,7 @@ public partial class GZipArchive
);
}
public static IWritableArchive OpenArchive(
public static IWritableArchive<GZipWriterOptions> OpenArchive(
IEnumerable<FileInfo> fileInfos,
ReaderOptions? readerOptions = null
)
@@ -72,7 +70,7 @@ public partial class GZipArchive
);
}
public static IWritableArchive OpenArchive(
public static IWritableArchive<GZipWriterOptions> OpenArchive(
IEnumerable<Stream> streams,
ReaderOptions? readerOptions = null
)
@@ -88,7 +86,10 @@ public partial class GZipArchive
);
}
public static IWritableArchive OpenArchive(Stream stream, ReaderOptions? readerOptions = null)
public static IWritableArchive<GZipWriterOptions> OpenArchive(
Stream stream,
ReaderOptions? readerOptions = null
)
{
stream.NotNull(nameof(stream));
@@ -102,49 +103,30 @@ public partial class GZipArchive
);
}
public static IWritableAsyncArchive OpenAsyncArchive(
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
Stream stream,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IWritableAsyncArchive)OpenArchive(stream, readerOptions);
}
ReaderOptions? readerOptions = null
) => (IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(stream, readerOptions);
public static IWritableAsyncArchive OpenAsyncArchive(
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
FileInfo fileInfo,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IWritableAsyncArchive)OpenArchive(fileInfo, readerOptions);
}
ReaderOptions? readerOptions = null
) => (IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(fileInfo, readerOptions);
public static IWritableAsyncArchive OpenAsyncArchive(
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
IReadOnlyList<Stream> streams,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IWritableAsyncArchive)OpenArchive(streams, readerOptions);
}
ReaderOptions? readerOptions = null
) => (IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(streams, readerOptions);
public static IWritableAsyncArchive OpenAsyncArchive(
public static IWritableAsyncArchive<GZipWriterOptions> OpenAsyncArchive(
IReadOnlyList<FileInfo> fileInfos,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IWritableAsyncArchive)OpenArchive(fileInfos, readerOptions);
}
ReaderOptions? readerOptions = null
) => (IWritableAsyncArchive<GZipWriterOptions>)OpenArchive(fileInfos, readerOptions);
public static IWritableArchive CreateArchive() => new GZipArchive();
public static IWritableArchive<GZipWriterOptions> CreateArchive() => new GZipArchive();
public static IWritableAsyncArchive CreateAsyncArchive() => new GZipArchive();
public static IWritableAsyncArchive<GZipWriterOptions> CreateAsyncArchive() =>
new GZipArchive();
public static bool IsGZipFile(string filePath) => IsGZipFile(new FileInfo(filePath));

View File

@@ -2,8 +2,6 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
using SharpCompress.Common.GZip;
using SharpCompress.Common.Options;
@@ -15,7 +13,8 @@ using SharpCompress.Writers.GZip;
namespace SharpCompress.Archives.GZip;
public partial class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZipVolume>
public partial class GZipArchive
: AbstractWritableArchive<GZipArchiveEntry, GZipVolume, GZipWriterOptions>
{
private GZipArchive(SourceStream sourceStream)
: base(ArchiveType.GZip, sourceStream) { }
@@ -34,7 +33,7 @@ public partial class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZi
public void SaveTo(FileInfo fileInfo)
{
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
SaveTo(stream, new WriterOptions(CompressionType.GZip));
SaveTo(stream, new GZipWriterOptions(CompressionType.GZip));
}
protected override GZipArchiveEntry CreateEntryInternal(
@@ -59,7 +58,7 @@ public partial class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZi
protected override void SaveTo(
Stream stream,
IWriterOptions options,
GZipWriterOptions options,
IEnumerable<GZipArchiveEntry> oldEntries,
IEnumerable<GZipArchiveEntry> newEntries
)
@@ -88,11 +87,8 @@ public partial class GZipArchive : AbstractWritableArchive<GZipArchiveEntry, GZi
var stream = volumes.Single().Stream;
yield return new GZipArchiveEntry(
this,
GZipFilePart.Create(
stream,
ReaderOptions.ArchiveEncoding,
ReaderOptions.CompressionProviders
)
GZipFilePart.Create(stream, ReaderOptions.ArchiveEncoding),
ReaderOptions
);
}

View File

@@ -1,15 +1,16 @@
using System.IO;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common.GZip;
using SharpCompress.Common.Options;
namespace SharpCompress.Archives.GZip;
public class GZipArchiveEntry : GZipEntry, IArchiveEntry
{
internal GZipArchiveEntry(GZipArchive archive, GZipFilePart? part)
: base(part) => Archive = archive;
internal GZipArchiveEntry(GZipArchive archive, GZipFilePart? part, IReaderOptions readerOptions)
: base(part, readerOptions) => Archive = archive;
public virtual Stream OpenEntryStream()
{

View File

@@ -19,7 +19,7 @@ internal sealed class GZipWritableArchiveEntry : GZipArchiveEntry, IWritableArch
DateTime? lastModified,
bool closeStream
)
: base(archive, null)
: base(archive, null, archive.ReaderOptions)
{
this.stream = stream;
Key = path;

View File

@@ -12,6 +12,11 @@ public interface IArchive : IDisposable
ArchiveType Type { get; }
/// <summary>
/// The options used when opening this archive, including extraction behavior settings.
/// </summary>
ReaderOptions ReaderOptions { get; }
/// <summary>
/// Use this method to extract all entries in an archive in order.
/// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be

View File

@@ -47,11 +47,13 @@ public static class IArchiveEntryExtensions
}
#if LEGACY_DOTNET
using var entryStream = await archiveEntry.OpenEntryStreamAsync(cancellationToken);
using var entryStream = await archiveEntry
.OpenEntryStreamAsync(cancellationToken)
.ConfigureAwait(false);
#else
await using var entryStream = await archiveEntry.OpenEntryStreamAsync(
cancellationToken
);
await using var entryStream = await archiveEntry
.OpenEntryStreamAsync(cancellationToken)
.ConfigureAwait(false);
#endif
var sourceStream = WrapWithProgress(entryStream, archiveEntry, progress);
await sourceStream
@@ -100,15 +102,11 @@ public static class IArchiveEntryExtensions
/// <summary>
/// Extract to specific directory, retaining filename
/// </summary>
public void WriteToDirectory(
string destinationDirectory,
ExtractionOptions? options = null
) =>
public void WriteToDirectory(string destinationDirectory) =>
ExtractionMethods.WriteEntryToDirectory(
entry,
destinationDirectory,
options,
entry.WriteToFile
(path) => entry.WriteToFile(path)
);
/// <summary>
@@ -116,15 +114,14 @@ public static class IArchiveEntryExtensions
/// </summary>
public async ValueTask WriteToDirectoryAsync(
string destinationDirectory,
ExtractionOptions? options = null,
CancellationToken cancellationToken = default
) =>
await ExtractionMethods
.WriteEntryToDirectoryAsync(
entry,
destinationDirectory,
options,
entry.WriteToFileAsync,
async (path, ct) =>
await entry.WriteToFileAsync(path, ct).ConfigureAwait(false),
cancellationToken
)
.ConfigureAwait(false);
@@ -132,11 +129,10 @@ public static class IArchiveEntryExtensions
/// <summary>
/// Extract to specific file
/// </summary>
public void WriteToFile(string destinationFileName, ExtractionOptions? options = null) =>
public void WriteToFile(string destinationFileName) =>
ExtractionMethods.WriteEntryToFile(
entry,
destinationFileName,
options,
(x, fm) =>
{
using var fs = File.Open(destinationFileName, fm);
@@ -149,14 +145,12 @@ public static class IArchiveEntryExtensions
/// </summary>
public async ValueTask WriteToFileAsync(
string destinationFileName,
ExtractionOptions? options = null,
CancellationToken cancellationToken = default
) =>
await ExtractionMethods
.WriteEntryToFileAsync(
entry,
destinationFileName,
options,
async (x, fm, ct) =>
{
using var fs = File.Open(destinationFileName, fm);

View File

@@ -14,28 +14,25 @@ public static class IArchiveExtensions
/// Extract to specific directory with progress reporting
/// </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>
public void WriteToDirectory(
string destinationDirectory,
ExtractionOptions? options = null,
IProgress<ProgressReport>? progress = null
)
{
if (archive.IsSolid || archive.Type == ArchiveType.SevenZip)
{
using var reader = archive.ExtractAllEntries();
reader.WriteAllToDirectory(destinationDirectory, options);
reader.WriteAllToDirectory(destinationDirectory);
}
else
{
archive.WriteToDirectoryInternal(destinationDirectory, options, progress);
archive.WriteToDirectoryInternal(destinationDirectory, progress);
}
}
private void WriteToDirectoryInternal(
string destinationDirectory,
ExtractionOptions? options,
IProgress<ProgressReport>? progress
)
{
@@ -61,7 +58,7 @@ public static class IArchiveExtensions
continue;
}
entry.WriteToDirectory(destinationDirectory, options);
entry.WriteToDirectory(destinationDirectory);
bytesRead += entry.Size;
progress?.Report(

View File

@@ -20,20 +20,17 @@ public interface IArchiveOpenable<TSync, TASync>
public static abstract TASync OpenAsyncArchive(
string path,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
ReaderOptions? readerOptions = null
);
public static abstract TASync OpenAsyncArchive(
Stream stream,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
ReaderOptions? readerOptions = null
);
public static abstract TASync OpenAsyncArchive(
FileInfo fileInfo,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
ReaderOptions? readerOptions = null
);
}

View File

@@ -17,44 +17,45 @@ public static class IAsyncArchiveExtensions
/// </summary>
/// <param name="archive">The archive to extract.</param>
/// <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 ValueTask WriteToDirectoryAsync(
string destinationDirectory,
ExtractionOptions? options = null,
IProgress<ProgressReport>? progress = null,
CancellationToken cancellationToken = default
)
{
if (await archive.IsSolidAsync() || archive.Type == ArchiveType.SevenZip)
if (
await archive.IsSolidAsync().ConfigureAwait(false)
|| archive.Type == ArchiveType.SevenZip
)
{
await using var reader = await archive.ExtractAllEntriesAsync();
await reader.WriteAllToDirectoryAsync(
destinationDirectory,
options,
cancellationToken
);
await using var reader = await archive
.ExtractAllEntriesAsync()
.ConfigureAwait(false);
await reader
.WriteAllToDirectoryAsync(destinationDirectory, cancellationToken)
.ConfigureAwait(false);
}
else
{
await archive.WriteToDirectoryAsyncInternal(
destinationDirectory,
options,
progress,
cancellationToken
);
await archive
.WriteToDirectoryAsyncInternal(
destinationDirectory,
progress,
cancellationToken
)
.ConfigureAwait(false);
}
}
private async ValueTask WriteToDirectoryAsyncInternal(
string destinationDirectory,
ExtractionOptions? options,
IProgress<ProgressReport>? progress,
CancellationToken cancellationToken
)
{
var totalBytes = await archive.TotalUncompressedSizeAsync();
var totalBytes = await archive.TotalUncompressedSizeAsync().ConfigureAwait(false);
var bytesRead = 0L;
var seenDirectories = new HashSet<string>();
@@ -79,7 +80,7 @@ public static class IAsyncArchiveExtensions
}
await entry
.WriteToDirectoryAsync(destinationDirectory, options, cancellationToken)
.WriteToDirectoryAsync(destinationDirectory, cancellationToken)
.ConfigureAwait(false);
bytesRead += entry.Size;

View File

@@ -50,10 +50,8 @@ public interface IMultiArchiveFactory : IFactory
/// </summary>
/// <param name="fileInfos"></param>
/// <param name="readerOptions">reading options.</param>
/// <param name="cancellationToken">Cancellation token.</param>
IAsyncArchive OpenAsyncArchive(
IReadOnlyList<FileInfo> fileInfos,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
ReaderOptions? readerOptions = null
);
}

View File

@@ -22,14 +22,12 @@ public interface IMultiArchiveOpenable<TSync, TASync>
public static abstract TASync OpenAsyncArchive(
IReadOnlyList<Stream> streams,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
ReaderOptions? readerOptions = null
);
public static abstract TASync OpenAsyncArchive(
IReadOnlyList<FileInfo> fileInfos,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
ReaderOptions? readerOptions = null
);
}
#endif

View File

@@ -28,28 +28,23 @@ public interface IWritableArchive : IArchive, IWritableArchiveCommon
IArchiveEntry AddDirectoryEntry(string key, DateTime? modified = null);
/// <summary>
/// Saves the archive to the specified stream using the given writer options.
/// </summary>
void SaveTo(Stream stream, IWriterOptions options);
/// <summary>
/// Removes the specified entry from the archive.
/// </summary>
void RemoveEntry(IArchiveEntry entry);
}
public interface IWritableAsyncArchive : IAsyncArchive, IWritableArchiveCommon
public interface IWritableArchive<TOptions> : IWritableArchive
where TOptions : IWriterOptions
{
/// <summary>
/// Asynchronously saves the archive to the specified stream using the given writer options.
/// Saves the archive to the specified stream using the given writer options.
/// </summary>
ValueTask SaveToAsync(
Stream stream,
IWriterOptions options,
CancellationToken cancellationToken = default
);
void SaveTo(Stream stream, TOptions options);
}
public interface IWritableAsyncArchive : IAsyncArchive, IWritableArchiveCommon
{
/// <summary>
/// Asynchronously adds an entry to the archive with the specified key, source stream, and options.
/// </summary>
@@ -76,3 +71,16 @@ public interface IWritableAsyncArchive : IAsyncArchive, IWritableArchiveCommon
/// </summary>
ValueTask RemoveEntryAsync(IArchiveEntry entry);
}
public interface IWritableAsyncArchive<TOptions> : IWritableAsyncArchive
where TOptions : IWriterOptions
{
/// <summary>
/// Asynchronously saves the archive to the specified stream using the given writer options.
/// </summary>
ValueTask SaveToAsync(
Stream stream,
TOptions options,
CancellationToken cancellationToken = default
);
}

View File

@@ -58,17 +58,23 @@ public static class IWritableArchiveExtensions
fileInfo.LastWriteTime
);
}
}
public void SaveTo(string filePath, IWriterOptions? options = null) =>
writableArchive.SaveTo(
new FileInfo(filePath),
options ?? new WriterOptions(CompressionType.Deflate)
);
public static void SaveTo<TOptions>(
this IWritableArchive<TOptions> writableArchive,
string filePath,
TOptions options
)
where TOptions : IWriterOptions => writableArchive.SaveTo(new FileInfo(filePath), options);
public void SaveTo(FileInfo fileInfo, IWriterOptions? options = null)
{
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
writableArchive.SaveTo(stream, options ?? new WriterOptions(CompressionType.Deflate));
}
public static void SaveTo<TOptions>(
this IWritableArchive<TOptions> writableArchive,
FileInfo fileInfo,
TOptions options
)
where TOptions : IWriterOptions
{
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
writableArchive.SaveTo(stream, options);
}
}

View File

@@ -1,10 +1,13 @@
using SharpCompress.Common.Options;
#if NET8_0_OR_GREATER
namespace SharpCompress.Archives;
public interface IWritableArchiveOpenable
: IArchiveOpenable<IWritableArchive, IWritableAsyncArchive>
public interface IWritableArchiveOpenable<TOptions>
: IArchiveOpenable<IWritableArchive<TOptions>, IWritableAsyncArchive<TOptions>>
where TOptions : IWriterOptions
{
public static abstract IWritableArchive CreateArchive();
public static abstract IWritableAsyncArchive CreateAsyncArchive();
public static abstract IWritableArchive<TOptions> CreateArchive();
public static abstract IWritableAsyncArchive<TOptions> CreateAsyncArchive();
}
#endif

View File

@@ -25,13 +25,15 @@ public static class IWritableAsyncArchiveExtensions
)
{
var fileInfo = new FileInfo(path);
await writableArchive.AddEntryAsync(
path.Substring(filePath.Length),
fileInfo.OpenRead(),
true,
fileInfo.Length,
fileInfo.LastWriteTime
);
await writableArchive
.AddEntryAsync(
path.Substring(filePath.Length),
fileInfo.OpenRead(),
true,
fileInfo.Length,
fileInfo.LastWriteTime
)
.ConfigureAwait(false);
}
}
}
@@ -60,32 +62,26 @@ public static class IWritableAsyncArchiveExtensions
fileInfo.LastWriteTime
);
}
}
public ValueTask SaveToAsync(
string filePath,
IWriterOptions? options = null,
CancellationToken cancellationToken = default
) =>
writableArchive.SaveToAsync(
new FileInfo(filePath),
options ?? new WriterOptions(CompressionType.Deflate),
cancellationToken
);
public static ValueTask SaveToAsync<TOptions>(
this IWritableAsyncArchive<TOptions> writableArchive,
string filePath,
TOptions options,
CancellationToken cancellationToken = default
)
where TOptions : IWriterOptions =>
writableArchive.SaveToAsync(new FileInfo(filePath), options, cancellationToken);
public async ValueTask SaveToAsync(
FileInfo fileInfo,
IWriterOptions? options = null,
CancellationToken cancellationToken = default
)
{
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
await writableArchive
.SaveToAsync(
stream,
options ?? new WriterOptions(CompressionType.Deflate),
cancellationToken
)
.ConfigureAwait(false);
}
public static async ValueTask SaveToAsync<TOptions>(
this IWritableAsyncArchive<TOptions> writableArchive,
FileInfo fileInfo,
TOptions options,
CancellationToken cancellationToken = default
)
where TOptions : IWriterOptions
{
using var stream = fileInfo.Open(FileMode.Create, FileAccess.Write);
await writableArchive.SaveToAsync(stream, options, cancellationToken).ConfigureAwait(false);
}
}

View File

@@ -1,3 +1,5 @@
using SharpCompress.Common.Options;
namespace SharpCompress.Archives;
/// <summary>
@@ -10,11 +12,12 @@ namespace SharpCompress.Archives;
/// <item><see cref="Factories.ZipFactory"/></item>
/// <item><see cref="Factories.GZipFactory"/></item>
/// </list>
public interface IWriteableArchiveFactory : Factories.IFactory
public interface IWriteableArchiveFactory<TOptions> : Factories.IFactory
where TOptions : IWriterOptions
{
/// <summary>
/// Creates a new, empty archive, ready to be written.
/// </summary>
/// <returns></returns>
IWritableArchive CreateArchive();
IWritableArchive<TOptions> CreateArchive();
}

View File

@@ -25,13 +25,13 @@ public partial class RarArchive
}
_disposed = true;
await base.DisposeAsync();
await base.DisposeAsync().ConfigureAwait(false);
}
}
protected override async ValueTask<IAsyncReader> CreateReaderForSolidExtractionAsync()
{
if (await this.IsMultipartVolumeAsync())
if (await this.IsMultipartVolumeAsync().ConfigureAwait(false))
{
var streams = await VolumesAsync
.Select(volume =>
@@ -39,15 +39,18 @@ public partial class RarArchive
volume.Stream.Position = 0;
return volume.Stream;
})
.ToListAsync();
.ToListAsync()
.ConfigureAwait(false);
return (RarReader)RarReader.OpenReader(streams, ReaderOptions);
}
var stream = (await VolumesAsync.FirstAsync()).Stream;
var stream = (await VolumesAsync.FirstAsync().ConfigureAwait(false)).Stream;
stream.Position = 0;
return (RarReader)RarReader.OpenReader(stream, ReaderOptions);
}
public override async ValueTask<bool> IsSolidAsync() =>
await (await VolumesAsync.CastAsync<RarVolume>().FirstAsync()).IsSolidArchiveAsync();
await (await VolumesAsync.CastAsync<RarVolume>().FirstAsync().ConfigureAwait(false))
.IsSolidArchiveAsync()
.ConfigureAwait(false);
}

View File

@@ -25,12 +25,16 @@ public static class RarArchiveExtensions
/// RarArchive is the first volume of a multi-part archive. If MultipartVolume is true and IsFirstVolume is false then the first volume file must be missing.
/// </summary>
public async ValueTask<bool> IsFirstVolumeAsync() =>
(await archive.VolumesAsync.CastAsync<RarVolume>().FirstAsync()).IsFirstVolume;
(
await archive.VolumesAsync.CastAsync<RarVolume>().FirstAsync().ConfigureAwait(false)
).IsFirstVolume;
/// <summary>
/// RarArchive is part of a multi-part archive.
/// </summary>
public async ValueTask<bool> IsMultipartVolumeAsync() =>
(await archive.VolumesAsync.CastAsync<RarVolume>().FirstAsync()).IsMultiVolume;
(
await archive.VolumesAsync.CastAsync<RarVolume>().FirstAsync().ConfigureAwait(false)
).IsMultiVolume;
}
}

View File

@@ -22,11 +22,9 @@ public partial class RarArchive
{
public static IRarAsyncArchive OpenAsyncArchive(
string path,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
ReaderOptions? readerOptions = null
)
{
cancellationToken.ThrowIfCancellationRequested();
path.NotNullOrEmpty(nameof(path));
return (IRarAsyncArchive)OpenArchive(new FileInfo(path), readerOptions);
}
@@ -102,41 +100,33 @@ public partial class RarArchive
public static IRarAsyncArchive OpenAsyncArchive(
Stream stream,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
ReaderOptions? readerOptions = null
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IRarAsyncArchive)OpenArchive(stream, readerOptions);
}
public static IRarAsyncArchive OpenAsyncArchive(
FileInfo fileInfo,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
ReaderOptions? readerOptions = null
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IRarAsyncArchive)OpenArchive(fileInfo, readerOptions);
}
public static IRarAsyncArchive OpenAsyncArchive(
IReadOnlyList<Stream> streams,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
ReaderOptions? readerOptions = null
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IRarAsyncArchive)OpenArchive(streams, readerOptions);
}
public static IRarAsyncArchive OpenAsyncArchive(
IReadOnlyList<FileInfo> fileInfos,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
ReaderOptions? readerOptions = null
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IRarAsyncArchive)OpenArchive(fileInfos, readerOptions);
}

View File

@@ -21,9 +21,9 @@ public partial class RarArchiveEntry
stream = new RarStream(
archive.UnpackV1.Value,
FileHeader,
await MultiVolumeReadOnlyAsyncStream.Create(
Parts.ToAsyncEnumerable().CastAsync<RarFilePart>()
)
await MultiVolumeReadOnlyAsyncStream
.Create(Parts.ToAsyncEnumerable().CastAsync<RarFilePart>())
.ConfigureAwait(false)
);
}
else
@@ -31,13 +31,13 @@ public partial class RarArchiveEntry
stream = new RarStream(
archive.UnpackV2017.Value,
FileHeader,
await MultiVolumeReadOnlyAsyncStream.Create(
Parts.ToAsyncEnumerable().CastAsync<RarFilePart>()
)
await MultiVolumeReadOnlyAsyncStream
.Create(Parts.ToAsyncEnumerable().CastAsync<RarFilePart>())
.ConfigureAwait(false)
);
}
await stream.InitializeAsync(cancellationToken);
await stream.InitializeAsync(cancellationToken).ConfigureAwait(false);
return stream;
}
}

View File

@@ -23,6 +23,7 @@ public partial class RarArchiveEntry : RarEntry, IArchiveEntry
IEnumerable<RarFilePart> parts,
ReaderOptions readerOptions
)
: base(readerOptions)
{
this.parts = parts.ToList();
this.archive = archive;

View File

@@ -21,15 +21,12 @@ public partial class SevenZipArchive
{
stream.Position = 0;
var reader = new ArchiveReader();
await reader.OpenAsync(
stream,
lookForHeader: ReaderOptions.LookForHeader,
cancellationToken
);
_database = await reader.ReadDatabaseAsync(
new PasswordProvider(ReaderOptions.Password),
cancellationToken
);
await reader
.OpenAsync(stream, lookForHeader: ReaderOptions.LookForHeader, cancellationToken)
.ConfigureAwait(false);
_database = await reader
.ReadDatabaseAsync(new PasswordProvider(ReaderOptions.Password), cancellationToken)
.ConfigureAwait(false);
}
}
@@ -37,8 +34,8 @@ public partial class SevenZipArchive
IAsyncEnumerable<SevenZipVolume> volumes
)
{
var stream = (await volumes.SingleAsync()).Stream;
await LoadFactoryAsync(stream);
var stream = (await volumes.SingleAsync().ConfigureAwait(false)).Stream;
await LoadFactoryAsync(stream).ConfigureAwait(false);
if (_database is null)
{
yield break;
@@ -49,7 +46,8 @@ public partial class SevenZipArchive
var file = _database._files[i];
entries[i] = new SevenZipArchiveEntry(
this,
new SevenZipFilePart(stream, _database, i, file, ReaderOptions.ArchiveEncoding)
new SevenZipFilePart(stream, _database, i, file, ReaderOptions.ArchiveEncoding),
ReaderOptions
);
}
foreach (var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder))

View File

@@ -16,13 +16,8 @@ public partial class SevenZipArchive
IMultiArchiveOpenable<IArchive, IAsyncArchive>
#endif
{
public static IAsyncArchive OpenAsyncArchive(
string path,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
public static IAsyncArchive OpenAsyncArchive(string path, ReaderOptions? readerOptions = null)
{
cancellationToken.ThrowIfCancellationRequested();
path.NotNullOrEmpty("path");
return (IAsyncArchive)OpenArchive(new FileInfo(path), readerOptions ?? new ReaderOptions());
}
@@ -91,43 +86,32 @@ public partial class SevenZipArchive
);
}
public static IAsyncArchive OpenAsyncArchive(
Stream stream,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
public static IAsyncArchive OpenAsyncArchive(Stream stream, ReaderOptions? readerOptions = null)
{
cancellationToken.ThrowIfCancellationRequested();
return (IAsyncArchive)OpenArchive(stream, readerOptions);
}
public static IAsyncArchive OpenAsyncArchive(
FileInfo fileInfo,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
ReaderOptions? readerOptions = null
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IAsyncArchive)OpenArchive(fileInfo, readerOptions);
}
public static IAsyncArchive OpenAsyncArchive(
IReadOnlyList<Stream> streams,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
ReaderOptions? readerOptions = null
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IAsyncArchive)OpenArchive(streams, readerOptions);
}
public static IAsyncArchive OpenAsyncArchive(
IReadOnlyList<FileInfo> fileInfos,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
ReaderOptions? readerOptions = null
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IAsyncArchive)OpenArchive(fileInfos, readerOptions);
}
@@ -163,7 +147,7 @@ public partial class SevenZipArchive
cancellationToken.ThrowIfCancellationRequested();
try
{
return await SignatureMatchAsync(stream, cancellationToken);
return await SignatureMatchAsync(stream, cancellationToken).ConfigureAwait(false);
}
catch
{

View File

@@ -55,7 +55,8 @@ public partial class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, Sev
i,
file,
ReaderOptions.ArchiveEncoding
)
),
ReaderOptions
);
}
foreach (

View File

@@ -1,20 +1,28 @@
using System.IO;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common.Options;
using SharpCompress.Common.SevenZip;
namespace SharpCompress.Archives.SevenZip;
public class SevenZipArchiveEntry : SevenZipEntry, IArchiveEntry
{
internal SevenZipArchiveEntry(SevenZipArchive archive, SevenZipFilePart part)
: base(part) => Archive = archive;
internal SevenZipArchiveEntry(
SevenZipArchive archive,
SevenZipFilePart part,
IReaderOptions readerOptions
)
: base(part, readerOptions) => Archive = archive;
public Stream OpenEntryStream() => FilePart.GetCompressedStream();
public async ValueTask<Stream> OpenEntryStreamAsync(
CancellationToken cancellationToken = default
) => (await FilePart.GetCompressedStreamAsync(cancellationToken)).NotNull();
) =>
(
await FilePart.GetCompressedStreamAsync(cancellationToken).ConfigureAwait(false)
).NotNull();
public IArchive Archive { get; }

View File

@@ -19,7 +19,7 @@ public partial class TarArchive
{
protected override async ValueTask SaveToAsync(
Stream stream,
IWriterOptions options,
TarWriterOptions options,
IAsyncEnumerable<TarArchiveEntry> oldEntries,
IEnumerable<TarArchiveEntry> newEntries,
CancellationToken cancellationToken = default
@@ -96,7 +96,7 @@ public partial class TarArchive
IAsyncEnumerable<TarVolume> volumes
)
{
var stream = (await volumes.SingleAsync()).Stream;
var stream = (await volumes.SingleAsync().ConfigureAwait(false)).Stream;
if (stream.CanSeek)
{
stream.Position = 0;
@@ -127,7 +127,8 @@ public partial class TarArchive
var entry = new TarArchiveEntry(
this,
new TarFilePart(previousHeader, stream),
CompressionType.None
CompressionType.None,
ReaderOptions
);
var oldStreamPos = stream.Position;
@@ -135,7 +136,7 @@ public partial class TarArchive
using (var entryStream = entry.OpenEntryStream())
{
using var memoryStream = new MemoryStream();
await entryStream.CopyToAsync(memoryStream);
await entryStream.CopyToAsync(memoryStream).ConfigureAwait(false);
memoryStream.Position = 0;
var bytes = memoryStream.ToArray();
@@ -151,7 +152,8 @@ public partial class TarArchive
yield return new TarArchiveEntry(
this,
new TarFilePart(header, stream),
CompressionType.None
CompressionType.None,
ReaderOptions
);
}
}

View File

@@ -9,22 +9,29 @@ using SharpCompress.Common;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.IO;
using SharpCompress.Readers;
using SharpCompress.Writers.Tar;
namespace SharpCompress.Archives.Tar;
public partial class TarArchive
#if NET8_0_OR_GREATER
: IWritableArchiveOpenable,
IMultiArchiveOpenable<IWritableArchive, IWritableAsyncArchive>
: IWritableArchiveOpenable<TarWriterOptions>,
IMultiArchiveOpenable<
IWritableArchive<TarWriterOptions>,
IWritableAsyncArchive<TarWriterOptions>
>
#endif
{
public static IWritableArchive OpenArchive(string filePath, ReaderOptions? readerOptions = null)
public static IWritableArchive<TarWriterOptions> OpenArchive(
string filePath,
ReaderOptions? readerOptions = null
)
{
filePath.NotNullOrEmpty(nameof(filePath));
return OpenArchive(new FileInfo(filePath), readerOptions);
}
public static IWritableArchive OpenArchive(
public static IWritableArchive<TarWriterOptions> OpenArchive(
FileInfo fileInfo,
ReaderOptions? readerOptions = null
)
@@ -39,7 +46,7 @@ public partial class TarArchive
);
}
public static IWritableArchive OpenArchive(
public static IWritableArchive<TarWriterOptions> OpenArchive(
IEnumerable<FileInfo> fileInfos,
ReaderOptions? readerOptions = null
)
@@ -55,7 +62,7 @@ public partial class TarArchive
);
}
public static IWritableArchive OpenArchive(
public static IWritableArchive<TarWriterOptions> OpenArchive(
IEnumerable<Stream> streams,
ReaderOptions? readerOptions = null
)
@@ -71,7 +78,10 @@ public partial class TarArchive
);
}
public static IWritableArchive OpenArchive(Stream stream, ReaderOptions? readerOptions = null)
public static IWritableArchive<TarWriterOptions> OpenArchive(
Stream stream,
ReaderOptions? readerOptions = null
)
{
stream.NotNull(nameof(stream));
@@ -85,55 +95,30 @@ public partial class TarArchive
);
}
public static IWritableAsyncArchive OpenAsyncArchive(
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
Stream stream,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IWritableAsyncArchive)OpenArchive(stream, readerOptions);
}
ReaderOptions? readerOptions = null
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(stream, readerOptions);
public static IWritableAsyncArchive OpenAsyncArchive(
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
string path,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IWritableAsyncArchive)OpenArchive(new FileInfo(path), readerOptions);
}
ReaderOptions? readerOptions = null
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(new FileInfo(path), readerOptions);
public static IWritableAsyncArchive OpenAsyncArchive(
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
FileInfo fileInfo,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IWritableAsyncArchive)OpenArchive(fileInfo, readerOptions);
}
ReaderOptions? readerOptions = null
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(fileInfo, readerOptions);
public static IWritableAsyncArchive OpenAsyncArchive(
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
IReadOnlyList<Stream> streams,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IWritableAsyncArchive)OpenArchive(streams, readerOptions);
}
ReaderOptions? readerOptions = null
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(streams, readerOptions);
public static IWritableAsyncArchive OpenAsyncArchive(
public static IWritableAsyncArchive<TarWriterOptions> OpenAsyncArchive(
IReadOnlyList<FileInfo> fileInfos,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IWritableAsyncArchive)OpenArchive(fileInfos, readerOptions);
}
ReaderOptions? readerOptions = null
) => (IWritableAsyncArchive<TarWriterOptions>)OpenArchive(fileInfos, readerOptions);
public static bool IsTarFile(string filePath) => IsTarFile(new FileInfo(filePath));
@@ -181,7 +166,7 @@ public partial class TarArchive
#else
using var reader = new AsyncBinaryReader(stream, leaveOpen: true);
#endif
var readSucceeded = await tarHeader.ReadAsync(reader);
var readSucceeded = await tarHeader.ReadAsync(reader).ConfigureAwait(false);
var isEmptyArchive =
tarHeader.Name?.Length == 0
&& tarHeader.Size == 0
@@ -196,7 +181,7 @@ public partial class TarArchive
}
}
public static IWritableArchive CreateArchive() => new TarArchive();
public static IWritableArchive<TarWriterOptions> CreateArchive() => new TarArchive();
public static IWritableAsyncArchive CreateAsyncArchive() => new TarArchive();
public static IWritableAsyncArchive<TarWriterOptions> CreateAsyncArchive() => new TarArchive();
}

View File

@@ -16,7 +16,8 @@ using SharpCompress.Writers.Tar;
namespace SharpCompress.Archives.Tar;
public partial class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
public partial class TarArchive
: AbstractWritableArchive<TarArchiveEntry, TarVolume, TarWriterOptions>
{
protected override IEnumerable<TarVolume> LoadVolumes(SourceStream sourceStream)
{
@@ -59,7 +60,8 @@ public partial class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVo
var entry = new TarArchiveEntry(
this,
new TarFilePart(previousHeader, stream),
CompressionType.None
CompressionType.None,
ReaderOptions
);
var oldStreamPos = stream.Position;
@@ -81,7 +83,8 @@ public partial class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVo
yield return new TarArchiveEntry(
this,
new TarFilePart(header, stream),
CompressionType.None
CompressionType.None,
ReaderOptions
);
}
}
@@ -116,7 +119,7 @@ public partial class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVo
protected override void SaveTo(
Stream stream,
IWriterOptions options,
TarWriterOptions options,
IEnumerable<TarArchiveEntry> oldEntries,
IEnumerable<TarArchiveEntry> newEntries
)

View File

@@ -1,22 +1,31 @@
using System.IO;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common;
using SharpCompress.Common.Options;
using SharpCompress.Common.Tar;
namespace SharpCompress.Archives.Tar;
public class TarArchiveEntry : TarEntry, IArchiveEntry
{
internal TarArchiveEntry(TarArchive archive, TarFilePart? part, CompressionType compressionType)
: base(part, compressionType) => Archive = archive;
internal TarArchiveEntry(
TarArchive archive,
TarFilePart? part,
CompressionType compressionType,
IReaderOptions readerOptions
)
: base(part, compressionType, readerOptions) => Archive = archive;
public virtual Stream OpenEntryStream() => Parts.Single().GetCompressedStream().NotNull();
public async ValueTask<Stream> OpenEntryStreamAsync(
CancellationToken cancellationToken = default
) => (await Parts.Single().GetCompressedStreamAsync(cancellationToken)).NotNull();
) =>
(
await Parts.Single().GetCompressedStreamAsync(cancellationToken).ConfigureAwait(false)
).NotNull();
#region IArchiveEntry Members

View File

@@ -21,7 +21,7 @@ internal sealed class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiv
DateTime? lastModified,
bool closeStream
)
: base(archive, null, compressionType)
: base(archive, null, compressionType, archive.ReaderOptions)
{
this.stream = stream;
Key = path;
@@ -36,7 +36,7 @@ internal sealed class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiv
string directoryPath,
DateTime? lastModified
)
: base(archive, null, CompressionType.None)
: base(archive, null, CompressionType.None, archive.ReaderOptions)
{
stream = null;
Key = directoryPath;

View File

@@ -21,7 +21,7 @@ public partial class ZipArchive
IAsyncEnumerable<ZipVolume> volumes
)
{
var vols = await volumes.ToListAsync();
var vols = await volumes.ToListAsync().ConfigureAwait(false);
var volsArray = vols.ToArray();
await foreach (
@@ -55,12 +55,8 @@ public partial class ZipArchive
yield return new ZipArchiveEntry(
this,
new SeekableZipFilePart(
headerFactory.NotNull(),
deh,
s,
ReaderOptions.CompressionProviders
)
new SeekableZipFilePart(headerFactory.NotNull(), deh, s),
ReaderOptions
);
}
break;
@@ -77,7 +73,7 @@ public partial class ZipArchive
protected override async ValueTask SaveToAsync(
Stream stream,
IWriterOptions options,
ZipWriterOptions options,
IAsyncEnumerable<ZipArchiveEntry> oldEntries,
IEnumerable<ZipArchiveEntry> newEntries,
CancellationToken cancellationToken = default

View File

@@ -9,22 +9,29 @@ using SharpCompress.Common.Zip;
using SharpCompress.Common.Zip.Headers;
using SharpCompress.IO;
using SharpCompress.Readers;
using SharpCompress.Writers.Zip;
namespace SharpCompress.Archives.Zip;
public partial class ZipArchive
#if NET8_0_OR_GREATER
: IWritableArchiveOpenable,
IMultiArchiveOpenable<IWritableArchive, IWritableAsyncArchive>
: IWritableArchiveOpenable<ZipWriterOptions>,
IMultiArchiveOpenable<
IWritableArchive<ZipWriterOptions>,
IWritableAsyncArchive<ZipWriterOptions>
>
#endif
{
public static IWritableArchive OpenArchive(string filePath, ReaderOptions? readerOptions = null)
public static IWritableArchive<ZipWriterOptions> OpenArchive(
string filePath,
ReaderOptions? readerOptions = null
)
{
filePath.NotNullOrEmpty(nameof(filePath));
return OpenArchive(new FileInfo(filePath), readerOptions);
}
public static IWritableArchive OpenArchive(
public static IWritableArchive<ZipWriterOptions> OpenArchive(
FileInfo fileInfo,
ReaderOptions? readerOptions = null
)
@@ -39,7 +46,7 @@ public partial class ZipArchive
);
}
public static IWritableArchive OpenArchive(
public static IWritableArchive<ZipWriterOptions> OpenArchive(
IEnumerable<FileInfo> fileInfos,
ReaderOptions? readerOptions = null
)
@@ -55,7 +62,7 @@ public partial class ZipArchive
);
}
public static IWritableArchive OpenArchive(
public static IWritableArchive<ZipWriterOptions> OpenArchive(
IEnumerable<Stream> streams,
ReaderOptions? readerOptions = null
)
@@ -71,7 +78,10 @@ public partial class ZipArchive
);
}
public static IWritableArchive OpenArchive(Stream stream, ReaderOptions? readerOptions = null)
public static IWritableArchive<ZipWriterOptions> OpenArchive(
Stream stream,
ReaderOptions? readerOptions = null
)
{
stream.NotNull(nameof(stream));
@@ -85,55 +95,30 @@ public partial class ZipArchive
);
}
public static IWritableAsyncArchive OpenAsyncArchive(
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
string path,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IWritableAsyncArchive)OpenArchive(path, readerOptions);
}
ReaderOptions? readerOptions = null
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(path, readerOptions);
public static IWritableAsyncArchive OpenAsyncArchive(
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
Stream stream,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IWritableAsyncArchive)OpenArchive(stream, readerOptions);
}
ReaderOptions? readerOptions = null
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(stream, readerOptions);
public static IWritableAsyncArchive OpenAsyncArchive(
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
FileInfo fileInfo,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IWritableAsyncArchive)OpenArchive(fileInfo, readerOptions);
}
ReaderOptions? readerOptions = null
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(fileInfo, readerOptions);
public static IWritableAsyncArchive OpenAsyncArchive(
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
IReadOnlyList<Stream> streams,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IWritableAsyncArchive)OpenArchive(streams, readerOptions);
}
ReaderOptions? readerOptions = null
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(streams, readerOptions);
public static IWritableAsyncArchive OpenAsyncArchive(
public static IWritableAsyncArchive<ZipWriterOptions> OpenAsyncArchive(
IReadOnlyList<FileInfo> fileInfos,
ReaderOptions? readerOptions = null,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
return (IWritableAsyncArchive)OpenArchive(fileInfos, readerOptions);
}
ReaderOptions? readerOptions = null
) => (IWritableAsyncArchive<ZipWriterOptions>)OpenArchive(fileInfos, readerOptions);
public static bool IsZipFile(string filePath, string? password = null) =>
IsZipFile(new FileInfo(filePath), password);
@@ -218,7 +203,8 @@ public partial class ZipArchive
var header = await headerFactory
.ReadStreamHeaderAsync(stream)
.Where(x => x.ZipHeaderType != ZipHeaderType.Split)
.FirstOrDefaultAsync(cancellationToken);
.FirstOrDefaultAsync(cancellationToken)
.ConfigureAwait(false);
if (header is null)
{
return false;
@@ -235,9 +221,9 @@ public partial class ZipArchive
}
}
public static IWritableArchive CreateArchive() => new ZipArchive();
public static IWritableArchive<ZipWriterOptions> CreateArchive() => new ZipArchive();
public static IWritableAsyncArchive CreateAsyncArchive() => new ZipArchive();
public static IWritableAsyncArchive<ZipWriterOptions> CreateAsyncArchive() => new ZipArchive();
public static async ValueTask<bool> IsZipMultiAsync(
Stream stream,
@@ -261,6 +247,7 @@ public partial class ZipArchive
await foreach (
var h in z.ReadSeekableHeaderAsync(stream)
.WithCancellation(cancellationToken)
.ConfigureAwait(false)
)
{
x = h;

View File

@@ -17,7 +17,8 @@ using SharpCompress.Writers.Zip;
namespace SharpCompress.Archives.Zip;
public partial class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
public partial class ZipArchive
: AbstractWritableArchive<ZipArchiveEntry, ZipVolume, ZipWriterOptions>
{
private readonly SeekableZipHeaderFactory? headerFactory;
@@ -95,12 +96,8 @@ public partial class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVo
yield return new ZipArchiveEntry(
this,
new SeekableZipFilePart(
headerFactory.NotNull(),
deh,
s,
ReaderOptions.CompressionProviders
)
new SeekableZipFilePart(headerFactory.NotNull(), deh, s),
ReaderOptions
);
}
break;
@@ -115,11 +112,12 @@ public partial class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVo
}
}
public void SaveTo(Stream stream) => SaveTo(stream, new WriterOptions(CompressionType.Deflate));
public void SaveTo(Stream stream) =>
SaveTo(stream, new ZipWriterOptions(CompressionType.Deflate));
protected override void SaveTo(
Stream stream,
IWriterOptions options,
ZipWriterOptions options,
IEnumerable<ZipArchiveEntry> oldEntries,
IEnumerable<ZipArchiveEntry> newEntries
)

View File

@@ -15,7 +15,9 @@ public partial class ZipArchiveEntry
var part = Parts.Single();
if (part is SeekableZipFilePart seekablePart)
{
return (await seekablePart.GetCompressedStreamAsync(cancellationToken)).NotNull();
return (
await seekablePart.GetCompressedStreamAsync(cancellationToken).ConfigureAwait(false)
).NotNull();
}
return OpenEntryStream();
}

View File

@@ -1,15 +1,20 @@
using System.IO;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Common.Options;
using SharpCompress.Common.Zip;
namespace SharpCompress.Archives.Zip;
public partial class ZipArchiveEntry : ZipEntry, IArchiveEntry
{
internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart? part)
: base(part) => Archive = archive;
internal ZipArchiveEntry(
ZipArchive archive,
SeekableZipFilePart? part,
IReaderOptions readerOptions
)
: base(part, readerOptions) => Archive = archive;
public virtual Stream OpenEntryStream() => Parts.Single().GetCompressedStream().NotNull();

View File

@@ -21,7 +21,7 @@ internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry
DateTime? lastModified,
bool closeStream
)
: base(archive, null)
: base(archive, null, archive.ReaderOptions)
{
this.stream = stream;
Key = path;
@@ -36,7 +36,7 @@ internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry
string directoryPath,
DateTime? lastModified
)
: base(archive, null)
: base(archive, null, archive.ReaderOptions)
{
stream = null;
Key = directoryPath;

View File

@@ -5,6 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpCompress.Common.Ace.Headers;
using SharpCompress.Common.Options;
namespace SharpCompress.Common.Ace;
@@ -12,7 +13,8 @@ public class AceEntry : Entry
{
private readonly AceFilePart _filePart;
internal AceEntry(AceFilePart filePart)
internal AceEntry(AceFilePart filePart, IReaderOptions readerOptions)
: base(readerOptions)
{
_filePart = filePart;
}

View File

@@ -18,7 +18,7 @@ public sealed partial class AceFileHeader
CancellationToken cancellationToken = default
)
{
var headerData = await ReadHeaderAsync(stream, cancellationToken);
var headerData = await ReadHeaderAsync(stream, cancellationToken).ConfigureAwait(false);
if (headerData.Length == 0)
{
return null;

View File

@@ -19,7 +19,9 @@ public abstract partial class AceHeader
{
// Read header CRC (2 bytes) and header size (2 bytes)
var headerBytes = new byte[4];
if (!await stream.ReadFullyAsync(headerBytes, 0, 4, cancellationToken))
if (
!await stream.ReadFullyAsync(headerBytes, 0, 4, cancellationToken).ConfigureAwait(false)
)
{
return Array.Empty<byte>();
}
@@ -33,7 +35,11 @@ public abstract partial class AceHeader
// Read the header data
var body = new byte[HeaderSize];
if (!await stream.ReadFullyAsync(body, 0, HeaderSize, cancellationToken))
if (
!await stream
.ReadFullyAsync(body, 0, HeaderSize, cancellationToken)
.ConfigureAwait(false)
)
{
return Array.Empty<byte>();
}
@@ -59,7 +65,7 @@ public abstract partial class AceHeader
)
{
var bytes = new byte[14];
if (!await stream.ReadFullyAsync(bytes, 0, 14, cancellationToken))
if (!await stream.ReadFullyAsync(bytes, 0, 14, cancellationToken).ConfigureAwait(false))
{
return false;
}

View File

@@ -19,7 +19,7 @@ public sealed partial class AceMainHeader
CancellationToken cancellationToken = default
)
{
var headerData = await ReadHeaderAsync(stream, cancellationToken);
var headerData = await ReadHeaderAsync(stream, cancellationToken).ConfigureAwait(false);
if (headerData.Length == 0)
{
return null;

View File

@@ -5,6 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpCompress.Common.GZip;
using SharpCompress.Common.Options;
using SharpCompress.Common.Tar;
namespace SharpCompress.Common.Arc;
@@ -13,7 +14,8 @@ public class ArcEntry : Entry
{
private readonly ArcFilePart? _filePart;
internal ArcEntry(ArcFilePart? filePart)
internal ArcEntry(ArcFilePart? filePart, IReaderOptions readerOptions)
: base(readerOptions)
{
_filePart = filePart;
}

View File

@@ -41,8 +41,9 @@ public class ArcEntryHeader
{
byte[] headerBytes = new byte[29];
if (
await stream.ReadAsync(headerBytes, 0, headerBytes.Length, cancellationToken)
!= headerBytes.Length
await stream
.ReadAsync(headerBytes, 0, headerBytes.Length, cancellationToken)
.ConfigureAwait(false) != headerBytes.Length
)
{
return null;

View File

@@ -31,11 +31,9 @@ public partial class ArcFilePart
compressedStream = new RunLength90Stream(_stream, (int)Header.CompressedSize);
break;
case CompressionType.Squeezed:
compressedStream = await SqueezeStream.CreateAsync(
_stream,
(int)Header.CompressedSize,
cancellationToken
);
compressedStream = await SqueezeStream
.CreateAsync(_stream, (int)Header.CompressedSize, cancellationToken)
.ConfigureAwait(false);
break;
case CompressionType.Crunched:
if (Header.OriginalSize > 128 * 1024)

View File

@@ -10,4 +10,5 @@ public enum ArchiveType
Arc,
Arj,
Ace,
Lzw,
}

View File

@@ -5,6 +5,7 @@ using System.Text;
using System.Threading.Tasks;
using SharpCompress.Common.Arc;
using SharpCompress.Common.Arj.Headers;
using SharpCompress.Common.Options;
namespace SharpCompress.Common.Arj;
@@ -12,7 +13,8 @@ public class ArjEntry : Entry
{
private readonly ArjFilePart _filePart;
internal ArjEntry(ArjFilePart filePart)
internal ArjEntry(ArjFilePart filePart, IReaderOptions readerOptions)
: base(readerOptions)
{
_filePart = filePart;
}
@@ -41,9 +43,9 @@ public class ArjEntry : Entry
public override DateTime? LastModifiedTime => _filePart.Header.DateTimeModified.DateTime;
public override DateTime? CreatedTime => _filePart.Header.DateTimeCreated.DateTime;
public override DateTime? CreatedTime => _filePart.Header.DateTimeCreated?.DateTime;
public override DateTime? LastAccessedTime => _filePart.Header.DateTimeAccessed.DateTime;
public override DateTime? LastAccessedTime => _filePart.Header.DateTimeAccessed?.DateTime;
public override DateTime? ArchivedTime => null;

View File

@@ -21,7 +21,7 @@ public abstract partial class ArjHeader
{
// check for magic bytes
var magic = new byte[2];
if (await stream.ReadAsync(magic, 0, 2, cancellationToken) != 2)
if (await stream.ReadAsync(magic, 0, 2, cancellationToken).ConfigureAwait(false) != 2)
{
return Array.Empty<byte>();
}
@@ -33,7 +33,7 @@ public abstract partial class ArjHeader
// read header_size
byte[] headerBytes = new byte[2];
await stream.ReadAsync(headerBytes, 0, 2, cancellationToken);
await stream.ReadAsync(headerBytes, 0, 2, cancellationToken).ConfigureAwait(false);
var headerSize = (ushort)(headerBytes[0] | headerBytes[1] << 8);
if (headerSize < 1)
{
@@ -41,14 +41,16 @@ public abstract partial class ArjHeader
}
var body = new byte[headerSize];
var read = await stream.ReadAsync(body, 0, headerSize, cancellationToken);
var read = await stream
.ReadAsync(body, 0, headerSize, cancellationToken)
.ConfigureAwait(false);
if (read < headerSize)
{
return Array.Empty<byte>();
}
byte[] crc = new byte[4];
read = await stream.ReadAsync(crc, 0, 4, cancellationToken);
await stream.ReadFullyAsync(crc, 0, 4, cancellationToken).ConfigureAwait(false);
var checksum = Crc32Stream.Compute(body);
// Compute the hash value
if (checksum != BitConverter.ToUInt32(crc, 0))
@@ -68,7 +70,9 @@ public abstract partial class ArjHeader
while (true)
{
int bytesRead = await reader.ReadAsync(buffer, 0, 2, cancellationToken);
int bytesRead = await reader
.ReadAsync(buffer, 0, 2, cancellationToken)
.ConfigureAwait(false);
if (bytesRead < 2)
{
throw new EndOfStreamException(
@@ -83,7 +87,9 @@ public abstract partial class ArjHeader
}
byte[] header = new byte[extHeaderSize];
bytesRead = await reader.ReadAsync(header, 0, extHeaderSize, cancellationToken);
bytesRead = await reader
.ReadAsync(header, 0, extHeaderSize, cancellationToken)
.ConfigureAwait(false);
if (bytesRead < extHeaderSize)
{
throw new EndOfStreamException(
@@ -92,7 +98,9 @@ public abstract partial class ArjHeader
}
byte[] crcextended = new byte[4];
bytesRead = await reader.ReadAsync(crcextended, 0, 4, cancellationToken);
bytesRead = await reader
.ReadAsync(crcextended, 0, 4, cancellationToken)
.ConfigureAwait(false);
if (bytesRead < 4)
{
throw new EndOfStreamException(
@@ -122,7 +130,7 @@ public abstract partial class ArjHeader
)
{
var bytes = new byte[2];
if (await stream.ReadAsync(bytes, 0, 2, cancellationToken) != 2)
if (await stream.ReadAsync(bytes, 0, 2, cancellationToken).ConfigureAwait(false) != 2)
{
return false;
}

View File

@@ -11,10 +11,10 @@ public partial class ArjLocalHeader
CancellationToken cancellationToken = default
)
{
var body = await ReadHeaderAsync(stream, cancellationToken);
var body = await ReadHeaderAsync(stream, cancellationToken).ConfigureAwait(false);
if (body.Length > 0)
{
await ReadExtendedHeadersAsync(stream, cancellationToken);
await ReadExtendedHeadersAsync(stream, cancellationToken).ConfigureAwait(false);
var header = LoadFrom(body);
header.DataStartPosition = stream.Position;
return header;

View File

@@ -27,8 +27,8 @@ public partial class ArjLocalHeader : ArjHeader
public byte FirstChapter { get; set; }
public byte LastChapter { get; set; }
public long ExtendedFilePosition { get; set; }
public DosDateTime DateTimeAccessed { get; set; } = new DosDateTime(0);
public DosDateTime DateTimeCreated { get; set; } = new DosDateTime(0);
public DosDateTime? DateTimeAccessed { get; set; }
public DosDateTime? DateTimeCreated { get; set; }
public long OriginalSizeEvenForVolumes { get; set; }
public string Name { get; set; } = string.Empty;
public string Comment { get; set; } = string.Empty;
@@ -119,11 +119,9 @@ public partial class ArjLocalHeader : ArjHeader
if (headerSize >= R9HdrSize)
{
rawTimestamp = ReadInt32();
DateTimeAccessed =
rawTimestamp != 0 ? new DosDateTime(rawTimestamp) : new DosDateTime(0);
DateTimeAccessed = rawTimestamp != 0 ? new DosDateTime(rawTimestamp) : null;
rawTimestamp = ReadInt32();
DateTimeCreated =
rawTimestamp != 0 ? new DosDateTime(rawTimestamp) : new DosDateTime(0);
DateTimeCreated = rawTimestamp != 0 ? new DosDateTime(rawTimestamp) : null;
OriginalSizeEvenForVolumes = ReadInt32();
}
}

View File

@@ -11,8 +11,8 @@ public partial class ArjMainHeader
CancellationToken cancellationToken = default
)
{
var body = await ReadHeaderAsync(stream, cancellationToken);
await ReadExtendedHeadersAsync(stream, cancellationToken);
var body = await ReadHeaderAsync(stream, cancellationToken).ConfigureAwait(false);
await ReadExtendedHeadersAsync(stream, cancellationToken).ConfigureAwait(false);
return LoadFrom(body);
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SharpCompress.Common.Options;
namespace SharpCompress.Common;
@@ -87,4 +88,14 @@ public abstract class Entry : IEntry
/// Entry file attribute.
/// </summary>
public virtual int? Attrib => throw new NotImplementedException();
/// <summary>
/// The options used when opening this entry's source (reader or archive).
/// </summary>
public IReaderOptions Options { get; protected set; }
protected Entry(IReaderOptions readerOptions)
{
Options = readerOptions;
}
}

View File

@@ -2,6 +2,7 @@ using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Readers;
namespace SharpCompress.Common;
@@ -10,8 +11,7 @@ internal static partial class ExtractionMethods
public static async ValueTask WriteEntryToDirectoryAsync(
IEntry entry,
string destinationDirectory,
ExtractionOptions? options,
Func<string, ExtractionOptions?, CancellationToken, ValueTask> writeAsync,
Func<string, CancellationToken, ValueTask> writeAsync,
CancellationToken cancellationToken = default
)
{
@@ -34,11 +34,9 @@ internal static partial class ExtractionMethods
);
}
options ??= new ExtractionOptions() { Overwrite = true };
var file = Path.GetFileName(entry.Key.NotNull("Entry Key is null")).NotNull("File is null");
file = Utility.ReplaceInvalidFileNameChars(file);
if (options.ExtractFullPath)
if (entry.Options.ExtractFullPath)
{
var folder = Path.GetDirectoryName(entry.Key.NotNull("Entry Key is null"))
.NotNull("Directory is null");
@@ -72,9 +70,9 @@ internal static partial class ExtractionMethods
"Entry is trying to write a file outside of the destination directory."
);
}
await writeAsync(destinationFileName, options, cancellationToken).ConfigureAwait(false);
await writeAsync(destinationFileName, cancellationToken).ConfigureAwait(false);
}
else if (options.ExtractFullPath && !Directory.Exists(destinationFileName))
else if (entry.Options.ExtractFullPath && !Directory.Exists(destinationFileName))
{
Directory.CreateDirectory(destinationFileName);
}
@@ -83,36 +81,34 @@ internal static partial class ExtractionMethods
public static async ValueTask WriteEntryToFileAsync(
IEntry entry,
string destinationFileName,
ExtractionOptions? options,
Func<string, FileMode, CancellationToken, ValueTask> openAndWriteAsync,
CancellationToken cancellationToken = default
)
{
if (entry.LinkTarget != null)
{
if (options?.SymbolicLinkHandler is not null)
if (entry.Options.SymbolicLinkHandler is not null)
{
options.SymbolicLinkHandler(destinationFileName, entry.LinkTarget);
entry.Options.SymbolicLinkHandler(destinationFileName, entry.LinkTarget);
}
else
{
ExtractionOptions.DefaultSymbolicLinkHandler(destinationFileName, entry.LinkTarget);
ReaderOptions.DefaultSymbolicLinkHandler(destinationFileName, entry.LinkTarget);
}
return;
}
else
{
var fm = FileMode.Create;
options ??= new ExtractionOptions() { Overwrite = true };
if (!options.Overwrite)
if (!entry.Options.Overwrite)
{
fm = FileMode.CreateNew;
}
await openAndWriteAsync(destinationFileName, fm, cancellationToken)
.ConfigureAwait(false);
entry.PreserveExtractionOptions(destinationFileName, options);
entry.PreserveExtractionOptions(destinationFileName);
}
}
}

View File

@@ -3,6 +3,7 @@ using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using SharpCompress.Readers;
namespace SharpCompress.Common;
@@ -23,8 +24,7 @@ internal static partial class ExtractionMethods
public static void WriteEntryToDirectory(
IEntry entry,
string destinationDirectory,
ExtractionOptions? options,
Action<string, ExtractionOptions?> write
Action<string> write
)
{
string destinationFileName;
@@ -46,11 +46,9 @@ internal static partial class ExtractionMethods
);
}
options ??= new ExtractionOptions() { Overwrite = true };
var file = Path.GetFileName(entry.Key.NotNull("Entry Key is null")).NotNull("File is null");
file = Utility.ReplaceInvalidFileNameChars(file);
if (options.ExtractFullPath)
if (entry.Options.ExtractFullPath)
{
var folder = Path.GetDirectoryName(entry.Key.NotNull("Entry Key is null"))
.NotNull("Directory is null");
@@ -84,9 +82,9 @@ internal static partial class ExtractionMethods
"Entry is trying to write a file outside of the destination directory."
);
}
write(destinationFileName, options);
write(destinationFileName);
}
else if (options.ExtractFullPath && !Directory.Exists(destinationFileName))
else if (entry.Options.ExtractFullPath && !Directory.Exists(destinationFileName))
{
Directory.CreateDirectory(destinationFileName);
}
@@ -95,34 +93,32 @@ internal static partial class ExtractionMethods
public static void WriteEntryToFile(
IEntry entry,
string destinationFileName,
ExtractionOptions? options,
Action<string, FileMode> openAndWrite
)
{
if (entry.LinkTarget != null)
{
if (options?.SymbolicLinkHandler is not null)
if (entry.Options.SymbolicLinkHandler is not null)
{
options.SymbolicLinkHandler(destinationFileName, entry.LinkTarget);
entry.Options.SymbolicLinkHandler(destinationFileName, entry.LinkTarget);
}
else
{
ExtractionOptions.DefaultSymbolicLinkHandler(destinationFileName, entry.LinkTarget);
ReaderOptions.DefaultSymbolicLinkHandler(destinationFileName, entry.LinkTarget);
}
return;
}
else
{
var fm = FileMode.Create;
options ??= new ExtractionOptions() { Overwrite = true };
if (!options.Overwrite)
if (!entry.Options.Overwrite)
{
fm = FileMode.CreateNew;
}
openAndWrite(destinationFileName, fm);
entry.PreserveExtractionOptions(destinationFileName, options);
entry.PreserveExtractionOptions(destinationFileName);
}
}
}

View File

@@ -1,108 +0,0 @@
using System;
namespace SharpCompress.Common;
/// <summary>
/// Options for configuring extraction behavior when extracting archive entries.
/// </summary>
/// <remarks>
/// This class is immutable. Use the <c>with</c> expression to create modified copies:
/// <code>
/// var options = new ExtractionOptions { Overwrite = false };
/// options = options with { PreserveFileTime = true };
/// </code>
/// </remarks>
public sealed record ExtractionOptions
{
/// <summary>
/// Overwrite target if it exists.
/// <para><b>Breaking change:</b> Default changed from false to true in version 0.40.0.</para>
/// </summary>
public bool Overwrite { get; init; } = true;
/// <summary>
/// Extract with internal directory structure.
/// <para><b>Breaking change:</b> Default changed from false to true in version 0.40.0.</para>
/// </summary>
public bool ExtractFullPath { get; init; } = true;
/// <summary>
/// Preserve file time.
/// <para><b>Breaking change:</b> Default changed from false to true in version 0.40.0.</para>
/// </summary>
public bool PreserveFileTime { get; init; } = true;
/// <summary>
/// Preserve windows file attributes.
/// </summary>
public bool PreserveAttributes { get; init; }
/// <summary>
/// Delegate for writing symbolic links to disk.
/// The first parameter is the source path (where the symlink is created).
/// The second parameter is the target path (what the symlink refers to).
/// </summary>
/// <remarks>
/// <b>Breaking change:</b> Changed from field to init-only property in version 0.40.0.
/// The default handler logs a warning message.
/// </remarks>
public Action<string, string>? SymbolicLinkHandler { get; init; }
/// <summary>
/// Creates a new ExtractionOptions instance with default values.
/// </summary>
public ExtractionOptions() { }
/// <summary>
/// Creates a new ExtractionOptions instance with the specified overwrite behavior.
/// </summary>
/// <param name="overwrite">Whether to overwrite existing files.</param>
public ExtractionOptions(bool overwrite)
{
Overwrite = overwrite;
}
/// <summary>
/// Creates a new ExtractionOptions instance with the specified extraction path and overwrite behavior.
/// </summary>
/// <param name="extractFullPath">Whether to preserve directory structure.</param>
/// <param name="overwrite">Whether to overwrite existing files.</param>
public ExtractionOptions(bool extractFullPath, bool overwrite)
{
ExtractFullPath = extractFullPath;
Overwrite = overwrite;
}
/// <summary>
/// Creates a new ExtractionOptions instance with the specified extraction path, overwrite behavior, and file time preservation.
/// </summary>
/// <param name="extractFullPath">Whether to preserve directory structure.</param>
/// <param name="overwrite">Whether to overwrite existing files.</param>
/// <param name="preserveFileTime">Whether to preserve file modification times.</param>
public ExtractionOptions(bool extractFullPath, bool overwrite, bool preserveFileTime)
{
ExtractFullPath = extractFullPath;
Overwrite = overwrite;
PreserveFileTime = preserveFileTime;
}
/// <summary>
/// Gets an ExtractionOptions instance configured for safe extraction (no overwrite).
/// </summary>
public static ExtractionOptions SafeExtract => new(overwrite: false);
/// <summary>
/// Gets an ExtractionOptions instance configured for flat extraction (no directory structure).
/// </summary>
public static ExtractionOptions FlatExtract => new(extractFullPath: false, overwrite: true);
/// <summary>
/// Default symbolic link handler that logs a warning message.
/// </summary>
public static void DefaultSymbolicLinkHandler(string sourcePath, string targetPath)
{
Console.WriteLine(
$"Could not write symlink {sourcePath} -> {targetPath}, for more information please see https://github.com/dotnet/runtime/issues/24271"
);
}
}

View File

@@ -12,11 +12,8 @@ public partial class GZipEntry
)
{
yield return new GZipEntry(
await GZipFilePart.CreateAsync(
stream,
options.ArchiveEncoding,
options.CompressionProviders
)
await GZipFilePart.CreateAsync(stream, options.ArchiveEncoding).ConfigureAwait(false),
options
);
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common.Options;
using SharpCompress.Readers;
namespace SharpCompress.Common.GZip;
@@ -9,7 +10,11 @@ public partial class GZipEntry : Entry
{
private readonly GZipFilePart? _filePart;
internal GZipEntry(GZipFilePart? filePart) => _filePart = filePart;
internal GZipEntry(GZipFilePart? filePart, IReaderOptions readerOptions)
: base(readerOptions)
{
_filePart = filePart;
}
public override CompressionType CompressionType => CompressionType.GZip;
@@ -41,9 +46,7 @@ public partial class GZipEntry : Entry
internal static IEnumerable<GZipEntry> GetEntries(Stream stream, ReaderOptions options)
{
yield return new GZipEntry(
GZipFilePart.Create(stream, options.ArchiveEncoding, options.CompressionProviders)
);
yield return new GZipEntry(GZipFilePart.Create(stream, options.ArchiveEncoding), options);
}
// Async methods moved to GZipEntry.Async.cs

View File

@@ -30,12 +30,12 @@ internal sealed partial class GZipFilePart
{
var part = new GZipFilePart(stream, archiveEncoding, compressionProviders);
await part.ReadAndValidateGzipHeaderAsync(cancellationToken);
await part.ReadAndValidateGzipHeaderAsync(cancellationToken).ConfigureAwait(false);
if (stream.CanSeek)
{
var position = stream.Position;
stream.Position = stream.Length - 8;
await part.ReadTrailerAsync(cancellationToken);
await part.ReadTrailerAsync(cancellationToken).ConfigureAwait(false);
stream.Position = position;
part.EntryStartPosition = position;
}
@@ -52,7 +52,7 @@ internal sealed partial class GZipFilePart
{
// Read and potentially verify the GZIP trailer: CRC32 and size mod 2^32
var trailer = new byte[8];
_ = await _stream.ReadFullyAsync(trailer, 0, 8, cancellationToken);
_ = await _stream.ReadFullyAsync(trailer, 0, 8, cancellationToken).ConfigureAwait(false);
Crc = BinaryPrimitives.ReadUInt32LittleEndian(trailer);
UncompressedSize = BinaryPrimitives.ReadUInt32LittleEndian(trailer.AsSpan().Slice(4));
@@ -64,7 +64,7 @@ internal sealed partial class GZipFilePart
{
// read the header on the first read
var header = new byte[10];
var n = await _stream.ReadAsync(header, 0, 10, cancellationToken);
var n = await _stream.ReadAsync(header, 0, 10, cancellationToken).ConfigureAwait(false);
// workitem 8501: handle edge case (decompress empty stream)
if (n == 0)
@@ -88,28 +88,29 @@ internal sealed partial class GZipFilePart
{
// read and discard extra field
var lengthField = new byte[2];
_ = await _stream.ReadAsync(lengthField, 0, 2, cancellationToken);
_ = await _stream.ReadAsync(lengthField, 0, 2, cancellationToken).ConfigureAwait(false);
var extraLength = (short)(lengthField[0] + (lengthField[1] * 256));
var extra = new byte[extraLength];
if (!await _stream.ReadFullyAsync(extra, cancellationToken))
if (!await _stream.ReadFullyAsync(extra, cancellationToken).ConfigureAwait(false))
{
throw new ZlibException("Unexpected end-of-file reading GZIP header.");
}
}
if ((header[3] & 0x08) == 0x08)
{
_name = await ReadZeroTerminatedStringAsync(_stream, cancellationToken);
_name = await ReadZeroTerminatedStringAsync(_stream, cancellationToken)
.ConfigureAwait(false);
}
if ((header[3] & 0x10) == 0x010)
{
await ReadZeroTerminatedStringAsync(_stream, cancellationToken);
await ReadZeroTerminatedStringAsync(_stream, cancellationToken).ConfigureAwait(false);
}
if ((header[3] & 0x02) == 0x02)
{
var buf = new byte[1];
_ = await _stream.ReadAsync(buf, 0, 1, cancellationToken); // CRC16, ignore
_ = await _stream.ReadAsync(buf, 0, 1, cancellationToken).ConfigureAwait(false); // CRC16, ignore
}
}
@@ -124,7 +125,7 @@ internal sealed partial class GZipFilePart
do
{
// workitem 7740
var n = await stream.ReadAsync(buf1, 0, 1, cancellationToken);
var n = await stream.ReadAsync(buf1, 0, 1, cancellationToken).ConfigureAwait(false);
if (n != 1)
{
throw new ZlibException("Unexpected EOF reading GZIP header.");

View File

@@ -4,13 +4,9 @@ namespace SharpCompress.Common;
internal static class EntryExtensions
{
internal static void PreserveExtractionOptions(
this IEntry entry,
string destinationFileName,
ExtractionOptions options
)
internal static void PreserveExtractionOptions(this IEntry entry, string destinationFileName)
{
if (options.PreserveFileTime || options.PreserveAttributes)
if (entry.Options.PreserveFileTime || entry.Options.PreserveAttributes)
{
var nf = new FileInfo(destinationFileName);
if (!nf.Exists)
@@ -19,7 +15,7 @@ internal static class EntryExtensions
}
// update file time to original packed time
if (options.PreserveFileTime)
if (entry.Options.PreserveFileTime)
{
if (entry.CreatedTime.HasValue)
{
@@ -37,7 +33,7 @@ internal static class EntryExtensions
}
}
if (options.PreserveAttributes)
if (entry.Options.PreserveAttributes)
{
if (entry.Attrib.HasValue)
{

View File

@@ -1,4 +1,5 @@
using System;
using SharpCompress.Common.Options;
namespace SharpCompress.Common;
@@ -21,4 +22,9 @@ public interface IEntry
DateTime? LastModifiedTime { get; }
long Size { get; }
int? Attrib { get; }
/// <summary>
/// The options used when opening this entry's source (reader or archive).
/// </summary>
IReaderOptions Options { get; }
}

View File

@@ -0,0 +1,22 @@
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading;
using SharpCompress.Readers;
namespace SharpCompress.Common.Lzw;
public partial class LzwEntry
{
internal static async IAsyncEnumerable<LzwEntry> GetEntriesAsync(
Stream stream,
ReaderOptions options,
[EnumeratorCancellation] CancellationToken cancellationToken = default
)
{
yield return new LzwEntry(
await LzwFilePart.CreateAsync(stream, options.ArchiveEncoding, cancellationToken),
options
);
}
}

View File

@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common.Options;
using SharpCompress.Readers;
namespace SharpCompress.Common.Lzw;
public partial class LzwEntry : Entry
{
private readonly LzwFilePart? _filePart;
internal LzwEntry(LzwFilePart? filePart, IReaderOptions readerOptions)
: base(readerOptions)
{
_filePart = filePart;
}
public override CompressionType CompressionType => CompressionType.Lzw;
public override long Crc => 0;
public override string? Key => _filePart?.FilePartName;
public override string? LinkTarget => null;
public override long CompressedSize => 0;
public override long Size => 0;
public override DateTime? LastModifiedTime => null;
public override DateTime? CreatedTime => null;
public override DateTime? LastAccessedTime => null;
public override DateTime? ArchivedTime => null;
public override bool IsEncrypted => false;
public override bool IsDirectory => false;
public override bool IsSplitAfter => false;
internal override IEnumerable<FilePart> Parts => _filePart.Empty();
internal static IEnumerable<LzwEntry> GetEntries(Stream stream, ReaderOptions options)
{
yield return new LzwEntry(LzwFilePart.Create(stream, options.ArchiveEncoding), options);
}
// Async methods moved to LzwEntry.Async.cs
}

View File

@@ -0,0 +1,23 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace SharpCompress.Common.Lzw;
internal sealed partial class LzwFilePart
{
internal static async ValueTask<LzwFilePart> CreateAsync(
Stream stream,
IArchiveEncoding archiveEncoding,
CancellationToken cancellationToken = default
)
{
cancellationToken.ThrowIfCancellationRequested();
var part = new LzwFilePart(stream, archiveEncoding);
// For non-seekable streams, we can't track position, so use 0 since the stream will be
// read sequentially from its current position.
part.EntryStartPosition = stream.CanSeek ? stream.Position : 0;
return part;
}
}

View File

@@ -0,0 +1,60 @@
using System.IO;
using SharpCompress.Compressors.Lzw;
namespace SharpCompress.Common.Lzw;
internal sealed partial class LzwFilePart : FilePart
{
private readonly Stream _stream;
private readonly string? _name;
internal static LzwFilePart Create(Stream stream, IArchiveEncoding archiveEncoding)
{
var part = new LzwFilePart(stream, archiveEncoding);
// For non-seekable streams, we can't track position, so use 0 since the stream will be
// read sequentially from its current position.
part.EntryStartPosition = stream.CanSeek ? stream.Position : 0;
return part;
}
private LzwFilePart(Stream stream, IArchiveEncoding archiveEncoding)
: base(archiveEncoding)
{
_stream = stream;
_name = DeriveFileName(stream);
}
internal long EntryStartPosition { get; private set; }
internal override string? FilePartName => _name;
internal override Stream GetCompressedStream() =>
new LzwStream(_stream) { IsStreamOwner = false };
internal override Stream GetRawStream() => _stream;
private static string? DeriveFileName(Stream stream)
{
// Unwrap SharpCompressStream to get to the underlying FileStream
var unwrappedStream = stream;
if (stream is SharpCompress.IO.IStreamStack streamStack)
{
unwrappedStream = streamStack.BaseStream();
}
// Try to derive filename from FileStream
if (unwrappedStream is FileStream fileStream && !string.IsNullOrEmpty(fileStream.Name))
{
var fileName = Path.GetFileName(fileStream.Name);
// Strip .Z extension if present
if (fileName.EndsWith(".Z", System.StringComparison.OrdinalIgnoreCase))
{
return fileName.Substring(0, fileName.Length - 2);
}
return fileName;
}
// Default name for non-file streams
return "data";
}
}

View File

@@ -0,0 +1,17 @@
using System.IO;
using SharpCompress.Readers;
namespace SharpCompress.Common.Lzw;
public class LzwVolume : Volume
{
public LzwVolume(Stream stream, ReaderOptions? options, int index)
: base(stream, options, index) { }
public LzwVolume(FileInfo fileInfo, ReaderOptions options)
: base(fileInfo.OpenRead(), options with { LeaveStreamOpen = false }) { }
public override bool IsFirstVolume => true;
public override bool IsMultiVolume => false;
}

View File

@@ -0,0 +1,39 @@
using System;
namespace SharpCompress.Common.Options;
/// <summary>
/// Options for configuring extraction behavior when extracting archive entries to the filesystem.
/// </summary>
public interface IExtractionOptions
{
/// <summary>
/// Overwrite target if it exists.
/// <para><b>Breaking change:</b> Default changed from false to true in version 0.40.0.</para>
/// </summary>
bool Overwrite { get; init; }
/// <summary>
/// Extract with internal directory structure.
/// <para><b>Breaking change:</b> Default changed from false to true in version 0.40.0.</para>
/// </summary>
bool ExtractFullPath { get; init; }
/// <summary>
/// Preserve file time.
/// <para><b>Breaking change:</b> Default changed from false to true in version 0.40.0.</para>
/// </summary>
bool PreserveFileTime { get; init; }
/// <summary>
/// Preserve windows file attributes.
/// </summary>
bool PreserveAttributes { get; init; }
/// <summary>
/// Delegate for writing symbolic links to disk.
/// The first parameter is the source path (where the symlink is created).
/// The second parameter is the target path (what the symlink refers to).
/// </summary>
Action<string, string>? SymbolicLinkHandler { get; init; }
}

View File

@@ -2,10 +2,11 @@ using SharpCompress.Compressors;
namespace SharpCompress.Common.Options;
/// <summary>
/// Options for configuring reader behavior when opening archives.
/// </summary>
public interface IReaderOptions : IStreamOptions, IEncodingOptions, IProgressOptions
public interface IReaderOptions
: IStreamOptions,
IEncodingOptions,
IProgressOptions,
IExtractionOptions
{
/// <summary>
/// Look for RarArchive (Check for self-extracting archives or cases where RarArchive isn't at the start of the file)

View File

@@ -26,7 +26,9 @@ internal sealed class AsyncRarCryptoBinaryReader : AsyncRarCrcBinaryReader
var binary = new AsyncRarCryptoBinaryReader(stream);
if (salt == null)
{
salt = await binary.ReadBytesAsyncBase(EncryptionConstV5.SIZE_SALT30);
salt = await binary
.ReadBytesAsyncBase(EncryptionConstV5.SIZE_SALT30)
.ConfigureAwait(false);
binary._readCount += EncryptionConstV5.SIZE_SALT30;
}
binary._rijndael = new BlockTransformer(cryptKey.Transformer(salt));

View File

@@ -27,6 +27,6 @@ internal sealed partial class ArchiveCryptHeader
CancellationToken cancellationToken = default
)
{
CryptInfo = await Rar5CryptoInfo.CreateAsync(reader, false);
CryptInfo = await Rar5CryptoInfo.CreateAsync(reader, false).ConfigureAwait(false);
}
}

View File

@@ -329,7 +329,9 @@ internal partial class FileHeader
if (HasFlag(FileFlagsV4.SALT))
{
R4Salt = await reader.ReadBytesAsync(EncryptionConstV5.SIZE_SALT30, cancellationToken);
R4Salt = await reader
.ReadBytesAsync(EncryptionConstV5.SIZE_SALT30, cancellationToken)
.ConfigureAwait(false);
}
if (HasFlag(FileFlagsV4.EXT_TIME))
{

View File

@@ -64,19 +64,19 @@ public partial class RarHeaderFactory
if (_isRar5 && _cryptInfo != null)
{
await _cryptInfo.ReadInitVAsync(new AsyncMarkingBinaryReader(stream));
await _cryptInfo
.ReadInitVAsync(new AsyncMarkingBinaryReader(stream))
.ConfigureAwait(false);
var _headerKey = new CryptKey5(Options.Password!, _cryptInfo);
reader = await AsyncRarCryptoBinaryReader.Create(
stream,
_headerKey,
_cryptInfo.Salt
);
reader = await AsyncRarCryptoBinaryReader
.Create(stream, _headerKey, _cryptInfo.Salt)
.ConfigureAwait(false);
}
else
{
var key = new CryptKey3(Options.Password);
reader = await AsyncRarCryptoBinaryReader.Create(stream, key);
reader = await AsyncRarCryptoBinaryReader.Create(stream, key).ConfigureAwait(false);
}
}

View File

@@ -57,47 +57,46 @@ internal class Rar5CryptoInfo
)
{
var cryptoInfo = new Rar5CryptoInfo();
var cryptVersion = await reader.ReadRarVIntUInt32Async(
cancellationToken: CancellationToken.None
);
var cryptVersion = await reader
.ReadRarVIntUInt32Async(cancellationToken: CancellationToken.None)
.ConfigureAwait(false);
if (cryptVersion > EncryptionConstV5.VERSION)
{
throw new CryptographicException($"Unsupported crypto version of {cryptVersion}");
}
var encryptionFlags = await reader.ReadRarVIntUInt32Async(
cancellationToken: CancellationToken.None
);
var encryptionFlags = await reader
.ReadRarVIntUInt32Async(cancellationToken: CancellationToken.None)
.ConfigureAwait(false);
cryptoInfo.UsePswCheck = FlagUtility.HasFlag(
encryptionFlags,
EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK
);
cryptoInfo.LG2Count = (int)
await reader.ReadRarVIntUInt32Async(cancellationToken: CancellationToken.None);
await reader
.ReadRarVIntUInt32Async(cancellationToken: CancellationToken.None)
.ConfigureAwait(false);
if (cryptoInfo.LG2Count > EncryptionConstV5.CRYPT5_KDF_LG2_COUNT_MAX)
{
throw new CryptographicException($"Unsupported LG2 count of {cryptoInfo.LG2Count}.");
}
cryptoInfo.Salt = await reader.ReadBytesAsync(
EncryptionConstV5.SIZE_SALT50,
CancellationToken.None
);
cryptoInfo.Salt = await reader
.ReadBytesAsync(EncryptionConstV5.SIZE_SALT50, CancellationToken.None)
.ConfigureAwait(false);
if (readInitV)
{
await cryptoInfo.ReadInitVAsync(reader);
await cryptoInfo.ReadInitVAsync(reader).ConfigureAwait(false);
}
if (cryptoInfo.UsePswCheck)
{
cryptoInfo.PswCheck = await reader.ReadBytesAsync(
EncryptionConstV5.SIZE_PSWCHECK,
CancellationToken.None
);
var _pswCheckCsm = await reader.ReadBytesAsync(
EncryptionConstV5.SIZE_PSWCHECK_CSUM,
CancellationToken.None
);
cryptoInfo.PswCheck = await reader
.ReadBytesAsync(EncryptionConstV5.SIZE_PSWCHECK, CancellationToken.None)
.ConfigureAwait(false);
var _pswCheckCsm = await reader
.ReadBytesAsync(EncryptionConstV5.SIZE_PSWCHECK_CSUM, CancellationToken.None)
.ConfigureAwait(false);
var sha = SHA256.Create();
cryptoInfo.UsePswCheck = sha.ComputeHash(cryptoInfo.PswCheck)
@@ -111,7 +110,9 @@ internal class Rar5CryptoInfo
InitV = reader.ReadBytes(EncryptionConstV5.SIZE_INITV);
public async ValueTask ReadInitVAsync(AsyncMarkingBinaryReader reader) =>
InitV = await reader.ReadBytesAsync(EncryptionConstV5.SIZE_INITV, CancellationToken.None);
InitV = await reader
.ReadBytesAsync(EncryptionConstV5.SIZE_INITV, CancellationToken.None)
.ConfigureAwait(false);
public bool UsePswCheck = false;

View File

@@ -1,4 +1,5 @@
using System;
using SharpCompress.Common.Options;
using SharpCompress.Common.Rar.Headers;
namespace SharpCompress.Common.Rar;
@@ -7,6 +8,9 @@ public abstract class RarEntry : Entry
{
internal abstract FileHeader FileHeader { get; }
protected RarEntry(IReaderOptions readerOptions)
: base(readerOptions) { }
/// <summary>
/// As the V2017 port isn't complete, add this check to use the legacy Rar code.
/// </summary>

View File

@@ -118,7 +118,8 @@ public abstract class RarVolume : Volume
var buffer = new byte[fh.CompressedSize];
await fh
.PackedStream.NotNull()
.ReadFullyAsync(buffer, cancellationToken);
.ReadFullyAsync(buffer, cancellationToken)
.ConfigureAwait(false);
Comment = Encoding.UTF8.GetString(buffer, 0, buffer.Length - 1);
}
}
@@ -184,7 +185,7 @@ public abstract class RarVolume : Volume
public async ValueTask<bool> IsSolidArchiveAsync(CancellationToken cancellationToken = default)
{
await EnsureArchiveHeaderLoadedAsync(cancellationToken);
await EnsureArchiveHeaderLoadedAsync(cancellationToken).ConfigureAwait(false);
return ArchiveHeader?.IsSolid ?? false;
}
@@ -248,7 +249,7 @@ public abstract class RarVolume : Volume
}
// we only want to load the archive header to avoid overhead but have to do the nasty thing and reset the stream
await GetVolumeFilePartsAsync(cancellationToken).FirstAsync();
await GetVolumeFilePartsAsync(cancellationToken).FirstAsync().ConfigureAwait(false);
Stream.Position = 0;
}
}

View File

@@ -29,7 +29,7 @@ internal sealed partial class ArchiveReader
{
// TODO: Check Signature!
_header = new byte[0x20];
await stream.ReadExactAsync(_header, 0, 0x20, cancellationToken);
await stream.ReadExactAsync(_header, 0, 0x20, cancellationToken).ConfigureAwait(false);
if (
!lookForHeader
@@ -107,7 +107,9 @@ internal sealed partial class ArchiveReader
_stream.Seek(nextHeaderOffset, SeekOrigin.Current);
var header = new byte[nextHeaderSize];
await _stream.ReadExactAsync(header, 0, header.Length, cancellationToken);
await _stream
.ReadExactAsync(header, 0, header.Length, cancellationToken)
.ConfigureAwait(false);
if (Crc.Finish(Crc.Update(Crc.INIT_CRC, header, 0, header.Length)) != nextHeaderCrc)
{

View File

@@ -1,11 +1,16 @@
using System;
using System;
using System.Collections.Generic;
using SharpCompress.Common.Options;
namespace SharpCompress.Common.SevenZip;
public class SevenZipEntry : Entry
{
internal SevenZipEntry(SevenZipFilePart filePart) => FilePart = filePart;
internal SevenZipEntry(SevenZipFilePart filePart, IReaderOptions readerOptions)
: base(readerOptions)
{
FilePart = filePart;
}
internal SevenZipFilePart FilePart { get; }

View File

@@ -68,12 +68,9 @@ internal class SevenZipFilePart : FilePart
{
return Stream.Null;
}
var folderStream = await _database.GetFolderStreamAsync(
_stream,
Folder!,
_database.PasswordProvider,
cancellationToken
);
var folderStream = await _database
.GetFolderStreamAsync(_stream, Folder!, _database.PasswordProvider, cancellationToken)
.ConfigureAwait(false);
var firstFileIndex = _database._folderStartFileIndex[_database._folders.IndexOf(Folder!)];
var skipCount = Index - firstFileIndex;
@@ -84,7 +81,7 @@ internal class SevenZipFilePart : FilePart
}
if (skipSize > 0)
{
await folderStream.SkipAsync(skipSize, cancellationToken);
await folderStream.SkipAsync(skipSize, cancellationToken).ConfigureAwait(false);
}
return new ReadOnlySubStream(folderStream, Header.Size, leaveOpen: false);
}

View File

@@ -20,10 +20,10 @@ internal sealed partial class TarHeader
switch (WriteFormat)
{
case TarHeaderWriteFormat.GNU_TAR_LONG_LINK:
await WriteGnuTarLongLinkAsync(output, cancellationToken);
await WriteGnuTarLongLinkAsync(output, cancellationToken).ConfigureAwait(false);
break;
case TarHeaderWriteFormat.USTAR:
await WriteUstarAsync(output, cancellationToken);
await WriteUstarAsync(output, cancellationToken).ConfigureAwait(false);
break;
default:
throw new Exception("This should be impossible...");
@@ -162,13 +162,13 @@ internal sealed partial class TarHeader
if (nameByteCount > 100)
{
await WriteLongFilenameHeaderAsync(output, cancellationToken);
await WriteLongFilenameHeaderAsync(output, cancellationToken).ConfigureAwait(false);
Name = ArchiveEncoding.Decode(
ArchiveEncoding.Encode(Name.NotNull("Name is null")),
0,
100 - ArchiveEncoding.GetEncoding().GetMaxByteCount(1)
);
await WriteGnuTarLongLinkAsync(output, cancellationToken);
await WriteGnuTarLongLinkAsync(output, cancellationToken).ConfigureAwait(false);
}
}
@@ -203,7 +203,7 @@ internal sealed partial class TarHeader
do
{
buffer = await ReadBlockAsync(reader);
buffer = await ReadBlockAsync(reader).ConfigureAwait(false);
if (buffer.Length == 0)
{
@@ -216,12 +216,12 @@ internal sealed partial class TarHeader
// to apply to the header that follows them.
if (entryType == EntryType.LongName)
{
longName = await ReadLongNameAsync(reader, buffer);
longName = await ReadLongNameAsync(reader, buffer).ConfigureAwait(false);
continue;
}
else if (entryType == EntryType.LongLink)
{
longLinkName = await ReadLongNameAsync(reader, buffer);
longLinkName = await ReadLongNameAsync(reader, buffer).ConfigureAwait(false);
continue;
}
@@ -282,7 +282,7 @@ internal sealed partial class TarHeader
var buffer = ArrayPool<byte>.Shared.Rent(BLOCK_SIZE);
try
{
await reader.ReadBytesAsync(buffer, 0, BLOCK_SIZE);
await reader.ReadBytesAsync(buffer, 0, BLOCK_SIZE).ConfigureAwait(false);
if (buffer.Length != 0 && buffer.Length < BLOCK_SIZE)
{
@@ -313,7 +313,7 @@ internal sealed partial class TarHeader
var nameBytes = ArrayPool<byte>.Shared.Rent(nameLength);
try
{
await reader.ReadBytesAsync(nameBytes, 0, nameLength);
await reader.ReadBytesAsync(nameBytes, 0, nameLength).ConfigureAwait(false);
var remainingBytesToRead = BLOCK_SIZE - (nameLength % BLOCK_SIZE);
// Read the rest of the block and discard the data
@@ -322,7 +322,9 @@ internal sealed partial class TarHeader
var remainingBytes = ArrayPool<byte>.Shared.Rent(remainingBytesToRead);
try
{
await reader.ReadBytesAsync(remainingBytes, 0, remainingBytesToRead);
await reader
.ReadBytesAsync(remainingBytes, 0, remainingBytesToRead)
.ConfigureAwait(false);
}
finally
{

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common.Options;
using SharpCompress.IO;
namespace SharpCompress.Common.Tar;
@@ -10,7 +11,8 @@ public partial class TarEntry
StreamingMode mode,
Stream stream,
CompressionType compressionType,
IArchiveEncoding archiveEncoding
IArchiveEncoding archiveEncoding,
IReaderOptions readerOptions
)
{
await foreach (
@@ -21,11 +23,19 @@ public partial class TarEntry
{
if (mode == StreamingMode.Seekable)
{
yield return new TarEntry(new TarFilePart(header, stream), compressionType);
yield return new TarEntry(
new TarFilePart(header, stream),
compressionType,
readerOptions
);
}
else
{
yield return new TarEntry(new TarFilePart(header, null), compressionType);
yield return new TarEntry(
new TarFilePart(header, null),
compressionType,
readerOptions
);
}
}
else

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common.Options;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.IO;
@@ -10,7 +11,8 @@ public partial class TarEntry : Entry
{
private readonly TarFilePart? _filePart;
internal TarEntry(TarFilePart? filePart, CompressionType type)
internal TarEntry(TarFilePart? filePart, CompressionType type, IReaderOptions readerOptions)
: base(readerOptions)
{
_filePart = filePart;
CompressionType = type;
@@ -54,7 +56,8 @@ public partial class TarEntry : Entry
StreamingMode mode,
Stream stream,
CompressionType compressionType,
IArchiveEncoding archiveEncoding
IArchiveEncoding archiveEncoding,
IReaderOptions readerOptions
)
{
foreach (var header in TarHeaderFactory.ReadHeader(mode, stream, archiveEncoding))
@@ -63,11 +66,19 @@ public partial class TarEntry : Entry
{
if (mode == StreamingMode.Seekable)
{
yield return new TarEntry(new TarFilePart(header, stream), compressionType);
yield return new TarEntry(
new TarFilePart(header, stream),
compressionType,
readerOptions
);
}
else
{
yield return new TarEntry(new TarFilePart(header, null), compressionType);
yield return new TarEntry(
new TarFilePart(header, null),
compressionType,
readerOptions
);
}
}
else

View File

@@ -25,7 +25,7 @@ internal static partial class TarHeaderFactory
try
{
header = new TarHeader(archiveEncoding);
if (!await header.ReadAsync(reader))
if (!await header.ReadAsync(reader).ConfigureAwait(false))
{
yield break;
}

View File

@@ -8,14 +8,14 @@ internal partial class DirectoryEndHeader
{
internal override async ValueTask Read(AsyncBinaryReader reader)
{
VolumeNumber = await reader.ReadUInt16Async();
FirstVolumeWithDirectory = await reader.ReadUInt16Async();
TotalNumberOfEntriesInDisk = await reader.ReadUInt16Async();
TotalNumberOfEntries = await reader.ReadUInt16Async();
DirectorySize = await reader.ReadUInt32Async();
DirectoryStartOffsetRelativeToDisk = await reader.ReadUInt32Async();
CommentLength = await reader.ReadUInt16Async();
VolumeNumber = await reader.ReadUInt16Async().ConfigureAwait(false);
FirstVolumeWithDirectory = await reader.ReadUInt16Async().ConfigureAwait(false);
TotalNumberOfEntriesInDisk = await reader.ReadUInt16Async().ConfigureAwait(false);
TotalNumberOfEntries = await reader.ReadUInt16Async().ConfigureAwait(false);
DirectorySize = await reader.ReadUInt32Async().ConfigureAwait(false);
DirectoryStartOffsetRelativeToDisk = await reader.ReadUInt32Async().ConfigureAwait(false);
CommentLength = await reader.ReadUInt16Async().ConfigureAwait(false);
Comment = new byte[CommentLength];
await reader.ReadBytesAsync(Comment, 0, CommentLength);
await reader.ReadBytesAsync(Comment, 0, CommentLength).ConfigureAwait(false);
}
}

View File

@@ -10,28 +10,33 @@ internal partial class DirectoryEntryHeader
{
internal override async ValueTask Read(AsyncBinaryReader reader)
{
Version = await reader.ReadUInt16Async();
VersionNeededToExtract = await reader.ReadUInt16Async();
Flags = (HeaderFlags)await reader.ReadUInt16Async();
CompressionMethod = (ZipCompressionMethod)await reader.ReadUInt16Async();
OriginalLastModifiedTime = LastModifiedTime = await reader.ReadUInt16Async();
OriginalLastModifiedDate = LastModifiedDate = await reader.ReadUInt16Async();
Crc = await reader.ReadUInt32Async();
CompressedSize = await reader.ReadUInt32Async();
UncompressedSize = await reader.ReadUInt32Async();
var nameLength = await reader.ReadUInt16Async();
var extraLength = await reader.ReadUInt16Async();
var commentLength = await reader.ReadUInt16Async();
DiskNumberStart = await reader.ReadUInt16Async();
InternalFileAttributes = await reader.ReadUInt16Async();
ExternalFileAttributes = await reader.ReadUInt32Async();
RelativeOffsetOfEntryHeader = await reader.ReadUInt32Async();
Version = await reader.ReadUInt16Async().ConfigureAwait(false);
VersionNeededToExtract = await reader.ReadUInt16Async().ConfigureAwait(false);
Flags = (HeaderFlags)await reader.ReadUInt16Async().ConfigureAwait(false);
CompressionMethod = (ZipCompressionMethod)
await reader.ReadUInt16Async().ConfigureAwait(false);
OriginalLastModifiedTime = LastModifiedTime = await reader
.ReadUInt16Async()
.ConfigureAwait(false);
OriginalLastModifiedDate = LastModifiedDate = await reader
.ReadUInt16Async()
.ConfigureAwait(false);
Crc = await reader.ReadUInt32Async().ConfigureAwait(false);
CompressedSize = await reader.ReadUInt32Async().ConfigureAwait(false);
UncompressedSize = await reader.ReadUInt32Async().ConfigureAwait(false);
var nameLength = await reader.ReadUInt16Async().ConfigureAwait(false);
var extraLength = await reader.ReadUInt16Async().ConfigureAwait(false);
var commentLength = await reader.ReadUInt16Async().ConfigureAwait(false);
DiskNumberStart = await reader.ReadUInt16Async().ConfigureAwait(false);
InternalFileAttributes = await reader.ReadUInt16Async().ConfigureAwait(false);
ExternalFileAttributes = await reader.ReadUInt32Async().ConfigureAwait(false);
RelativeOffsetOfEntryHeader = await reader.ReadUInt32Async().ConfigureAwait(false);
var name = new byte[nameLength];
var extra = new byte[extraLength];
var comment = new byte[commentLength];
await reader.ReadBytesAsync(name, 0, nameLength);
await reader.ReadBytesAsync(extra, 0, extraLength);
await reader.ReadBytesAsync(comment, 0, commentLength);
await reader.ReadBytesAsync(name, 0, nameLength).ConfigureAwait(false);
await reader.ReadBytesAsync(extra, 0, extraLength).ConfigureAwait(false);
await reader.ReadBytesAsync(comment, 0, commentLength).ConfigureAwait(false);
ProcessReadData(name, extra, comment);
}

View File

@@ -9,20 +9,25 @@ internal partial class LocalEntryHeader
{
internal override async ValueTask Read(AsyncBinaryReader reader)
{
Version = await reader.ReadUInt16Async();
Flags = (HeaderFlags)await reader.ReadUInt16Async();
CompressionMethod = (ZipCompressionMethod)await reader.ReadUInt16Async();
OriginalLastModifiedTime = LastModifiedTime = await reader.ReadUInt16Async();
OriginalLastModifiedDate = LastModifiedDate = await reader.ReadUInt16Async();
Crc = await reader.ReadUInt32Async();
CompressedSize = await reader.ReadUInt32Async();
UncompressedSize = await reader.ReadUInt32Async();
var nameLength = await reader.ReadUInt16Async();
var extraLength = await reader.ReadUInt16Async();
Version = await reader.ReadUInt16Async().ConfigureAwait(false);
Flags = (HeaderFlags)await reader.ReadUInt16Async().ConfigureAwait(false);
CompressionMethod = (ZipCompressionMethod)
await reader.ReadUInt16Async().ConfigureAwait(false);
OriginalLastModifiedTime = LastModifiedTime = await reader
.ReadUInt16Async()
.ConfigureAwait(false);
OriginalLastModifiedDate = LastModifiedDate = await reader
.ReadUInt16Async()
.ConfigureAwait(false);
Crc = await reader.ReadUInt32Async().ConfigureAwait(false);
CompressedSize = await reader.ReadUInt32Async().ConfigureAwait(false);
UncompressedSize = await reader.ReadUInt32Async().ConfigureAwait(false);
var nameLength = await reader.ReadUInt16Async().ConfigureAwait(false);
var extraLength = await reader.ReadUInt16Async().ConfigureAwait(false);
var name = new byte[nameLength];
var extra = new byte[extraLength];
await reader.ReadBytesAsync(name, 0, nameLength);
await reader.ReadBytesAsync(extra, 0, extraLength);
await reader.ReadBytesAsync(name, 0, nameLength).ConfigureAwait(false);
await reader.ReadBytesAsync(extra, 0, extraLength).ConfigureAwait(false);
ProcessReadData(name, extra);
}

View File

@@ -8,19 +8,20 @@ internal partial class Zip64DirectoryEndHeader
{
internal override async ValueTask Read(AsyncBinaryReader reader)
{
SizeOfDirectoryEndRecord = (long)await reader.ReadUInt64Async();
VersionMadeBy = await reader.ReadUInt16Async();
VersionNeededToExtract = await reader.ReadUInt16Async();
VolumeNumber = await reader.ReadUInt32Async();
FirstVolumeWithDirectory = await reader.ReadUInt32Async();
TotalNumberOfEntriesInDisk = (long)await reader.ReadUInt64Async();
TotalNumberOfEntries = (long)await reader.ReadUInt64Async();
DirectorySize = (long)await reader.ReadUInt64Async();
DirectoryStartOffsetRelativeToDisk = (long)await reader.ReadUInt64Async();
SizeOfDirectoryEndRecord = (long)await reader.ReadUInt64Async().ConfigureAwait(false);
VersionMadeBy = await reader.ReadUInt16Async().ConfigureAwait(false);
VersionNeededToExtract = await reader.ReadUInt16Async().ConfigureAwait(false);
VolumeNumber = await reader.ReadUInt32Async().ConfigureAwait(false);
FirstVolumeWithDirectory = await reader.ReadUInt32Async().ConfigureAwait(false);
TotalNumberOfEntriesInDisk = (long)await reader.ReadUInt64Async().ConfigureAwait(false);
TotalNumberOfEntries = (long)await reader.ReadUInt64Async().ConfigureAwait(false);
DirectorySize = (long)await reader.ReadUInt64Async().ConfigureAwait(false);
DirectoryStartOffsetRelativeToDisk = (long)
await reader.ReadUInt64Async().ConfigureAwait(false);
var size = (int)(
SizeOfDirectoryEndRecord - SIZE_OF_FIXED_HEADER_DATA_EXCEPT_SIGNATURE_AND_SIZE_FIELDS
);
DataSector = new byte[size];
await reader.ReadBytesAsync(DataSector, 0, size);
await reader.ReadBytesAsync(DataSector, 0, size).ConfigureAwait(false);
}
}

View File

@@ -8,8 +8,9 @@ internal partial class Zip64DirectoryEndLocatorHeader
{
internal override async ValueTask Read(AsyncBinaryReader reader)
{
FirstVolumeWithDirectory = await reader.ReadUInt32Async();
RelativeOffsetOfTheEndOfDirectoryRecord = (long)await reader.ReadUInt64Async();
TotalNumberOfVolumes = await reader.ReadUInt32Async();
FirstVolumeWithDirectory = await reader.ReadUInt32Async().ConfigureAwait(false);
RelativeOffsetOfTheEndOfDirectoryRecord = (long)
await reader.ReadUInt64Async().ConfigureAwait(false);
TotalNumberOfVolumes = await reader.ReadUInt32Async().ConfigureAwait(false);
}
}

View File

@@ -13,12 +13,14 @@ internal partial class SeekableZipFilePart
{
if (!_isLocalHeaderLoaded)
{
await LoadLocalHeaderAsync(cancellationToken);
await LoadLocalHeaderAsync(cancellationToken).ConfigureAwait(false);
_isLocalHeaderLoaded = true;
}
return await base.GetCompressedStreamAsync(cancellationToken);
return await base.GetCompressedStreamAsync(cancellationToken).ConfigureAwait(false);
}
private async ValueTask LoadLocalHeaderAsync(CancellationToken cancellationToken = default) =>
Header = await _headerFactory.GetLocalHeaderAsync(BaseStream, (DirectoryEntryHeader)Header);
Header = await _headerFactory
.GetLocalHeaderAsync(BaseStream, (DirectoryEntryHeader)Header)
.ConfigureAwait(false);
}

View File

@@ -18,11 +18,11 @@ internal sealed partial class SeekableZipHeaderFactory
using var reader = new AsyncBinaryReader(stream, leaveOpen: true);
#endif
await SeekBackToHeaderAsync(stream, reader);
await SeekBackToHeaderAsync(stream, reader).ConfigureAwait(false);
var eocd_location = stream.Position;
var entry = new DirectoryEndHeader();
await entry.Read(reader);
await entry.Read(reader).ConfigureAwait(false);
if (entry.IsZip64)
{
@@ -30,24 +30,24 @@ internal sealed partial class SeekableZipHeaderFactory
// ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR should be before the EOCD
stream.Seek(eocd_location - ZIP64_EOCD_LENGTH - 4, SeekOrigin.Begin);
uint zip64_locator = await reader.ReadUInt32Async();
uint zip64_locator = await reader.ReadUInt32Async().ConfigureAwait(false);
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);
await zip64Locator.Read(reader).ConfigureAwait(false);
stream.Seek(zip64Locator.RelativeOffsetOfTheEndOfDirectoryRecord, SeekOrigin.Begin);
var zip64Signature = await reader.ReadUInt32Async();
var zip64Signature = await reader.ReadUInt32Async().ConfigureAwait(false);
if (zip64Signature != ZIP64_END_OF_CENTRAL_DIRECTORY)
{
throw new ArchiveException("Failed to locate the Zip64 Header");
}
var zip64Entry = new Zip64DirectoryEndHeader();
await zip64Entry.Read(reader);
await zip64Entry.Read(reader).ConfigureAwait(false);
stream.Seek(zip64Entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin);
}
else
@@ -59,8 +59,8 @@ internal sealed partial class SeekableZipHeaderFactory
while (true)
{
stream.Position = position;
var signature = await reader.ReadUInt32Async();
var nextHeader = await ReadHeader(signature, reader, _zip64);
var signature = await reader.ReadUInt32Async().ConfigureAwait(false);
var nextHeader = await ReadHeader(signature, reader, _zip64).ConfigureAwait(false);
position = stream.Position;
if (nextHeader is null)
@@ -101,7 +101,7 @@ internal sealed partial class SeekableZipHeaderFactory
try
{
await reader.ReadBytesAsync(seek, 0, len, default);
await reader.ReadBytesAsync(seek, 0, len, default).ConfigureAwait(false);
var memory = new Memory<byte>(seek, 0, len);
var span = memory.Span;
span.Reverse();
@@ -137,8 +137,11 @@ internal sealed partial class SeekableZipHeaderFactory
#else
using var reader = new AsyncBinaryReader(stream, leaveOpen: true);
#endif
var signature = await reader.ReadUInt32Async();
if (await ReadHeader(signature, reader, _zip64) is not LocalEntryHeader localEntryHeader)
var signature = await reader.ReadUInt32Async().ConfigureAwait(false);
if (
await ReadHeader(signature, reader, _zip64).ConfigureAwait(false)
is not LocalEntryHeader localEntryHeader
)
{
throw new InvalidOperationException();
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SharpCompress.Common.Options;
using SharpCompress.Common.Zip.Headers;
namespace SharpCompress.Common.Zip;
@@ -9,7 +10,8 @@ public class ZipEntry : Entry
{
private readonly ZipFilePart? _filePart;
internal ZipEntry(ZipFilePart? filePart)
internal ZipEntry(ZipFilePart? filePart, IReaderOptions readerOptions)
: base(readerOptions)
{
if (filePart == null)
{

View File

@@ -148,53 +148,63 @@ internal abstract partial class ZipFilePart
}
case ZipCompressionMethod.Reduce1:
{
return await ReduceStream.CreateAsync(
stream,
Header.CompressedSize,
Header.UncompressedSize,
1,
cancellationToken
);
return await ReduceStream
.CreateAsync(
stream,
Header.CompressedSize,
Header.UncompressedSize,
1,
cancellationToken
)
.ConfigureAwait(false);
}
case ZipCompressionMethod.Reduce2:
{
return await ReduceStream.CreateAsync(
stream,
Header.CompressedSize,
Header.UncompressedSize,
2,
cancellationToken
);
return await ReduceStream
.CreateAsync(
stream,
Header.CompressedSize,
Header.UncompressedSize,
2,
cancellationToken
)
.ConfigureAwait(false);
}
case ZipCompressionMethod.Reduce3:
{
return await ReduceStream.CreateAsync(
stream,
Header.CompressedSize,
Header.UncompressedSize,
3,
cancellationToken
);
return await ReduceStream
.CreateAsync(
stream,
Header.CompressedSize,
Header.UncompressedSize,
3,
cancellationToken
)
.ConfigureAwait(false);
}
case ZipCompressionMethod.Reduce4:
{
return await ReduceStream.CreateAsync(
stream,
Header.CompressedSize,
Header.UncompressedSize,
4,
cancellationToken
);
return await ReduceStream
.CreateAsync(
stream,
Header.CompressedSize,
Header.UncompressedSize,
4,
cancellationToken
)
.ConfigureAwait(false);
}
case ZipCompressionMethod.Explode:
{
return await ExplodeStream.CreateAsync(
stream,
Header.CompressedSize,
Header.UncompressedSize,
Header.Flags,
cancellationToken
);
return await ExplodeStream
.CreateAsync(
stream,
Header.CompressedSize,
Header.UncompressedSize,
Header.Flags,
cancellationToken
)
.ConfigureAwait(false);
}
case ZipCompressionMethod.Deflate:
@@ -207,12 +217,14 @@ internal abstract partial class ZipFilePart
}
case ZipCompressionMethod.BZip2:
{
return await BZip2Stream.CreateAsync(
stream,
CompressionMode.Decompress,
false,
cancellationToken: cancellationToken
);
return await BZip2Stream
.CreateAsync(
stream,
CompressionMode.Decompress,
false,
cancellationToken: cancellationToken
)
.ConfigureAwait(false);
}
case ZipCompressionMethod.LZMA:
{
@@ -228,14 +240,16 @@ internal abstract partial class ZipFilePart
await stream
.ReadFullyAsync(props, 0, propsSize, cancellationToken)
.ConfigureAwait(false);
return await LzmaStream.CreateAsync(
props,
stream,
Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1,
FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
? -1
: Header.UncompressedSize
);
return await LzmaStream
.CreateAsync(
props,
stream,
Header.CompressedSize > 0 ? Header.CompressedSize - 4 - props.Length : -1,
FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
? -1
: Header.UncompressedSize
)
.ConfigureAwait(false);
}
case ZipCompressionMethod.Xz:
{
@@ -284,11 +298,12 @@ internal abstract partial class ZipFilePart
}
return await CreateDecompressionStreamAsync(
stream,
(ZipCompressionMethod)
BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(5)),
cancellationToken
);
stream,
(ZipCompressionMethod)
BinaryPrimitives.ReadUInt16LittleEndian(data.DataBytes.AsSpan(5)),
cancellationToken
)
.ConfigureAwait(false);
}
default:
{

View File

@@ -21,7 +21,7 @@ internal partial class ZipHeaderFactory
case ENTRY_HEADER_BYTES:
{
var entryHeader = new LocalEntryHeader(_archiveEncoding);
await entryHeader.Read(reader);
await entryHeader.Read(reader).ConfigureAwait(false);
await LoadHeaderAsync(entryHeader, reader.BaseStream).ConfigureAwait(false);
_lastEntryHeader = entryHeader;
@@ -30,7 +30,7 @@ internal partial class ZipHeaderFactory
case DIRECTORY_START_HEADER_BYTES:
{
var entry = new DirectoryEntryHeader(_archiveEncoding);
await entry.Read(reader);
await entry.Read(reader).ConfigureAwait(false);
return entry;
}
case POST_DATA_DESCRIPTOR:
@@ -43,17 +43,17 @@ internal partial class ZipHeaderFactory
)
)
{
_lastEntryHeader.Crc = await reader.ReadUInt32Async();
_lastEntryHeader.Crc = await reader.ReadUInt32Async().ConfigureAwait(false);
_lastEntryHeader.CompressedSize = zip64
? (long)await reader.ReadUInt64Async()
: await reader.ReadUInt32Async();
? (long)await reader.ReadUInt64Async().ConfigureAwait(false)
: await reader.ReadUInt32Async().ConfigureAwait(false);
_lastEntryHeader.UncompressedSize = zip64
? (long)await reader.ReadUInt64Async()
: await reader.ReadUInt32Async();
? (long)await reader.ReadUInt64Async().ConfigureAwait(false)
: await reader.ReadUInt32Async().ConfigureAwait(false);
}
else
{
await reader.SkipAsync(zip64 ? 20 : 12);
await reader.SkipAsync(zip64 ? 20 : 12).ConfigureAwait(false);
}
return null;
}
@@ -62,7 +62,7 @@ internal partial class ZipHeaderFactory
case DIRECTORY_END_HEADER_BYTES:
{
var entry = new DirectoryEndHeader();
await entry.Read(reader);
await entry.Read(reader).ConfigureAwait(false);
return entry;
}
case SPLIT_ARCHIVE_HEADER_BYTES:
@@ -72,13 +72,13 @@ internal partial class ZipHeaderFactory
case ZIP64_END_OF_CENTRAL_DIRECTORY:
{
var entry = new Zip64DirectoryEndHeader();
await entry.Read(reader);
await entry.Read(reader).ConfigureAwait(false);
return entry;
}
case ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR:
{
var entry = new Zip64DirectoryEndLocatorHeader();
await entry.Read(reader);
await entry.Read(reader).ConfigureAwait(false);
return entry;
}
default:

View File

@@ -19,7 +19,9 @@ public static partial class ADCBase
byte[] input,
int bufferSize = 262144,
CancellationToken cancellationToken = default
) => await DecompressAsync(new MemoryStream(input), bufferSize, cancellationToken);
) =>
await DecompressAsync(new MemoryStream(input), bufferSize, cancellationToken)
.ConfigureAwait(false);
/// <summary>
/// Decompresses a stream asynchronously that's compressed with ADC
@@ -76,12 +78,9 @@ public static partial class ADCBase
break;
}
var readCount = await input.ReadAsync(
buffer,
outPosition,
chunkSize,
cancellationToken
);
var readCount = await input
.ReadAsync(buffer, outPosition, chunkSize, cancellationToken)
.ConfigureAwait(false);
outPosition += readCount;
position += readCount + 1;
break;

View File

@@ -66,10 +66,9 @@ public sealed partial class ADCStream
if (_outBuffer is null)
{
var result = await ADCBase.DecompressAsync(
_stream,
cancellationToken: cancellationToken
);
var result = await ADCBase
.DecompressAsync(_stream, cancellationToken: cancellationToken)
.ConfigureAwait(false);
_outBuffer = result.Output;
_outPosition = 0;
}
@@ -87,10 +86,9 @@ public sealed partial class ADCStream
copied += piece;
_position += piece;
toCopy -= piece;
var result = await ADCBase.DecompressAsync(
_stream,
cancellationToken: cancellationToken
);
var result = await ADCBase
.DecompressAsync(_stream, cancellationToken: cancellationToken)
.ConfigureAwait(false);
_outBuffer = result.Output;
_outPosition = 0;
if (result.BytesRead == 0 || _outBuffer is null || _outBuffer.Length == 0)

View File

@@ -31,12 +31,9 @@ public sealed partial class BZip2Stream
}
else
{
bZip2Stream.stream = await CBZip2InputStream.CreateAsync(
stream,
decompressConcatenated,
leaveOpen,
cancellationToken
);
bZip2Stream.stream = await CBZip2InputStream
.CreateAsync(stream, decompressConcatenated, leaveOpen, cancellationToken)
.ConfigureAwait(false);
}
return bZip2Stream;
@@ -55,7 +52,9 @@ public sealed partial class BZip2Stream
{
cancellationToken.ThrowIfCancellationRequested();
var buffer = new byte[2];
var bytesRead = await stream.ReadAsync(buffer, 0, 2, cancellationToken);
var bytesRead = await stream
.ReadAsync(buffer, 0, 2, cancellationToken)
.ConfigureAwait(false);
if (bytesRead < 2 || buffer[0] != 'B' || buffer[1] != 'Z')
{
return false;

View File

@@ -800,14 +800,6 @@ internal partial class CBZip2InputStream
return k;
}
private async ValueTask BsSetStreamAsync(Stream f, CancellationToken cancellationToken)
{
bsStream = f;
bsLive = 0;
bsBuff = 0;
await Task.CompletedTask;
}
private async ValueTask<int> BsRAsync(int n, CancellationToken cancellationToken)
{
int v;
@@ -818,7 +810,7 @@ internal partial class CBZip2InputStream
var b = ArrayPool<byte>.Shared.Rent(1);
try
{
await bsStream.ReadExactAsync(b, 0, 1, cancellationToken);
await bsStream.ReadExactAsync(b, 0, 1, cancellationToken).ConfigureAwait(false);
thech = (char)b[0];
}
catch (IOException)
@@ -844,15 +836,15 @@ internal partial class CBZip2InputStream
}
private async ValueTask<char> BsGetUCharAsync(CancellationToken cancellationToken) =>
(char)await BsRAsync(8, cancellationToken);
(char)await BsRAsync(8, cancellationToken).ConfigureAwait(false);
private async ValueTask<int> BsGetIntVSAsync(
int numBits,
CancellationToken cancellationToken
) => await BsRAsync(numBits, cancellationToken);
) => await BsRAsync(numBits, cancellationToken).ConfigureAwait(false);
private async ValueTask<int> BsGetInt32Async(CancellationToken cancellationToken) =>
await BsGetintAsync(cancellationToken);
await BsGetintAsync(cancellationToken).ConfigureAwait(false);
public static async ValueTask<CBZip2InputStream> CreateAsync(
Stream zStream,
@@ -864,10 +856,10 @@ internal partial class CBZip2InputStream
var cbZip2InputStream = new CBZip2InputStream(decompressConcatenated, leaveOpen);
cbZip2InputStream.ll8 = null;
cbZip2InputStream.tt = null;
await cbZip2InputStream.BsSetStreamAsync(zStream, cancellationToken);
await cbZip2InputStream.InitializeAsync(true, cancellationToken);
await cbZip2InputStream.InitBlockAsync(cancellationToken);
await cbZip2InputStream.SetupBlockAsync(cancellationToken);
cbZip2InputStream.BsSetStream(zStream);
await cbZip2InputStream.InitializeAsync(true, cancellationToken).ConfigureAwait(false);
await cbZip2InputStream.InitBlockAsync(cancellationToken).ConfigureAwait(false);
await cbZip2InputStream.SetupBlockAsync(cancellationToken).ConfigureAwait(false);
return cbZip2InputStream;
}
}

Some files were not shown because too many files have changed in this diff Show More