Skip to content

Add ability to have alternate compressions#1197

Merged
adamhathcock merged 26 commits intomasterfrom
adam/add-alternate-compressions
Feb 13, 2026
Merged

Add ability to have alternate compressions#1197
adamhathcock merged 26 commits intomasterfrom
adam/add-alternate-compressions

Conversation

@adamhathcock
Copy link
Owner

#1196

This pull request introduces support for custom compression providers throughout the SharpCompress library, allowing users to swap out the built-in compression implementations for alternatives (such as using System.IO.Compression for GZip/Deflate). The changes include updates to the API, documentation, and internal handling of compression streams to make the provider registry configurable and accessible wherever compression or decompression occurs.

API and Core Library Updates:

  • Added a Providers property of type CompressionProviderRegistry to both ReaderOptions and WriterOptions, allowing users to specify custom compression providers. This property defaults to the built-in registry but can be overridden as needed. [1] [2] [3]
  • Updated constructors and methods for GZipFilePart, SeekableZipFilePart, StreamingZipFilePart, and ZipFilePart to accept and use the CompressionProviderRegistry for creating decompression streams, replacing hardcoded usage of built-in codecs. [1] [2] [3] [4] [5] [6] [7]
  • Modified all relevant archive and entry-loading code paths (GZip and Zip) to pass the Providers registry from options to file part constructors, ensuring the custom provider is used throughout. [1] [2] [3] [4] [5] [6]

Documentation Improvements:

  • Added new sections to README.md, docs/API.md, and docs/USAGE.md explaining how to configure and use custom compression providers, with code samples and guidance for replacing or extending built-in codecs. [1] [2] [3]

Internal Refactoring:

  • Refactored the handling of decompression streams in GZipFilePart and ZipFilePart to use the provider registry, removing direct references to specific codec classes and making the implementation more flexible. [1] [2]
  • Removed unused or now-unnecessary codec-specific logic, such as direct instantiation of DeflateStream in favor of using the provider registry abstraction.

These changes make it much easier to integrate alternative or third-party compression libraries, improve testability, and allow for more flexible deployment scenarios.

