Consolidate

This commit is contained in:
Adam Hathcock
2026-02-10 15:32:23 +00:00
parent 04c3b84fc0
commit f0da1b3a93
24 changed files with 92 additions and 133 deletions

View File

@@ -87,7 +87,11 @@ public partial class GZipArchive
var stream = volumes.Single().Stream;
yield return new GZipArchiveEntry(
this,
GZipFilePart.Create(stream, ReaderOptions.ArchiveEncoding),
GZipFilePart.Create(
stream,
ReaderOptions.ArchiveEncoding,
ReaderOptions.CompressionProviders
),
ReaderOptions
);
}

View File

@@ -55,7 +55,12 @@ public partial class ZipArchive
yield return new ZipArchiveEntry(
this,
new SeekableZipFilePart(headerFactory.NotNull(), deh, s),
new SeekableZipFilePart(
headerFactory.NotNull(),
deh,
s,
ReaderOptions.CompressionProviders
),
ReaderOptions
);
}

View File

@@ -96,7 +96,12 @@ public partial class ZipArchive
yield return new ZipArchiveEntry(
this,
new SeekableZipFilePart(headerFactory.NotNull(), deh, s),
new SeekableZipFilePart(
headerFactory.NotNull(),
deh,
s,
ReaderOptions.CompressionProviders
),
ReaderOptions
);
}

View File

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

View File

@@ -46,7 +46,10 @@ public partial class GZipEntry : Entry
internal static IEnumerable<GZipEntry> GetEntries(Stream stream, ReaderOptions options)
{
yield return new GZipEntry(GZipFilePart.Create(stream, options.ArchiveEncoding), options);
yield return new GZipEntry(
GZipFilePart.Create(stream, options.ArchiveEncoding, options.CompressionProviders),
options
);
}
// Async methods moved to GZipEntry.Async.cs

View File

@@ -15,16 +15,7 @@ internal sealed partial class GZipFilePart
internal static async ValueTask<GZipFilePart> CreateAsync(
Stream stream,
IArchiveEncoding archiveEncoding,
CancellationToken cancellationToken = default
)
{
return await CreateAsync(stream, archiveEncoding, null, cancellationToken);
}
internal static async ValueTask<GZipFilePart> CreateAsync(
Stream stream,
IArchiveEncoding archiveEncoding,
CompressionProviderRegistry? compressionProviders,
CompressionProviderRegistry compressionProviders,
CancellationToken cancellationToken = default
)
{

View File

@@ -12,34 +12,12 @@ internal sealed partial class GZipFilePart : FilePart
{
private string? _name;
private readonly Stream _stream;
private readonly CompressionProviderRegistry? _compressionProviders;
internal static GZipFilePart Create(Stream stream, IArchiveEncoding archiveEncoding)
{
var part = new GZipFilePart(stream, archiveEncoding, null);
part.ReadAndValidateGzipHeader();
if (stream.CanSeek)
{
var position = stream.Position;
stream.Position = stream.Length - 8;
part.ReadTrailer();
stream.Position = position;
part.EntryStartPosition = position;
}
else
{
// For non-seekable streams, we can't read the trailer or track position.
// Set to 0 since the stream will be read sequentially from its current position.
part.EntryStartPosition = 0;
}
return part;
}
private readonly CompressionProviderRegistry _compressionProviders;
internal static GZipFilePart Create(
Stream stream,
IArchiveEncoding archiveEncoding,
CompressionProviderRegistry? compressionProviders
CompressionProviderRegistry compressionProviders
)
{
var part = new GZipFilePart(stream, archiveEncoding, compressionProviders);
@@ -62,13 +40,10 @@ internal sealed partial class GZipFilePart : FilePart
return part;
}
private GZipFilePart(Stream stream, IArchiveEncoding archiveEncoding)
: base(archiveEncoding) => _stream = stream;
private GZipFilePart(
Stream stream,
IArchiveEncoding archiveEncoding,
CompressionProviderRegistry? compressionProviders
CompressionProviderRegistry compressionProviders
)
: base(archiveEncoding)
{
@@ -86,8 +61,7 @@ internal sealed partial class GZipFilePart : FilePart
internal override Stream GetCompressedStream()
{
var providers = _compressionProviders ?? CompressionProviderRegistry.Default;
return providers.CreateDecompressStream(CompressionType.Deflate, _stream);
return _compressionProviders.CreateDecompressStream(CompressionType.Deflate, _stream);
}
internal override Stream GetRawStream() => _stream;

View File

@@ -39,9 +39,9 @@ public interface IReaderOptions
int? RewindableBufferSize { get; init; }
/// <summary>
/// Optional registry of compression providers.
/// If null, the default registry (SharpCompress internal implementations) will be used.
/// Registry of compression providers.
/// Defaults to <see cref="CompressionProviderRegistry.Default" /> but can be replaced with custom providers.
/// Use this to provide alternative decompression implementations.
/// </summary>
CompressionProviderRegistry? CompressionProviders { get; init; }
CompressionProviderRegistry CompressionProviders { get; init; }
}

View File

@@ -19,10 +19,9 @@ public interface IWriterOptions : IStreamOptions, IEncodingOptions, IProgressOpt
int CompressionLevel { get; init; }
/// <summary>
/// Optional registry of compression providers.
/// If null, the default registry (SharpCompress internal implementations) will be used.
/// Use this to provide alternative compression implementations, such as
/// Registry of compression providers.
/// Defaults to <see cref="CompressionProviderRegistry.Default" /> but can be replaced with custom providers, such as
/// System.IO.Compression for Deflate/GZip on modern .NET.
/// </summary>
CompressionProviderRegistry? CompressionProviders { get; init; }
CompressionProviderRegistry CompressionProviders { get; init; }
}

View File

@@ -9,18 +9,11 @@ internal partial class SeekableZipFilePart : ZipFilePart
private bool _isLocalHeaderLoaded;
private readonly SeekableZipHeaderFactory _headerFactory;
internal SeekableZipFilePart(
SeekableZipHeaderFactory headerFactory,
DirectoryEntryHeader header,
Stream stream
)
: base(header, stream) => _headerFactory = headerFactory;
internal SeekableZipFilePart(
SeekableZipHeaderFactory headerFactory,
DirectoryEntryHeader header,
Stream stream,
CompressionProviderRegistry? compressionProviders
CompressionProviderRegistry compressionProviders
)
: base(header, stream, compressionProviders) => _headerFactory = headerFactory;

View File

@@ -9,13 +9,10 @@ internal sealed partial class StreamingZipFilePart : ZipFilePart
{
private Stream? _decompressionStream;
internal StreamingZipFilePart(ZipFileEntry header, Stream stream)
: base(header, stream) { }
internal StreamingZipFilePart(
ZipFileEntry header,
Stream stream,
CompressionProviderRegistry? compressionProviders
CompressionProviderRegistry compressionProviders
)
: base(header, stream, compressionProviders) { }

View File

@@ -20,39 +20,24 @@ namespace SharpCompress.Common.Zip;
internal abstract partial class ZipFilePart : FilePart
{
private CompressionProviderRegistry? _compressionProviders;
private readonly CompressionProviderRegistry _compressionProviders;
internal ZipFilePart(ZipFileEntry header, Stream stream)
internal ZipFilePart(
ZipFileEntry header,
Stream stream,
CompressionProviderRegistry compressionProviders
)
: base(header.ArchiveEncoding)
{
Header = header;
header.Part = this;
BaseStream = stream;
}
internal ZipFilePart(
ZipFileEntry header,
Stream stream,
CompressionProviderRegistry? compressionProviders
)
: this(header, stream)
{
_compressionProviders = compressionProviders;
}
internal Stream BaseStream { get; }
internal ZipFileEntry Header { get; set; }
/// <summary>
/// Gets or sets the compression provider registry.
/// If null, uses the default registry.
/// </summary>
internal CompressionProviderRegistry? CompressionProviders
{
get => _compressionProviders;
set => _compressionProviders = value;
}
internal override string? FilePartName => Header.Name;
internal override Stream GetCompressedStream()
@@ -89,8 +74,7 @@ internal abstract partial class ZipFilePart : FilePart
/// <summary>
/// Gets the compression provider registry, falling back to default if not set.
/// </summary>
protected CompressionProviderRegistry GetProviders() =>
_compressionProviders ?? CompressionProviderRegistry.Default;
protected CompressionProviderRegistry GetProviders() => _compressionProviders;
/// <summary>
/// Converts ZipCompressionMethod to CompressionType.

View File

@@ -149,12 +149,13 @@ public sealed record ReaderOptions : IReaderOptions
/// The default handler logs a warning message.
/// </remarks>
public Action<string, string>? SymbolicLinkHandler { get; init; }
/// Optional registry of compression providers.
/// If null, the default registry (SharpCompress internal implementations) will be used.
/// Use this to provide alternative decompression implementations, such as
/// Registry of compression providers.
/// Defaults to <see cref="CompressionProviderRegistry.Default" /> but can be replaced with custom implementations, such as
/// System.IO.Compression for Deflate/GZip on modern .NET.
/// </summary>
public CompressionProviderRegistry? CompressionProviders { get; init; }
public CompressionProviderRegistry CompressionProviders { get; init; } =
CompressionProviderRegistry.Default;
/// <summary>
/// Creates a new ReaderOptions instance with default values.

View File

@@ -33,8 +33,7 @@ public partial class TarReader : AbstractReader<TarEntry, TarVolume>
{
var stream = base.RequestInitialStream();
// Get compression providers from options, falling back to default
var providers = Options.CompressionProviders ?? CompressionProviderRegistry.Default;
var providers = Options.CompressionProviders;
return compressionType switch
{

View File

@@ -21,24 +21,21 @@ public partial class ZipReader
private readonly StreamingZipHeaderFactory _headerFactory;
private readonly Stream _stream;
private readonly IReaderOptions _options;
private readonly CompressionProviderRegistry? _compressionProviders;
public ZipEntryAsyncEnumerable(
StreamingZipHeaderFactory headerFactory,
Stream stream,
IReaderOptions options,
CompressionProviderRegistry? compressionProviders
IReaderOptions options
)
{
_headerFactory = headerFactory;
_stream = stream;
_options = options;
_compressionProviders = compressionProviders;
}
public IAsyncEnumerator<ZipEntry> GetAsyncEnumerator(
CancellationToken cancellationToken = default
) => new ZipEntryAsyncEnumerator(_headerFactory, _stream, _options, _compressionProviders, cancellationToken);
) => new ZipEntryAsyncEnumerator(_headerFactory, _stream, _options, cancellationToken);
}
/// <summary>
@@ -49,20 +46,17 @@ public partial class ZipReader
private readonly Stream _stream;
private readonly IAsyncEnumerator<ZipHeader> _headerEnumerator;
private readonly IReaderOptions _options;
private readonly CompressionProviderRegistry? _compressionProviders;
private ZipEntry? _current;
public ZipEntryAsyncEnumerator(
StreamingZipHeaderFactory headerFactory,
Stream stream,
IReaderOptions options,
CompressionProviderRegistry? compressionProviders,
CancellationToken cancellationToken
)
{
_stream = stream;
_options = options;
_compressionProviders = compressionProviders;
_headerEnumerator = headerFactory
.ReadStreamHeaderAsync(stream)
.GetAsyncEnumerator(cancellationToken);
@@ -84,7 +78,11 @@ public partial class ZipReader
{
case ZipHeaderType.LocalEntry:
_current = new ZipEntry(
new StreamingZipFilePart((LocalEntryHeader)header, _stream),
new StreamingZipFilePart(
(LocalEntryHeader)header,
_stream,
_options.CompressionProviders
),
_options
);
return true;

View File

@@ -74,7 +74,11 @@ public partial class ZipReader : AbstractReader<ZipEntry, ZipVolume>
case ZipHeaderType.LocalEntry:
{
yield return new ZipEntry(
new StreamingZipFilePart((LocalEntryHeader)h, stream),
new StreamingZipFilePart(
(LocalEntryHeader)h,
stream,
Options.CompressionProviders
),
Options
);
}
@@ -100,7 +104,7 @@ public partial class ZipReader : AbstractReader<ZipEntry, ZipVolume>
/// Returns entries asynchronously for streams that only support async reads.
/// </summary>
protected override IAsyncEnumerable<ZipEntry> GetEntriesAsync(Stream stream) =>
new ZipEntryAsyncEnumerable(_headerFactory, stream, Options, Options.CompressionProviders);
new ZipEntryAsyncEnumerable(_headerFactory, stream, Options);
// Async nested classes moved to ZipReader.Async.cs
}

View File

@@ -19,14 +19,14 @@ public sealed partial class GZipWriter : AbstractWriter
destination = SharpCompressStream.CreateNonDisposing(destination);
}
// Get compression providers from options, falling back to default
var providers = options?.CompressionProviders ?? CompressionProviderRegistry.Default;
// Use the configured compression providers
var providers = WriterOptions.CompressionProviders;
// Create the GZip stream using the provider
var compressionStream = providers.CreateCompressStream(
CompressionType.GZip,
destination,
options?.CompressionLevel ?? (int)CompressionLevel.Default
WriterOptions.CompressionLevel
);
// If using internal GZipStream, set the encoding for header filename

View File

@@ -68,12 +68,12 @@ public sealed record GZipWriterOptions : IWriterOptions
public IProgress<ProgressReport>? Progress { get; init; }
/// <summary>
/// Optional registry of compression providers.
/// If null, the default registry (SharpCompress internal implementations) will be used.
/// Use this to provide alternative compression implementations, such as
/// Registry of compression providers.
/// Defaults to <see cref="CompressionProviderRegistry.Default" /> but can be replaced with custom implementations, such as
/// System.IO.Compression for GZip on modern .NET.
/// </summary>
public CompressionProviderRegistry? CompressionProviders { get; init; }
public CompressionProviderRegistry CompressionProviders { get; init; } =
CompressionProviderRegistry.Default;
/// <summary>
/// Creates a new GZipWriterOptions instance with default values.
@@ -114,6 +114,7 @@ public sealed record GZipWriterOptions : IWriterOptions
LeaveStreamOpen = options.LeaveStreamOpen;
ArchiveEncoding = options.ArchiveEncoding;
Progress = options.Progress;
CompressionProviders = options.CompressionProviders;
}
/// <summary>
@@ -126,5 +127,6 @@ public sealed record GZipWriterOptions : IWriterOptions
LeaveStreamOpen = options.LeaveStreamOpen;
ArchiveEncoding = options.ArchiveEncoding;
Progress = options.Progress;
CompressionProviders = options.CompressionProviders;
}
}

View File

@@ -29,8 +29,7 @@ public partial class TarWriter : AbstractWriter
destination = SharpCompressStream.CreateNonDisposing(destination);
}
// Get compression providers from options, falling back to default
var providers = options.CompressionProviders ?? CompressionProviderRegistry.Default;
var providers = options.CompressionProviders;
destination = options.CompressionType switch
{

View File

@@ -44,11 +44,11 @@ public sealed record TarWriterOptions : IWriterOptions
public IProgress<ProgressReport>? Progress { get; init; }
/// <summary>
/// Optional registry of compression providers.
/// If null, the default registry (SharpCompress internal implementations) will be used.
/// Use this to provide alternative compression implementations.
/// Registry of compression providers.
/// Defaults to <see cref="CompressionProviderRegistry.Default" /> but can be replaced with custom implementations.
/// </summary>
public CompressionProviderRegistry? CompressionProviders { get; init; }
public CompressionProviderRegistry CompressionProviders { get; init; } =
CompressionProviderRegistry.Default;
/// <summary>
/// Indicates if archive should be finalized (by 2 empty blocks) on close.
@@ -104,6 +104,7 @@ public sealed record TarWriterOptions : IWriterOptions
LeaveStreamOpen = options.LeaveStreamOpen;
ArchiveEncoding = options.ArchiveEncoding;
Progress = options.Progress;
CompressionProviders = options.CompressionProviders;
}
/// <summary>
@@ -117,6 +118,7 @@ public sealed record TarWriterOptions : IWriterOptions
LeaveStreamOpen = options.LeaveStreamOpen;
ArchiveEncoding = options.ArchiveEncoding;
Progress = options.Progress;
CompressionProviders = options.CompressionProviders;
}
/// <summary>

View File

@@ -64,12 +64,12 @@ public sealed record WriterOptions : IWriterOptions
public IProgress<ProgressReport>? Progress { get; init; }
/// <summary>
/// Optional registry of compression providers.
/// If null, the default registry (SharpCompress internal implementations) will be used.
/// Use this to provide alternative compression implementations, such as
/// Registry of compression providers.
/// Defaults to <see cref="CompressionProviderRegistry.Default" /> but can be replaced with custom implementations, such as
/// System.IO.Compression for Deflate/GZip on modern .NET.
/// </summary>
public CompressionProviderRegistry? CompressionProviders { get; init; }
public CompressionProviderRegistry CompressionProviders { get; init; } =
CompressionProviderRegistry.Default;
/// <summary>
/// Creates a new WriterOptions instance with the specified compression type.

View File

@@ -421,9 +421,7 @@ public partial class ZipWriter : AbstractWriter
counting = new CountingStream(SharpCompressStream.CreateNonDisposing(writeStream));
Stream output = counting;
// Get compression providers from writer options, falling back to default
var providers =
writer.WriterOptions.CompressionProviders ?? CompressionProviderRegistry.Default;
var providers = writer.WriterOptions.CompressionProviders;
switch (zipCompressionMethod)
{

View File

@@ -61,11 +61,11 @@ public sealed record ZipWriterOptions : IWriterOptions
public IProgress<ProgressReport>? Progress { get; init; }
/// <summary>
/// Optional registry of compression providers.
/// If null, the default registry (SharpCompress internal implementations) will be used.
/// Use this to provide alternative compression implementations.
/// Registry of compression providers.
/// Defaults to <see cref="CompressionProviderRegistry.Default" /> but can be replaced with custom implementations.
/// </summary>
public CompressionProviderRegistry? CompressionProviders { get; init; }
public CompressionProviderRegistry CompressionProviders { get; init; } =
CompressionProviderRegistry.Default;
/// <summary>
/// Optional comment for the archive.
@@ -127,6 +127,7 @@ public sealed record ZipWriterOptions : IWriterOptions
LeaveStreamOpen = options.LeaveStreamOpen;
ArchiveEncoding = options.ArchiveEncoding;
Progress = options.Progress;
CompressionProviders = options.CompressionProviders;
}
/// <summary>
@@ -139,6 +140,7 @@ public sealed record ZipWriterOptions : IWriterOptions
LeaveStreamOpen = options.LeaveStreamOpen;
ArchiveEncoding = options.ArchiveEncoding;
Progress = options.Progress;
CompressionProviders = options.CompressionProviders;
}
/// <summary>

View File

@@ -134,13 +134,10 @@ public class CompressionProviderTests
}
[Fact]
public void TarWriter_WithNullProvider_UsesDefault()
public void TarWriter_WithoutCustomProvider_UsesDefault()
{
using var stream = new MemoryStream();
var options = new TarWriterOptions(CompressionType.GZip, true)
{
CompressionProviders = null, // Should use default
};
var options = new TarWriterOptions(CompressionType.GZip, true);
using (var writer = new TarWriter(stream, options))
{