…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
Copilot AI review requested due to automatic review settings February 10, 2026 15:52
);
internal override Stream GetCompressedStream()
{
return _compressionProviders.CreateDecompressStream(CompressionType.Deflate, _stream);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: GZip uses Deflate compression, but this hardcodes CompressionType.Deflate instead of using CompressionType.GZip.

When a custom provider is registered for GZip, this code will still use the Deflate provider for decompression. This breaks the provider abstraction for GZip files.

Consider using CompressionType.GZip here, or ensure the provider registry properly maps GZip to use the correct decompression implementation.

@kilo-code-bot
Copy link
Contributor

kilo-code-bot bot commented Feb 10, 2026

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (84 files)
  • README.md
  • docs/API.md
  • docs/USAGE.md
  • src/SharpCompress/Archives/GZip/GZipArchive.Async.cs
  • src/SharpCompress/Archives/GZip/GZipArchive.cs
  • src/SharpCompress/Archives/GZip/GZipArchiveEntry.cs
  • src/SharpCompress/Archives/Tar/TarArchive.Async.cs
  • src/SharpCompress/Archives/Tar/TarArchive.Factory.cs
  • src/SharpCompress/Archives/Tar/TarArchive.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/GZip/GZipFilePart.Async.cs
  • src/SharpCompress/Common/GZip/GZipFilePart.cs
  • src/SharpCompress/Common/Lzw/LzwEntry.Async.cs
  • src/SharpCompress/Common/Lzw/LzwEntry.cs
  • src/SharpCompress/Common/Lzw/LzwFilePart.Async.cs
  • src/SharpCompress/Common/Lzw/LzwFilePart.cs
  • src/SharpCompress/Common/Options/IReaderOptions.cs
  • src/SharpCompress/Common/Options/IWriterOptions.cs
  • src/SharpCompress/Common/Zip/SeekableZipFilePart.cs
  • src/SharpCompress/Common/Zip/StreamingZipFilePart.cs
  • src/SharpCompress/Common/Zip/ZipFilePart.Async.cs
  • src/SharpCompress/Common/Zip/ZipFilePart.cs
  • src/SharpCompress/Compressors/BZip2/BZip2Stream.cs
  • src/SharpCompress/Compressors/Deflate/GZipStream.cs
  • src/SharpCompress/Compressors/LZMA/LZipStream.cs
  • src/SharpCompress/Factories/Factory.cs
  • src/SharpCompress/Factories/GZipFactory.cs
  • src/SharpCompress/Factories/LzwFactory.cs
  • src/SharpCompress/Factories/TarFactory.cs
  • src/SharpCompress/IO/SharpCompressStream.cs
  • src/SharpCompress/Providers/CompressionContext.cs
  • src/SharpCompress/Providers/CompressionContextExtensions.cs
  • src/SharpCompress/Providers/CompressionProviderBase.cs
  • src/SharpCompress/Providers/CompressionProviderRegistry.cs
  • src/SharpCompress/Providers/ContextRequiredDecompressionProviderBase.cs
  • src/SharpCompress/Providers/DecompressionOnlyProviderBase.cs
  • src/SharpCompress/Providers/Default/BZip2CompressionProvider.cs
  • src/SharpCompress/Providers/Default/Deflate64CompressionProvider.cs
  • src/SharpCompress/Providers/Default/DeflateCompressionProvider.cs
  • src/SharpCompress/Providers/Default/ExplodeCompressionProvider.cs
  • src/SharpCompress/Providers/Default/GZipCompressionProvider.cs
  • src/SharpCompress/Providers/Default/LZipCompressionProvider.cs
  • src/SharpCompress/Providers/Default/LzmaCompressingProvider.cs
  • src/SharpCompress/Providers/Default/LzwCompressionProvider.cs
  • src/SharpCompress/Providers/Default/PpmdCompressingProvider.cs
  • src/SharpCompress/Providers/Default/Reduce1CompressionProvider.cs
  • src/SharpCompress/Providers/Default/Reduce2CompressionProvider.cs
  • src/SharpCompress/Providers/Default/Reduce3CompressionProvider.cs
  • src/SharpCompress/Providers/Default/Reduce4CompressionProvider.cs
  • src/SharpCompress/Providers/Default/ReduceCompressionProviderBase.cs
  • src/SharpCompress/Providers/Default/ShrinkCompressionProvider.cs
  • src/SharpCompress/Providers/Default/XzCompressionProvider.cs
  • src/SharpCompress/Providers/Default/ZStandardCompressionProvider.cs
  • src/SharpCompress/Providers/ICompressionProvider.cs
  • src/SharpCompress/Providers/ICompressionProviderHooks.cs
  • src/SharpCompress/Providers/IFinishable.cs
  • src/SharpCompress/Providers/System/SystemDeflateCompressionProvider.cs
  • src/SharpCompress/Providers/System/SystemGZipCompressionProvider.cs
  • src/SharpCompress/Readers/AbstractReader.Async.cs
  • src/SharpCompress/Readers/AbstractReader.cs
  • src/SharpCompress/Readers/ReaderFactory.Async.cs
  • src/SharpCompress/Readers/ReaderOptions.cs
  • src/SharpCompress/Readers/ReaderOptionsExtensions.cs
  • src/SharpCompress/Readers/Tar/TarReader.Factory.cs
  • src/SharpCompress/Readers/Tar/TarReader.cs
  • src/SharpCompress/Readers/Zip/ZipReader.Async.cs
  • src/SharpCompress/Readers/Zip/ZipReader.cs
  • src/SharpCompress/Writers/GZip/GZipWriter.cs
  • src/SharpCompress/Writers/GZip/GZipWriterOptions.cs
  • src/SharpCompress/Writers/Tar/TarWriter.cs
  • src/SharpCompress/Writers/Tar/TarWriterOptions.cs
  • src/SharpCompress/Writers/WriterOptions.cs
  • src/SharpCompress/Writers/WriterOptionsExtensions.cs
  • src/SharpCompress/Writers/Zip/ZipWriter.cs
  • src/SharpCompress/Writers/Zip/ZipWriterOptions.cs
  • tests/SharpCompress.Performance/Benchmarks/TarBenchmarks.cs
  • tests/SharpCompress.Performance/Benchmarks/ZipBenchmarks.cs
  • tests/SharpCompress.Performance/baseline-results.md
  • tests/SharpCompress.Test/CompressionProviderTests.cs
  • tests/SharpCompress.Test/ReaderTests.cs
  • tests/SharpCompress.Test/Streams/SharpCompressStreamAsyncTest.cs
  • tests/SharpCompress.Test/Streams/SharpCompressStreamEdgeAsyncTest.cs
  • tests/SharpCompress.Test/Streams/SharpCompressStreamEdgeTest.cs
  • tests/SharpCompress.Test/Streams/SharpCompressStreamErrorAsyncTest.cs
  • tests/SharpCompress.Test/Streams/SharpCompressStreamErrorTest.cs
  • tests/SharpCompress.Test/Streams/SharpCompressStreamFactoryAsyncTest.cs
  • tests/SharpCompress.Test/Streams/SharpCompressStreamFactoryTest.cs
  • tests/SharpCompress.Test/Streams/SharpCompressStreamPassthroughAsyncTest.cs
  • tests/SharpCompress.Test/Streams/SharpCompressStreamPassthroughTest.cs
  • tests/SharpCompress.Test/Streams/SharpCompressStreamPropertyTest.cs
  • tests/SharpCompress.Test/Streams/SharpCompressStreamSeekAsyncTest.cs
  • tests/SharpCompress.Test/Streams/SharpCompressStreamSeekTest.cs
  • tests/SharpCompress.Test/Streams/SharpCompressStreamTest.cs
  • tests/SharpCompress.Test/Tar/TarReaderAsyncTests.cs
  • tests/SharpCompress.Test/WriterTests.cs

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a configurable CompressionProviderRegistry that flows through SharpCompress reader/writer options so callers can swap compression stream implementations (e.g., use System.IO.Compression for GZip/Deflate) while keeping internal defaults.

Changes:

  • Introduces ICompressionProvider, CompressionProviderRegistry, and CompressionContext (plus hook/finalization interfaces) and internal default provider implementations for many CompressionTypes.
  • Threads Providers through ReaderOptions/WriterOptions (and format-specific options) into ZIP/GZip/Tar read/write pipelines.
  • Adds docs + tests demonstrating replacing providers and validating round-trips / compatibility.

Reviewed changes

Copilot reviewed 55 out of 55 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
tests/SharpCompress.Test/CompressionProviderTests.cs New unit tests covering default registry, replacement, cloning, and System.IO.Compression provider scenarios.
src/SharpCompress/Writers/Zip/ZipWriterOptions.cs Adds Providers to zip writer options and copies it from generic options.
src/SharpCompress/Writers/Zip/ZipWriter.cs Uses provider registry for ZIP compression streams; introduces hook-based init for LZMA/PPMd.
src/SharpCompress/Writers/WriterOptionsExtensions.cs Adds WithProviders(...) helper for WriterOptions.
src/SharpCompress/Writers/WriterOptions.cs Adds Providers to generic writer options (defaulting to CompressionProviderRegistry.Default).
src/SharpCompress/Writers/Tar/TarWriterOptions.cs Adds Providers and copies from generic options.
src/SharpCompress/Writers/Tar/TarWriter.cs Uses provider registry to create compression stream; finalizes via IFinishable.
src/SharpCompress/Writers/GZip/GZipWriterOptions.cs Adds Providers and copies from generic options.
src/SharpCompress/Writers/GZip/GZipWriter.cs Creates gzip compression stream via provider registry instead of hard-coded internal stream construction.
src/SharpCompress/Readers/Zip/ZipReader.cs Passes Options.Providers into ZIP file parts for decompression.
src/SharpCompress/Readers/Zip/ZipReader.Async.cs Passes _options.Providers into streaming ZIP file parts for decompression.
src/SharpCompress/Readers/Tar/TarReader.cs Uses provider registry for tar wrapper decompression stream creation.
src/SharpCompress/Readers/ReaderOptionsExtensions.cs Adds WithProviders(...) helper for ReaderOptions.
src/SharpCompress/Readers/ReaderOptions.cs Adds Providers to reader options (defaulting to CompressionProviderRegistry.Default).
src/SharpCompress/Compressors/Providers/ZStandardCompressionProvider.cs Internal ZStandard provider implementation.
src/SharpCompress/Compressors/Providers/XzCompressionProvider.cs Internal XZ provider (decompress-only).
src/SharpCompress/Compressors/Providers/SystemGZipCompressionProvider.cs System.IO.Compression-based GZip provider.
src/SharpCompress/Compressors/Providers/SystemDeflateCompressionProvider.cs System.IO.Compression-based Deflate provider.
src/SharpCompress/Compressors/Providers/ShrinkCompressionProvider.cs Internal Shrink provider (decompress-only, context sizes required).
src/SharpCompress/Compressors/Providers/Reduce4CompressionProvider.cs Internal Reduce4 provider (decompress-only, context sizes required).
src/SharpCompress/Compressors/Providers/Reduce3CompressionProvider.cs Internal Reduce3 provider (decompress-only, context sizes required).
src/SharpCompress/Compressors/Providers/Reduce2CompressionProvider.cs Internal Reduce2 provider (decompress-only, context sizes required).
src/SharpCompress/Compressors/Providers/Reduce1CompressionProvider.cs Internal Reduce1 provider (decompress-only, context sizes required).
src/SharpCompress/Compressors/Providers/PpmdCompressingProvider.cs Internal PPMd provider implementing ICompressionProviderHooks.
src/SharpCompress/Compressors/Providers/LzwCompressionProvider.cs Internal LZW provider (decompress-only).
src/SharpCompress/Compressors/Providers/LzmaCompressingProvider.cs Internal LZMA provider implementing ICompressionProviderHooks.
src/SharpCompress/Compressors/Providers/LZipCompressionProvider.cs Internal LZip provider.
src/SharpCompress/Compressors/Providers/GZipCompressionProvider.cs Internal GZip provider.
src/SharpCompress/Compressors/Providers/ExplodeCompressionProvider.cs Internal Explode provider (decompress-only, context required).
src/SharpCompress/Compressors/Providers/DeflateCompressionProvider.cs Internal Deflate provider.
src/SharpCompress/Compressors/Providers/Deflate64CompressionProvider.cs Internal Deflate64 provider (decompress-only).
src/SharpCompress/Compressors/Providers/BZip2CompressionProvider.cs Internal BZip2 provider.
src/SharpCompress/Compressors/LZMA/LZipStream.cs Implements IFinishable for generic finalization.
src/SharpCompress/Compressors/IFinishable.cs New interface for streams needing explicit finalization.
src/SharpCompress/Compressors/ICompressionProviderHooks.cs Hook interface for pre/properties/post data patterns (e.g., LZMA/PPMd in Zip).
src/SharpCompress/Compressors/ICompressionProvider.cs New provider abstraction for compress/decompress stream creation.
src/SharpCompress/Compressors/CompressionProviderRegistry.cs New immutable registry with default internal providers and helper methods.
src/SharpCompress/Compressors/CompressionContext.cs New context record carrying sizes/properties/format options for providers.
src/SharpCompress/Compressors/BZip2/BZip2Stream.cs Implements IFinishable for generic finalization.
src/SharpCompress/Common/Zip/ZipFilePart.cs Uses provider registry + CompressionContext for ZIP entry decompression.
src/SharpCompress/Common/Zip/StreamingZipFilePart.cs Accepts provider registry and passes through to base ZIP part.
src/SharpCompress/Common/Zip/SeekableZipFilePart.cs Accepts provider registry and passes through to base ZIP part.
src/SharpCompress/Common/Options/IWriterOptions.cs Adds Providers to writer options interface.
src/SharpCompress/Common/Options/IReaderOptions.cs Adds Providers to reader options interface.
src/SharpCompress/Common/GZip/GZipFilePart.cs Accepts provider registry for gzip payload decompression stream creation.
src/SharpCompress/Common/GZip/GZipFilePart.Async.cs Async create path accepts provider registry.
src/SharpCompress/Common/GZip/GZipEntry.cs Threads options.Providers into GZipFilePart.Create.
src/SharpCompress/Common/GZip/GZipEntry.Async.cs Threads options.Providers into GZipFilePart.CreateAsync.
src/SharpCompress/Archives/Zip/ZipArchive.cs Passes ReaderOptions.Providers into seekable ZIP parts.
src/SharpCompress/Archives/Zip/ZipArchive.Async.cs Passes ReaderOptions.Providers into seekable ZIP parts (async).
src/SharpCompress/Archives/GZip/GZipArchive.cs Passes ReaderOptions.Providers into GZipFilePart.Create.
src/SharpCompress/Archives/GZip/GZipArchive.Async.cs Passes ReaderOptions.Providers into GZipFilePart.CreateAsync.
docs/USAGE.md Adds usage guide for custom compression providers.
docs/API.md Documents Providers registry and hook contract.
README.md Adds a high-level overview and links for custom compression providers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +121 to +130
// Get the compression type and providers
var compressionType = ToCompressionType(method);
var providers = GetProviders();

// Build context with header information
var context = new CompressionContext
{
InputSize = Header.CompressedSize,
OutputSize = Header.UncompressedSize,
CanSeek = stream.CanSeek,
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ZipFilePart.cs still imports a number of compressor implementation namespaces (BZip2/Deflate/Deflate64/Explode/LZMA/PPMd/Reduce/Shrink/Xz/ZStandard), but the refactored implementation now resolves decompression via CompressionProviderRegistry and no longer references those types. With TreatWarningsAsErrors enabled, the resulting CS8019 warnings will fail the build; remove the unused using directives.

Copilot uses AI. Check for mistakes.
Comment on lines 8 to 11
using SharpCompress.Common.Zip;
using SharpCompress.Common.Zip.Headers;
using SharpCompress.Compressors;

Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ZipReader.Async.cs adds using SharpCompress.Compressors;, but this file doesn’t reference any types from that namespace (it only accesses _options.Providers). With TreatWarningsAsErrors enabled, this will trigger CS8019 and fail the build; remove the unused using directive.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,44 @@
using System;
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CompressionContext.cs includes using System; which is unused in this file. With TreatWarningsAsErrors enabled, this will fail the build (CS8019). Remove the unused using directive.

Suggested change
using System;

Copilot uses AI. Check for mistakes.
Comment on lines +22 to 30
// Use the configured compression providers
var providers = WriterOptions.Providers;

// Create the GZip stream using the provider
var compressionStream = providers.CreateCompressStream(
CompressionType.GZip,
destination,
WriterOptions.CompressionLevel
);
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GZipWriter used to pass WriterOptions.ArchiveEncoding.GetEncoding() into the internal SharpCompress.Compressors.Deflate.GZipStream constructor. With the new provider-based creation, internal gzip streams will always use the default UTF-8 encoding, changing the bytes written for the header filename/comment when a non-default ArchiveEncoding is configured. Consider using the provider overload that accepts a CompressionContext (e.g., pass the encoding via context.FormatOptions or a dedicated field) and update GZipCompressionProvider to honor it by calling the 4-arg GZipStream constructor.

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +65
internal override Stream GetCompressedStream()
{
//GZip uses Deflate compression, at this point we need a deflate stream
return _compressionProviders.CreateDecompressStream(CompressionType.Deflate, _stream);
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GZipFilePart.GetCompressedStream() always resolves CompressionType.Deflate from the provider registry. That means swapping the CompressionType.GZip provider (e.g., to SystemGZipCompressionProvider) will not affect reading .gz archives via GZipArchive/GZipEntry; only replacing the Deflate provider would. If the intent is that .gz reading honors the GZip provider, this needs a different integration point (or the docs should explicitly note that .gz uses the Deflate provider).

Copilot uses AI. Check for mistakes.
Comment on lines +424 to 427
var providers = writer.WriterOptions.Providers;

switch (zipCompressionMethod)
{
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After refactoring to provider-based compression, ZipWriter.cs no longer references several compression-implementation types directly, but the corresponding using SharpCompress.Compressors.* directives at the top of the file remain. With warnings treated as errors, the resulting “unnecessary using directive” warnings (CS8019) will fail the build; remove any now-unused compressor usings (e.g., BZip2/Deflate/LZMA/ZStandard) and keep only the ones still needed (like PPMd if referenced).

Copilot uses AI. Check for mistakes.
Comment on lines +450 to +513
// Use ICompressionProviderHooks for complex initialization
var compressingProvider = providers.GetCompressingProvider(
CompressionType.LZMA
);
counting.Write(lzmaStream.Properties, 0, lzmaStream.Properties.Length);
if (compressingProvider is null)
{
throw new InvalidOperationException("LZMA compression provider not found.");
}

var context = new CompressionContext { CanSeek = originalStream.CanSeek };

// Write pre-compression data (magic bytes)
var preData = compressingProvider.GetPreCompressionData(context);
if (preData != null)
{
counting.Write(preData, 0, preData.Length);
}

// Create compression stream
var lzmaStream = compressingProvider.CreateCompressStream(
counting,
compressionLevel,
context
);

// Write compression properties
var props = compressingProvider.GetCompressionProperties(lzmaStream, context);
if (props != null)
{
counting.Write(props, 0, props.Length);
}

return lzmaStream;
}
case ZipCompressionMethod.PPMd:
{
counting.Write(writer.PpmdProperties.Properties, 0, 2);
return PpmdStream.Create(writer.PpmdProperties, counting, true);
// Use ICompressionProviderHooks for complex initialization
var compressingProvider = providers.GetCompressingProvider(
CompressionType.PPMd
);
if (compressingProvider is null)
{
throw new InvalidOperationException("PPMd compression provider not found.");
}

var context = new CompressionContext
{
CanSeek = originalStream.CanSeek,
FormatOptions = writer.PpmdProperties,
};

// Write pre-compression data (properties)
var preData = compressingProvider.GetPreCompressionData(context);
if (preData != null)
{
counting.Write(preData, 0, preData.Length);
}

// Create compression stream
return compressingProvider.CreateCompressStream(
counting,
compressionLevel,
context
);
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ZipWriter uses ICompressionProviderHooks for pre-stream bytes and properties, but never calls GetPostCompressionData(...). That makes it impossible for a custom provider to append required footer bytes after the compression stream completes, and also risks incorrect entry.Compressed sizing when such footers are needed. Consider capturing the selected hooks-provider + context and, in ZipWritingStream.Dispose, after disposing the compression stream but before reading counting.BytesWritten, write any post-compression bytes returned by the provider.

Copilot uses AI. Check for mistakes.
);

// If using internal GZipStream, set the encoding for header filename
if (compressionStream is GZipStream gzipStream)
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assignment to gzipStream is useless, since its value is never read.

Copilot uses AI. Check for mistakes.
{
var original = CompressionProviderRegistry.Default;
var customProvider = new DeflateCompressionProvider();
var modified = original.With(customProvider);
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assignment to modified is useless, since its value is never read.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings February 10, 2026 16:25
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 61 out of 61 changed files in this pull request and generated 9 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +17 to +31
public Stream CreateCompressStream(Stream destination, int compressionLevel)
{
var level = (CompressionLevel)compressionLevel;
return new GZipStream(destination, CompressionMode.Compress, level);
}

public Stream CreateCompressStream(
Stream destination,
int compressionLevel,
CompressionContext context
)
{
// Context not used for simple GZip compression
return CreateCompressStream(destination, compressionLevel);
}
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The internal GZipCompressionProvider always constructs SharpCompress.Compressors.Deflate.GZipStream with its default encoding (UTF-8). Since GZipWriter previously used WriterOptions.ArchiveEncoding, the provider should accept/consume encoding from CompressionContext (or similar) so callers can preserve non-UTF8 header encoding when needed.

Copilot uses AI. Check for mistakes.
FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor) || Header.IsZip64;

/// <summary>
/// Gets the compression provider registry, falling back to default if not set.
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doc comment says GetProviders() “falls back to default if not set”, but _compressionProviders is required by the constructor and the method just returns the field. Either implement an actual fallback (e.g., null/optional ctor param) or adjust the comment to match behavior.

Suggested change
/// Gets the compression provider registry, falling back to default if not set.
/// Gets the configured compression provider registry.

Copilot uses AI. Check for mistakes.
Comment on lines +63 to +67
foreach (var entry in archive.Entries.Where(e => !e.IsDirectory))
{
using var entryStream = entry.OpenEntryStream();
entryStream.CopyTo(Stream.Null);
}
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This foreach loop immediately maps its iteration variable to another variable - consider mapping the sequence explicitly using '.Select(...)'.

Copilot uses AI. Check for mistakes.
Comment on lines +37 to +41
foreach (var entry in archive.Entries.Where(e => !e.IsDirectory))
{
using var entryStream = entry.OpenEntryStream();
entryStream.CopyTo(Stream.Null);
}
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This foreach loop immediately maps its iteration variable to another variable - consider mapping the sequence explicitly using '.Select(...)'.

Copilot uses AI. Check for mistakes.
@adamhathcock adamhathcock force-pushed the adam/add-alternate-compressions branch from c4fb32a to 5fe248e Compare February 11, 2026 10:09
Copilot AI review requested due to automatic review settings February 11, 2026 10:24
@adamhathcock adamhathcock force-pushed the adam/add-alternate-compressions branch from 5fe248e to c4fb32a Compare February 11, 2026 10:24
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 61 out of 61 changed files in this pull request and generated 8 comments.

Comments suppressed due to low confidence (1)

tests/SharpCompress.Test/ReaderTests.cs:117

  • Second IsArchiveAsync call also opens a new FileStream without disposing it. Please ensure the stream is disposed (and ideally avoid opening the file twice).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

# Conflicts:
#	tests/SharpCompress.Performance/Benchmarks/TarBenchmarks.cs
#	tests/SharpCompress.Performance/Benchmarks/ZipBenchmarks.cs
#	tests/SharpCompress.Performance/baseline-results.md
Copilot AI review requested due to automatic review settings February 12, 2026 17:03
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 81 out of 82 changed files in this pull request and generated 23 comments.

Comments suppressed due to low confidence (1)

tests/SharpCompress.Test/ReaderTests.cs:116

  • IsArchiveAsync is called with new FileInfo(testArchive).OpenRead() but the stream is not disposed. Use a using/await using to avoid leaking file handles in tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

using System.IO;
using SharpCompress.Common.Zip.Headers;
using SharpCompress.Compressors.Deflate;
using SharpCompress.Compressors;
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using SharpCompress.Compressors; appears unused in this file and may trigger CS8019 under warnings-as-errors. Remove the unused using directive.

Suggested change
using SharpCompress.Compressors;

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 28
using SharpCompress.Common;
using SharpCompress.Compressors;
using SharpCompress.Providers;

namespace SharpCompress.Common.Options;

/// <summary>
/// Options for configuring writer behavior when creating archives.
/// </summary>
public interface IWriterOptions : IStreamOptions, IEncodingOptions, IProgressOptions
{
/// <summary>
/// The compression type to use for the archive.
/// </summary>
CompressionType CompressionType { get; init; }

/// <summary>
/// The compression level to be used when the compression type supports variable levels.
/// </summary>
int CompressionLevel { get; init; }

/// <summary>
/// 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 Providers { get; init; }
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using SharpCompress.Compressors; appears unused in this file and will trigger CS8019 (unnecessary using directive). Since the repo treats warnings as errors, this can break the build; remove the unused using.

Suggested change
using SharpCompress.Common;
using SharpCompress.Compressors;
using SharpCompress.Providers;
namespace SharpCompress.Common.Options;
/// <summary>
/// Options for configuring writer behavior when creating archives.
/// </summary>
public interface IWriterOptions : IStreamOptions, IEncodingOptions, IProgressOptions
{
/// <summary>
/// The compression type to use for the archive.
/// </summary>
CompressionType CompressionType { get; init; }
/// <summary>
/// The compression level to be used when the compression type supports variable levels.
/// </summary>
int CompressionLevel { get; init; }
/// <summary>
/// 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 Providers { get; init; }
}
using SharpCompress.Common;
using SharpCompress.Providers;
namespace SharpCompress.Common.Options;
/// <summary>
/// Options for configuring writer behavior when creating archives.
/// </summary>
public interface IWriterOptions : IStreamOptions, IEncodingOptions, IProgressOptions
{
/// <summary>
/// The compression type to use for the archive.
/// </summary>
CompressionType CompressionType { get; init; }
/// <summary>
/// The compression level to be used when the compression type supports variable levels.
/// </summary>
int CompressionLevel { get; init; }
/// <summary>
/// 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 Providers { get; init; }
}

Copilot uses AI. Check for mistakes.
Comment on lines +69 to +73
CompressionContext context,
CancellationToken cancellationToken = default
)
{
return CreateCompressStreamAsync(destination, compressionLevel, cancellationToken);
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default CreateCompressStreamAsync(..., CompressionContext, ...) implementation ignores the provided context and delegates to the non-context overload. This breaks providers that require context (e.g., LZMA needs CanSeek, PPMd may need FormatOptions) when used via the async context overload. The default implementation should delegate to the synchronous context overload (or call a context-aware async override) so context is honored.

Copilot uses AI. Check for mistakes.
Comment on lines +22 to +27
/// <summary>
/// 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 Providers { get; init; }
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding Providers to this public options interface is a breaking change for any external implementations of IWriterOptions (they now must add a new init property). If preserving binary/source compatibility is important, consider introducing a separate interface (e.g., ICompressionProviderOptions) or providing an adapter/default implementation path that doesn’t require all implementers to update immediately.

Copilot uses AI. Check for mistakes.
using System;
using SharpCompress.Common;
using SharpCompress.Common.Options;
using SharpCompress.Compressors;
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using SharpCompress.Compressors; is not referenced in this file and can trigger CS8019 (unnecessary using directive). Given warnings-as-errors, remove the unused using to avoid breaking builds.

Copilot uses AI. Check for mistakes.
using System;
using SharpCompress.Common;
using SharpCompress.Common.Options;
using SharpCompress.Compressors;
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using SharpCompress.Compressors; is unused in this file and can trigger CS8019. With warnings-as-errors, remove the unused using to keep builds green.

Copilot uses AI. Check for mistakes.
using SharpCompress.Common;
using SharpCompress.Common.Options;
using SharpCompress.Common.Tar.Headers;
using SharpCompress.Compressors;
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using SharpCompress.Compressors; does not appear to be used in this file (CompressionType comes from SharpCompress.Common). This will trigger CS8019 under warnings-as-errors; remove the unused using.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings February 13, 2026 12:46
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 97 out of 98 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

)
{
var data = Encoding.UTF8.GetBytes("zip async provider usage");
writer.Write("test.txt", new MemoryStream(data));
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disposable 'MemoryStream' is created but not disposed.

Copilot uses AI. Check for mistakes.
)
{
var data = Encoding.UTF8.GetBytes("hook provider");
writer.Write("test.txt", new MemoryStream(data));
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disposable 'MemoryStream' is created but not disposed.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants